Implement dock icon progress bar indicator for many processing operations, including adding tracks, removing tracks, and loading or reloading track metadata
parent
0d90ccb7c1
commit
7fe67b1630
|
@ -16,6 +16,11 @@
|
|||
IBOutlet PlaybackController *playbackController;
|
||||
|
||||
NSInteger lastPlaybackStatus;
|
||||
NSInteger lastColorfulStatus;
|
||||
NSNumber *lastProgressStatus;
|
||||
|
||||
NSImageView *imageView;
|
||||
NSProgressIndicator *progressIndicator;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -17,12 +17,14 @@ static NSString *DockIconPlaybackStatusObservationContext = @"DockIconPlaybackSt
|
|||
- (void)startObserving
|
||||
{
|
||||
[playbackController addObserver:self forKeyPath:@"playbackStatus" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:(__bridge void * _Nullable)(DockIconPlaybackStatusObservationContext)];
|
||||
[playbackController addObserver:self forKeyPath:@"progressBarStatus" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:(__bridge void * _Nullable)(DockIconPlaybackStatusObservationContext)];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.colorfulDockIcons" options:0 context:(__bridge void * _Nullable)(DockIconPlaybackStatusObservationContext)];
|
||||
}
|
||||
|
||||
- (void)stopObserving
|
||||
{
|
||||
[playbackController removeObserver:self forKeyPath:@"playbackStatus"];
|
||||
[playbackController removeObserver:self forKeyPath:@"progressBarStatus"];
|
||||
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.colorfulDockIcons"];
|
||||
}
|
||||
|
||||
|
@ -38,41 +40,123 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons)
|
|||
}
|
||||
}
|
||||
|
||||
- (void)refreshDockIcon:(NSInteger)playbackStatus
|
||||
- (void)refreshDockIcon:(NSInteger)playbackStatus withProgress:(double)progressStatus
|
||||
{
|
||||
BOOL displayChanged = NO;
|
||||
BOOL drawIcon = NO;
|
||||
BOOL removeProgress = NO;
|
||||
|
||||
if ( playbackStatus < 0 )
|
||||
playbackStatus = lastPlaybackStatus;
|
||||
else
|
||||
{
|
||||
lastPlaybackStatus = playbackStatus;
|
||||
drawIcon = YES;
|
||||
}
|
||||
|
||||
if ( progressStatus < -2 )
|
||||
progressStatus = [lastProgressStatus doubleValue];
|
||||
else
|
||||
{
|
||||
if (progressStatus < 0 && [lastProgressStatus doubleValue] >= 0)
|
||||
removeProgress = YES;
|
||||
lastProgressStatus = [NSNumber numberWithDouble:progressStatus];
|
||||
}
|
||||
|
||||
BOOL displayProgress = (progressStatus >= 0.0);
|
||||
|
||||
NSImage *badgeImage = nil;
|
||||
|
||||
BOOL colorfulIcons = [[NSUserDefaults standardUserDefaults] boolForKey:@"colorfulDockIcons"];
|
||||
|
||||
switch (playbackStatus) {
|
||||
case CogStatusPlaying:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"playDockBadge", colorfulIcons)];
|
||||
break;
|
||||
case CogStatusPaused:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"pauseDockBadge", colorfulIcons)];
|
||||
break;
|
||||
|
||||
default:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"stopDockBadge", colorfulIcons)];
|
||||
break;
|
||||
if ((colorfulIcons && lastColorfulStatus < 1) ||
|
||||
(!colorfulIcons && lastColorfulStatus != 0))
|
||||
{
|
||||
lastColorfulStatus = colorfulIcons ? 1 : 0;
|
||||
drawIcon = YES;
|
||||
}
|
||||
|
||||
NSSize badgeSize = [badgeImage size];
|
||||
NSDockTile *dockTile = [NSApp dockTile];
|
||||
|
||||
if (drawIcon)
|
||||
{
|
||||
switch (playbackStatus) {
|
||||
case CogStatusPlaying:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"playDockBadge", colorfulIcons)];
|
||||
break;
|
||||
case CogStatusPaused:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"pauseDockBadge", colorfulIcons)];
|
||||
break;
|
||||
|
||||
default:
|
||||
badgeImage = [NSImage imageNamed:getBadgeName(@"stopDockBadge", colorfulIcons)];
|
||||
break;
|
||||
}
|
||||
|
||||
NSImage *newDockImage = [dockImage copy];
|
||||
[newDockImage lockFocus];
|
||||
NSSize badgeSize = [badgeImage size];
|
||||
|
||||
[badgeImage drawInRect:NSMakeRect(0, 0, 128, 128)
|
||||
fromRect:NSMakeRect(0, 0, badgeSize.width, badgeSize.height)
|
||||
operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
NSImage *newDockImage = [dockImage copy];
|
||||
[newDockImage lockFocus];
|
||||
|
||||
[newDockImage unlockFocus];
|
||||
[NSApp setApplicationIconImage:newDockImage];
|
||||
[badgeImage drawInRect:NSMakeRect(0, 0, 128, 128)
|
||||
fromRect:NSMakeRect(0, 0, badgeSize.width, badgeSize.height)
|
||||
operation:NSCompositingOperationSourceOver fraction:1.0];
|
||||
|
||||
[newDockImage unlockFocus];
|
||||
|
||||
imageView = [[NSImageView alloc] init];
|
||||
[imageView setImage:newDockImage];
|
||||
[dockTile setContentView:imageView];
|
||||
|
||||
progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, dockTile.size.width, 10.0)];
|
||||
[progressIndicator setStyle:NSProgressIndicatorBarStyle];
|
||||
[progressIndicator setIndeterminate:NO];
|
||||
[progressIndicator setBezeled:YES];
|
||||
[progressIndicator setMinValue:0];
|
||||
[progressIndicator setMaxValue:100];
|
||||
[progressIndicator setHidden:YES];
|
||||
|
||||
[imageView addSubview:progressIndicator];
|
||||
|
||||
displayChanged = YES;
|
||||
}
|
||||
|
||||
if (displayProgress)
|
||||
{
|
||||
if (!imageView)
|
||||
{
|
||||
imageView = [[NSImageView alloc] init];
|
||||
[imageView setImage:[NSApp applicationIconImage]];
|
||||
[dockTile setContentView:imageView];
|
||||
}
|
||||
|
||||
if (!progressIndicator)
|
||||
{
|
||||
progressIndicator = [[NSProgressIndicator alloc] initWithFrame:NSMakeRect(0.0, 0.0, dockTile.size.width, 10.0)];
|
||||
[progressIndicator setIndeterminate:NO];
|
||||
[progressIndicator setBezeled:YES];
|
||||
[progressIndicator setMinValue:0];
|
||||
[progressIndicator setMaxValue:100];
|
||||
|
||||
[imageView addSubview:progressIndicator];
|
||||
}
|
||||
|
||||
[progressIndicator setDoubleValue:progressStatus];
|
||||
[progressIndicator setHidden:NO];
|
||||
|
||||
displayChanged = YES;
|
||||
}
|
||||
|
||||
if (removeProgress)
|
||||
{
|
||||
if (progressIndicator)
|
||||
[progressIndicator setHidden:YES];
|
||||
|
||||
displayChanged = YES;
|
||||
}
|
||||
|
||||
if (displayChanged)
|
||||
[dockTile display];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
|
||||
|
@ -83,11 +167,17 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons)
|
|||
{
|
||||
NSInteger playbackStatus = [[change objectForKey:NSKeyValueChangeNewKey] integerValue];
|
||||
|
||||
[self refreshDockIcon:playbackStatus];
|
||||
[self refreshDockIcon:playbackStatus withProgress:-10];
|
||||
}
|
||||
else if ([keyPath isEqualToString:@"progressBarStatus"])
|
||||
{
|
||||
double progressStatus = [[change objectForKey:NSKeyValueChangeNewKey] doubleValue];
|
||||
|
||||
[self refreshDockIcon:-1 withProgress:progressStatus];
|
||||
}
|
||||
else if ([keyPath isEqualToString:@"values.colorfulDockIcons"])
|
||||
{
|
||||
[self refreshDockIcon:-1];
|
||||
[self refreshDockIcon:-1 withProgress:-10];
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -99,6 +189,10 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons)
|
|||
- (void)awakeFromNib
|
||||
{
|
||||
dockImage = [[NSImage imageNamed:@"icon_blank"] copy];
|
||||
lastColorfulStatus = -1;
|
||||
lastProgressStatus = [NSNumber numberWithDouble:-1];
|
||||
imageView = nil;
|
||||
progressIndicator = nil;
|
||||
[self startObserving];
|
||||
}
|
||||
|
||||
|
|
|
@ -39,10 +39,15 @@ extern NSDictionary * makeRGInfo(PlaylistEntry *pe);
|
|||
double position;
|
||||
BOOL seekable;
|
||||
BOOL fading;
|
||||
|
||||
// progress bar display
|
||||
double progressBarStatus;
|
||||
}
|
||||
|
||||
@property CogStatus playbackStatus;
|
||||
|
||||
@property double progressBarStatus;
|
||||
|
||||
- (IBAction)changeVolume:(id)sender;
|
||||
- (IBAction)volumeDown:(id)sender;
|
||||
- (IBAction)volumeUp:(id)sender;
|
||||
|
|
|
@ -27,6 +27,8 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|||
|
||||
@synthesize playbackStatus;
|
||||
|
||||
@synthesize progressBarStatus;
|
||||
|
||||
+ (NSSet *)keyPathsForValuesAffectingSeekable
|
||||
{
|
||||
return [NSSet setWithObjects:@"playlistController.currentEntry",@"playlistController.currentEntry.seekable",nil];
|
||||
|
@ -41,6 +43,8 @@ NSString *CogPlaybackDidStopNotficiation = @"CogPlaybackDidStopNotficiation";
|
|||
|
||||
seekable = NO;
|
||||
fading = NO;
|
||||
|
||||
progressBarStatus = -1;
|
||||
|
||||
audioPlayer = [[AudioPlayer alloc] init];
|
||||
[audioPlayer setDelegate:self];
|
||||
|
|
|
@ -1770,6 +1770,7 @@ Gw
|
|||
<connections>
|
||||
<outlet property="playlistController" destination="218" id="1320"/>
|
||||
<outlet property="playlistView" destination="206" id="6MS-vO-DQp"/>
|
||||
<outlet property="playbackController" destination="705" id="EBV-A8-3bM"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<menu title="Menu" id="1324" userLabel="TableMenu">
|
||||
|
|
|
@ -117,6 +117,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_block_t block) {
|
||||
if (dispatch_queue_get_label(queue) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)) {
|
||||
block();
|
||||
}
|
||||
else {
|
||||
dispatch_sync(queue, block);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProgressBarStatus:(double)status {
|
||||
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
|
||||
[self->playbackController setProgressBarStatus:status];
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.001]];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)updatePlaylistIndexes {
|
||||
NSArray *arranged = [self arrangedObjects];
|
||||
NSUInteger n = [arranged count];
|
||||
|
@ -129,7 +145,9 @@
|
|||
}
|
||||
}
|
||||
if (updated) {
|
||||
[[SQLiteStore sharedStore] syncPlaylistEntries:arranged];
|
||||
[[SQLiteStore sharedStore] syncPlaylistEntries:arranged progressCall:^(double progress) {
|
||||
[self setProgressBarStatus:progress];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +414,9 @@
|
|||
[NSString stringWithFormat:@"Adding %lu entries", (unsigned long) [objects count]];
|
||||
[[self undoManager] setActionName:actionName];
|
||||
|
||||
[[SQLiteStore sharedStore] playlistInsertTracks:objects atObjectIndexes:indexes];
|
||||
[[SQLiteStore sharedStore] playlistInsertTracks:objects atObjectIndexes:indexes progressCall:^(double progress) {
|
||||
[self setProgressBarStatus:progress];
|
||||
}];
|
||||
|
||||
[super insertObjects:objects atArrangedObjectIndexes:indexes];
|
||||
|
||||
|
@ -443,7 +463,9 @@
|
|||
currentEntry.index = -i - 1;
|
||||
}
|
||||
|
||||
[[SQLiteStore sharedStore] playlistRemoveTracksAtIndexes:unarrangedIndexes];
|
||||
[[SQLiteStore sharedStore] playlistRemoveTracksAtIndexes:unarrangedIndexes progressCall:^(double progress) {
|
||||
[self setProgressBarStatus:progress];
|
||||
}];
|
||||
|
||||
[super removeObjectsAtArrangedObjectIndexes:indexes];
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ typedef enum {
|
|||
@interface PlaylistLoader : NSObject {
|
||||
IBOutlet PlaylistController *playlistController;
|
||||
IBOutlet NSScrollView *playlistView;
|
||||
IBOutlet PlaybackController *playbackController;
|
||||
|
||||
NSOperationQueue *queue;
|
||||
}
|
||||
|
|
|
@ -119,6 +119,7 @@
|
|||
return NO;
|
||||
}
|
||||
[fileHandle truncateFileAtOffset:0];
|
||||
[fileHandle writeData:[@"#\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
|
||||
for (PlaylistEntry *pe in [playlistController arrangedObjects])
|
||||
{
|
||||
|
@ -281,6 +282,21 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
return urls;
|
||||
}
|
||||
|
||||
static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_block_t block) {
|
||||
if (dispatch_queue_get_label(queue) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)) {
|
||||
block();
|
||||
}
|
||||
else {
|
||||
dispatch_sync(queue, block);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setProgressBarStatus:(double)status {
|
||||
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
|
||||
[self->playbackController setProgressBarStatus:status];
|
||||
});
|
||||
}
|
||||
|
||||
- (NSArray*)insertURLs:(NSArray *)urls atIndex:(NSInteger)index sort:(BOOL)sort
|
||||
{
|
||||
NSMutableSet *uniqueURLs = [NSMutableSet set];
|
||||
|
@ -290,12 +306,21 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
NSMutableArray *fileURLs = [NSMutableArray array];
|
||||
NSMutableArray *validURLs = [NSMutableArray array];
|
||||
NSDictionary *xmlData = nil;
|
||||
|
||||
double progress = 0.0;
|
||||
|
||||
if (!urls)
|
||||
{
|
||||
[self setProgressBarStatus:-1];
|
||||
return [NSArray array];
|
||||
}
|
||||
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
double progressstep = [urls count] ? 20.0 / (double)([urls count]) : 0;
|
||||
|
||||
NSURL *url;
|
||||
for (url in urls)
|
||||
|
@ -320,7 +345,15 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
//Non-file URL..
|
||||
[expandedURLs addObject:url];
|
||||
}
|
||||
|
||||
progress += progressstep;
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
}
|
||||
|
||||
progress = 20.0;
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
DLog(@"Expanded urls: %@", expandedURLs);
|
||||
|
||||
|
@ -334,6 +367,8 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
{
|
||||
sortedURLs = expandedURLs;
|
||||
}
|
||||
|
||||
progressstep = [sortedURLs count] ? 20.0 / (double)([sortedURLs count]) : 0;
|
||||
|
||||
for (url in sortedURLs)
|
||||
{
|
||||
|
@ -360,14 +395,24 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
{
|
||||
[fileURLs addObject:url];
|
||||
}
|
||||
|
||||
progress += progressstep;
|
||||
[self setProgressBarStatus:progress];
|
||||
}
|
||||
|
||||
progress = 40.0;
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
DLog(@"File urls: %@", fileURLs);
|
||||
|
||||
DLog(@"Contained urls: %@", containedURLs);
|
||||
|
||||
progressstep = [fileURLs count] ? 20.0 / (double)([fileURLs count]) : 0;
|
||||
|
||||
for (url in fileURLs)
|
||||
{
|
||||
progress += progressstep;
|
||||
|
||||
if (![[AudioPlayer schemes] containsObject:[url scheme]])
|
||||
continue;
|
||||
|
||||
|
@ -383,12 +428,22 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
|
||||
[uniqueURLs addObject:url];
|
||||
}
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
}
|
||||
|
||||
progress = 60.0;
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
DLog(@"Valid urls: %@", validURLs);
|
||||
|
||||
progressstep = [containedURLs count] ? 20.0 / (double)([containedURLs count]) : 0;
|
||||
|
||||
for (url in containedURLs)
|
||||
{
|
||||
progress += progressstep;
|
||||
|
||||
if (![[AudioPlayer schemes] containsObject:[url scheme]])
|
||||
continue;
|
||||
|
||||
|
@ -397,7 +452,13 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
continue;
|
||||
|
||||
[validURLs addObject:url];
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
}
|
||||
|
||||
progress = 80.0;
|
||||
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
//Create actual entries
|
||||
int count = (int) [validURLs count];
|
||||
|
@ -405,7 +466,12 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
|
||||
// no valid URLs, or they use an unsupported URL scheme
|
||||
if (!count)
|
||||
{
|
||||
[self setProgressBarStatus:-1];
|
||||
return [NSArray array];
|
||||
}
|
||||
|
||||
progressstep = 20.0 / (double)(count);
|
||||
|
||||
NSInteger i = 0;
|
||||
NSMutableArray *entries = [NSMutableArray arrayWithCapacity:count];
|
||||
|
@ -421,6 +487,9 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
[entries addObject:pe];
|
||||
|
||||
++i;
|
||||
|
||||
progress += progressstep;
|
||||
[self setProgressBarStatus:progress];
|
||||
}
|
||||
|
||||
NSInteger j = index + i;
|
||||
|
@ -441,6 +510,9 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
}
|
||||
}
|
||||
|
||||
progress = 100.0;
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
NSIndexSet *is = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, [entries count])];
|
||||
|
||||
[playlistController insertObjects:entries atArrangedObjectIndexes:is];
|
||||
|
@ -470,23 +542,24 @@ NSMutableDictionary * dictionaryWithPropertiesOfObject(id obj, NSArray * filterL
|
|||
NSArray* arrayFirst = [NSArray arrayWithObject:[entries objectAtIndex:0]];
|
||||
NSMutableArray* arrayRest = [entries mutableCopy];
|
||||
[arrayRest removeObjectAtIndex:0];
|
||||
|
||||
progress = 0.0;
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
[self performSelectorOnMainThread:@selector(syncLoadInfoForEntries:) withObject:arrayFirst waitUntilDone:YES];
|
||||
|
||||
progressstep = 100.0 / (double)([entries count]);
|
||||
progress += progressstep;
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
if ([arrayRest count])
|
||||
[self performSelectorInBackground:@selector(loadInfoForEntries:) withObject:arrayRest];
|
||||
else
|
||||
[self setProgressBarStatus:-1];
|
||||
return entries;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_block_t block) {
|
||||
if (dispatch_queue_get_label(queue) == dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL)) {
|
||||
block();
|
||||
}
|
||||
else {
|
||||
dispatch_sync(queue, block);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadInfoForEntries:(NSArray *)entries
|
||||
{
|
||||
NSMutableIndexSet *update_indexes = [[NSMutableIndexSet alloc] init];
|
||||
|
@ -494,6 +567,18 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
NSMutableIndexSet *load_info_indexes = [[NSMutableIndexSet alloc] init];
|
||||
|
||||
SQLiteStore *store = [SQLiteStore sharedStore];
|
||||
|
||||
__block double progress = [playbackController progressBarStatus];
|
||||
|
||||
if (progress < 0 || progress >= 100)
|
||||
progress = 0;
|
||||
|
||||
double progressRemaining = 100.0 - progress;
|
||||
|
||||
// 50% for properties reading, 50% for applying them to the main thread
|
||||
const double progressstep = [entries count] ? (progressRemaining / 2.0) / [entries count] : 0;
|
||||
|
||||
progressRemaining = progress + (progressRemaining / 2.0);
|
||||
|
||||
i = 0;
|
||||
j = 0;
|
||||
|
@ -529,6 +614,10 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
NSBlockOperation *op = [[NSBlockOperation alloc] init];
|
||||
|
||||
[op addExecutionBlock:^{
|
||||
[weakLock lock];
|
||||
progress += progressstep;
|
||||
[weakLock unlock];
|
||||
|
||||
NSMutableDictionary *entryInfo = [NSMutableDictionary dictionaryWithCapacity:20];
|
||||
|
||||
NSDictionary *entryProperties = [AudioPropertiesReader propertiesForURL:weakPe.URL];
|
||||
|
@ -541,6 +630,7 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
[weakLock lock];
|
||||
[weakArray addObject:weakPe];
|
||||
[weakArray addObject:entryInfo];
|
||||
[self setProgressBarStatus:progress];
|
||||
[weakLock unlock];
|
||||
}];
|
||||
|
||||
|
@ -549,6 +639,9 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
}
|
||||
|
||||
[queue waitUntilAllOperationsAreFinished];
|
||||
|
||||
progress = progressRemaining;
|
||||
[self setProgressBarStatus:progress];
|
||||
|
||||
for (i = 0, j = [outArray count]; i < j; i += 2) {
|
||||
__block PlaylistEntry *weakPe = [outArray objectAtIndex:i];
|
||||
|
@ -556,6 +649,8 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
dispatch_sync_reentrant(dispatch_get_main_queue(), ^{
|
||||
[weakPe setMetadata:entryInfo];
|
||||
[store trackUpdate:weakPe];
|
||||
progress += progressstep;
|
||||
[self setProgressBarStatus:progress];
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -569,6 +664,8 @@ static inline void dispatch_sync_reentrant(dispatch_queue_t queue, dispatch_bloc
|
|||
[weakPlaylistView.documentView reloadDataForRowIndexes:weakIndexSet columnIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0,columns)]];
|
||||
});
|
||||
}
|
||||
|
||||
[self setProgressBarStatus:-1];
|
||||
}
|
||||
// To be called on main thread only
|
||||
- (void)syncLoadInfoForEntries:(NSArray *)entries
|
||||
|
|
|
@ -27,17 +27,17 @@
|
|||
|
||||
- (void) trackUpdate:(PlaylistEntry *)track;
|
||||
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atIndex:(int64_t)index;
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atObjectIndexes:(NSIndexSet *)indexes;
|
||||
- (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count;
|
||||
- (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes;
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atIndex:(int64_t)index progressCall:(void(^)(double progress))callback;
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atObjectIndexes:(NSIndexSet *)indexes progressCall:(void(^)(double progress))callback;
|
||||
- (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count progressCall:(void(^)(double progress))callback;
|
||||
- (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes progressCall:(void(^)(double progress))callback;
|
||||
- (PlaylistEntry *)playlistGetItem:(int64_t)index;
|
||||
- (int64_t)playlistGetCount;
|
||||
#if 0
|
||||
- (void)playlistMoveObjectsInArrangedObjectsFromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex;
|
||||
#endif
|
||||
|
||||
- (void)syncPlaylistEntries:(NSArray *)entries;
|
||||
- (void)syncPlaylistEntries:(NSArray *)entries progressCall:(void(^)(double progress))callback;
|
||||
|
||||
- (void)queueAddItem:(int64_t)playlistIndex;
|
||||
- (void)queueAddItems:(NSArray *)playlistIndexes;
|
||||
|
|
|
@ -1466,9 +1466,15 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
}
|
||||
}
|
||||
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atIndex:(int64_t)index
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atIndex:(int64_t)index progressCall:(void (^)(double))callback
|
||||
{
|
||||
if (!tracks) return;
|
||||
if (!tracks)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(0);
|
||||
|
||||
sqlite3_stmt *st = stmt[stmt_increment_playlist_for_insert];
|
||||
|
||||
|
@ -1478,9 +1484,15 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_step(st) != SQLITE_DONE ||
|
||||
sqlite3_reset(st))
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(25);
|
||||
|
||||
double progress = 25.0;
|
||||
double progressstep = [tracks count] ? 75.0 / (double)([tracks count]) : 0;
|
||||
|
||||
st = stmt[stmt_add_playlist];
|
||||
|
||||
for (PlaylistEntry *entry in tracks)
|
||||
|
@ -1492,32 +1504,61 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_bind_int64(st, add_playlist_in_track_id, trackId) ||
|
||||
sqlite3_step(st) != SQLITE_DONE)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
progress += progressstep;
|
||||
callback(progress);
|
||||
}
|
||||
|
||||
sqlite3_reset(st);
|
||||
|
||||
callback(-1);
|
||||
}
|
||||
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atObjectIndexes:(NSIndexSet *)indexes
|
||||
- (void)playlistInsertTracks:(NSArray *)tracks atObjectIndexes:(NSIndexSet *)indexes progressCall:(void (^)(double))callback
|
||||
{
|
||||
if (!tracks || !indexes) return;
|
||||
if (!tracks || !indexes)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
__block int64_t total_count = 0;
|
||||
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
|
||||
total_count += range.length;
|
||||
}];
|
||||
|
||||
__block int64_t i = 0;
|
||||
|
||||
__block double progress = 0;
|
||||
|
||||
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
|
||||
double progresschunk = (double)range.length / (double)total_count;
|
||||
double progressbase = progress;
|
||||
NSRange trackRange = NSMakeRange(i, range.length);
|
||||
NSArray *trackSet = (i == 0 && range.length == [tracks count]) ? tracks : [tracks subarrayWithRange:trackRange];
|
||||
[self playlistInsertTracks:trackSet atIndex:range.location];
|
||||
[self playlistInsertTracks:trackSet atIndex:range.location progressCall:^(double _progress){
|
||||
if (_progress < 0) return;
|
||||
callback(progressbase + progresschunk * _progress);
|
||||
}];
|
||||
i += range.length;
|
||||
progress += 100.0 * progresschunk;
|
||||
callback(progress);
|
||||
}];
|
||||
callback(-1);
|
||||
}
|
||||
|
||||
- (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count
|
||||
- (void)playlistRemoveTracks:(int64_t)index forCount:(int64_t)count progressCall:(void (^)(double))callback
|
||||
{
|
||||
if (!count) return;
|
||||
if (!count)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
sqlite3_stmt *st = stmt[stmt_select_playlist_range];
|
||||
|
||||
|
@ -1525,9 +1566,15 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_bind_int64(st, select_playlist_range_in_id_low, index) ||
|
||||
sqlite3_bind_int64(st, select_playlist_range_in_id_high, index + count - 1))
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(0);
|
||||
|
||||
double progress = 0;
|
||||
double progressstep = 100.0 / ((double)count);
|
||||
|
||||
int rc = sqlite3_step(st);
|
||||
|
||||
while (rc == SQLITE_ROW)
|
||||
|
@ -1535,8 +1582,12 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
int64_t trackId = sqlite3_column_int64(st, select_playlist_range_out_track_id);
|
||||
[self removeTrack:trackId];
|
||||
rc = sqlite3_step(st);
|
||||
progress += progressstep;
|
||||
callback(progress);
|
||||
}
|
||||
|
||||
callback(100);
|
||||
|
||||
sqlite3_reset(st);
|
||||
|
||||
if (rc != SQLITE_DONE)
|
||||
|
@ -1552,6 +1603,7 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_step(st) != SQLITE_DONE ||
|
||||
sqlite3_reset(st))
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1563,6 +1615,7 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_step(st) != SQLITE_DONE ||
|
||||
sqlite3_reset(st))
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1574,18 +1627,42 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
}
|
||||
|
||||
[self queueRemovePlaylistItems:items];
|
||||
|
||||
callback(-1);
|
||||
}
|
||||
|
||||
- (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes
|
||||
- (void)playlistRemoveTracksAtIndexes:(NSIndexSet *)indexes progressCall:(void (^)(double))callback
|
||||
{
|
||||
if (!indexes) return;
|
||||
if (!indexes)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
__block int64_t total_count = 0;
|
||||
|
||||
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
|
||||
total_count += range.length;
|
||||
}];
|
||||
|
||||
__block int64_t i = 0;
|
||||
|
||||
__block double progress = 0;
|
||||
|
||||
callback(progress);
|
||||
|
||||
[indexes enumerateRangesUsingBlock:^(NSRange range, BOOL * _Nonnull stop) {
|
||||
[self playlistRemoveTracks:(range.location - i) forCount:range.length];
|
||||
double progresschunk = (double)range.length / (double)total_count;
|
||||
double progressbase = progress;
|
||||
[self playlistRemoveTracks:(range.location - i) forCount:range.length progressCall:^(double _progress) {
|
||||
if (_progress < 0) return;
|
||||
callback(progressbase + progresschunk * _progress);
|
||||
}];
|
||||
i += range.length;
|
||||
progress += 100.0 * progresschunk;
|
||||
callback(progress);
|
||||
}];
|
||||
callback(-1);
|
||||
}
|
||||
|
||||
- (PlaylistEntry *)playlistGetItem:(int64_t)index
|
||||
|
@ -1740,18 +1817,27 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
}
|
||||
#endif
|
||||
|
||||
- (void)syncPlaylistEntries:(NSArray *)entries
|
||||
- (void)syncPlaylistEntries:(NSArray *)entries progressCall:(void (^)(double))callback
|
||||
{
|
||||
if (!entries || ![entries count])
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t count = [self playlistGetCount];
|
||||
|
||||
if (count != [entries count])
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(0);
|
||||
|
||||
double progress = 0;
|
||||
double progressstep = 50.0 / (double)(count);
|
||||
|
||||
NSMutableArray * entryIds = [[NSMutableArray alloc] init];
|
||||
NSMutableArray * entryIndexes = [[NSMutableArray alloc] init];
|
||||
NSMutableArray * trackIds = [[NSMutableArray alloc] init];
|
||||
|
@ -1763,6 +1849,7 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
if (sqlite3_reset(st) ||
|
||||
(rc = sqlite3_step(st)) != SQLITE_ROW)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1777,11 +1864,17 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
[trackIds addObject:[NSNumber numberWithInteger:trackId]];
|
||||
|
||||
rc = sqlite3_step(st);
|
||||
|
||||
progress += progressstep;
|
||||
callback(progress);
|
||||
}
|
||||
while (rc == SQLITE_ROW);
|
||||
|
||||
sqlite3_reset(st);
|
||||
|
||||
progress = 50;
|
||||
callback(progress);
|
||||
|
||||
st = stmt[stmt_update_playlist];
|
||||
|
||||
int64_t i = 0;
|
||||
|
@ -1793,6 +1886,7 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
int64_t trackId = [[trackIds objectAtIndex:i] integerValue];
|
||||
|
||||
++i;
|
||||
progress += progressstep;
|
||||
|
||||
if ([entry index] == entryIndex &&
|
||||
[entry dbIndex] == trackId)
|
||||
|
@ -1804,11 +1898,16 @@ static SQLiteStore *g_sharedStore = NULL;
|
|||
sqlite3_bind_int64(st, update_playlist_in_id, entryId) ||
|
||||
sqlite3_step(st) != SQLITE_DONE)
|
||||
{
|
||||
callback(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
callback(progress);
|
||||
}
|
||||
|
||||
sqlite3_reset(st);
|
||||
|
||||
callback(-1);
|
||||
}
|
||||
|
||||
- (void)queueAddItem:(int64_t)playlistIndex
|
||||
|
|
Loading…
Reference in New Issue