diff --git a/ExplodingTextViewController.m b/ExplodingTextViewController.m index 8bf41d6..00882df 100644 --- a/ExplodingTextViewController.m +++ b/ExplodingTextViewController.m @@ -67,7 +67,8 @@ - (void)explodeText:(NSString *)text { [[SongGongAppDelegate mainView] addSubview:self.view]; - self.view.center = [SongGongAppDelegate mainView].center; + self.view.center = CGPointMake(self.view.frame.size.width/2,self.view.frame.size.height/2); + //self.view.center = [SongGongAppDelegate mainView].center; } [self retain]; diff --git a/NSObject+SPInvocationGrabbing.h b/NSObject+SPInvocationGrabbing.h new file mode 100644 index 0000000..d30233d --- /dev/null +++ b/NSObject+SPInvocationGrabbing.h @@ -0,0 +1,30 @@ +#import + +@interface SPInvocationGrabber : NSObject { + id _object; + NSInvocation *_invocation; + int frameCount; + char **frameStrings; + BOOL backgroundAfterForward; + BOOL onMainAfterForward; + BOOL waitUntilDone; +} +-(id)initWithObject:(id)obj; +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +@property (readonly, retain, nonatomic) id object; +@property (readonly, retain, nonatomic) NSInvocation *invocation; +@property BOOL backgroundAfterForward; +@property BOOL onMainAfterForward; +@property BOOL waitUntilDone; +-(void)invoke; // will release object and invocation +-(void)printBacktrace; +-(void)saveBacktrace; +@end + +@interface NSObject (SPInvocationGrabbing) +-(id)grab; +-(id)invokeAfter:(NSTimeInterval)delta; +-(id)nextRunloop; +-(id)inBackground; +-(id)onMainAsync:(BOOL)async; +@end diff --git a/NSObject+SPInvocationGrabbing.m b/NSObject+SPInvocationGrabbing.m new file mode 100644 index 0000000..b0fdf14 --- /dev/null +++ b/NSObject+SPInvocationGrabbing.m @@ -0,0 +1,128 @@ +#import "NSObject+SPInvocationGrabbing.h" +#import + +#pragma mark Invocation grabbing +@interface SPInvocationGrabber () +@property (readwrite, retain, nonatomic) id object; +@property (readwrite, retain, nonatomic) NSInvocation *invocation; + +@end + +@implementation SPInvocationGrabber +- (id)initWithObject:(id)obj; +{ + return [self initWithObject:obj stacktraceSaving:YES]; +} + +-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack; +{ + self.object = obj; + + if(saveStack) + [self saveBacktrace]; + + return self; +} +-(void)dealloc; +{ + free(frameStrings); + self.object = nil; + self.invocation = nil; + [super dealloc]; +} +@synthesize invocation = _invocation, object = _object; + +@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone; +- (void)runInBackground; +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + @try { + [self invoke]; + } + @finally { + [pool drain]; + } +} + + +- (void)forwardInvocation:(NSInvocation *)anInvocation { + [anInvocation retainArguments]; + anInvocation.target = _object; + self.invocation = anInvocation; + + if(backgroundAfterForward) + [NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil]; + else if(onMainAfterForward) + [self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone]; +} +- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector { + NSMethodSignature *signature = [super methodSignatureForSelector:inSelector]; + if (signature == NULL) + signature = [_object methodSignatureForSelector:inSelector]; + + return signature; +} + +- (void)invoke; +{ + + @try { + [_invocation invoke]; + } + @catch (NSException * e) { + NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e); + [self printBacktrace]; + printf("\n"); + [e raise]; + } + + self.invocation = nil; + self.object = nil; +} + +-(void)saveBacktrace; +{ + void *backtraceFrames[128]; + frameCount = backtrace(&backtraceFrames[0], 128); + frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount); +} +-(void)printBacktrace; +{ + int x; + for(x = 3; x < frameCount; x++) { + if(frameStrings[x] == NULL) { break; } + printf("%s\n", frameStrings[x]); + } +} +@end + +@implementation NSObject (SPInvocationGrabbing) +-(id)grab; +{ + return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease]; +} +-(id)invokeAfter:(NSTimeInterval)delta; +{ + id grabber = [self grab]; + [NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO]; + return grabber; +} +- (id)nextRunloop; +{ + return [self invokeAfter:0]; +} +-(id)inBackground; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.backgroundAfterForward = YES; + return grabber; +} +-(id)onMainAsync:(BOOL)async; +{ + SPInvocationGrabber *grabber = [self grab]; + grabber.onMainAfterForward = YES; + grabber.waitUntilDone = !async; + return grabber; +} + +@end \ No newline at end of file diff --git a/SGCarouselViewController.m b/SGCarouselViewController.m index f909514..046400a 100644 --- a/SGCarouselViewController.m +++ b/SGCarouselViewController.m @@ -73,7 +73,7 @@ - (void)viewDidLoad currentCarouselSource = [[carouselSourceViewControllers objectAtIndex:0] source]; [[carouselSourceViewControllers objectAtIndex:0] carouselDidBringViewToFront]; -// [self performSelector:@selector(playIfIdle:) withObject:nil afterDelay:4.0]; + [self performSelector:@selector(playIfIdle:) withObject:nil afterDelay:4.0]; } - (void)playIfIdle:(id)obj diff --git a/SGIPodSource.h b/SGIPodSource.h index 813e13a..8e234e4 100644 --- a/SGIPodSource.h +++ b/SGIPodSource.h @@ -24,6 +24,8 @@ @property (nonatomic, retain) id currentPlaylist; @property (readwrite, retain) NSArray *playlists; @property (readwrite, assign) id delegate; + +@property (readwrite, retain) MPMusicPlayerController *player; @end @@ -41,6 +43,7 @@ - (id )previousItem; - (id )nextItem; - (void)playItem:(id )item; +@property (readwrite, retain) NSTimer *updateTimer; @property (readwrite, retain) NSString *title; @property (readwrite, retain) id currentItem; @property (readwrite, retain) NSArray *itemIds; diff --git a/SGIPodSource.m b/SGIPodSource.m index b9b73f6..3ec9a39 100644 --- a/SGIPodSource.m +++ b/SGIPodSource.m @@ -10,6 +10,7 @@ #import #import #import "ExplodingTextViewController.h" +#import "NSObject+SPInvocationGrabbing.h" #define PREFERRED_ARTWORK_SIZE 256.0 @@ -28,7 +29,7 @@ - (id)initWithiPodItem:(MPMediaItem *)item; @end @implementation SGIPodSource -@synthesize playlists, sourceName, currentPlaylist, currentItem, splashColor, delegate; +@synthesize playlists, sourceName, currentPlaylist, currentItem, splashColor, delegate, player; - (id)init { @@ -58,6 +59,7 @@ - (id)init [playlist release]; } self.playlists = [NSArray arrayWithArray:thePlaylists]; + self.player =[MPMusicPlayerController applicationMusicPlayer]; } return self; @@ -81,10 +83,9 @@ - (void)play:(id)sender { MPMediaQuery *query = [MPMediaQuery songsQuery]; [[MPMusicPlayerController applicationMusicPlayer] setQueueWithQuery:query]; - } - [[MPMusicPlayerController applicationMusicPlayer] play]; + [[[MPMusicPlayerController applicationMusicPlayer] onMainAsync:YES] play]; } - (void)stop:(id)sender @@ -123,7 +124,7 @@ - (void)togglePlay:(id)sender [[MPMusicPlayerController applicationMusicPlayer] pause]; } else { [self willChangeValueForKey:@"currentItem"]; - [[MPMusicPlayerController applicationMusicPlayer] play]; + [[[MPMusicPlayerController applicationMusicPlayer] onMainAsync:YES] play]; [self didChangeValueForKey:@"currentItem"]; [delegate mediaDidChange:self.currentItem]; } @@ -144,13 +145,7 @@ - (void)playNextPlaylist return; [delegate playlistWillChange:nextPlaylist.title direction:0]; - self.currentPlaylist = nextPlaylist; - NSLog(@"%@ vs: %@", self.currentPlaylist, nextPlaylist); - [self willChangeValueForKey:@"currentItem"]; - [self play:nil]; - [self didChangeValueForKey:@"currentItem"]; - [delegate mediaDidChange:self.currentItem]; - + self.currentPlaylist = nextPlaylist; } @@ -164,15 +159,6 @@ - (void)playPreviousPlaylist } [delegate playlistWillChange:prev.title direction:0]; - - [self willChangeValueForKey:@"currentItem"]; - [self play:nil]; - self.currentPlaylist = prev; - [self didChangeValueForKey:@"currentItem"]; - [delegate mediaDidChange:self.currentItem]; - - - return; } - (id )previousPlaylist @@ -218,14 +204,14 @@ - (void)playPreviousItem [[MPMusicPlayerController applicationMusicPlayer] setCurrentPlaybackTime:0.0]; if ([[MPMusicPlayerController applicationMusicPlayer] playbackState] != MPMusicPlaybackStatePlaying) { - [[MPMusicPlayerController applicationMusicPlayer] play]; + [[[MPMusicPlayerController applicationMusicPlayer] onMainAsync:YES] play]; [delegate mediaDidChange:self.currentItem]; } return; } [self willChangeValueForKey:@"currentItem"]; [[MPMusicPlayerController applicationMusicPlayer] skipToPreviousItem]; - [[MPMusicPlayerController applicationMusicPlayer] play]; + [[[MPMusicPlayerController applicationMusicPlayer] onMainAsync:YES] play]; [self didChangeValueForKey:@"currentItem"]; [delegate mediaDidChange:self.currentItem]; return; @@ -235,7 +221,7 @@ - (void)playNextItem { [self willChangeValueForKey:@"currentItem"]; [[MPMusicPlayerController applicationMusicPlayer] skipToNextItem]; - [[MPMusicPlayerController applicationMusicPlayer] play]; + [[[MPMusicPlayerController applicationMusicPlayer] onMainAsync:YES] play]; [self didChangeValueForKey:@"currentItem"]; [delegate mediaDidChange:self.currentItem]; return; @@ -357,7 +343,21 @@ - (id)initWithiPodItem:(MPMediaItem *)item self.artist = [item valueForProperty:MPMediaItemPropertyArtist]; self.album = [item valueForProperty:MPMediaItemPropertyAlbumTitle]; self.persistentId = [item valueForProperty:MPMediaItemPropertyPersistentID]; - return self; + [[MPMusicPlayerController applicationMusicPlayer] addObserver:self forKeyPath:@"currentPlaybackTime" options:0 context:nil]; + return self; +} + +- (void)dealloc +{ + [[MPMusicPlayerController applicationMusicPlayer] removeObserver:self forKeyPath:@"currentPlaybackTime"]; + [super dealloc]; +} + +- (void)updateProgress:(id)obj +{ + [self willChangeValueForKey:@"progress"]; + + [self didChangeValueForKey:@"progress"]; } - (MPMediaItem *)mpItem @@ -383,8 +383,21 @@ - (void)togglePlay:(id)sender [[MPMusicPlayerController applicationMusicPlayer] play]; [self didChangeValueForKey:@"currentItem"]; } + - (float)progress { return [[MPMusicPlayerController applicationMusicPlayer] currentPlaybackTime]/[[[self mpItem] valueForProperty:MPMediaItemPropertyPlaybackDuration]doubleValue]; } + +#pragma mark - +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@"currentPlaybackTime"]) + { + [self willChangeValueForKey:@"progress"]; + + [self didChangeValueForKey:@"progress"]; + + } +} @end diff --git a/SongGong.xcodeproj/project.pbxproj b/SongGong.xcodeproj/project.pbxproj index 3381035..5688489 100644 --- a/SongGong.xcodeproj/project.pbxproj +++ b/SongGong.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ A73D786013D38FED00837A2F /* BlankAudio.png in Resources */ = {isa = PBXBuildFile; fileRef = A73D785F13D38FED00837A2F /* BlankAudio.png */; }; + A73D786313D39E2C00837A2F /* NSObject+SPInvocationGrabbing.m in Sources */ = {isa = PBXBuildFile; fileRef = A73D786213D39E2B00837A2F /* NSObject+SPInvocationGrabbing.m */; }; A7462B6E13D36CF300C5CEB5 /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = A7462B6D13D36CF300C5CEB5 /* icon.png */; }; A7462B9F13D3779600C5CEB5 /* mainicons_1.png in Resources */ = {isa = PBXBuildFile; fileRef = A7462B9513D3779600C5CEB5 /* mainicons_1.png */; }; A7462BA013D3779600C5CEB5 /* mainicons_2.png in Resources */ = {isa = PBXBuildFile; fileRef = A7462B9613D3779600C5CEB5 /* mainicons_2.png */; }; @@ -62,6 +63,8 @@ /* Begin PBXFileReference section */ A73D785F13D38FED00837A2F /* BlankAudio.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = BlankAudio.png; path = Resources/BlankAudio.png; sourceTree = SOURCE_ROOT; }; + A73D786113D39E2B00837A2F /* NSObject+SPInvocationGrabbing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SPInvocationGrabbing.h"; sourceTree = SOURCE_ROOT; }; + A73D786213D39E2B00837A2F /* NSObject+SPInvocationGrabbing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SPInvocationGrabbing.m"; sourceTree = SOURCE_ROOT; }; A7462B6D13D36CF300C5CEB5 /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = icon.png; path = Resources/icon.png; sourceTree = SOURCE_ROOT; }; A7462B9513D3779600C5CEB5 /* mainicons_1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = mainicons_1.png; path = "Resources/carousel icons/mainicons_1.png"; sourceTree = SOURCE_ROOT; }; A7462B9613D3779600C5CEB5 /* mainicons_2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = mainicons_2.png; path = "Resources/carousel icons/mainicons_2.png"; sourceTree = SOURCE_ROOT; }; @@ -258,6 +261,8 @@ A7E0002C13D15A3D0048B9EC /* SongGong */ = { isa = PBXGroup; children = ( + A73D786113D39E2B00837A2F /* NSObject+SPInvocationGrabbing.h */, + A73D786213D39E2B00837A2F /* NSObject+SPInvocationGrabbing.m */, BC8F929913D3757300824DB6 /* Rdio Source */, A7462BAE13D3841700C5CEB5 /* DummySource.h */, A7462BAF13D3841700C5CEB5 /* DummySource.m */, @@ -416,6 +421,7 @@ BC8F929C13D375E500824DB6 /* SGRdioSource.m in Sources */, A7462BB013D3841800C5CEB5 /* DummySource.m in Sources */, BCC1BFC613D38876004C0EE2 /* SGRdioSourceViewController.m in Sources */, + A73D786313D39E2C00837A2F /* NSObject+SPInvocationGrabbing.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };