mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-08-21 18:28:47 -04:00
Merge pull request #377 from bhackel/gesture-improvement
Gesture improvement
This commit is contained in:
@@ -372,7 +372,9 @@ static const NSInteger YTLiteSection = 789;
|
|||||||
createSectionGestureSelector(@"BOTTOM_SECTION", @"playerGestureBottomSelection"),
|
createSectionGestureSelector(@"BOTTOM_SECTION", @"playerGestureBottomSelection"),
|
||||||
// Pickers for configuration settings
|
// Pickers for configuration settings
|
||||||
deadzonePicker,
|
deadzonePicker,
|
||||||
sensitivityPicker
|
sensitivityPicker,
|
||||||
|
// Toggle for haptic feedback
|
||||||
|
BASIC_SWITCH(LOC(@"PLAYER_GESTURES_HAPTIC_FEEDBACK"), nil, @"playerGesturesHapticFeedback_enabled"),
|
||||||
];
|
];
|
||||||
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Player Gestures (Beta)") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
YTSettingsPickerViewController *picker = [[%c(YTSettingsPickerViewController) alloc] initWithNavTitle:LOC(@"Player Gestures (Beta)") pickerSectionTitle:nil rows:rows selectedItemIndex:NSNotFound parentResponder:[self parentResponder]];
|
||||||
[settingsViewController pushViewController:picker];
|
[settingsViewController pushViewController:picker];
|
||||||
|
19
YTLitePlus.h
19
YTLitePlus.h
@@ -48,6 +48,7 @@
|
|||||||
#import "Tweaks/YouTubeHeader/YTWatchLayerViewController.h"
|
#import "Tweaks/YouTubeHeader/YTWatchLayerViewController.h"
|
||||||
#import "Tweaks/YouTubeHeader/YTPageStyleController.h"
|
#import "Tweaks/YouTubeHeader/YTPageStyleController.h"
|
||||||
#import "Tweaks/YouTubeHeader/YTRightNavigationButtons.h"
|
#import "Tweaks/YouTubeHeader/YTRightNavigationButtons.h"
|
||||||
|
#import "Tweaks/YouTubeHeader/YTInlinePlayerBarView.h"
|
||||||
|
|
||||||
#define LOC(x) [tweakBundle localizedStringForKey:x value:nil table:nil]
|
#define LOC(x) [tweakBundle localizedStringForKey:x value:nil table:nil]
|
||||||
#define YT_BUNDLE_ID @"com.google.ios.youtube"
|
#define YT_BUNDLE_ID @"com.google.ios.youtube"
|
||||||
@@ -155,6 +156,10 @@ typedef NS_ENUM(NSUInteger, GestureSection) {
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
// Player Gestures - @bhackel
|
// Player Gestures - @bhackel
|
||||||
|
@interface YTFineScrubberFilmstripView : UIView
|
||||||
|
@end
|
||||||
|
@interface YTFineScrubberFilmstripCollectionView : UICollectionView
|
||||||
|
@end
|
||||||
@interface YTPlayerViewController (YTLitePlus) <UIGestureRecognizerDelegate>
|
@interface YTPlayerViewController (YTLitePlus) <UIGestureRecognizerDelegate>
|
||||||
@property (nonatomic, retain) UIPanGestureRecognizer *YTLitePlusPanGesture;
|
@property (nonatomic, retain) UIPanGestureRecognizer *YTLitePlusPanGesture;
|
||||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
|
||||||
@@ -164,6 +169,20 @@ typedef NS_ENUM(NSUInteger, GestureSection) {
|
|||||||
@interface MPVolumeController : NSObject
|
@interface MPVolumeController : NSObject
|
||||||
@property (nonatomic, assign, readwrite) float volumeValue;
|
@property (nonatomic, assign, readwrite) float volumeValue;
|
||||||
@end
|
@end
|
||||||
|
@interface YTPlayerBarController (YTLitePlus)
|
||||||
|
- (void)didScrub:(UIPanGestureRecognizer *)gestureRecognizer;
|
||||||
|
- (void)startScrubbing;
|
||||||
|
- (void)didScrubToPoint:(CGPoint)point;
|
||||||
|
- (void)endScrubbingForSeekSource:(int)seekSource;
|
||||||
|
@end
|
||||||
|
@interface YTMainAppVideoPlayerOverlayViewController (YTLitePlus)
|
||||||
|
@property (nonatomic, strong, readwrite) YTPlayerBarController *playerBarController;
|
||||||
|
@end
|
||||||
|
@interface YTInlinePlayerBarContainerView (YTLitePlus)
|
||||||
|
@property UIPanGestureRecognizer *scrubGestureRecognizer;
|
||||||
|
@property (nonatomic, strong, readwrite) YTFineScrubberFilmstripView *fineScrubberFilmstrip;
|
||||||
|
- (CGFloat)scrubXForScrubRange:(CGFloat)scrubRange;
|
||||||
|
@end
|
||||||
|
|
||||||
// Hide Collapse Button - @arichornlover
|
// Hide Collapse Button - @arichornlover
|
||||||
@interface YTMainAppControlsOverlayView (YTLitePlus)
|
@interface YTMainAppControlsOverlayView (YTLitePlus)
|
||||||
|
299
YTLitePlus.xm
299
YTLitePlus.xm
@@ -641,7 +641,7 @@ BOOL isTabSelected = NO;
|
|||||||
%end
|
%end
|
||||||
|
|
||||||
// Gestures - @bhackel
|
// Gestures - @bhackel
|
||||||
%group playerGestures
|
%group gPlayerGestures
|
||||||
%hook YTWatchLayerViewController
|
%hook YTWatchLayerViewController
|
||||||
// invoked when the player view controller is either created or destroyed
|
// invoked when the player view controller is either created or destroyed
|
||||||
- (void)watchController:(YTWatchController *)watchController didSetPlayerViewController:(YTPlayerViewController *)playerViewController {
|
- (void)watchController:(YTWatchController *)watchController didSetPlayerViewController:(YTPlayerViewController *)playerViewController {
|
||||||
@@ -662,14 +662,22 @@ BOOL isTabSelected = NO;
|
|||||||
%hook YTPlayerViewController
|
%hook YTPlayerViewController
|
||||||
// the pan gesture that will be created and added to the player view
|
// the pan gesture that will be created and added to the player view
|
||||||
%property (nonatomic, retain) UIPanGestureRecognizer *YTLitePlusPanGesture;
|
%property (nonatomic, retain) UIPanGestureRecognizer *YTLitePlusPanGesture;
|
||||||
|
/**
|
||||||
|
* This method is called when the pan gesture is started, changed, or ended. It handles
|
||||||
|
* 12 different possible cases depending on the configuration: 3 zones with 4 choices
|
||||||
|
* for each zone. The zones are horizontal sections that divide the player into
|
||||||
|
* 3 equal parts. The choices are volume, brightness, seek, and disabled.
|
||||||
|
* There is also a deadzone that can be configured in the settings.
|
||||||
|
* There are 4 logical states: initial, changed in deadzone, changed, end.
|
||||||
|
*/
|
||||||
%new
|
%new
|
||||||
- (void)YTLitePlusHandlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer {
|
- (void)YTLitePlusHandlePanGesture:(UIPanGestureRecognizer *)panGestureRecognizer {
|
||||||
// Haptic feedback generator
|
// Haptic feedback generator
|
||||||
static UIImpactFeedbackGenerator *feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
|
static UIImpactFeedbackGenerator *feedbackGenerator;
|
||||||
// Variables for storing initial values to be adjusted
|
// Variables for storing initial values to be adjusted
|
||||||
static float initialVolume;
|
static float initialVolume;
|
||||||
static float initialBrightness;
|
static float initialBrightness;
|
||||||
static CGFloat currentTime;
|
static CGFloat initialTime;
|
||||||
// Flag to determine if the pan gesture is valid
|
// Flag to determine if the pan gesture is valid
|
||||||
static BOOL isValidHorizontalPan = NO;
|
static BOOL isValidHorizontalPan = NO;
|
||||||
// Variable to store the section of the screen the gesture is in
|
// Variable to store the section of the screen the gesture is in
|
||||||
@@ -678,62 +686,128 @@ BOOL isTabSelected = NO;
|
|||||||
static CGPoint startLocation;
|
static CGPoint startLocation;
|
||||||
// Variable to track the X translation when exiting the deadzone
|
// Variable to track the X translation when exiting the deadzone
|
||||||
static CGFloat deadzoneStartingXTranslation;
|
static CGFloat deadzoneStartingXTranslation;
|
||||||
|
// Variable to track the X translation of the pan gesture after exiting the deadzone
|
||||||
|
static CGFloat adjustedTranslationX;
|
||||||
|
// Variable used to smooth out the X translation
|
||||||
|
static CGFloat smoothedTranslationX = 0;
|
||||||
|
// Constant for the filter constant to change responsiveness
|
||||||
|
static const CGFloat filterConstant = 0.1;
|
||||||
// Constant for the deadzone radius that can be changed in the settings
|
// Constant for the deadzone radius that can be changed in the settings
|
||||||
static CGFloat deadzoneRadius = (CGFloat)GetFloat(@"playerGesturesDeadzone");
|
static CGFloat deadzoneRadius = (CGFloat)GetFloat(@"playerGesturesDeadzone");
|
||||||
// Constant for the sensitivity factor that can be changed in the settings
|
// Constant for the sensitivity factor that can be changed in the settings
|
||||||
static CGFloat sensitivityFactor = (CGFloat)GetFloat(@"playerGesturesSensitivity");
|
static CGFloat sensitivityFactor = (CGFloat)GetFloat(@"playerGesturesSensitivity");
|
||||||
|
// Objects for modifying the system volume
|
||||||
/***** Helper functions *****/
|
static MPVolumeView *volumeView;
|
||||||
// Helper function to adjust brightness
|
static UISlider *volumeViewSlider;
|
||||||
void (^adjustBrightness)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat initialBrightness) {
|
// Get objects that should only be initialized once
|
||||||
float newBrightness = initialBrightness + ((translationX / 1000.0) * sensitivityFactor);
|
static dispatch_once_t onceToken;
|
||||||
newBrightness = fmaxf(fminf(newBrightness, 1.0), 0.0);
|
dispatch_once(&onceToken, ^{
|
||||||
[[UIScreen mainScreen] setBrightness:newBrightness];
|
volumeView = [[MPVolumeView alloc] init];
|
||||||
};
|
|
||||||
// Helper function to adjust volume
|
|
||||||
void (^adjustVolume)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat initialVolume) {
|
|
||||||
float newVolume = initialVolume + ((translationX / 1000.0) * sensitivityFactor);
|
|
||||||
newVolume = fmaxf(fminf(newVolume, 1.0), 0.0);
|
|
||||||
// https://stackoverflow.com/questions/50737943/how-to-change-volume-programmatically-on-ios-11-4
|
|
||||||
MPVolumeView *volumeView = [[MPVolumeView alloc] init];
|
|
||||||
UISlider *volumeViewSlider = nil;
|
|
||||||
for (UIView *view in volumeView.subviews) {
|
for (UIView *view in volumeView.subviews) {
|
||||||
if ([view isKindOfClass:[UISlider class]]) {
|
if ([view isKindOfClass:[UISlider class]]) {
|
||||||
volumeViewSlider = (UISlider *)view;
|
volumeViewSlider = (UISlider *)view;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleMedium];
|
||||||
|
});
|
||||||
|
// Get objects used to seek nicely in the video player
|
||||||
|
static YTMainAppVideoPlayerOverlayViewController *mainVideoPlayerController = (YTMainAppVideoPlayerOverlayViewController *)self.childViewControllers.firstObject;
|
||||||
|
static YTPlayerBarController *playerBarController = mainVideoPlayerController.playerBarController;
|
||||||
|
static YTInlinePlayerBarContainerView *playerBar = playerBarController.playerBar;
|
||||||
|
|
||||||
|
/***** Helper functions for adjusting player state *****/
|
||||||
|
// Helper function to adjust brightness
|
||||||
|
void (^adjustBrightness)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat initialBrightness) {
|
||||||
|
float brightnessSensitivityFactor = 3;
|
||||||
|
float newBrightness = initialBrightness + ((translationX / 1000.0) * sensitivityFactor * brightnessSensitivityFactor);
|
||||||
|
newBrightness = fmaxf(fminf(newBrightness, 1.0), 0.0);
|
||||||
|
[[UIScreen mainScreen] setBrightness:newBrightness];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to adjust volume
|
||||||
|
void (^adjustVolume)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat initialVolume) {
|
||||||
|
float volumeSensitivityFactor = 3.0;
|
||||||
|
float newVolume = initialVolume + ((translationX / 1000.0) * sensitivityFactor * volumeSensitivityFactor);
|
||||||
|
newVolume = fmaxf(fminf(newVolume, 1.0), 0.0);
|
||||||
|
// Improve smoothness - ignore if the volume is within 0.01 of the current volume
|
||||||
|
CGFloat currentVolume = [[AVAudioSession sharedInstance] outputVolume];
|
||||||
|
if (fabs(newVolume - currentVolume) < 0.01 && currentVolume > 0.01 && currentVolume < 0.99) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// https://stackoverflow.com/questions/50737943/how-to-change-volume-programmatically-on-ios-11-4
|
||||||
|
|
||||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||||
volumeViewSlider.value = newVolume;
|
volumeViewSlider.value = newVolume;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to adjust seek time
|
// Helper function to adjust seek time
|
||||||
void (^adjustSeek)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat currentTime) {
|
void (^adjustSeek)(CGFloat, CGFloat) = ^(CGFloat translationX, CGFloat initialTime) {
|
||||||
// Calculate a seek fraction based on the horizontal translation
|
// Get the location in view for the current video time
|
||||||
CGFloat totalDuration = self.currentVideoTotalMediaTime;
|
CGFloat totalTime = self.currentVideoTotalMediaTime;
|
||||||
CGFloat viewWidth = self.view.bounds.size.width;
|
CGFloat videoFraction = initialTime / totalTime;
|
||||||
CGFloat seekFraction = (translationX / viewWidth);
|
CGFloat initialTimeXPosition = [playerBar scrubXForScrubRange:videoFraction];
|
||||||
// Seek to the new time based on the calculated offset
|
// Calculate the new seek X position
|
||||||
CGFloat sensitivityFactor = 1; // Adjust this value to make seeking less sensitive
|
CGFloat sensitivityFactor = 1; // Adjust this value to make seeking more/less sensitive
|
||||||
seekFraction = sensitivityFactor * seekFraction;
|
CGFloat newSeekXPosition = initialTimeXPosition + translationX * sensitivityFactor;
|
||||||
CGFloat seekTime = currentTime + totalDuration * seekFraction;
|
// Create a CGPoint using this new X position
|
||||||
[self seekToTime:seekTime];
|
CGPoint newSeekPoint = CGPointMake(newSeekXPosition, 0);
|
||||||
|
// Send this to a seek method in the player bar controller
|
||||||
|
[playerBarController didScrubToPoint:newSeekPoint];
|
||||||
};
|
};
|
||||||
// Helper function to run the selected gesture action
|
|
||||||
void (^runSelectedGesture)(NSString*, CGFloat, CGFloat, CGFloat, CGFloat)
|
// Helper function to smooth out the X translation
|
||||||
= ^(NSString *sectionKey, CGFloat translationX, CGFloat initialBrightness, CGFloat initialVolume, CGFloat currentTime) {
|
CGFloat (^applyLowPassFilter)(CGFloat) = ^(CGFloat newTranslation) {
|
||||||
|
smoothedTranslationX = filterConstant * newTranslation + (1 - filterConstant) * smoothedTranslationX;
|
||||||
|
return smoothedTranslationX;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***** Helper functions for running the selected gesture *****/
|
||||||
|
// Helper function to run any setup for the selected gesture mode
|
||||||
|
void (^runSelectedGestureSetup)(NSString*) = ^(NSString *sectionKey) {
|
||||||
|
// Determine the selected gesture mode using the section key
|
||||||
|
GestureMode selectedGestureMode = (GestureMode)GetInteger(sectionKey);
|
||||||
|
// Handle the setup based on the selected mode
|
||||||
|
switch (selectedGestureMode) {
|
||||||
|
case GestureModeVolume:
|
||||||
|
initialVolume = [[AVAudioSession sharedInstance] outputVolume];
|
||||||
|
break;
|
||||||
|
case GestureModeBrightness:
|
||||||
|
initialBrightness = [UIScreen mainScreen].brightness;
|
||||||
|
break;
|
||||||
|
case GestureModeSeek:
|
||||||
|
initialTime = self.currentVideoMediaTime;
|
||||||
|
// Start a seek action
|
||||||
|
[playerBarController startScrubbing];
|
||||||
|
break;
|
||||||
|
case GestureModeDisabled:
|
||||||
|
// Do nothing if the gesture is disabled
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Show an alert if the gesture mode is invalid
|
||||||
|
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Invalid Gesture Mode" message:@"Please report this bug." preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
|
||||||
|
[alertController addAction:okAction];
|
||||||
|
[self presentViewController:alertController animated:YES completion:nil];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function to run the selected gesture action when the gesture changes
|
||||||
|
void (^runSelectedGestureChanged)(NSString*) = ^(NSString *sectionKey) {
|
||||||
// Determine the selected gesture mode using the section key
|
// Determine the selected gesture mode using the section key
|
||||||
GestureMode selectedGestureMode = (GestureMode)GetInteger(sectionKey);
|
GestureMode selectedGestureMode = (GestureMode)GetInteger(sectionKey);
|
||||||
// Handle the gesture action based on the selected mode
|
// Handle the gesture action based on the selected mode
|
||||||
switch (selectedGestureMode) {
|
switch (selectedGestureMode) {
|
||||||
case GestureModeVolume:
|
case GestureModeVolume:
|
||||||
adjustVolume(translationX, initialVolume);
|
adjustVolume(adjustedTranslationX, initialVolume);
|
||||||
break;
|
break;
|
||||||
case GestureModeBrightness:
|
case GestureModeBrightness:
|
||||||
adjustBrightness(translationX, initialBrightness);
|
adjustBrightness(adjustedTranslationX, initialBrightness);
|
||||||
break;
|
break;
|
||||||
case GestureModeSeek:
|
case GestureModeSeek:
|
||||||
adjustSeek(translationX, currentTime);
|
adjustSeek(adjustedTranslationX, initialTime);
|
||||||
break;
|
break;
|
||||||
case GestureModeDisabled:
|
case GestureModeDisabled:
|
||||||
// Do nothing if the gesture is disabled
|
// Do nothing if the gesture is disabled
|
||||||
@@ -747,6 +821,31 @@ BOOL isTabSelected = NO;
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper function to run the selected gesture action when the gesture ends
|
||||||
|
void (^runSelectedGestureEnded)(NSString*) = ^(NSString *sectionKey) {
|
||||||
|
// Determine the selected gesture mode using the section key
|
||||||
|
GestureMode selectedGestureMode = (GestureMode)GetInteger(sectionKey);
|
||||||
|
// Handle the gesture action based on the selected mode
|
||||||
|
switch (selectedGestureMode) {
|
||||||
|
case GestureModeVolume:
|
||||||
|
break;
|
||||||
|
case GestureModeBrightness:
|
||||||
|
break;
|
||||||
|
case GestureModeSeek:
|
||||||
|
[playerBarController endScrubbingForSeekSource:0];
|
||||||
|
break;
|
||||||
|
case GestureModeDisabled:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Show an alert if the gesture mode is invalid
|
||||||
|
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Invalid Gesture Mode" message:@"Please report this bug." preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
|
||||||
|
[alertController addAction:okAction];
|
||||||
|
[self presentViewController:alertController animated:YES completion:nil];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
/***** End of Helper functions *****/
|
/***** End of Helper functions *****/
|
||||||
|
|
||||||
// Handle gesture based on current gesture state
|
// Handle gesture based on current gesture state
|
||||||
@@ -754,37 +853,29 @@ BOOL isTabSelected = NO;
|
|||||||
// Get the gesture's start position
|
// Get the gesture's start position
|
||||||
startLocation = [panGestureRecognizer locationInView:self.view];
|
startLocation = [panGestureRecognizer locationInView:self.view];
|
||||||
CGFloat viewHeight = self.view.bounds.size.height;
|
CGFloat viewHeight = self.view.bounds.size.height;
|
||||||
|
// Determine the section based on the start position by dividing the view into thirds
|
||||||
// Determine the section based on the start position
|
|
||||||
// by dividing the view into thirds
|
|
||||||
if (startLocation.y <= viewHeight / 3.0) {
|
if (startLocation.y <= viewHeight / 3.0) {
|
||||||
gestureSection = GestureSectionTop;
|
gestureSection = GestureSectionTop;
|
||||||
// Cancel the gesture if the mode is disabled
|
|
||||||
if (GetInteger(@"playerGestureTopSelection") == GestureModeDisabled) {
|
|
||||||
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (startLocation.y <= 2 * viewHeight / 3.0) {
|
} else if (startLocation.y <= 2 * viewHeight / 3.0) {
|
||||||
gestureSection = GestureSectionMiddle;
|
gestureSection = GestureSectionMiddle;
|
||||||
// Cancel the gesture if the mode is disabled
|
|
||||||
if (GetInteger(@"playerGestureMiddleSelection") == GestureModeDisabled) {
|
|
||||||
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if (startLocation.y <= viewHeight) {
|
} else if (startLocation.y <= viewHeight) {
|
||||||
gestureSection = GestureSectionBottom;
|
gestureSection = GestureSectionBottom;
|
||||||
// Cancel the gesture if the mode is disabled
|
|
||||||
if (GetInteger(@"playerGestureBottomSelection") == GestureModeDisabled) {
|
|
||||||
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
gestureSection = GestureSectionInvalid;
|
gestureSection = GestureSectionInvalid;
|
||||||
}
|
}
|
||||||
|
// Cancel the gesture if the chosen mode for this section is disabled
|
||||||
|
if ( ((gestureSection == GestureSectionTop) && (GetInteger(@"playerGestureTopSelection") == GestureModeDisabled))
|
||||||
|
|| ((gestureSection == GestureSectionMiddle) && (GetInteger(@"playerGestureMiddleSelection") == GestureModeDisabled))
|
||||||
|
|| ((gestureSection == GestureSectionBottom) && (GetInteger(@"playerGestureBottomSelection") == GestureModeDisabled))) {
|
||||||
|
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Deactive the activity flag
|
// Deactive the activity flag
|
||||||
isValidHorizontalPan = NO;
|
isValidHorizontalPan = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle changed gesture state by activating the gesture once it has exited the deadzone,
|
||||||
|
// and then adjusting the player based on the selected gesture mode
|
||||||
if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
|
if (panGestureRecognizer.state == UIGestureRecognizerStateChanged) {
|
||||||
// Determine if the gesture is predominantly horizontal
|
// Determine if the gesture is predominantly horizontal
|
||||||
CGPoint translation = [panGestureRecognizer translationInView:self.view];
|
CGPoint translation = [panGestureRecognizer translationInView:self.view];
|
||||||
@@ -799,12 +890,29 @@ BOOL isTabSelected = NO;
|
|||||||
// If outside the deadzone, activate the pan gesture and store the initial values
|
// If outside the deadzone, activate the pan gesture and store the initial values
|
||||||
isValidHorizontalPan = YES;
|
isValidHorizontalPan = YES;
|
||||||
deadzoneStartingXTranslation = translation.x;
|
deadzoneStartingXTranslation = translation.x;
|
||||||
initialBrightness = [UIScreen mainScreen].brightness;
|
adjustedTranslationX = 0;
|
||||||
initialVolume = [[AVAudioSession sharedInstance] outputVolume];
|
smoothedTranslationX = 0;
|
||||||
currentTime = self.currentVideoMediaTime;
|
// Run the setup for the selected gesture mode
|
||||||
|
switch (gestureSection) {
|
||||||
|
case GestureSectionTop:
|
||||||
|
runSelectedGestureSetup(@"playerGestureTopSelection");
|
||||||
|
break;
|
||||||
|
case GestureSectionMiddle:
|
||||||
|
runSelectedGestureSetup(@"playerGestureMiddleSelection");
|
||||||
|
break;
|
||||||
|
case GestureSectionBottom:
|
||||||
|
runSelectedGestureSetup(@"playerGestureBottomSelection");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// If the section is invalid, cancel the gesture
|
||||||
|
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
||||||
|
break;
|
||||||
|
}
|
||||||
// Provide haptic feedback to indicate a gesture start
|
// Provide haptic feedback to indicate a gesture start
|
||||||
[feedbackGenerator prepare];
|
if (IS_ENABLED(@"playerGesturesHapticFeedback_enabled")) {
|
||||||
[feedbackGenerator impactOccurred];
|
[feedbackGenerator prepare];
|
||||||
|
[feedbackGenerator impactOccurred];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Cancel the gesture if the translation is not horizontal
|
// Cancel the gesture if the translation is not horizontal
|
||||||
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
||||||
@@ -814,34 +922,72 @@ BOOL isTabSelected = NO;
|
|||||||
|
|
||||||
// Handle the gesture based on the identified section
|
// Handle the gesture based on the identified section
|
||||||
if (isValidHorizontalPan) {
|
if (isValidHorizontalPan) {
|
||||||
// Adjust the X translation based on the value hit after
|
// Adjust the X translation based on the value hit after exiting the deadzone
|
||||||
// exiting the deadzone
|
adjustedTranslationX = translation.x - deadzoneStartingXTranslation;
|
||||||
CGFloat adjustedTranslationX = translation.x - deadzoneStartingXTranslation;
|
// Smooth the translation value
|
||||||
|
adjustedTranslationX = applyLowPassFilter(adjustedTranslationX);
|
||||||
// Pass the adjusted translation to the selected gesture
|
// Pass the adjusted translation to the selected gesture
|
||||||
if (gestureSection == GestureSectionTop) {
|
switch (gestureSection) {
|
||||||
runSelectedGesture(@"playerGestureTopSelection", adjustedTranslationX, initialBrightness, initialVolume, currentTime);
|
case GestureSectionTop:
|
||||||
} else if (gestureSection == GestureSectionMiddle) {
|
runSelectedGestureChanged(@"playerGestureTopSelection");
|
||||||
runSelectedGesture(@"playerGestureMiddleSelection", adjustedTranslationX, initialBrightness, initialVolume, currentTime);
|
break;
|
||||||
} else if (gestureSection == GestureSectionBottom) {
|
case GestureSectionMiddle:
|
||||||
runSelectedGesture(@"playerGestureBottomSelection", adjustedTranslationX, initialBrightness, initialVolume, currentTime);
|
runSelectedGestureChanged(@"playerGestureMiddleSelection");
|
||||||
} else {
|
break;
|
||||||
// If the section is invalid, cancel the gesture
|
case GestureSectionBottom:
|
||||||
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
runSelectedGestureChanged(@"playerGestureBottomSelection");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// If the section is invalid, cancel the gesture
|
||||||
|
panGestureRecognizer.state = UIGestureRecognizerStateCancelled;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (panGestureRecognizer.state == UIGestureRecognizerStateEnded) {
|
|
||||||
if (isValidHorizontalPan) {
|
// Handle the gesture end state by running the selected gesture mode's end action
|
||||||
// Provide haptic feedback upon successful gesture recognition
|
if (panGestureRecognizer.state == UIGestureRecognizerStateEnded && isValidHorizontalPan) {
|
||||||
[feedbackGenerator prepare];
|
switch (gestureSection) {
|
||||||
[feedbackGenerator impactOccurred];
|
case GestureSectionTop:
|
||||||
|
runSelectedGestureEnded(@"playerGestureTopSelection");
|
||||||
|
break;
|
||||||
|
case GestureSectionMiddle:
|
||||||
|
runSelectedGestureEnded(@"playerGestureMiddleSelection");
|
||||||
|
break;
|
||||||
|
case GestureSectionBottom:
|
||||||
|
runSelectedGestureEnded(@"playerGestureBottomSelection");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
// Provide haptic feedback upon successful gesture recognition
|
||||||
|
// [feedbackGenerator prepare];
|
||||||
|
// [feedbackGenerator impactOccurred];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// allow the pan gesture to be recognized simultaneously with other gestures
|
// allow the pan gesture to be recognized simultaneously with other gestures
|
||||||
%new
|
%new
|
||||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||||
|
if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
||||||
|
// Do not allow this gesture to activate with the normal seek bar gesture
|
||||||
|
YTMainAppVideoPlayerOverlayViewController *mainVideoPlayerController = (YTMainAppVideoPlayerOverlayViewController *)self.childViewControllers.firstObject;
|
||||||
|
YTPlayerBarController *playerBarController = mainVideoPlayerController.playerBarController;
|
||||||
|
YTInlinePlayerBarContainerView *playerBar = playerBarController.playerBar;
|
||||||
|
if (otherGestureRecognizer == playerBar.scrubGestureRecognizer) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
// Do not allow this gesture to activate with the fine scrubber gesture
|
||||||
|
YTFineScrubberFilmstripView *fineScrubberFilmstrip = playerBar.fineScrubberFilmstrip;
|
||||||
|
if (!fineScrubberFilmstrip) {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
YTFineScrubberFilmstripCollectionView *filmstripCollectionView = [fineScrubberFilmstrip valueForKey:@"_filmstripCollectionView"];
|
||||||
|
if (filmstripCollectionView && otherGestureRecognizer == filmstripCollectionView.panGestureRecognizer) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
%end
|
%end
|
||||||
@@ -1156,7 +1302,7 @@ NSInteger pageStyle = 0;
|
|||||||
%init(gDisableEngagementOverlay);
|
%init(gDisableEngagementOverlay);
|
||||||
}
|
}
|
||||||
if (IsEnabled(@"playerGestures_enabled")) {
|
if (IsEnabled(@"playerGestures_enabled")) {
|
||||||
%init(playerGestures);
|
%init(gPlayerGestures);
|
||||||
}
|
}
|
||||||
if (IsEnabled(@"videoPlayerButton_enabled")) {
|
if (IsEnabled(@"videoPlayerButton_enabled")) {
|
||||||
%init(gVideoPlayerButton);
|
%init(gVideoPlayerButton);
|
||||||
@@ -1196,4 +1342,7 @@ NSInteger pageStyle = 0;
|
|||||||
if (![allKeys containsObject:@"playerGesturesSensitivity"]) {
|
if (![allKeys containsObject:@"playerGesturesSensitivity"]) {
|
||||||
[[NSUserDefaults standardUserDefaults] setFloat:1.0 forKey:@"playerGesturesSensitivity"];
|
[[NSUserDefaults standardUserDefaults] setFloat:1.0 forKey:@"playerGesturesSensitivity"];
|
||||||
}
|
}
|
||||||
|
if (![allKeys containsObject:@"playerGesturesHapticFeedback_enabled"]) {
|
||||||
|
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"playerGesturesHapticFeedback_enabled"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "خيارات تراكب ضوابط الفيديو";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "خيارات تراكب ضوابط الفيديو";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Опции за контрол на видеото";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Опции за контрол на видеото";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Overlay-Optionen für Videosteuerungen";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Overlay-Optionen für Videosteuerungen";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opciones de superposición de controles de vídeo";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opciones de superposición de controles de vídeo";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Options de l'overlay des contrôles vidéo";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Options de l'overlay des contrôles vidéo";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "動画コントロールオーバーレイの設定";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "動画コントロールオーバーレイの設定";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opções de Sobreposição de Controles de Vídeo";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opções de Sobreposição de Controles de Vídeo";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opțiuni Overlay Controale Video";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Opțiuni Overlay Controale Video";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
||||||
|
@@ -46,6 +46,7 @@ https://github.com/PoomSmart/Return-YouTube-Dislikes/tree/main/layout/Library/Ap
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Controls Overlay Options";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Kontrol Seç.";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "Video Kontrol Seç.";
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video player options
|
// Video player options
|
||||||
"VIDEO_PLAYER_OPTIONS" = "Tùy chọn trình phát video";
|
"VIDEO_PLAYER_OPTIONS" = "Tùy chọn trình phát video";
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
"TOP_SECTION" = "Top Section";
|
"TOP_SECTION" = "Top Section";
|
||||||
"MIDDLE_SECTION" = "Middle Section";
|
"MIDDLE_SECTION" = "Middle Section";
|
||||||
"BOTTOM_SECTION" = "Bottom Section";
|
"BOTTOM_SECTION" = "Bottom Section";
|
||||||
|
"PLAYER_GESTURES_HAPTIC_FEEDBACK" = "Enable Haptic Feedback";
|
||||||
|
|
||||||
// Video controls overlay options
|
// Video controls overlay options
|
||||||
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "影片區覆蓋按鈕設定";
|
"VIDEO_CONTROLS_OVERLAY_OPTIONS" = "影片區覆蓋按鈕設定";
|
||||||
|
Reference in New Issue
Block a user