From ba624caefdd73bdf9b2fdf98e2ba3e666b32fa75 Mon Sep 17 00:00:00 2001 From: Adam Demasi Date: Fri, 17 Mar 2017 12:41:14 +1030 Subject: [PATCH] first! --- .gitignore | 5 + Canzone.plist | 13 ++ HBCZNowPlayingBulletinProvider.h | 12 ++ HBCZNowPlayingBulletinProvider.m | 196 +++++++++++++++++ HBCZNowPlayingController.h | 7 + HBCZNowPlayingController.x | 114 ++++++++++ HBCZPreferences.h | 13 ++ HBCZPreferences.m | 46 ++++ LICENSE.md | 202 ++++++++++++++++++ Makefile | 36 ++++ README.md | 2 + Tweak.x | 35 +++ app/Makefile | 10 + app/Resources/AppIcon60x60@2x.png | Bin 0 -> 3205 bytes app/Resources/AppIcon60x60@3x.png | Bin 0 -> 4913 bytes app/Resources/AppIcon76x76@2x.png | Bin 0 -> 4053 bytes app/Resources/AppIcon83.5x83.5@2x.png | Bin 0 -> 4526 bytes app/Resources/Info.plist | 64 ++++++ app/main.m | 3 + control | 17 ++ notification-content/BridgingHeader.h | 11 + notification-content/Makefile | 12 ++ .../NotificationViewController.swift | 122 +++++++++++ notification-content/Resources/Info.plist | 40 ++++ postinst/BridgingHeader.h | 6 + postinst/Makefile | 9 + postinst/postinst.swift | 46 ++++ prefs/HBCZAboutListController.h | 5 + prefs/HBCZAboutListController.m | 9 + prefs/HBCZAuthorsTableCell.h | 6 + prefs/HBCZAuthorsTableCell.m | 50 +++++ prefs/HBCZRootListController.h | 5 + prefs/HBCZRootListController.x | 76 +++++++ prefs/Makefile | 14 ++ prefs/Resources/About.plist | 89 ++++++++ prefs/Resources/Info.plist | 30 +++ prefs/Resources/Root.plist | 161 ++++++++++++++ prefs/Resources/en.lproj/About.strings | 9 + prefs/Resources/en.lproj/Root.strings | 57 +++++ prefs/Resources/en_AU.lproj/About.strings | 9 + prefs/Resources/en_AU.lproj/Root.strings | 57 +++++ prefs/Resources/en_GB.lproj/About.strings | 9 + prefs/Resources/en_GB.lproj/Root.strings | 57 +++++ prefs/Resources/icon@2x.png | Bin 0 -> 2032 bytes prefs/Resources/icon@3x.png | Bin 0 -> 2979 bytes prefs/Resources/typestatusplus@2x.png | Bin 0 -> 2591 bytes prefs/entry.plist | 21 ++ provider/HBCZMusicProvider.h | 5 + provider/HBCZMusicProvider.m | 19 ++ provider/Makefile | 13 ++ .../Resources/Black_TypeStatusPlusMusic.png | Bin 0 -> 133 bytes .../Black_TypeStatusPlusMusic@2x.png | Bin 0 -> 156 bytes .../Black_TypeStatusPlusMusic@3x.png | Bin 0 -> 173 bytes provider/Resources/Info.plist | 12 ++ .../LockScreen_TypeStatusPlusMusic.png | Bin 0 -> 174 bytes .../LockScreen_TypeStatusPlusMusic@2x.png | Bin 0 -> 194 bytes .../LockScreen_TypeStatusPlusMusic@3x.png | Bin 0 -> 205 bytes widget/BridgingHeader.h | 3 + widget/Makefile | 13 ++ widget/Resources/Info.plist | 31 +++ widget/TodayViewController.swift | 36 ++++ 61 files changed, 1817 insertions(+) create mode 100644 .gitignore create mode 100644 Canzone.plist create mode 100644 HBCZNowPlayingBulletinProvider.h create mode 100644 HBCZNowPlayingBulletinProvider.m create mode 100644 HBCZNowPlayingController.h create mode 100644 HBCZNowPlayingController.x create mode 100644 HBCZPreferences.h create mode 100644 HBCZPreferences.m create mode 100644 LICENSE.md create mode 100644 Makefile create mode 100644 README.md create mode 100644 Tweak.x create mode 100644 app/Makefile create mode 100644 app/Resources/AppIcon60x60@2x.png create mode 100644 app/Resources/AppIcon60x60@3x.png create mode 100644 app/Resources/AppIcon76x76@2x.png create mode 100644 app/Resources/AppIcon83.5x83.5@2x.png create mode 100644 app/Resources/Info.plist create mode 100644 app/main.m create mode 100644 control create mode 100644 notification-content/BridgingHeader.h create mode 100644 notification-content/Makefile create mode 100644 notification-content/NotificationViewController.swift create mode 100644 notification-content/Resources/Info.plist create mode 100644 postinst/BridgingHeader.h create mode 100644 postinst/Makefile create mode 100644 postinst/postinst.swift create mode 100644 prefs/HBCZAboutListController.h create mode 100644 prefs/HBCZAboutListController.m create mode 100644 prefs/HBCZAuthorsTableCell.h create mode 100644 prefs/HBCZAuthorsTableCell.m create mode 100644 prefs/HBCZRootListController.h create mode 100644 prefs/HBCZRootListController.x create mode 100644 prefs/Makefile create mode 100644 prefs/Resources/About.plist create mode 100644 prefs/Resources/Info.plist create mode 100644 prefs/Resources/Root.plist create mode 100644 prefs/Resources/en.lproj/About.strings create mode 100644 prefs/Resources/en.lproj/Root.strings create mode 100644 prefs/Resources/en_AU.lproj/About.strings create mode 100644 prefs/Resources/en_AU.lproj/Root.strings create mode 100644 prefs/Resources/en_GB.lproj/About.strings create mode 100644 prefs/Resources/en_GB.lproj/Root.strings create mode 100644 prefs/Resources/icon@2x.png create mode 100644 prefs/Resources/icon@3x.png create mode 100644 prefs/Resources/typestatusplus@2x.png create mode 100644 prefs/entry.plist create mode 100644 provider/HBCZMusicProvider.h create mode 100644 provider/HBCZMusicProvider.m create mode 100644 provider/Makefile create mode 100644 provider/Resources/Black_TypeStatusPlusMusic.png create mode 100644 provider/Resources/Black_TypeStatusPlusMusic@2x.png create mode 100644 provider/Resources/Black_TypeStatusPlusMusic@3x.png create mode 100644 provider/Resources/Info.plist create mode 100644 provider/Resources/LockScreen_TypeStatusPlusMusic.png create mode 100644 provider/Resources/LockScreen_TypeStatusPlusMusic@2x.png create mode 100644 provider/Resources/LockScreen_TypeStatusPlusMusic@3x.png create mode 100644 widget/BridgingHeader.h create mode 100644 widget/Makefile create mode 100644 widget/Resources/Info.plist create mode 100644 widget/TodayViewController.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..98f25d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +.theos +packages + +libswiftQuartzCore.dylib diff --git a/Canzone.plist b/Canzone.plist new file mode 100644 index 0000000..0e4b901 --- /dev/null +++ b/Canzone.plist @@ -0,0 +1,13 @@ + + + + + Filter + + Bundles + + com.apple.springboard + + + + diff --git a/HBCZNowPlayingBulletinProvider.h b/HBCZNowPlayingBulletinProvider.h new file mode 100644 index 0000000..16e25cc --- /dev/null +++ b/HBCZNowPlayingBulletinProvider.h @@ -0,0 +1,12 @@ +#import + +@class SBApplication; + +@interface HBCZNowPlayingBulletinProvider : BBDataProvider + ++ (instancetype)sharedInstance; + +- (void)postBulletinForApp:(SBApplication *)app title:(NSString *)title artist:(NSString *)artist album:(NSString *)album art:(NSData *)art; +- (void)clearAllBulletins; + +@end diff --git a/HBCZNowPlayingBulletinProvider.m b/HBCZNowPlayingBulletinProvider.m new file mode 100644 index 0000000..eff7752 --- /dev/null +++ b/HBCZNowPlayingBulletinProvider.m @@ -0,0 +1,196 @@ +#import "HBCZNowPlayingBulletinProvider.h" +#import "HBCZNowPlayingController.h" +#import "HBCZPreferences.h" +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +static NSString *const kHBCZNowPlayingSubsectionIdentifier = @"ws.hbang.canzone.nowplayingsection"; +static NSString *const kHBCZNowPlayingLockSubsectionIdentifier = @"ws.hbang.canzone.nowplayinglocksection"; +static NSString *const kHBCZNowPlayingBulletinRecordIdentifier = @"ws.hbang.canzone.nowplaying"; +static NSString *const kHBCZNowPlayingCategoryIdentifier = @"CanzoneNowPlayingCategory"; + +@interface BBSectionSubtypeParameters () + +@property (nonatomic, copy) NSString *alternateActionLabel; +@property (nonatomic, copy) NSString *secondaryContentRemoteServiceBundleIdentifier; +@property (nonatomic, copy) NSString *secondaryContentRemoteViewControllerClassName; + +@end + +@implementation HBCZNowPlayingBulletinProvider { + HBCZPreferences *_preferences; + + UIImage *_currentArt; + NSMutableSet *_sentBulletins; +} + +#pragma mark - Singleton + ++ (instancetype)sharedInstance { + static HBCZNowPlayingBulletinProvider *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +#pragma mark - NSObject + +- (instancetype)init { + self = [super init]; + + if (self) { + // set up variables + _preferences = [HBCZPreferences sharedInstance]; + _currentArt = nil; + _sentBulletins = [NSMutableSet setWithCapacity:1]; + + // construct our data provider identity + BBDataProviderIdentity *identity = [BBDataProviderIdentity identityForDataProvider:self]; + + // give it our identifier and name + identity.sectionIdentifier = kHBCZAppIdentifier; + identity.sectionDisplayName = @"Now Playing"; + + // set ourself as only displaying alerts, not sounds or badges + identity.defaultSectionInfo.pushSettings = BBSectionInfoPushSettingsAlerts; + + // make up our subsection and set them + BBSectionInfo *mainSubsection = [BBSectionInfo defaultSectionInfoForType:2]; + mainSubsection.sectionID = identity.sectionIdentifier; + mainSubsection.subsectionID = kHBCZNowPlayingSubsectionIdentifier; + mainSubsection.allowsAddingToLockScreenWhenUnlocked = YES; + mainSubsection.allowsAutomaticRemovalFromLockScreen = NO; + mainSubsection.prioritizeAtTopOfLockScreen = YES; + + identity.defaultSubsectionInfos = @[ mainSubsection ]; + + // construct our default subtype parameters + BBSectionSubtypeParameters *subtypeParameters = identity.sectionParameters.defaultSubtypeParameters; + subtypeParameters.secondaryContentRemoteServiceBundleIdentifier = @"ws.hbang.canzone.app.notificationcontent"; + subtypeParameters.secondaryContentRemoteViewControllerClassName = @"NotificationViewController"; + + // construct our “replace lock media controls” subtype + BBSectionSubtypeParameters *lockParameters = [[BBSectionSubtypeParameters alloc] init]; + + identity.sectionParameters.allSubtypeParameters = [@{ + @2: lockParameters + } mutableCopy]; + + self.identity = identity; + } + + return self; +} + +#pragma mark - Post bulletin + +- (void)postBulletinForApp:(SBApplication *)app title:(NSString *)title artist:(NSString *)artist album:(NSString *)album art:(NSData *)art { + // if we need to pull the previous bulletins, do that first + if (!_preferences.nowPlayingKeepBulletins) { + [self clearAllBulletins]; + } + + // construct our bulletin + BBBulletinRequest *bulletin = [[BBBulletinRequest alloc] init]; + + // set the basic stuff + bulletin.bulletinID = [NSUUID UUID].UUIDString; + bulletin.sectionID = kHBCZAppIdentifier; + // bulletin.categoryID = kHBCZNowPlayingCategoryIdentifier; + + // set the record id based on the keep all bulletins setting + bulletin.recordID = bulletin.bulletinID; + + // set the subsection based on the hide music controls setting + bulletin.subsectionIDs = [NSSet setWithObject:_preferences.hideLockMusicControls ? kHBCZNowPlayingLockSubsectionIdentifier : kHBCZNowPlayingSubsectionIdentifier]; + + // set the text fields + bulletin.title = title; + + // if we have an album and artist, have them both separated by newline. otherwise, use whichever + // of the two exists (or none!) + if (album && artist) { + bulletin.message = [NSString stringWithFormat:@"%@\n%@", album, artist]; + } else { + bulletin.message = album ?: artist; + } + + // set all the rest + bulletin.date = [NSDate date]; + bulletin.lastInterruptDate = bulletin.date; + bulletin.turnsOnDisplay = _preferences.nowPlayingWakeWhenLocked; + bulletin.primaryAttachmentType = BBAttachmentMetadataTypeImage; + + // set a callback to open the app + bulletin.defaultAction = [BBAction actionWithLaunchBundleID:app.bundleIdentifier callblock:nil]; + + // on apple watch, launch NanoNowPlaying + // TODO: this doesn’t work :( maybe we’ll have to go back to the phone, then have the phone tell + // the watch to open the app + BBAction *watchAction = [BBAction actionWithAppearance:[BBAppearance appearanceWithTitle:@"Open"]]; + watchAction.identifier = @"open-on-watch"; + watchAction.callblock = ^{ HBLogWarn(@"watch out bitchezz"); }; + + // set all our supplementary actions + bulletin.supplementaryActionsByLayout = @{ + @1: @[ watchAction ] + }; + + // get a UIImage of the art and hold onto it + _currentArt = [[UIImage alloc] initWithData:art]; + + // send it! + BBDataProviderAddBulletin(self, bulletin); + [_sentBulletins addObject:bulletin]; +} + +- (void)clearAllBulletins { + // loop and remove all notifications we’ve sent + for (BBBulletinRequest *bulletin in _sentBulletins) { + BBDataProviderWithdrawBulletinsWithRecordID(self, bulletin.recordID); + } + + // empty the set + [_sentBulletins removeAllObjects]; +} + +#pragma mark - BBDataProvider + +- (NSArray *)sortDescriptors { + return @[ [NSSortDescriptor sortDescriptorWithKey:@"date" ascending:NO] ]; +} + +- (NSData *)attachmentPNGDataForRecordID:(NSString *)recordID sizeConstraints:(BBThumbnailSizeConstraints *)constraints { + // return the current item’s album art. this is only called once when the bulletin is being + // prepared for display; after that it’s stored, well, somewhere + + // no art? nothing for us to do + if (!_currentArt) { + return nil; + } + + // determine the size to use + CGSize size = [constraints sizeFromAspectRatio:1]; + + // render at the new size + UIGraphicsBeginImageContextWithOptions(size, NO, 0); + [_currentArt drawInRect:(CGRect){ CGPointZero, size }]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + // turn it back into a png and return it + return UIImagePNGRepresentation(newImage); +} + +@end diff --git a/HBCZNowPlayingController.h b/HBCZNowPlayingController.h new file mode 100644 index 0000000..642ae7f --- /dev/null +++ b/HBCZNowPlayingController.h @@ -0,0 +1,7 @@ +static NSString *const kHBCZAppIdentifier = @"ws.hbang.canzone.app"; + +@interface HBCZNowPlayingController : NSObject + ++ (instancetype)sharedInstance; + +@end diff --git a/HBCZNowPlayingController.x b/HBCZNowPlayingController.x new file mode 100644 index 0000000..d46840d --- /dev/null +++ b/HBCZNowPlayingController.x @@ -0,0 +1,114 @@ +#import "HBCZNowPlayingController.h" +#import "HBCZNowPlayingBulletinProvider.h" +#import "HBCZPreferences.h" +#import +#import +#import +#import +#import +#import + +@implementation HBCZNowPlayingController { + HBCZPreferences *_preferences; + HBCZNowPlayingBulletinProvider *_bulletinProvider; + + NSString *_lastSongIdentifier; +} + ++ (instancetype)sharedInstance { + static HBCZNowPlayingController *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +#pragma mark - NSObject + +- (instancetype)init { + self = [super init]; + + if (self) { + // set up variables + _preferences = [HBCZPreferences sharedInstance]; + _bulletinProvider = [HBCZNowPlayingBulletinProvider sharedInstance]; + _lastSongIdentifier = @""; + + // listen for the now playing change notification + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_mediaInfoDidChange:) name:(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDidChangeNotification object:nil]; + } + + return self; +} + +#pragma mark - Notification callbacks + +- (void)_mediaInfoDidChange:(NSNotification *)nsNotification { + MRMediaRemoteGetNowPlayingInfo(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(CFDictionaryRef result) { + // no really, why would you torture yourself and your clients by designing an api that uses + // CF objects? + NSDictionary *dictionary = (__bridge NSDictionary *)result; + NSString *title = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle]; + NSString *artist = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist]; + NSString *album = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum]; + NSData *art = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData]; + + // get the now playing app + SBApplication *nowPlayingApp = ((SBMediaController *)[%c(SBMediaController) sharedInstance]).nowPlayingApplication; + + // no title or app? that’s weird. we can’t really do much without those things + if (!title || !nowPlayingApp) { + return; + } + + // construct our internal identifier + NSString *identifier = [NSString stringWithFormat:@"title = %@, artist = %@, album = %@", title, artist, album]; + + // have we just shown one for this? ignore it + if ([_lastSongIdentifier isEqualToString:identifier]) { + return; + } + + // store the identifier + _lastSongIdentifier = identifier; + + // get the frontmost app + SBApplication *frontmostApp = ((SpringBoard *)[UIApplication sharedApplication])._accessibilityFrontMostApplication; + + // if the now playing provider is enabled, and typestatus plus is present + if (_preferences.nowPlayingProvider && %c(HBTSPlusProviderController)) { + // as long as this isn’t coming from the frontmost app + if (![frontmostApp.bundleIdentifier isEqualToString:nowPlayingApp.bundleIdentifier]) { + // post it as a provider notification + [self _postProviderNotificationForApp:nowPlayingApp title:title artist:artist]; + } + } else { + // else, post a bulletin + [_bulletinProvider postBulletinForApp:nowPlayingApp title:title artist:artist album:album art:art]; + } + }); +} + +#pragma mark - TypeStatus Provider + +- (void)_postProviderNotificationForApp:(SBApplication *)app title:(NSString *)title artist:(NSString *)artist { + // if typestatus plus provider api isn’t available, don’t do anything + if (!%c(HBTSPlusProviderController)) { + return; + } + + // construct a notification + HBTSNotification *notification = [[%c(HBTSNotification) alloc] init]; + notification.content = artist ? [NSString stringWithFormat:@"%@ – %@", title, artist] : title; + notification.boldRange = NSMakeRange(0, title.length); + notification.statusBarIconName = @"TypeStatusPlusMusic"; + notification.sourceBundleID = app.bundleIdentifier; + + // grab our provider and show it + HBTSPlusProvider *provider = [[%c(HBTSPlusProviderController) sharedInstance] providerWithAppIdentifier:kHBCZAppIdentifier]; + [provider showNotification:notification]; +} + +@end diff --git a/HBCZPreferences.h b/HBCZPreferences.h new file mode 100644 index 0000000..348f730 --- /dev/null +++ b/HBCZPreferences.h @@ -0,0 +1,13 @@ +#import + +@interface HBCZPreferences : NSObject + ++ (instancetype)sharedInstance; + +@property (readonly) BOOL nowPlayingKeepBulletins, nowPlayingWakeWhenLocked, hideLockMusicControls; + +@property (readonly) BOOL nowPlayingProvider; + +- (void)registerPreferenceChangeBlock:(HBPreferencesChangeCallback)callback; + +@end diff --git a/HBCZPreferences.m b/HBCZPreferences.m new file mode 100644 index 0000000..3fad504 --- /dev/null +++ b/HBCZPreferences.m @@ -0,0 +1,46 @@ +#import "HBCZPreferences.h" + +@implementation HBCZPreferences { + HBPreferences *_preferences; +} + ++ (instancetype)sharedInstance { + static HBCZPreferences *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _preferences = [[HBPreferences alloc] initWithIdentifier:@"ws.hbang.canzone"]; + + // if typestatus plus is installed, enable the provider and disable hiding lock music controls + // by default + if (!_preferences[@"NowPlayingProvider"]) { + BOOL hasTypeStatusPlus = [[NSFileManager defaultManager] fileExistsAtPath:@"/Library/MobileSubstrate/DynamicLibraries/TypeStatusPlus.dylib"]; + + _preferences[@"NowPlayingProvider"] = @(hasTypeStatusPlus); + _preferences[@"HideLockMusicControls"] = @(!hasTypeStatusPlus); + } + + [_preferences registerBool:&_nowPlayingKeepBulletins default:NO forKey:@"NowPlayingKeepBulletins"]; + [_preferences registerBool:&_nowPlayingWakeWhenLocked default:NO forKey:@"NowPlayingWakeWhenLocked"]; + [_preferences registerBool:&_hideLockMusicControls default:YES forKey:@"HideLockMusicControls"]; + + [_preferences registerBool:&_nowPlayingProvider default:YES forKey:@"NowPlayingProvider"]; + } + + return self; +} + +- (void)registerPreferenceChangeBlock:(HBPreferencesChangeCallback)callback { + [_preferences registerPreferenceChangeBlock:callback]; +} + +@end diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..189712d --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +export TARGET = iphone:10.1:10.0 + +# since this is for iOS 10 only, and there isn’t a jailbreak for 32-bit devices yet, cheat a bit +# and only build for arm64 +export ARCHS = arm64 + +INSTALL_TARGET_PROCESSES = Preferences CanzoneNowPlayingWidget CanzoneNotificationContent + +ifneq ($(RESPRING),0) +INSTALL_TARGET_PROCESSES += SpringBoard +endif + +include $(THEOS)/makefiles/common.mk + +TWEAK_NAME = Canzone +Canzone_FILES = $(wildcard *.x) $(wildcard *.m) +Canzone_FRAMEWORKS = UIKit +Canzone_PRIVATE_FRAMEWORKS = BulletinBoard MediaRemote +Canzone_EXTRA_FRAMEWORKS = Cephei +Canzone_CFLAGS = -fobjc-arc + +include $(THEOS_MAKE_PATH)/tweak.mk + +ifneq ($(TARGET),simulator) +SUBPROJECTS += widget notification-content provider prefs postinst app +include $(THEOS_MAKE_PATH)/aggregate.mk +endif + +after-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Applications/Canzone.app/Frameworks$(ECHO_END) + $(ECHO_NOTHING)cp libswiftQuartzCore.dylib $(THEOS_STAGING_DIR)/Applications/Canzone.app/Frameworks$(ECHO_END) + +after-install:: +ifeq ($(RESPRING),0) + install.exec "uiopen prefs:root=Canzone" +endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..b7721ed --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Canzone +Licensed under the Apache License, version 2.0. Refer to [LICENSE.md](LICENSE.md). diff --git a/Tweak.x b/Tweak.x new file mode 100644 index 0000000..19428d9 --- /dev/null +++ b/Tweak.x @@ -0,0 +1,35 @@ +#import "HBCZNowPlayingBulletinProvider.h" +#import "HBCZNowPlayingController.h" +#import + +#pragma mark - Notification Center + +%hook BBLocalDataProviderStore + +- (void)loadAllDataProvidersAndPerformMigration:(BOOL)performMigration { + %orig; + + // add ourself as a data provider + [self addDataProvider:[HBCZNowPlayingBulletinProvider sharedInstance] performMigration:YES]; +} + +%end + +#pragma mark - Hide now playing controls + +%hook SBLockScreenNowPlayingController + +- (void)_updateToState:(long long)state { + // TODO: work out the enum values + // but basically, anything over 2 is “enabled”, 0 and 1 are “disabled” in some way + %orig(preferences.hideLockMusicControls && state > 1 ? 0 : state); +} + +%end + +#pragma mark - Constructor + +%ctor { + // get the controller rolling + [HBCZNowPlayingController sharedInstance]; +} diff --git a/app/Makefile b/app/Makefile new file mode 100644 index 0000000..128152e --- /dev/null +++ b/app/Makefile @@ -0,0 +1,10 @@ +TARGET = iphone:10.1:10.0 + +include $(THEOS)/makefiles/common.mk + +APPLICATION_NAME = Canzone +Canzone_FILES = main.m +Canzone_FRAMEWORKS = UIKit +Canzone_ARCHS = armv7 + +include $(THEOS_MAKE_PATH)/application.mk diff --git a/app/Resources/AppIcon60x60@2x.png b/app/Resources/AppIcon60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..edb32f33bb8dee3d289a41792598e11f5270c0dd GIT binary patch literal 3205 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 literal 0 HcmV?d00001 diff --git a/app/Resources/AppIcon60x60@3x.png b/app/Resources/AppIcon60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..dc5902e0e4fb9d51c109e4d9715536feebf3e5e5 GIT binary patch literal 4913 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 Hu0mjfYq45J literal 0 HcmV?d00001 diff --git a/app/Resources/AppIcon83.5x83.5@2x.png b/app/Resources/AppIcon83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a48d873bbbcd626926a896bb2435e8f08032b780 GIT binary patch literal 4526 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 + + + + CFBundleExecutable + Canzone + CFBundleIcons + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon60x60 + + UIPrerenderedIcon + + + + CFBundleIcons~ipad + + CFBundlePrimaryIcon + + CFBundleIconFiles + + AppIcon76x76 + AppIcon83.5x83.5 + + UIPrerenderedIcon + + + + CFBundleIdentifier + ws.hbang.canzone.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + armv7 + + SBAppTags + + hidden + + HBAppRequiresContainer + + + diff --git a/app/main.m b/app/main.m new file mode 100644 index 0000000..cb3f748 --- /dev/null +++ b/app/main.m @@ -0,0 +1,3 @@ +int main() { + return 0; +} diff --git a/control b/control new file mode 100644 index 0000000..d04adb4 --- /dev/null +++ b/control @@ -0,0 +1,17 @@ +Package: ws.hbang.canzone +Name: Canzone +Depends: firmware (>= 10.0), firmware (<< 10.3), mobilesubstrate, preferenceloader, ws.hbang.common (>= 1.10) +Suggests: ws.hbang.typestatusplus +Conflicts: ws.hbang.typestatusplusproviders (<< 1.1) +Replaces: ws.hbang.typestatusplusproviders (<< 1.1) +Version: 1.0 +Architecture: iphoneos-arm +Description: Widget and notifications for now playing music +Maintainer: HASHBANG Productions +Author: HASHBANG Productions +Section: Tweaks +Icon: file:///Library/PreferenceBundles/Canzone.bundle/icon@2x.png +Depiction: https://cydia.hbang.ws/depiction/ws.hbang.canzone/ +Support: https://www.hbang.ws/support/ +Sponsor: thebigboss.org +dev: hbang diff --git a/notification-content/BridgingHeader.h b/notification-content/BridgingHeader.h new file mode 100644 index 0000000..daea0ba --- /dev/null +++ b/notification-content/BridgingHeader.h @@ -0,0 +1,11 @@ +@import UIKit; +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/notification-content/Makefile b/notification-content/Makefile new file mode 100644 index 0000000..deba333 --- /dev/null +++ b/notification-content/Makefile @@ -0,0 +1,12 @@ +include $(THEOS)/makefiles/common.mk + +APPEX_NAME = CanzoneNotificationContent +CanzoneNotificationContent_FILES = $(wildcard *.swift) +CanzoneNotificationContent_INSTALL_PATH = /Applications/Canzone.app/PlugIns +CanzoneNotificationContent_FRAMEWORKS = UserNotifications UserNotificationsUI +CanzoneNotificationContent_PRIVATE_FRAMEWORKS = MediaPlayerUI MediaRemote +CanzoneNotificationContent_EXTRA_FRAMEWORKS = Cephei +CanzoneNotificationContent_SWIFT_BRIDGING_HEADER = BridgingHeader.h +CanzoneNotificationContent_LDFLAGS = -L.. -lswiftQuartzCore + +include $(THEOS_MAKE_PATH)/appex.mk diff --git a/notification-content/NotificationViewController.swift b/notification-content/NotificationViewController.swift new file mode 100644 index 0000000..00fb3fc --- /dev/null +++ b/notification-content/NotificationViewController.swift @@ -0,0 +1,122 @@ +import MobileCoreServices +import UIKit +import UserNotifications +import UserNotificationsUI + +@objc(NotificationViewController) +class NotificationViewController: UIViewController, UNNotificationContentExtension, MPUNowPlayingDelegate { + + // we need to keep strong references around to these, otherwise they’d be released by ARC and we + // don’t get to have the goodness they provide + var nowPlayingController: MPUNowPlayingController! + var controlsViewController: MPUControlCenterMediaControlsViewController! + + var artworkView: MPUNowPlayingArtworkView! + var infoLabel: UILabel! + var transportControls: UIView! + + // MARK: - View controller + + override func loadView() { + super.loadView() + + view.translatesAutoresizingMaskIntoConstraints = false + + // construct the views + // we disable user interaction on the artworkView as this allows touches to fall through to the + // tap gesture recognizer in springboard, which will open the app + artworkView = MPUNowPlayingArtworkView() + artworkView.activated = true + artworkView.translatesAutoresizingMaskIntoConstraints = false + artworkView.isUserInteractionEnabled = false + view.addSubview(artworkView) + + let labelsContainerView = UIView() + labelsContainerView.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(labelsContainerView) + + infoLabel = UILabel() + infoLabel.translatesAutoresizingMaskIntoConstraints = false + infoLabel.numberOfLines = 0 + labelsContainerView.addSubview(infoLabel) + + // steal the transport controls from MPUControlCenterMediaControlsViewController, which will + // manage them for us + controlsViewController = MPUControlCenterMediaControlsViewController() + transportControls = controlsViewController.view.transportControls + transportControls.translatesAutoresizingMaskIntoConstraints = false + labelsContainerView.addSubview(transportControls) + + let metrics: [String: NSNumber] = [ + "outerMargin": 20, + "innerMargin": 15, + "labelSpacing": 4, + "artworkSize": 151, + "controlsMargin": 15, + "transportControlsHeight": 44 + ] + + let views: [String: UIView] = [ + "view": view, + "artworkView": artworkView, + "labelsContainerView": labelsContainerView, + "infoLabel": infoLabel, + "transportControls": transportControls + ] + + view.hb_addCompactConstraints([ + "artworkView.width = artworkSize", + "artworkView.height = artworkSize", + "artworkView.top = view.top + outerMargin", + "artworkView.left = view.left + outerMargin", + "artworkView.bottom = view.bottom - outerMargin", + "labelsContainerView.left = artworkView.right + innerMargin", + "labelsContainerView.right = view.right - outerMargin", + "labelsContainerView.centerY = artworkView.centerY" + ], metrics: metrics, views: views) + + labelsContainerView.hb_addCompactConstraints([ + "infoLabel.top = self.top", + "infoLabel.left = self.left", + "infoLabel.right = self.right", + "transportControls.top = infoLabel.bottom", + "transportControls.left = self.left + controlsMargin", + "transportControls.right = self.right + controlsMargin", + "transportControls.bottom = self.bottom", + "transportControls.height = transportControlsHeight" + ], metrics: metrics, views: views) + + nowPlayingController = MPUNowPlayingController() + nowPlayingController.delegate = self + nowPlayingController.startUpdating() + } + + // MARK: - Now playing + + func nowPlayingController(_ nowPlayingController: MPUNowPlayingController!, nowPlayingInfoDidChange info: [AnyHashable: Any]!) { + artworkView.artworkImage = nowPlayingController.currentNowPlayingArtwork + + let metadata = nowPlayingController.currentNowPlayingMetadata! + + infoLabel.text = "\(metadata.title ?? "")\n\(metadata.album ?? "")\n\(metadata.artist ?? "")" + + /*if nowPlayingController.nowPlayingAppDisplayID == nil { + appNameLabel.text = "" + } else { + if let app = LSApplicationProxy(forIdentifier: nowPlayingController.nowPlayingAppDisplayID) { + appNameLabel.text = app.localizedName.localizedUppercase + } + }*/ + } + + func nowPlayingController(_ nowPlayingController: MPUNowPlayingController!, playbackStateDidChange state: Bool) { + artworkView.setActivated(state, animated: true) + } + + // MARK: - Notification content + + func didReceive(_ notification: UNNotification) { + // do nothing, just have to implement this to make the protocol happy + } + +} diff --git a/notification-content/Resources/Info.plist b/notification-content/Resources/Info.plist new file mode 100644 index 0000000..8c7b592 --- /dev/null +++ b/notification-content/Resources/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Canzone Notification Content + CFBundleExecutable + CanzoneNotificationContent + CFBundleIdentifier + ws.hbang.canzone.app.notificationcontent + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CanzoneNotificationContent + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionPrincipalClass + NotificationViewController + NSExtensionAttributes + + UNNotificationExtensionCategory + CanzoneNowPlayingCategory + UNNotificationExtensionDefaultContentHidden + + UNNotificationExtensionInitialContentSizeRatio + 0.5 + + NSExtensionPointIdentifier + com.apple.usernotifications.content-extension + + + diff --git a/postinst/BridgingHeader.h b/postinst/BridgingHeader.h new file mode 100644 index 0000000..244b3e4 --- /dev/null +++ b/postinst/BridgingHeader.h @@ -0,0 +1,6 @@ +@import Foundation; +@import MobileCoreServices; + +#import +#import +#import diff --git a/postinst/Makefile b/postinst/Makefile new file mode 100644 index 0000000..f4ad6d9 --- /dev/null +++ b/postinst/Makefile @@ -0,0 +1,9 @@ +include $(THEOS)/makefiles/common.mk + +TOOL_NAME = postinst + +postinst_FILES = postinst.swift +postinst_INSTALL_PATH = /DEBIAN +postinst_SWIFT_BRIDGING_HEADER = BridgingHeader.h + +include $(THEOS_MAKE_PATH)/tool.mk diff --git a/postinst/postinst.swift b/postinst/postinst.swift new file mode 100644 index 0000000..5f89f1a --- /dev/null +++ b/postinst/postinst.swift @@ -0,0 +1,46 @@ +import MobileCoreServices + +let workspace = LSApplicationWorkspace.default()! + +func registerApp(identifier: String, path: URL) { + // try to get an app with a matching name + let app = LSApplicationProxy(forIdentifier: identifier) + + // if we got nothing back, we’re not registered + if app == nil { + // ask to be registered + let result = workspace.registerApplication(path) + + // hopefully it doesn’t fail… if it does then print and fail + if !result { + print("Failed to register the \(identifier) app!") + exit(1) + } + } +} + +func registerPlugin(identifier: String, path: URL) { + // get all plugins matching ours – which, for whatever reason, returns all plugins if it can’t + // find a match… + let plugins = workspace.plugins(withIdentifiers: [ identifier ], protocols: nil, version: nil) as! [LSPlugInKitProxy] + + // …so filter to plugins matching our identifier + let ourPlugin = plugins.filter { $0.pluginIdentifier == identifier } + + // if we got nothing back, we’re not registered + if ourPlugin.count == 0 { + // ask to be registered + let result = workspace.registerPlugin(path) + + // hopefully it doesn’t fail… if it does then print and fail + if !result { + print("Failed to register the \(identifier) plugin!") + exit(1) + } + } +} + +// register the app, followed by its plugins. ew this could be better :/ +registerApp(identifier: "ws.hbang.canzone.app", path: URL(fileURLWithPath: "/Applications/Canzone.app")) +registerPlugin(identifier: "ws.hbang.canzone.app.nowplayingwidget", path: URL(fileURLWithPath: "/Applications/Canzone.app/PlugIns/CanzoneNowPlayingWidget.appex")) +registerPlugin(identifier: "ws.hbang.canzone.app.notificationcontent", path: URL(fileURLWithPath: "/Applications/Canzone.app/PlugIns/CanzoneNotificationContent.appex")) diff --git a/prefs/HBCZAboutListController.h b/prefs/HBCZAboutListController.h new file mode 100644 index 0000000..63afae9 --- /dev/null +++ b/prefs/HBCZAboutListController.h @@ -0,0 +1,5 @@ +#import + +@interface HBCZAboutListController : HBAboutListController + +@end diff --git a/prefs/HBCZAboutListController.m b/prefs/HBCZAboutListController.m new file mode 100644 index 0000000..d857096 --- /dev/null +++ b/prefs/HBCZAboutListController.m @@ -0,0 +1,9 @@ +#import "HBCZAboutListController.h" + +@implementation HBCZAboutListController + ++ (NSString *)hb_specifierPlist { + return @"About"; +} + +@end diff --git a/prefs/HBCZAuthorsTableCell.h b/prefs/HBCZAuthorsTableCell.h new file mode 100644 index 0000000..352d832 --- /dev/null +++ b/prefs/HBCZAuthorsTableCell.h @@ -0,0 +1,6 @@ +#import +#import + +@interface HBCZAuthorsTableCell : PSTableCell + +@end diff --git a/prefs/HBCZAuthorsTableCell.m b/prefs/HBCZAuthorsTableCell.m new file mode 100644 index 0000000..7985b8e --- /dev/null +++ b/prefs/HBCZAuthorsTableCell.m @@ -0,0 +1,50 @@ +#import "HBCZAuthorsTableCell.h" + +@implementation HBCZAuthorsTableCell { + UITextView *_textView; +} + +- (instancetype)initWithSpecifier:(PSSpecifier *)specifier { + self = [self initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil specifier:specifier]; + + if (self) { + // construct an attributed string + NSString *text = NSLocalizedStringFromTableInBundle(@"AUTHORS_LABEL", @"About", [NSBundle bundleForClass:self.class], @""); + + NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; + paragraphStyle.alignment = NSTextAlignmentCenter; + + NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:@{ + NSFontAttributeName: [UIFont systemFontOfSize:14.f], + NSForegroundColorAttributeName: [UIColor colorWithWhite:40.f / 255.f alpha:1], + NSBaselineOffsetAttributeName: @(6.f), + NSParagraphStyleAttributeName: paragraphStyle, + }]; + + // set up the links + [attributedString addAttributes:@{ + NSLinkAttributeName: [NSURL URLWithString:@"https://twitter.com/tmnlsthrn"] + } range:[text rangeOfString:@"Timon Olsthoorn"]]; + + [attributedString addAttributes:@{ + NSLinkAttributeName: [NSURL URLWithString:@"http://kirb.me/"] + } range:[text rangeOfString:@"Adam Demasi"]]; + + // instantiate and add a text view with the attributed string + _textView = [[UITextView alloc] initWithFrame:self.contentView.bounds]; + _textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _textView.backgroundColor = nil; + _textView.attributedText = attributedString; + _textView.editable = NO; + _textView.scrollEnabled = NO; + [self.contentView addSubview:_textView]; + } + + return self; +} + +- (CGFloat)preferredHeightForWidth:(CGFloat)width { + return ceilf([_textView sizeThatFits:CGSizeMake(width - 30.f, CGFLOAT_MAX)].height); +} + +@end diff --git a/prefs/HBCZRootListController.h b/prefs/HBCZRootListController.h new file mode 100644 index 0000000..e85d48a --- /dev/null +++ b/prefs/HBCZRootListController.h @@ -0,0 +1,5 @@ +#import + +@interface HBCZRootListController : HBRootListController + +@end diff --git a/prefs/HBCZRootListController.x b/prefs/HBCZRootListController.x new file mode 100644 index 0000000..feebab3 --- /dev/null +++ b/prefs/HBCZRootListController.x @@ -0,0 +1,76 @@ +#import "HBCZRootListController.h" +#import +#import +#import + +@implementation HBCZRootListController + +#pragma mark - Constants + ++ (NSString *)hb_specifierPlist { + return @"Root"; +} + ++ (NSString *)hb_shareText { + NSBundle *bundle = [NSBundle bundleForClass:self.class]; + return [NSString stringWithFormat:[bundle localizedStringForKey:@"SHARE_TEXT" value:nil table:@"Root"], [UIDevice currentDevice].localizedModel]; +} + ++ (NSURL *)hb_shareURL { + return [NSURL URLWithString:@"https://cydia.hbang.ws/package/ws.hbang.canzone/"]; +} + +#pragma mark - UIViewController + +- (instancetype)init { + self = [super init]; + + if (self) { + HBAppearanceSettings *appearanceSettings = [[HBAppearanceSettings alloc] init]; + appearanceSettings.tintColor = [UIColor colorWithRed:255.f / 255.f green:45.f / 255.f blue:85.f / 255.f alpha:1]; + self.hb_appearanceSettings = appearanceSettings; + } + + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + [self setUpSpecifiers]; +} + +- (void)reloadSpecifiers { + [super reloadSpecifiers]; + [self setUpSpecifiers]; +} + +- (void)setUpSpecifiers { + // grab the typestatus plus bundle + NSBundle *plusBundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/TypeStatusPlus.bundle"]; + PSSpecifier *notificationSpecifier; + + // remove specifiers based on whether it’s installed or not + if (plusBundle.executableURL) { + [self removeSpecifierID:@"NotificationsGroup"]; + [self removeSpecifierID:@"TypeStatusPlusNotInstalledGroup"]; + [self removeSpecifierID:@"TypeStatusPlusNotInstalled"]; + notificationSpecifier = [self specifierForID:@"TypeStatusPlusNotificationsGroup"]; + } else { + [self removeSpecifierID:@"TypeStatusPlusNotificationsGroup"]; + [self removeSpecifierID:@"TypeStatusPlusGroup"]; + [self removeSpecifierID:@"TypeStatusPlus"]; + notificationSpecifier = [self specifierForID:@"NotificationsGroup"]; + } + + // construct a system notification settings cell + PSSystemPolicyForApp *policy = [[PSSystemPolicyForApp alloc] initWithBundleIdentifier:@"ws.hbang.canzone.app"]; + + // this usually returns an array of specifiers, including the “allow [app] to access” group + // specifier, which we kinda don’t want. after this method does its thing, notificationSpecifier + // will be non-nil, and we can just add that + [policy specifiersForPolicyOptions:PSSystemPolicyOptionsNotifications force:YES]; + + [self insertSpecifier:policy.notificationSpecifier afterSpecifier:notificationSpecifier]; +} + +@end diff --git a/prefs/Makefile b/prefs/Makefile new file mode 100644 index 0000000..09d9782 --- /dev/null +++ b/prefs/Makefile @@ -0,0 +1,14 @@ +include $(THEOS)/makefiles/common.mk + +BUNDLE_NAME = Canzone +Canzone_FILES = $(wildcard *.m) $(wildcard *.x) +Canzone_INSTALL_PATH = /Library/PreferenceBundles +Canzone_CFLAGS = -fobjc-arc +Canzone_PRIVATE_FRAMEWORKS = Preferences +Canzone_EXTRA_FRAMEWORKS = CydiaSubstrate CepheiPrefs + +include $(THEOS_MAKE_PATH)/bundle.mk + +internal-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) + $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/Canzone.plist$(ECHO_END) diff --git a/prefs/Resources/About.plist b/prefs/Resources/About.plist new file mode 100644 index 0000000..b95b696 --- /dev/null +++ b/prefs/Resources/About.plist @@ -0,0 +1,89 @@ + + + + + items + + + cell + PSGroupCell + condensed + + headerCellClass + HBPackageNameHeaderCell + icon + icon.png + packageIdentifier + ws.hbang.canzone + + + cell + PSGroupCell + headerCellClass + HBCZAuthorsTableCell + + + cell + PSGroupCell + + + cell + PSButtonCell + cellClass + HBLinkTableCell + label + hbang.ws + url + https://hbang.ws/ + + + cell + PSGroupCell + + + action + hb_sendSupportEmail + cell + PSLinkCell + cellClass + HBTintedTableCell + defaults + ws.hbang.canzone + label + EMAIL_SUPPORT + + + cell + PSGroupCell + + + cell + PSButtonCell + cellClass + HBLinkTableCell + label + TRANSLATORS + url + https://hbang.ws/translations/ + + + cell + PSGroupCell + footerText + DONATE_FOOTER + + + cell + PSButtonCell + cellClass + HBLinkTableCell + label + DONATE + url + https://hbang.ws/donate/ + + + title + ABOUT + + diff --git a/prefs/Resources/Info.plist b/prefs/Resources/Info.plist new file mode 100644 index 0000000..c7e42d7 --- /dev/null +++ b/prefs/Resources/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Canzone + CFBundleIdentifier + ws.hbang.canzone + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Canzone + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + DTPlatformName + iphoneos + HBPackageIdentifier + ws.hbang.canzone + NSPrincipalClass + HBCZRootListController + + diff --git a/prefs/Resources/Root.plist b/prefs/Resources/Root.plist new file mode 100644 index 0000000..4829457 --- /dev/null +++ b/prefs/Resources/Root.plist @@ -0,0 +1,161 @@ + + + + + items + + + cell + PSGroupCell + footerText + WIDGET_EXPLANATION + + + cell + PSGroupCell + id + TypeStatusPlusGroup + label + TYPESTATUS_PLUS + footerText + TYPESTATUS_PLUS_PROVIDER_EXPLANATION + + + cell + PSSwitchCell + default + + defaults + ws.hbang.canzone + key + NowPlayingProvider + label + TYPESTATUS_PLUS_PROVIDER + PostNotification + ws.hbang.canzone/ReloadPrefs + + + cell + PSGroupCell + id + TypeStatusPlusNotificationsGroup + label + NOTIFICATIONS + footerText + NOW_PLAYING_BULLETINS_EXPLANATION + + + cell + PSGroupCell + id + NotificationsGroup + footerText + NOW_PLAYING_BULLETINS_EXPLANATION + + + id + NotificationsCell + + + cell + PSGroupCell + footerText + KEEP_ALL_NOTIFICATIONS_EXPLANATION + + + cell + PSSwitchCell + default + + defaults + ws.hbang.canzone + key + NowPlayingKeepBulletins + label + KEEP_ALL_NOTIFICATIONS + PostNotification + ws.hbang.canzone/ReloadPrefs + + + cell + PSGroupCell + footerText + WAKE_WHEN_LOCKED_EXPLANATION + + + cell + PSSwitchCell + default + + defaults + ws.hbang.canzone + key + NowPlayingWakeWhenLocked + label + WAKE_WHEN_LOCKED + PostNotification + ws.hbang.canzone/ReloadPrefs + + + cell + PSGroupCell + footerText + HIDE_LOCK_MUSIC_CONTROLS_EXPLANATION + + + cell + PSSwitchCell + default + + defaults + ws.hbang.canzone + key + HideLockMusicControls + label + HIDE_LOCK_MUSIC_CONTROLS + PostNotification + ws.hbang.canzone/ReloadPrefs + + + cell + PSGroupCell + id + TypeStatusPlusNotInstalledGroup + + + big + + cellClass + HBLinkTableCell + height + 64 + icon + typestatusplus.png + id + TypeStatusPlusNotInstalled + label + TYPESTATUS_PLUS + subtitle + TYPESTATUS_PLUS_SUBTITLE + url + https://typestatus.com/plus/ + + + cell + PSGroupCell + + + cell + PSLinkCell + detail + HBCZAboutListController + isController + + label + ABOUT + + + title + Canzone + + diff --git a/prefs/Resources/en.lproj/About.strings b/prefs/Resources/en.lproj/About.strings new file mode 100644 index 0000000..05f36a0 --- /dev/null +++ b/prefs/Resources/en.lproj/About.strings @@ -0,0 +1,9 @@ + + + + + AUTHORS_LABEL + Designed by Timon Olsthoorn in the Netherlands +Assembled by Adam Demasi in Australia + + diff --git a/prefs/Resources/en.lproj/Root.strings b/prefs/Resources/en.lproj/Root.strings new file mode 100644 index 0000000..0349eb3 --- /dev/null +++ b/prefs/Resources/en.lproj/Root.strings @@ -0,0 +1,57 @@ + + + + + + WIDGET_EXPLANATION + Enable the Now Playing widget via the Notification Center Today page. + + + NOTIFICATIONS + Notifications + + + NOW_PLAYING_BULLETINS_EXPLANATION + Show a notification when the now playing song changes. Swipe or 3D Touch to reveal playback controls. + + + KEEP_ALL_NOTIFICATIONS + Keep All Notifications + + + KEEP_ALL_NOTIFICATIONS_EXPLANATION + Keep all now playing notifications in the Notification Center, or only show the latest. + + + WAKE_WHEN_LOCKED + Wake When Locked + + + WAKE_WHEN_LOCKED_EXPLANATION + Wake the screen when showing a now playing notification while the device is locked. + + + HIDE_LOCK_MUSIC_CONTROLS + Replace Lock Screen Music Controls + + + HIDE_LOCK_MUSIC_CONTROLS_EXPLANATION + Use the now playing notification or widget to control your music. + + + TYPESTATUS_PLUS + TypeStatus Plus + + + TYPESTATUS_PLUS_PROVIDER + Provider + + + TYPESTATUS_PLUS_PROVIDER_EXPLANATION + Use subtle TypeStatus notifications instead of banners. + + + TYPESTATUS_PLUS_SUBTITLE + Get subtle now playing notifications in your status bar, and more, with TypeStatus Plus. + + diff --git a/prefs/Resources/en_AU.lproj/About.strings b/prefs/Resources/en_AU.lproj/About.strings new file mode 100644 index 0000000..05f36a0 --- /dev/null +++ b/prefs/Resources/en_AU.lproj/About.strings @@ -0,0 +1,9 @@ + + + + + AUTHORS_LABEL + Designed by Timon Olsthoorn in the Netherlands +Assembled by Adam Demasi in Australia + + diff --git a/prefs/Resources/en_AU.lproj/Root.strings b/prefs/Resources/en_AU.lproj/Root.strings new file mode 100644 index 0000000..2cfcf1b --- /dev/null +++ b/prefs/Resources/en_AU.lproj/Root.strings @@ -0,0 +1,57 @@ + + + + + + WIDGET_EXPLANATION + Enable the Now Playing widget via the Notification Centre Today page. + + + NOTIFICATIONS + Notifications + + + NOW_PLAYING_BULLETINS_EXPLANATION + Show a notification when the now playing song changes. Swipe or 3D Touch to reveal playback controls. + + + KEEP_ALL_NOTIFICATIONS + Keep All Notifications + + + KEEP_ALL_NOTIFICATIONS_EXPLANATION + Keep all now playing notifications in the Notification Centre, or only show the latest. + + + WAKE_WHEN_LOCKED + Wake When Locked + + + WAKE_WHEN_LOCKED_EXPLANATION + Wake the screen when showing a now playing notification while the device is locked. + + + HIDE_LOCK_MUSIC_CONTROLS + Replace Lock Screen Music Controls + + + HIDE_LOCK_MUSIC_CONTROLS_EXPLANATION + Use the now playing notification or widget to control your music. + + + TYPESTATUS_PLUS + TypeStatus Plus + + + TYPESTATUS_PLUS_PROVIDER + Provider + + + TYPESTATUS_PLUS_PROVIDER_EXPLANATION + Use subtle TypeStatus notifications instead of banners. + + + TYPESTATUS_PLUS_SUBTITLE + Get subtle now playing notifications in your status bar, and more, with TypeStatus Plus. + + diff --git a/prefs/Resources/en_GB.lproj/About.strings b/prefs/Resources/en_GB.lproj/About.strings new file mode 100644 index 0000000..05f36a0 --- /dev/null +++ b/prefs/Resources/en_GB.lproj/About.strings @@ -0,0 +1,9 @@ + + + + + AUTHORS_LABEL + Designed by Timon Olsthoorn in the Netherlands +Assembled by Adam Demasi in Australia + + diff --git a/prefs/Resources/en_GB.lproj/Root.strings b/prefs/Resources/en_GB.lproj/Root.strings new file mode 100644 index 0000000..dcdc529 --- /dev/null +++ b/prefs/Resources/en_GB.lproj/Root.strings @@ -0,0 +1,57 @@ + + + + + + WIDGET_EXPLANATION + Enable the Now Playing widget via the Notification Centre Today page. + + + NOTIFICATIONS + Notifications + + + NOW_PLAYING_BULLETINS_EXPLANATION + Show a notification when the now playing song changes. Swipe or 3D Touch to reveal playback controls. + + + KEEP_ALL_NOTIFICATIONS + Keep All Notifications + + + KEEP_ALL_NOTIFICATIONS_EXPLANATION + Keep all now playing notifications in the Notification Centre, or only show the latest. + + + WAKE_WHEN_LOCKED + Wake When Locked + + + WAKE_WHEN_LOCKED_EXPLANATION + Wake the screen when showing a now playing notification while the device is locked. + + + HIDE_LOCK_MUSIC_CONTROLS + Replace Lock Screen Music Controls + + + HIDE_LOCK_MUSIC_CONTROLS_EXPLANATION + Use the now playing notification or widget to control your music. + + + TYPESTATUS_PLUS + TypeStatus Plus + + + TYPESTATUS_PLUS_PROVIDER + Provider + + + TYPESTATUS_PLUS_PROVIDER_EXPLANATION + Use subtle TypeStatus notifications instead of banners. + + + TYPESTATUS_PLUS_SUBTITLE + Get subtle now playing notifications in your status bar, and more, with TypeStatus Plus. + + diff --git a/prefs/Resources/icon@2x.png b/prefs/Resources/icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..942a2975660ea11a60fa6f10f3f82a6b27247b89 GIT binary patch literal 2032 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 XN4ueBK2Lc6^DX3P=W1JR9gzAz>IVNX literal 0 HcmV?d00001 diff --git a/prefs/Resources/typestatusplus@2x.png b/prefs/Resources/typestatusplus@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..40c977fc78b0c1fe468568c39e7c278509ad233d GIT binary patch literal 2591 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 + + + + entry + + bundle + Canzone + cell + PSLinkCell + detail + HBCZRootListController + icon + icon.png + isController + + label + Canzone + + + diff --git a/provider/HBCZMusicProvider.h b/provider/HBCZMusicProvider.h new file mode 100644 index 0000000..9908f6f --- /dev/null +++ b/provider/HBCZMusicProvider.h @@ -0,0 +1,5 @@ +#import + +@interface HBCZMusicProvider : HBTSPlusProvider + +@end diff --git a/provider/HBCZMusicProvider.m b/provider/HBCZMusicProvider.m new file mode 100644 index 0000000..a831e31 --- /dev/null +++ b/provider/HBCZMusicProvider.m @@ -0,0 +1,19 @@ +#import "HBCZMusicProvider.h" + +@implementation HBCZMusicProvider { + NSString *_lastSongIdentifier; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + self.name = @"Canzone"; + self.preferencesBundle = [NSBundle bundleWithPath:@"/Library/PreferenceBundles/Canzone.bundle"]; + self.preferencesClass = @"HBCZRootListController"; + } + + return self; +} + +@end diff --git a/provider/Makefile b/provider/Makefile new file mode 100644 index 0000000..cd3500f --- /dev/null +++ b/provider/Makefile @@ -0,0 +1,13 @@ +include $(THEOS)/makefiles/common.mk + +BUNDLE_NAME = Music +Music_FILES = $(wildcard *.m) +Music_INSTALL_PATH = /Library/TypeStatus/Providers +Music_EXTRA_FRAMEWORKS = TypeStatusPlusProvider +Music_CFLAGS = -fobjc-arc + +include $(THEOS_MAKE_PATH)/bundle.mk + +after-Music-stage:: + $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/System/Library/Frameworks/UIKit.framework$(ECHO_END) + $(ECHO_NOTHING)cp Resources/*.png $(THEOS_STAGING_DIR)/System/Library/Frameworks/UIKit.framework$(ECHO_END) diff --git a/provider/Resources/Black_TypeStatusPlusMusic.png b/provider/Resources/Black_TypeStatusPlusMusic.png new file mode 100644 index 0000000000000000000000000000000000000000..fcc0e33f7cfa45f358b3aad0f641ac4554fa29e1 GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^+(0bC!3HFwb&h8MDIZT4#}JM4$q5pyJii-%*o#bF zFk@olPZbVhLj!+hC&SD29BKFbqmQ29IkVD-$46CR)`BF3-*zEy>}o~-w8*sFI hVN&_Y&MAt#3<}=1$*1|Ic>~R5@O1TaS?83{1OTNbD)ayV literal 0 HcmV?d00001 diff --git a/provider/Resources/Black_TypeStatusPlusMusic@2x.png b/provider/Resources/Black_TypeStatusPlusMusic@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..550315348e9d6fa62fbac9ebe1d1c9d12aa51a84 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^VnD3H!3HFM9pQQgq>?>d978-h-<~g) zxw$Ou1^s##oSzr6>VJLY80{M1*iv&s*XDrb_w#HFPZQd%3rfA_d?k07QRgcMUmNfI z!;D>wbG`-FFrRztesjaa>JKsf3Huv^e+TYrnOiKsg(2$k*Z7-CQLBK~F?hQAxvX0`!3HE>thuZOq)I$p977^n-(FGVYcLRSxwvrc znrC_(mnIh&@*H=Ww$4?@(PZJ1|0ygtyOvMr0D?PS(X|pB0`e{{N6$uw&D*W4*7{0U zQ&d2~p+SQ0;y&^B{Mp~%bu6f;c>k7 + + + + CFBundleIdentifier + ws.hbang.typestatusplusmusicprovider + HBTSApplicationBundleIdentifier + ws.hbang.canzone.app + NSPrincipalClass + HBCZMusicProvider + + diff --git a/provider/Resources/LockScreen_TypeStatusPlusMusic.png b/provider/Resources/LockScreen_TypeStatusPlusMusic.png new file mode 100644 index 0000000000000000000000000000000000000000..c0a72486c74008b958545d9d01e6c8b7d2c440cc GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp@KrF$*1|$_fl!pMRQcoAhkP61+1exDWfm$3} zT%v$<+fs=oJKAQciLr@EFL>l2@GRxQl&fhM(wH|UT1-)#BDo?!u)}%5jaievSa2~& XT?#zT9-QX}bO3{=tDnm{r-UW|VckAo literal 0 HcmV?d00001 diff --git a/provider/Resources/LockScreen_TypeStatusPlusMusic@2x.png b/provider/Resources/LockScreen_TypeStatusPlusMusic@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..52b9eb7079db3570f821cde97e2807841d594298 GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^Qb26L!3HGxYqRD7sZLK9$B+ufw`aEsHaRk|KKxr) z&aJ;#B#6t=$cf`+bBE9bxfLAcI=V}xLiA2a&DYzPcxX;-g;-pX7=|!Vk$E#0zDL4MK&d$zrDfyTl(q^ u501~btVrLaa*`ptbU|f;rHjjx!ed{i+FCb-&glX=iow&>&t;ucLK6Vh*H7^P literal 0 HcmV?d00001 diff --git a/provider/Resources/LockScreen_TypeStatusPlusMusic@3x.png b/provider/Resources/LockScreen_TypeStatusPlusMusic@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..eb8f0e9aa32f3d6e4b1ea0c83e369e188892f5fd GIT binary patch literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^>Okzl!3HEt8Q<&zQd2x#978G?-<~s_)a1y(`tbYi zWjlT|7CeuWnOzd;p*YL)!@pH=W|x?NN=rNVW9tY!9pGHQLocYZw-2b51$Atoz~NS0J9JtDnm{r-UW|-OEvy literal 0 HcmV?d00001 diff --git a/widget/BridgingHeader.h b/widget/BridgingHeader.h new file mode 100644 index 0000000..f54a83a --- /dev/null +++ b/widget/BridgingHeader.h @@ -0,0 +1,3 @@ +@import UIKit; +#import +#import diff --git a/widget/Makefile b/widget/Makefile new file mode 100644 index 0000000..53169f8 --- /dev/null +++ b/widget/Makefile @@ -0,0 +1,13 @@ +TARGET = iphone:10.1:10.0 +SDKVERSION = 10.1 + +include $(THEOS)/makefiles/common.mk + +APPEX_NAME = CanzoneNowPlayingWidget +CanzoneNowPlayingWidget_FILES = $(wildcard *.swift) +CanzoneNowPlayingWidget_INSTALL_PATH = /Applications/Canzone.app/PlugIns +CanzoneNowPlayingWidget_FRAMEWORKS = NotificationCenter +CanzoneNowPlayingWidget_PRIVATE_FRAMEWORKS = MediaPlayerUI +CanzoneNowPlayingWidget_SWIFT_BRIDGING_HEADER = BridgingHeader.h + +include $(THEOS_MAKE_PATH)/appex.mk diff --git a/widget/Resources/Info.plist b/widget/Resources/Info.plist new file mode 100644 index 0000000..1c09dbd --- /dev/null +++ b/widget/Resources/Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleDisplayName + Now Playing + CFBundleExecutable + CanzoneNowPlayingWidget + CFBundleIdentifier + ws.hbang.canzone.app.nowplayingwidget + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Now Playing + CFBundlePackageType + XPC! + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionPrincipalClass + TodayViewController + NSExtensionPointIdentifier + com.apple.widget-extension + + + diff --git a/widget/TodayViewController.swift b/widget/TodayViewController.swift new file mode 100644 index 0000000..818c70c --- /dev/null +++ b/widget/TodayViewController.swift @@ -0,0 +1,36 @@ +import UIKit +import NotificationCenter + +@objc(TodayViewController) +class TodayViewController: UIViewController, NCWidgetProviding { + + override func viewDidLoad() { + super.viewDidLoad() + + // indicate that we support an expanded style + extensionContext!.widgetLargestAvailableDisplayMode = .expanded + + // instantiate the view controller + let viewController = MPUControlCenterMediaControlsViewController() + + // make it fill the entire space + viewController.view.frame = CGRect(x: 0, y: 20, width: view.frame.size.width, height: view.frame.size.height - 20) + viewController.view.autoresizingMask = [ .flexibleWidth, .flexibleHeight ] + + // add it as a child view controller + addChildViewController(viewController) + view.addSubview(viewController.view) + } + + func widgetActiveDisplayModeDidChange(_ activeDisplayMode: NCWidgetDisplayMode, withMaximumSize maxSize: CGSize) { + // set the content size. if our preferred height is larger than the maximum we’re currently + // allowed, then we need to just go with the max. this also makes it use ios’s default compact + // height when in compact mode (currently, 95pt) + preferredContentSize = CGSize(width: maxSize.width, height: min(maxSize.height, 370)) + } + + func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) { + completionHandler(NCUpdateResult.newData) + } + +}