Commit 5a3acda9 authored by Felix Paul Kühne's avatar Felix Paul Kühne

remote playback: split item deletion code into separate parent class

parent a9f45e41
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
* Felix Paul Kühne <fkuehne # videolan.org>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import <UIKit/UIKit.h>
@interface VLCDeletionCapableViewController : UIViewController
@property (nonatomic, weak) IBOutlet UIView *deleteHintView;
@property (nonatomic, readonly, nullable) NSIndexPath *indexPathToDelete;
@property (nonatomic, readonly, nullable) NSString *itemToDelete;
@end
/*****************************************************************************
* VLC for iOS
*****************************************************************************
* Copyright (c) 2015 VideoLAN. All rights reserved.
* $Id$
*
* Authors: Tobias Conradi <videolan # tobias-conradi.de>
* Felix Paul Kühne <fkuehne # videolan.org>
*
* Refer to the COPYING file of the official project for license.
*****************************************************************************/
#import "VLCDeletionCapableViewController.h"
@interface VLCDeletionCapableViewController ()
@property (nonatomic) UITapGestureRecognizer *playPausePressRecognizer;
@property (nonatomic) UITapGestureRecognizer *cancelRecognizer;
@property (nonatomic) NSIndexPath *currentlyFocusedIndexPath;
@property (nonatomic) NSTimer *hintTimer;
@end
@implementation VLCDeletionCapableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(startEditMode)];
recognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
recognizer.minimumPressDuration = 1.0;
[self.view addGestureRecognizer:recognizer];
UITapGestureRecognizer *cancelRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(endEditMode)];
cancelRecognizer.allowedPressTypes = @[@(UIPressTypeSelect),@(UIPressTypeMenu)];
self.cancelRecognizer = cancelRecognizer;
[self.view addGestureRecognizer:cancelRecognizer];
UITapGestureRecognizer *playPauseRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handlePlayPausePress)];
playPauseRecognizer.allowedPressTypes = @[@(UIPressTypePlayPause)];
self.playPausePressRecognizer = playPauseRecognizer;
[self.view addGestureRecognizer:playPauseRecognizer];
}
- (void)handlePlayPausePress
{
NSString *fileToDelete = self.itemToDelete;
if (fileToDelete == nil)
return;
NSIndexPath *indexPathToDelete = self.indexPathToDelete;
NSString *title = fileToDelete.lastPathComponent;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_DELETE", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * _Nonnull action) {
[self deleteFileAtIndex:indexPathToDelete];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_CANCEL", nil)
style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
self.editing = NO;
}];
[alertController addAction:deleteAction];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)deleteFileAtIndex:(NSIndexPath *)indexPathToDelete
{
// NO-OP, implemented by subclass
}
- (void)animateDeletHintToVisibility:(BOOL)visible
{
const NSTimeInterval duration = 0.5;
UIView *hintView = self.deleteHintView;
if (hintView.hidden) {
hintView.alpha = 0.0;
}
if (hintView.alpha == 0.0) {
hintView.hidden = NO;
}
const CGFloat targetAlpha = visible ? 1.0 : 0.0;
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
hintView.alpha = targetAlpha;
}
completion:^(BOOL finished) {
if (hintView.alpha == 0.0) {
hintView.hidden = YES;
}
}];
}
- (void)hintTimerFired:(NSTimer *)timer
{
const NSTimeInterval waitUntilHideInterval = 5.0;
NSNumber *userInfo = [timer userInfo];
BOOL shouldShow = [userInfo isKindOfClass:[NSNumber class]] && [userInfo boolValue];
[self animateDeletHintToVisibility:shouldShow];
if (shouldShow) {
[self.hintTimer invalidate];
self.hintTimer = [NSTimer scheduledTimerWithTimeInterval:waitUntilHideInterval target:self selector:@selector(hintTimerFired:) userInfo:@(NO) repeats:NO];
}
}
- (void)startEditMode
{
self.editing = YES;
}
- (void)endEditMode
{
self.editing = NO;
}
- (void)setEditing:(BOOL)editing
{
[super setEditing:editing];
if (editing) {
[self.hintTimer invalidate];
self.hintTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(hintTimerFired:) userInfo:@(YES) repeats:NO];
} else {
[self.hintTimer invalidate];
self.hintTimer = nil;
[self animateDeletHintToVisibility:NO];
}
self.cancelRecognizer.enabled = editing;
self.playPausePressRecognizer.enabled = editing;
}
@end
......@@ -10,9 +10,9 @@
*****************************************************************************/
#import <UIKit/UIKit.h>
#import "VLCRemoteBrowsingCollectionViewController.h"
#import "VLCDeletionCapableViewController.h"
@interface VLCRemotePlaybackViewController : UIViewController
@interface VLCRemotePlaybackViewController : VLCDeletionCapableViewController
@property (readwrite, nonatomic, weak) IBOutlet UILabel *httpServerLabel;
@property (readwrite, nonatomic, weak) IBOutlet UIButton *toggleHTTPServerButton;
......@@ -20,7 +20,6 @@
@property (readwrite, nonatomic, weak) IBOutlet UILabel *cachedMediaLabel;
@property (readwrite, nonatomic, weak) IBOutlet UILabel *cachedMediaLongLabel;
@property (readwrite, nonatomic, weak) IBOutlet UICollectionView *cachedMediaCollectionView;
@property (nonatomic, weak) IBOutlet UIView *deleteHintView;
- (IBAction)toggleHTTPServer:(id)sender;
......
......@@ -27,10 +27,7 @@ static NSString *const VLCWiggleAnimationKey = @"VLCWiggleAnimation";
Reachability *_reachability;
NSMutableArray<NSString *> *_discoveredFiles;
}
@property (nonatomic) UITapGestureRecognizer *playPausePressRecognizer;
@property (nonatomic) UITapGestureRecognizer *cancelRecognizer;
@property (nonatomic) NSIndexPath *currentlyFocusedIndexPath;
@property (nonatomic) NSTimer *hintTimer;
@end
......@@ -72,21 +69,6 @@ static NSString *const VLCWiggleAnimationKey = @"VLCWiggleAnimation";
[discoverer addObserver:self];
[discoverer startDiscovering];
UILongPressGestureRecognizer *recognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(startEditMode)];
recognizer.allowedPressTypes = @[@(UIPressTypeSelect)];
recognizer.minimumPressDuration = 1.0;
[self.view addGestureRecognizer:recognizer];
UITapGestureRecognizer *cancelRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(endEditMode)];
cancelRecognizer.allowedPressTypes = @[@(UIPressTypeSelect),@(UIPressTypeMenu)];
self.cancelRecognizer = cancelRecognizer;
[self.view addGestureRecognizer:cancelRecognizer];
UITapGestureRecognizer *playPauseRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handlePlayPausePress)];
playPauseRecognizer.allowedPressTypes = @[@(UIPressTypePlayPause)];
self.playPausePressRecognizer = playPauseRecognizer;
[self.view addGestureRecognizer:playPauseRecognizer];
self.cachedMediaLabel.text = NSLocalizedString(@"CACHED_MEDIA", nil);
self.cachedMediaLongLabel.text = NSLocalizedString(@"CACHED_MEDIA_LONG", nil);
}
......@@ -159,130 +141,6 @@ static NSString *const VLCWiggleAnimationKey = @"VLCWiggleAnimation";
[[NSUserDefaults standardUserDefaults] synchronize];
}
#pragma mark - editing
- (void)handlePlayPausePress
{
NSIndexPath *indexPathToDelete = self.currentlyFocusedIndexPath;
if (!indexPathToDelete) {
return;
}
NSString *fileToDelete = nil;
@synchronized(_discoveredFiles) {
fileToDelete = _discoveredFiles[indexPathToDelete.item];
}
NSString *title = fileToDelete.lastPathComponent;
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_DELETE", nil)
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction * _Nonnull action) {
[self deleteFileAtIndex:indexPathToDelete];
}];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_CANCEL", nil)
style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
self.editing = NO;
}];
[alertController addAction:deleteAction];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
- (void)deleteFileAtIndex:(NSIndexPath *)indexPathToDelete
{
if (!indexPathToDelete) {
return;
}
__block NSString *fileToDelete = nil;
[self.cachedMediaCollectionView performBatchUpdates:^{
@synchronized(_discoveredFiles) {
fileToDelete = _discoveredFiles[indexPathToDelete.item];
[_discoveredFiles removeObject:fileToDelete];
}
[self.cachedMediaCollectionView deleteItemsAtIndexPaths:@[indexPathToDelete]];
} completion:^(BOOL finished) {
[[NSFileManager defaultManager] removeItemAtPath:fileToDelete error:nil];
self.editing = NO;
}];
}
- (void)animateDeletHintToVisibility:(BOOL)visible
{
const NSTimeInterval duration = 0.5;
UIView *hintView = self.deleteHintView;
if (hintView.hidden) {
hintView.alpha = 0.0;
}
if (hintView.alpha == 0.0) {
hintView.hidden = NO;
}
const CGFloat targetAlpha = visible ? 1.0 : 0.0;
[UIView animateWithDuration:duration
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
hintView.alpha = targetAlpha;
}
completion:^(BOOL finished) {
if (hintView.alpha == 0.0) {
hintView.hidden = YES;
}
}];
}
- (void)hintTimerFired:(NSTimer *)timer
{
const NSTimeInterval waitUntilHideInterval = 5.0;
NSNumber *userInfo = [timer userInfo];
BOOL shouldShow = [userInfo isKindOfClass:[NSNumber class]] && [userInfo boolValue];
[self animateDeletHintToVisibility:shouldShow];
if (shouldShow) {
[self.hintTimer invalidate];
self.hintTimer = [NSTimer scheduledTimerWithTimeInterval:waitUntilHideInterval target:self selector:@selector(hintTimerFired:) userInfo:@(NO) repeats:NO];
}
}
- (void)startEditMode
{
self.editing = YES;
}
- (void)endEditMode
{
self.editing = NO;
}
- (void)setEditing:(BOOL)editing
{
[super setEditing:editing];
UICollectionViewCell *focusedCell = [self.cachedMediaCollectionView cellForItemAtIndexPath:self.currentlyFocusedIndexPath];
if (editing) {
[focusedCell.layer addAnimation:[CAAnimation vlc_wiggleAnimation]
forKey:VLCWiggleAnimationKey];
[self.hintTimer invalidate];
self.hintTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(hintTimerFired:) userInfo:@(YES) repeats:NO];
} else {
[focusedCell.layer removeAnimationForKey:VLCWiggleAnimationKey];
[self.hintTimer invalidate];
self.hintTimer = nil;
[self animateDeletHintToVisibility:NO];
}
self.cancelRecognizer.enabled = editing;
self.playPausePressRecognizer.enabled = editing;
}
#pragma mark - collection view data source
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
......@@ -339,6 +197,59 @@ static NSString *const VLCWiggleAnimationKey = @"VLCWiggleAnimation";
self.currentlyFocusedIndexPath = nextPath;
}
#pragma mark - editing
- (NSIndexPath *)indexPathToDelete
{
NSIndexPath *indexPathToDelete = self.currentlyFocusedIndexPath;
return indexPathToDelete;
}
- (NSString *)itemToDelete
{
NSIndexPath *indexPathToDelete = self.indexPathToDelete;
if (!indexPathToDelete) {
return nil;
}
NSString *ret;
@synchronized(_discoveredFiles) {
ret = _discoveredFiles[indexPathToDelete.item];
}
return ret;
}
- (void)setEditing:(BOOL)editing
{
[super setEditing:editing];
UICollectionViewCell *focusedCell = [self.cachedMediaCollectionView cellForItemAtIndexPath:self.currentlyFocusedIndexPath];
if (editing) {
[focusedCell.layer addAnimation:[CAAnimation vlc_wiggleAnimation]
forKey:VLCWiggleAnimationKey];
} else {
[focusedCell.layer removeAnimationForKey:VLCWiggleAnimationKey];
}
}
- (void)deleteFileAtIndex:(NSIndexPath *)indexPathToDelete
{
if (!indexPathToDelete) {
return;
}
__block NSString *fileToDelete = nil;
[self.cachedMediaCollectionView performBatchUpdates:^{
@synchronized(_discoveredFiles) {
fileToDelete = _discoveredFiles[indexPathToDelete.item];
[_discoveredFiles removeObject:fileToDelete];
}
[self.cachedMediaCollectionView deleteItemsAtIndexPaths:@[indexPathToDelete]];
} completion:^(BOOL finished) {
[[NSFileManager defaultManager] removeItemAtPath:fileToDelete error:nil];
self.editing = NO;
}];
}
#pragma mark - collection view delegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
......
......@@ -161,6 +161,7 @@
7D5CAA8C1A4AD8E5003F2CBC /* VLCTrackSelectorHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D5CAA8B1A4AD8E5003F2CBC /* VLCTrackSelectorHeaderView.m */; };
7D5DD5C717590ABF001421E3 /* About Contents.html in Resources */ = {isa = PBXBuildFile; fileRef = 7D5DD5C617590ABF001421E3 /* About Contents.html */; };
7D6069691BD92E6900AB765C /* libSDropboxSDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D5278CD1BD7DE3D00D0CA0E /* libSDropboxSDK.a */; };
7D62621A1C18AECD00F7CB24 /* VLCDeletionCapableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D6262191C18AECD00F7CB24 /* VLCDeletionCapableViewController.m */; };
7D63C19018774B1700BD5256 /* VLCFirstStepsSecondPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D63C18E18774B1700BD5256 /* VLCFirstStepsSecondPageViewController.m */; };
7D63C19518774E0100BD5256 /* VLCFirstStepsThirdPageViewController~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D63C19418774E0100BD5256 /* VLCFirstStepsThirdPageViewController~ipad.xib */; };
7D63C19718774F1000BD5256 /* VLCFirstStepsFourthPageViewController~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D63C19618774F1000BD5256 /* VLCFirstStepsFourthPageViewController~ipad.xib */; };
......@@ -1046,6 +1047,8 @@
7D5CAA8A1A4AD8E5003F2CBC /* VLCTrackSelectorHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VLCTrackSelectorHeaderView.h; path = Sources/VLCTrackSelectorHeaderView.h; sourceTree = SOURCE_ROOT; };
7D5CAA8B1A4AD8E5003F2CBC /* VLCTrackSelectorHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = VLCTrackSelectorHeaderView.m; path = Sources/VLCTrackSelectorHeaderView.m; sourceTree = SOURCE_ROOT; };
7D5DD5C617590ABF001421E3 /* About Contents.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "About Contents.html"; sourceTree = "<group>"; };
7D6262181C18AECD00F7CB24 /* VLCDeletionCapableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCDeletionCapableViewController.h; sourceTree = "<group>"; };
7D6262191C18AECD00F7CB24 /* VLCDeletionCapableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCDeletionCapableViewController.m; sourceTree = "<group>"; };
7D62C8A51C08B512007A6EF3 /* HockeySDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HockeySDK.framework; path = "ImportedSources/HockeySDK-tvOS/Support/build/Debug-appletvos/HockeySDK.framework"; sourceTree = "<group>"; };
7D62C8AB1C08B874007A6EF3 /* libHockeySDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libHockeySDK.a; path = "ImportedSources/HockeySDK-tvOS/Support/build/Debug-appletvos/libHockeySDK.a"; sourceTree = "<group>"; };
7D62C9271C08B9C7007A6EF3 /* CrashReporter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporter.framework; path = "ImportedSources/HockeySDK-tvOS/Vendor/CrashReporter.framework"; sourceTree = "<group>"; };
......@@ -2332,6 +2335,8 @@
7D1A2DB01BF66335002E0962 /* VLCMDFBrowsingArtworkProvider.m */,
DD9D8F5D1C00C73F00B4060F /* VLCDeleteHintTVView.h */,
DD9D8F5E1C00C73F00B4060F /* VLCDeleteHintTVView.m */,
7D6262181C18AECD00F7CB24 /* VLCDeletionCapableViewController.h */,
7D6262191C18AECD00F7CB24 /* VLCDeletionCapableViewController.m */,
);
name = "Common Code";
sourceTree = "<group>";
......@@ -3411,6 +3416,7 @@
7D1334801BE132F10012E919 /* VLCNetworkServerBrowserUPnP.m in Sources */,
DD4089FA1BF659030022745E /* VLCPlaybackInfoTVCollectionSectionTitleView.m in Sources */,
7DF383D01BF24BB100D71A5C /* VLCBoxCollectionViewController.m in Sources */,
7D62621A1C18AECD00F7CB24 /* VLCDeletionCapableViewController.m in Sources */,
DDEAECC71BDEC79D00756C83 /* VLCLocalNetworkServiceBrowserSAP.m in Sources */,
7D1329441BA1F10100BE647E /* AppleTVAppDelegate.m in Sources */,
7D1329411BA1F10100BE647E /* main.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