├── ReachPlayer.plist
├── packages
├── .DS_Store
└── com.nahtedetihw.reachplayer_2.6_iphoneos-arm.deb
├── reachplayerprefs
├── .DS_Store
├── Resources
│ ├── PAYPAL.png
│ ├── banner.png
│ ├── MISC@2x.png
│ ├── MISC@3x.png
│ ├── icon@2x.png
│ ├── icon@3x.png
│ ├── twitter.png
│ ├── CHANGELOG.png
│ ├── CHECKMARK.png
│ ├── ENABLE@2x.png
│ ├── ENABLE@3x.png
│ ├── LAYOUT@2x.png
│ ├── LAYOUT@3x.png
│ ├── PAYPAL@2x.png
│ ├── PAYPAL@3x.png
│ ├── twitter@2x.png
│ ├── twitter@3x.png
│ ├── ACTIVATION@2x.png
│ ├── ACTIVATION@3x.png
│ ├── BACKGROUND@2x.png
│ ├── BACKGROUND@3x.png
│ ├── CHANGELOG@2x.png
│ ├── CHANGELOG@3x.png
│ ├── CHECKMARK@2x.png
│ ├── CHECKMARK@3x.png
│ ├── DefaultContainerArtwork.png
│ ├── changelogControllerIcon.png
│ ├── Info.plist
│ ├── ACTIVATION.plist
│ ├── BACKGROUND.plist
│ ├── MISC.plist
│ ├── Root.plist
│ └── LAYOUT.plist
├── Makefile
├── layout
│ └── Library
│ │ └── PreferenceLoader
│ │ └── Preferences
│ │ └── reachplayerprefs.plist
├── REACHPLAYERPreferences.h
└── REACHPLAYERPreferences.m
├── control
├── README.md
├── Makefile
├── ReachPlayerContainerView.h
├── Tweak.h
├── Tweak.xm
└── ReachPlayerContainerView.xm
/ReachPlayer.plist:
--------------------------------------------------------------------------------
1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; }
2 |
--------------------------------------------------------------------------------
/packages/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/packages/.DS_Store
--------------------------------------------------------------------------------
/reachplayerprefs/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/.DS_Store
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/PAYPAL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/PAYPAL.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/banner.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/MISC@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/MISC@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/MISC@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/MISC@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/icon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/icon@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/icon@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/icon@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/twitter.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHANGELOG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHANGELOG.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHECKMARK.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHECKMARK.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/ENABLE@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/ENABLE@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/ENABLE@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/ENABLE@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/LAYOUT@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/LAYOUT@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/LAYOUT@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/LAYOUT@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/PAYPAL@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/PAYPAL@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/PAYPAL@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/PAYPAL@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/twitter@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/twitter@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/twitter@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/twitter@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/ACTIVATION@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/ACTIVATION@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/ACTIVATION@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/ACTIVATION@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/BACKGROUND@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/BACKGROUND@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/BACKGROUND@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/BACKGROUND@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHANGELOG@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHANGELOG@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHANGELOG@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHANGELOG@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHECKMARK@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHECKMARK@2x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/CHECKMARK@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/CHECKMARK@3x.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/DefaultContainerArtwork.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/DefaultContainerArtwork.png
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/changelogControllerIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/reachplayerprefs/Resources/changelogControllerIcon.png
--------------------------------------------------------------------------------
/packages/com.nahtedetihw.reachplayer_2.6_iphoneos-arm.deb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nahtedetihw/ReachPlayer/HEAD/packages/com.nahtedetihw.reachplayer_2.6_iphoneos-arm.deb
--------------------------------------------------------------------------------
/control:
--------------------------------------------------------------------------------
1 | Package: com.nahtedetihw.reachplayer
2 | Name: ReachPlayer
3 | Version: 2.6
4 | Architecture: iphoneos-arm
5 | Description: Now Playing info in Reachability Window!
6 | Maintainer: Ethan Whited
7 | Author: Ethan Whited
8 | Section: Tweaks
9 | Depends: mobilesubstrate
10 |
--------------------------------------------------------------------------------
/reachplayerprefs/Makefile:
--------------------------------------------------------------------------------
1 | ARCHS = arm64 arm64e
2 |
3 | include $(THEOS)/makefiles/common.mk
4 |
5 | SYSROOT=$(THEOS)/sdks/iphoneos14.2.sdk
6 |
7 | ##THEOS_PACKAGE_SCHEME=rootless
8 |
9 | BUNDLE_NAME = reachplayerprefs
10 | $(BUNDLE_NAME)_FILES = REACHPLAYERPreferences.m
11 | $(BUNDLE_NAME)_INSTALL_PATH = /Library/PreferenceBundles
12 | $(BUNDLE_NAME)_FRAMEWORKS = UIKit OnBoardingKit
13 | $(BUNDLE_NAME)_PRIVATE_FRAMEWORKS = Preferences
14 | $(BUNDLE_NAME)_CFLAGS = -fobjc-arc -Wdeprecated-declarations -Wno-deprecated-declarations
15 |
16 | include $(THEOS_MAKE_PATH)/bundle.mk
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # ReachPlayer
4 |
5 | ## Now Playing info in Reachability Window!
6 |
7 | ** ReachPlayer adds a sleek interface to your Reachability Window with the now playing song. **
8 |
9 | * Join my Discord today to report any issues: https://discord.gg/64kVRNzKnF
10 |
11 | ### Source Code
12 | https://github.com/nahtedetihw/ReachPlayer
13 |
14 | ### Follow
15 |
16 | * [**ETHN**](https://twitter.com/ethanwhited) - follow me for more up to date info, or ask me anything.
17 |
18 | * [**Email**](mailto:ethanwhited2208@gmail.com) - open to any questions or concerns.
19 |
--------------------------------------------------------------------------------
/reachplayerprefs/layout/Library/PreferenceLoader/Preferences/reachplayerprefs.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | entry
6 |
7 | bundle
8 | reachplayerprefs
9 | cell
10 | PSLinkCell
11 | detail
12 | REACHPLAYERPreferencesListController
13 | icon
14 | icon.png
15 | isController
16 |
17 | label
18 | ReachPlayer
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | TARGET := iphone:clang:latest:13.0
2 | INSTALL_TARGET_PROCESSES = SpringBoard
3 |
4 | DEBUG=0
5 | FINALPACKAGE=1
6 | ## THEOS_PACKAGE_SCHEME=rootless
7 |
8 | SYSROOT=$(THEOS)/sdks/iphoneos14.2.sdk
9 |
10 | include $(THEOS)/makefiles/common.mk
11 |
12 | TWEAK_NAME = ReachPlayer
13 |
14 | ReachPlayer_FILES = Tweak.xm ReachPlayerContainerView.xm
15 | ReachPlayer_CFLAGS = -fobjc-arc -Wdeprecated-declarations -Wno-deprecated-declarations
16 | ReachPlayer_PRIVATE_FRAMEWORKS = MediaRemote
17 |
18 | include $(THEOS_MAKE_PATH)/tweak.mk
19 |
20 | after-install::
21 | install.exec "killall -9 Preferences && killall -9 SpringBoard"
22 | SUBPROJECTS += reachplayerprefs
23 | include $(THEOS_MAKE_PATH)/aggregate.mk
24 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | reachplayerprefs
9 | CFBundleIdentifier
10 | com.nahtedetihw.reachplayerprefs
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1.0
21 | NSPrincipalClass
22 | REACHPLAYERPreferencesListController
23 |
24 |
25 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/ACTIVATION.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | cell
9 | PSGroupCell
10 | label
11 | Activation Style
12 |
13 |
14 | cell
15 | PSSegmentCell
16 | default
17 | 0
18 | defaults
19 | com.nahtedetihw.reachplayerprefs
20 | key
21 | activationStyle
22 | validValues
23 |
24 | 0
25 | 1
26 |
27 | validTitles
28 |
29 | StatusBar (Tapx2)
30 | Shake Device
31 |
32 | alignment
33 | 1
34 | PostNotification
35 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
36 |
37 |
38 | cell
39 | PSGroupCell
40 | footerAlignment
41 | 1
42 | footerText
43 | ReachPlayer
44 |
45 |
46 | cell
47 | PSGroupCell
48 | footerAlignment
49 | 1
50 | footerText
51 | 2023 © nahtedetihw
52 |
53 |
54 | title
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/BACKGROUND.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | cell
9 | PSGroupCell
10 | label
11 | Blurred Background
12 |
13 |
14 | cell
15 | PSSwitchCell
16 | default
17 |
18 | defaults
19 | com.nahtedetihw.reachplayerprefs
20 | key
21 | enableBlur
22 | label
23 | Enable Blurred Background
24 | PostNotification
25 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
26 |
27 |
28 | cell
29 | PSGroupCell
30 | label
31 | Blur Style
32 |
33 |
34 | cell
35 | PSSegmentCell
36 | default
37 | 0
38 | defaults
39 | com.nahtedetihw.reachplayerprefs
40 | key
41 | blurStyle
42 | validValues
43 |
44 | 0
45 | 1
46 | 2
47 |
48 | validTitles
49 |
50 | Dark
51 | Clear
52 | Light
53 |
54 | alignment
55 | 1
56 | PostNotification
57 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
58 |
59 |
60 | cell
61 | PSGroupCell
62 | footerAlignment
63 | 1
64 | footerText
65 | ReachPlayer
66 |
67 |
68 | cell
69 | PSGroupCell
70 | footerAlignment
71 | 1
72 | footerText
73 | 2023 © nahtedetihw
74 |
75 |
76 | title
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/reachplayerprefs/REACHPLAYERPreferences.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | @interface UIPopoverPresentationController (Private)
6 | @property (assign,setter=_setPopoverBackgroundStyle:,nonatomic) long long _popoverBackgroundStyle;
7 | @property (assign,setter=_setBackgroundBlurDisabled:,nonatomic) BOOL _backgroundBlurDisabled;
8 | @end
9 |
10 | @interface OBButtonTray : UIView
11 | @property (nonatomic,retain) UIVisualEffectView * effectView;
12 | - (void)addButton:(id)arg1;
13 | - (void)addCaptionText:(id)arg1;;
14 | @end
15 |
16 | @interface OBBoldTrayButton : UIButton
17 | - (void)setTitle:(id)arg1 forState:(unsigned long long)arg2;
18 | + (id)buttonWithType:(long long)arg1;
19 | @end
20 |
21 | @interface OBBulletedListItem : UIView
22 | @property (nonatomic,retain) UIImageView * imageView;
23 | @end
24 |
25 | @interface OBBulletedList : UIView
26 | @property (nonatomic,retain) NSMutableArray * items;
27 | @end
28 |
29 | @interface OBWelcomeController : UIViewController
30 | @property (nonatomic,retain) OBBulletedList * bulletedList;
31 | @property (nonatomic, retain) UIView *viewIfLoaded;
32 | @property (nonatomic, strong) UIColor *backgroundColor;
33 | - (OBButtonTray *)buttonTray;
34 | - (id)initWithTitle:(id)arg1 detailText:(id)arg2 icon:(id)arg3;
35 | - (void)addBulletedListItemWithTitle:(id)arg1 description:(id)arg2 image:(id)arg3;
36 | @end
37 |
38 | @interface REACHPLAYERPreferencesListController : PSListController {
39 |
40 | UITableView * _table;
41 |
42 | }
43 | @property (nonatomic, retain) UIBarButtonItem *killButton;
44 | @property (nonatomic, retain) UIView *headerView;
45 | @property (nonatomic, retain) UIImageView *headerImageView;
46 | @property (nonatomic, retain) UILabel *titleLabel;
47 | @property (nonatomic, retain) UIImageView *iconView;
48 | @property (nonatomic, retain) NSArray *versionArray;
49 | @property (nonatomic, retain) OBWelcomeController *changelogController;
50 | - (void)apply:(UIButton *)sender;
51 | - (void)twitter:(UIButton *)sender;
52 | - (void)paypal:(UIButton *)sender;
53 | - (void)handleYesGesture;
54 | - (void)handleNoGesture:(UIButton *)sender;
55 | @end
56 |
57 | @interface REACHPLAYERACTIVATIONPreferencesListController : PSListController
58 | @end
59 |
60 | @interface REACHPLAYERLAYOUTPreferencesListController : PSListController
61 | @end
62 |
63 | @interface REACHPLAYERBACKGROUNDPreferencesListController : PSListController
64 | @end
65 |
66 | @interface REACHPLAYERMISCPreferencesListController : PSListController
67 | @end
68 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/MISC.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | cell
9 | PSGroupCell
10 | label
11 | Reachability Height
12 |
13 |
14 | cell
15 | PSSliderCell
16 | default
17 | 0.4
18 | defaults
19 | com.nahtedetihw.reachplayerprefs
20 | key
21 | reachOffset
22 | max
23 | 0.75
24 | min
25 | 0
26 | isSegmented
27 |
28 | showValue
29 |
30 | PostNotification
31 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
32 |
33 |
34 | cell
35 | PSGroupCell
36 | label
37 | Chevron Transparency
38 |
39 |
40 | cell
41 | PSSliderCell
42 | default
43 | 1
44 | defaults
45 | com.nahtedetihw.reachplayerprefs
46 | key
47 | chevronOpacity
48 | max
49 | 1
50 | min
51 | 0
52 | isSegmented
53 |
54 | showValue
55 |
56 | PostNotification
57 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
58 |
59 |
60 | cell
61 | PSGroupCell
62 | label
63 | Timeout Duration (seconds)
64 |
65 |
66 | cell
67 | PSSliderCell
68 | default
69 | 8
70 | defaults
71 | com.nahtedetihw.reachplayerprefs
72 | key
73 | keepAliveDuration
74 | max
75 | 120
76 | min
77 | 1
78 | isSegmented
79 |
80 | showValue
81 |
82 | PostNotification
83 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
84 |
85 |
86 | cell
87 | PSGroupCell
88 | label
89 | Reachability will stay open for the above number of seconds you choose
90 |
91 |
92 | cell
93 | PSGroupCell
94 | footerAlignment
95 | 1
96 | footerText
97 | ReachPlayer
98 |
99 |
100 | cell
101 | PSGroupCell
102 | footerAlignment
103 | 1
104 | footerText
105 | 2023 © nahtedetihw
106 |
107 |
108 | title
109 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/ReachPlayerContainerView.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import "MediaRemote.h"
4 |
5 | static NSString *preferencesNotification = @"com.nahtedetihw.reachplayerprefs/ReloadPrefs";
6 |
7 | #define bundlePath ([[NSFileManager defaultManager] fileExistsAtPath:@"/Library/PreferenceBundles/reachplayerprefs.bundle/"] ? @"/Library/PreferenceBundles/reachplayerprefs.bundle/" : @"/var/jb/Library/PreferenceBundles/reachplayerprefs.bundle/")
8 |
9 | #define plistPath ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist"] ? @"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist" : @"/var/jb/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist")
10 |
11 | double positionXRP, positionYRP, artworkSizeRP, reachOffsetRP;
12 | NSInteger layoutStyleRP, blurStyleRP;
13 |
14 | static void loadPreferences() {
15 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath];
16 |
17 | positionXRP = dict[@"positionX"] ? [dict[@"positionX"] doubleValue] : 0;
18 | positionYRP = dict[@"positionY"] ? [dict[@"positionY"] doubleValue] : 0;
19 | artworkSizeRP = dict[@"artworkSize"] ? [dict[@"artworkSize"] doubleValue] : 160.0;
20 |
21 | layoutStyleRP = dict[@"layoutStyle"] ? [dict[@"layoutStyle"] integerValue] : 0;
22 | blurStyleRP = dict[@"blurStyle"] ? [dict[@"blurStyle"] integerValue] : 0;
23 | }
24 |
25 | @interface _UIBackdropView : UIView
26 | @property (assign,nonatomic) BOOL blurRadiusSetOnce;
27 | @property (nonatomic,copy) NSString * _blurQuality;
28 | @property (assign,nonatomic) double _blurRadius;
29 | -(id)initWithFrame:(CGRect)arg1 autosizesToFitSuperview:(BOOL)arg2 settings:(id)arg3 ;
30 | -(id)initWithSettings:(id)arg1 ;
31 | @end
32 |
33 | @interface _UIBackdropViewSettings : NSObject
34 | +(id)settingsForStyle:(long long)arg1 ;
35 | @end
36 |
37 | @interface UILabel (RP)
38 | - (void)setMarqueeRunning:(BOOL)arg1;
39 | - (void)setMarqueeEnabled:(BOOL)arg1;
40 | - (BOOL)marqueeEnabled;
41 | - (BOOL)marqueeRunning;
42 | @end
43 |
44 | @interface ReachPlayerArtworkContainerView : UIView
45 | @property (nonatomic, strong) UIImageView *artworkView;
46 | @end
47 |
48 | @implementation ReachPlayerArtworkContainerView
49 | @end
50 |
51 | @interface ReachPlayerContainerView : UIView
52 | @property (nonatomic, retain) UIImageView *backgroundImageView;
53 | @property (nonatomic, retain) _UIBackdropView *backgroundBlurView;
54 | @property (nonatomic, retain) ReachPlayerArtworkContainerView *artworkContainerView;
55 | @property (nonatomic, retain) UILabel *nowPlayingInfoSong;
56 | @property (nonatomic, retain) UILabel *nowPlayingInfoArtist;
57 | @property (nonatomic, retain) UILabel *nowPlayingInfoAlbum;
58 | @property (nonatomic, retain) UIStackView *labelsStackView;
59 | @property (nonatomic, retain) UIButton *playPauseButton;
60 | @property (nonatomic, retain) UIButton *nextButton;
61 | @property (nonatomic, retain) UIButton *previousButton;
62 | @property (nonatomic, retain) UIStackView *controlsStackView;
63 | - (void)addBackgroundImage;
64 | - (void)addBackgroundBlur;
65 | - (void)addArtworkContainerView;
66 | - (void)addNowPlayingInfoSong;
67 | - (void)addNowPlayingInfoAlbum;
68 | - (void)addPlayPauseButton;
69 | - (void)addNextButton;
70 | - (void)addPreviousButton;
71 | - (void)playingDidChange:(NSNotification *)notification;
72 | - (void)updateTransition;
73 | - (void)playPause;
74 | -(void)next;
75 | -(void)previous;
76 | - (void)updateImage;
77 | - (void)addLabelsStackView;
78 | - (void)addControlsStackView;
79 | @end
80 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/Root.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | cell
9 | PSSwitchCell
10 | default
11 |
12 | defaults
13 | com.nahtedetihw.reachplayerprefs
14 | key
15 | enable
16 | label
17 | Enable
18 | PostNotification
19 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
20 | icon
21 | ENABLE.png
22 |
23 |
24 | cell
25 | PSGroupCell
26 | label
27 |
28 |
29 |
30 | cell
31 | PSLinkListCell
32 | default
33 |
34 | detail
35 | REACHPLAYERACTIVATIONPreferencesListController
36 | defaults
37 | com.nahtedetihw.reachplayerprefs
38 | label
39 | Activation
40 | icon
41 | ACTIVATION.png
42 |
43 |
44 | cell
45 | PSGroupCell
46 | label
47 |
48 |
49 |
50 | cell
51 | PSLinkListCell
52 | default
53 |
54 | detail
55 | REACHPLAYERLAYOUTPreferencesListController
56 | defaults
57 | com.nahtedetihw.reachplayerprefs
58 | label
59 | Layout
60 | icon
61 | LAYOUT.png
62 |
63 |
64 | cell
65 | PSGroupCell
66 | label
67 |
68 |
69 |
70 | cell
71 | PSLinkListCell
72 | default
73 |
74 | detail
75 | REACHPLAYERBACKGROUNDPreferencesListController
76 | defaults
77 | com.nahtedetihw.reachplayerprefs
78 | label
79 | Background
80 | icon
81 | BACKGROUND.png
82 |
83 |
84 | cell
85 | PSGroupCell
86 | label
87 |
88 |
89 |
90 | cell
91 | PSLinkListCell
92 | default
93 |
94 | detail
95 | REACHPLAYERMISCPreferencesListController
96 | defaults
97 | com.nahtedetihw.reachplayerprefs
98 | label
99 | Misc
100 | icon
101 | MISC.png
102 |
103 |
104 | cell
105 | PSGroupCell
106 | footerAlignment
107 | 1
108 | footerText
109 | ReachPlayer 2.6
110 |
111 |
112 | cell
113 | PSGroupCell
114 | footerAlignment
115 | 1
116 | footerText
117 | 2023 © nahtedetihw
118 |
119 |
120 | title
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/reachplayerprefs/Resources/LAYOUT.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | items
6 |
7 |
8 | cell
9 | PSGroupCell
10 | label
11 | Layout
12 |
13 |
14 | cell
15 | PSSegmentCell
16 | default
17 | 0
18 | defaults
19 | com.nahtedetihw.reachplayerprefs
20 | key
21 | layoutStyle
22 | validValues
23 |
24 | 0
25 | 1
26 |
27 | validTitles
28 |
29 | Side-by-side
30 | Centered
31 |
32 | alignment
33 | 1
34 | PostNotification
35 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
36 |
37 |
38 | cell
39 | PSGroupCell
40 | label
41 | Artwork Size
42 |
43 |
44 | cell
45 | PSSliderCell
46 | default
47 | 180
48 | defaults
49 | com.nahtedetihw.reachplayerprefs
50 | key
51 | artworkSize
52 | max
53 | 400
54 | min
55 | 0
56 | isSegmented
57 |
58 | showValue
59 |
60 | PostNotification
61 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
62 |
63 |
64 | cell
65 | PSGroupCell
66 | label
67 | Position Horizontal
68 |
69 |
70 | cell
71 | PSSliderCell
72 | default
73 | 0
74 | defaults
75 | com.nahtedetihw.reachplayerprefs
76 | key
77 | positionX
78 | max
79 | 500
80 | min
81 | -500
82 | isSegmented
83 |
84 | showValue
85 |
86 | PostNotification
87 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
88 |
89 |
90 | cell
91 | PSGroupCell
92 | label
93 | Position Vertical
94 |
95 |
96 | cell
97 | PSSliderCell
98 | default
99 | 0
100 | defaults
101 | com.nahtedetihw.reachplayerprefs
102 | key
103 | positionY
104 | max
105 | 500
106 | min
107 | -500
108 | isSegmented
109 |
110 | showValue
111 |
112 | PostNotification
113 | com.nahtedetihw.reachplayerprefs/ReloadPrefs
114 |
115 |
116 | cell
117 | PSGroupCell
118 | footerAlignment
119 | 1
120 | footerText
121 | ReachPlayer
122 |
123 |
124 | cell
125 | PSGroupCell
126 | footerAlignment
127 | 1
128 | footerText
129 | 2023 © nahtedetihw
130 |
131 |
132 | title
133 |
134 |
135 |
136 |
--------------------------------------------------------------------------------
/Tweak.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | #define plistPath ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist"] ? @"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist" : @"/var/jb/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist")
4 |
5 | static NSString *preferencesNotification = @"com.nahtedetihw.reachplayerprefs/ReloadPrefs";
6 |
7 | BOOL enable, enableBlur;
8 | double chevronOpacity, keepAliveDuration, positionX, positionY, artworkSize, reachOffset;
9 | NSInteger layoutStyle, blurStyle, activationStyle;
10 |
11 | static void loadPreferences() {
12 | NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:plistPath];
13 |
14 | enable = dict[@"enable"] ? [dict[@"enable"] boolValue] : NO;
15 | enableBlur = dict[@"enableBlur"] ? [dict[@"enableBlur"] boolValue] : NO;
16 |
17 | chevronOpacity = dict[@"chevronOpacity"] ? [dict[@"chevronOpacity"] doubleValue] : 1.0;
18 | keepAliveDuration = dict[@"keepAliveDuration"] ? [dict[@"keepAliveDuration"] doubleValue] : 0.8;
19 | positionX = dict[@"positionX"] ? [dict[@"positionX"] doubleValue] : 0;
20 | positionY = dict[@"positionY"] ? [dict[@"positionY"] doubleValue] : 0;
21 | artworkSize = dict[@"artworkSize"] ? [dict[@"artworkSize"] doubleValue] : 160.0;
22 | reachOffset = dict[@"reachOffset"] ? [dict[@"reachOffset"] doubleValue] : 0.4;
23 |
24 | layoutStyle = dict[@"layoutStyle"] ? [dict[@"layoutStyle"] integerValue] : 0;
25 | blurStyle = dict[@"blurStyle"] ? [dict[@"blurStyle"] integerValue] : 0;
26 | activationStyle = dict[@"activationStyle"] ? [dict[@"activationStyle"] integerValue] : 0;
27 | }
28 |
29 | @interface SBLockScreenManager : NSObject
30 | +(id)sharedInstance;
31 | -(BOOL)isScreenOn;
32 | @end
33 |
34 | @interface _UIBackdropView : UIView
35 | @property (assign,nonatomic) BOOL blurRadiusSetOnce;
36 | @property (nonatomic,copy) NSString * _blurQuality;
37 | @property (assign,nonatomic) double _blurRadius;
38 | -(id)initWithFrame:(CGRect)arg1 autosizesToFitSuperview:(BOOL)arg2 settings:(id)arg3 ;
39 | -(id)initWithSettings:(id)arg1 ;
40 | @end
41 |
42 | @interface _UIBackdropViewSettings : NSObject
43 | +(id)settingsForStyle:(long long)arg1 ;
44 | @end
45 |
46 | @interface ReachPlayerArtworkContainerView : UIView
47 | @property (nonatomic, strong) UIImageView *artworkView;
48 | @end
49 |
50 | @interface ReachPlayerContainerView : UIView
51 | @property (nonatomic, retain) UIImageView *backgroundImageView;
52 | @property (nonatomic, retain) _UIBackdropView *backgroundBlurView;
53 | @property (nonatomic, retain) ReachPlayerArtworkContainerView *artworkContainerView;
54 | @property (nonatomic, retain) UILabel *nowPlayingInfoSong;
55 | @property (nonatomic, retain) UILabel *nowPlayingInfoArtist;
56 | @property (nonatomic, retain) UILabel *nowPlayingInfoAlbum;
57 | @property (nonatomic, retain) UIButton *playPauseButton;
58 | @property (nonatomic, retain) UIButton *nextButton;
59 | @property (nonatomic, retain) UIButton *previousButton;
60 | @end
61 |
62 | @interface SBWallpaperEffectView : UIVisualEffectView
63 | @end
64 |
65 | @interface SBReachabilityBackgroundView : UIView
66 | @end
67 |
68 | @interface SBReachabilityBackgroundViewController : UIViewController
69 | @property (nonatomic, retain) NSTimer *updateTimer;
70 | - (void)updateReachability;
71 | - (void)addReachPlayerContainerView;
72 | @end
73 |
74 | @interface UIColor (Private)
75 | -(BOOL)_isSimilarToColor:(id)arg1 withinPercentage:(double)arg2 ;
76 | @end
77 |
78 | @interface SBReachabilityManager : NSObject
79 | -(void)_setKeepAliveTimer;
80 | +(id)sharedInstance;
81 | -(void)toggleReachability;
82 | -(BOOL)reachabilityModeActive;
83 | -(void)deactivateReachability;
84 | -(void)_notifyObserversReachabilityYOffsetDidChange;
85 | @end
86 |
87 | @interface SBMediaController
88 | + (id)sharedInstance;
89 | - (BOOL)isPlaying;
90 | @end
91 |
92 | @interface SBReachabilityWindow : UIWindow
93 | - (id)view;
94 | @end
95 |
96 | @interface SBHomeScreenSpotlightViewController : UIViewController
97 | @end
98 |
99 | @interface _UIStatusBarForegroundView : UIView
100 | - (void)toggleStatusReachability:(id)sender;
101 | @end
102 |
--------------------------------------------------------------------------------
/Tweak.xm:
--------------------------------------------------------------------------------
1 | #import "Tweak.h"
2 |
3 | UIView *emptyView;
4 | ReachPlayerContainerView *containerView;
5 |
6 | %group ReachPlayer
7 |
8 | %hook _UIStatusBarForegroundView
9 | // Double tap status bar to activate
10 | - (id)initWithFrame:(CGRect)frame {
11 | self = %orig;
12 | if (activationStyle == 0) {
13 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleStatusReachability:)];
14 | self.userInteractionEnabled = YES;
15 | tapGesture.numberOfTapsRequired = 2;
16 | [self addGestureRecognizer:tapGesture];
17 | }
18 | return self;
19 | }
20 |
21 | %new
22 | - (void)toggleStatusReachability:(id)sender {
23 | [[%c(SBReachabilityManager) sharedInstance] toggleReachability];
24 | }
25 | %end
26 |
27 | %hook UIWindow
28 | // Shake device to activate
29 | - (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
30 | %orig;
31 | if (activationStyle == 1) {
32 | BOOL isScreenOn = MSHookIvar([%c(SBLockScreenManager) sharedInstance], "_isScreenOn");
33 | if (event.type == UIEventSubtypeMotionShake && self == [[UIApplication sharedApplication] keyWindow] && isScreenOn == YES) {
34 | [[%c(SBReachabilityManager) sharedInstance] toggleReachability];
35 | }
36 | }
37 | }
38 |
39 | %end
40 |
41 | %hook SBSearchScrollView
42 | // disable Spotlight when Reachability active
43 | -(bool) gestureRecognizerShouldBegin:(id)arg1 {
44 | if ([[%c(SBReachabilityManager) sharedInstance] reachabilityModeActive] == YES) {
45 | return NO;
46 | }
47 | return %orig;
48 | }
49 |
50 | // disable Spotlight when Reachability active
51 | -(BOOL)gestureRecognizer:(id)arg1 shouldRequireFailureOfGestureRecognizer:(id)arg2 {
52 | if ([[%c(SBReachabilityManager) sharedInstance] reachabilityModeActive] == YES) {
53 | return NO;
54 | }
55 | return %orig;
56 | }
57 | %end
58 |
59 | %hook SBReachabilitySettings
60 | -(double)yOffsetFactor {
61 | return reachOffset;
62 | }
63 |
64 | // Sets the vertical offset
65 | - (void)setYOffsetFactor:(double)arg1 {
66 | %orig(reachOffset);
67 | }
68 |
69 | // Support for other devices
70 | - (bool)allowOnAllDevices {
71 | return YES;
72 | }
73 |
74 | // Support for other devices
75 | - (void)setAllowOnAllDevices:(bool)arg1 {
76 | %orig(YES);
77 | }
78 |
79 | %end
80 |
81 | %hook SBReachabilityManager
82 | //-(void)_setKeepAliveTimer {
83 | // remove orig timer
84 | //}
85 |
86 | -(void)_pingKeepAliveWithDuration:(double)arg1 interactedBeforePing:(BOOL)arg2 initialKeepAliveTime:(double)arg3 {
87 | %orig(keepAliveDuration,arg2,0.0);
88 | }
89 |
90 | // Support for other devices
91 | + (bool)reachabilitySupported {
92 | return YES;
93 | }
94 |
95 | // Support for other devices
96 | - (bool)reachabilityEnabled {
97 | return YES;
98 | }
99 |
100 | // Support for other devices
101 | - (void)setReachabilityEnabled:(bool)arg1 {
102 | %orig(YES);
103 | }
104 |
105 | - (void)_panToDeactivateReachability:(id)arg1 {
106 | if (![arg1 isKindOfClass:%c(SBScreenEdgePanGestureRecognizer)]) return;
107 | %orig;
108 | }
109 |
110 | - (_Bool)gestureRecognizerShouldBegin:(id)arg1 {
111 | if ((![arg1 isKindOfClass:%c(SBScreenEdgePanGestureRecognizer)] && ![arg1 isKindOfClass:%c(SBReachabilityGestureRecognizer)])) return false;
112 | return %orig;
113 | }
114 |
115 | - (void)_tapToDeactivateReachability:(id)arg1 {
116 | //remove tap gesture
117 | }
118 | %end
119 |
120 | %hook SBSearchViewController
121 | // Support for other devices
122 | - (bool)reachabilitySupported {
123 | return YES;
124 | }
125 | %end
126 |
127 |
128 | %hook SBAppSwitcherController
129 | // Support for other devices
130 | - (bool)_shouldRespondToReachability {
131 | return YES;
132 | }
133 | %end
134 |
135 | %hook SBIconController
136 | // Support for other devices
137 | - (bool)_shouldRespondToReachability {
138 | return YES;
139 | }
140 | %end
141 |
142 | %hook SBApplication
143 | // Support for other devices
144 | - (bool)isReachabilitySupported {
145 | return YES;
146 | }
147 |
148 | - (void)setReachabilitySupported:(bool)arg1 {
149 | %orig(YES);
150 | }
151 | %end
152 |
153 | %hook SpringBoard
154 | // Support for other devices
155 | - (void)_setReachabilitySupported:(bool)arg1 {
156 | %orig(YES);
157 | }
158 | %end
159 |
160 | %hook SBReachabilityWindow
161 | // thanks NEPETA! put my own twist on it though (passes touches to our view)
162 | - (id)hitTest:(CGPoint)arg1 withEvent:(id)arg2 {
163 | UIView *candidate = %orig;
164 | SBWallpaperEffectView *correctView = MSHookIvar(((SBReachabilityBackgroundView *)self.rootViewController.view), "_topWallpaperEffectView");
165 | if (arg1.y <= 0) {
166 | candidate = [correctView hitTest:[correctView convertPoint:arg1 fromView:self] withEvent:arg2];
167 | if (emptyView) {
168 | candidate = emptyView;
169 | emptyView = nil;
170 | } else {
171 | emptyView = candidate;
172 | }
173 | }
174 | return candidate;
175 | }
176 | %end
177 |
178 | %hook SBReachabilityBackgroundView
179 | - (void)setChevronAlpha:(double)arg1 {
180 | if (enable) {
181 | arg1 = chevronOpacity;
182 | %orig;
183 | }
184 | %orig;
185 | }
186 | %end
187 |
188 | %hook SBReachabilityBackgroundViewController
189 | %property (nonatomic, retain) NSTimer *updateTimer;
190 | -(void)viewWillAppear:(BOOL)arg1 {
191 | %orig;
192 | [[%c(SBReachabilityManager) sharedInstance] _notifyObserversReachabilityYOffsetDidChange];
193 | [self addReachPlayerContainerView];
194 | }
195 |
196 | %new
197 | - (void)addReachPlayerContainerView {
198 | SBWallpaperEffectView *topWallpaperEffectView = MSHookIvar(((SBReachabilityBackgroundView *)self.view), "_topWallpaperEffectView");
199 |
200 | if (topWallpaperEffectView != nil) {
201 | containerView = [ReachPlayerContainerView new];
202 | containerView.frame = topWallpaperEffectView.bounds;
203 | if (enableBlur) {
204 | containerView.backgroundImageView.hidden = NO;
205 | containerView.backgroundBlurView.hidden = NO;
206 | } else {
207 | containerView.backgroundImageView.hidden = YES;
208 | containerView.backgroundBlurView.hidden = YES;
209 | }
210 | [topWallpaperEffectView addSubview:containerView];
211 |
212 | containerView.translatesAutoresizingMaskIntoConstraints = false;
213 | [containerView.bottomAnchor constraintEqualToAnchor:topWallpaperEffectView.bottomAnchor constant:0].active = YES;
214 | [containerView.leftAnchor constraintEqualToAnchor:topWallpaperEffectView.leftAnchor constant:0].active = YES;
215 | [containerView.rightAnchor constraintEqualToAnchor:topWallpaperEffectView.rightAnchor constant:0].active = YES;
216 | [containerView.topAnchor constraintEqualToAnchor:topWallpaperEffectView.topAnchor constant:0].active = YES;
217 | }
218 | }
219 | /*
220 | %new
221 | - (void)updateReachability {
222 | if ([[%c(SBReachabilityManager) sharedInstance] reachabilityModeActive] == YES) {
223 | [[%c(SBReachabilityManager) sharedInstance] toggleReachability];
224 | }
225 | }
226 | */
227 | %end
228 |
229 | %hook SpringBoard
230 | - (void)applicationDidFinishLaunching:(UIApplication *)application {
231 | %orig;
232 | loadPreferences();
233 | }
234 | %end
235 | %end
236 |
237 | %ctor {
238 |
239 | BOOL shouldLoad = NO;
240 | NSArray *args = [[NSClassFromString(@"NSProcessInfo") processInfo] arguments];
241 | NSUInteger count = args.count;
242 | if (count != 0) {
243 | NSString *executablePath = args[0];
244 | if (executablePath) {
245 | NSString *processName = [executablePath lastPathComponent];
246 | BOOL isSpringBoard = [processName isEqualToString:@"SpringBoard"];
247 | BOOL isPreferences = [processName isEqualToString:@"Preferences"];
248 | BOOL isApplication = [executablePath rangeOfString:@"/Application/"].location != NSNotFound || [executablePath rangeOfString:@"/Applications/"].location != NSNotFound;
249 | BOOL isFileProvider = [[processName lowercaseString] rangeOfString:@"fileprovider"].location != NSNotFound;
250 | BOOL skip = [processName isEqualToString:@"AdSheet"]
251 | || [processName isEqualToString:@"CoreAuthUI"]
252 | || [processName isEqualToString:@"InCallService"]
253 | || [processName isEqualToString:@"MessagesNotificationViewService"]
254 | || [executablePath rangeOfString:@".appex/"].location != NSNotFound;
255 | if (!isFileProvider && (isSpringBoard || isApplication || isPreferences) && !skip) {
256 | shouldLoad = YES;
257 | }
258 | }
259 | }
260 | if (shouldLoad) {
261 |
262 | loadPreferences(); // Load prefs
263 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)loadPreferences, (CFStringRef)preferencesNotification, NULL, CFNotificationSuspensionBehaviorCoalesce);
264 |
265 | if (enable) {
266 | %init(ReachPlayer);
267 | return;
268 | }
269 | return;
270 | }
271 | }
272 |
--------------------------------------------------------------------------------
/reachplayerprefs/REACHPLAYERPreferences.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import "REACHPLAYERPreferences.h"
3 | #import
4 |
5 | static NSString *preferencesNotification = @"com.nahtedetihw.reachplayerprefs/ReloadPrefs";
6 |
7 | #define bundlePath ([[NSFileManager defaultManager] fileExistsAtPath:@"/Library/PreferenceBundles/reachplayerprefs.bundle/"] ? @"/Library/PreferenceBundles/reachplayerprefs.bundle/" : @"/var/jb/Library/PreferenceBundles/reachplayerprefs.bundle/")
8 |
9 | #define plistPath ([[NSFileManager defaultManager] fileExistsAtPath:@"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist"] ? @"/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist" : @"/var/jb/var/mobile/Library/Preferences/com.nahtedetihw.reachplayerprefs.plist")
10 |
11 | UIBarButtonItem *changelogButtonItem;
12 | UIBarButtonItem *respringButtonItem;
13 | UIBarButtonItem *twitterButtonItem;
14 | UIBarButtonItem *paypalButtonItem;
15 | UIViewController *popController;
16 |
17 | @implementation REACHPLAYERPreferencesListController
18 | @synthesize killButton;
19 | @synthesize versionArray;
20 |
21 | - (NSArray *)specifiers {
22 | if (!_specifiers) {
23 | _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self];
24 | }
25 |
26 | return _specifiers;
27 | }
28 |
29 | - (UITableViewStyle)tableViewStyle {
30 | return UITableViewStyleInsetGrouped;
31 | }
32 |
33 | - (instancetype)init {
34 |
35 | self = [super init];
36 |
37 | if (self) {
38 |
39 | UIButton *respringButton = [UIButton buttonWithType:UIButtonTypeCustom];
40 | respringButton.frame = CGRectMake(0,0,30,30);
41 | respringButton.layer.cornerRadius = respringButton.frame.size.height / 2;
42 | respringButton.layer.masksToBounds = YES;
43 | respringButton.backgroundColor = [UIColor colorWithRed:72/255.0f green:97/255.0f blue:112/255.0f alpha:1.0f];
44 | [respringButton setImage:[[UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@CHECKMARK.png", bundlePath]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
45 | [respringButton addTarget:self action:@selector(apply:) forControlEvents:UIControlEventTouchUpInside];
46 | respringButton.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
47 |
48 | respringButtonItem = [[UIBarButtonItem alloc] initWithCustomView:respringButton];
49 |
50 | UIButton *changelogButton = [UIButton buttonWithType:UIButtonTypeCustom];
51 | changelogButton.frame = CGRectMake(0,0,30,30);
52 | changelogButton.layer.cornerRadius = changelogButton.frame.size.height / 2;
53 | changelogButton.layer.masksToBounds = YES;
54 | changelogButton.backgroundColor = [UIColor colorWithRed:72/255.0f green:97/255.0f blue:112/255.0f alpha:1.0f];
55 | [changelogButton setImage:[[UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@CHANGELOG.png", bundlePath]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
56 | [changelogButton addTarget:self action:@selector(showMenu:) forControlEvents:UIControlEventTouchUpInside];
57 | changelogButton.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
58 |
59 | changelogButtonItem = [[UIBarButtonItem alloc] initWithCustomView:changelogButton];
60 |
61 | UIButton *twitterButton = [UIButton buttonWithType:UIButtonTypeCustom];
62 | twitterButton.frame = CGRectMake(0,0,30,30);
63 | twitterButton.layer.cornerRadius = twitterButton.frame.size.height / 2;
64 | twitterButton.layer.masksToBounds = YES;
65 | twitterButton.backgroundColor = [UIColor colorWithRed:72/255.0f green:97/255.0f blue:112/255.0f alpha:1.0f];
66 | [twitterButton setImage:[[UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@TWITTER.png", bundlePath]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
67 | [twitterButton addTarget:self action:@selector(twitter:) forControlEvents:UIControlEventTouchUpInside];
68 | twitterButton.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
69 |
70 | twitterButtonItem = [[UIBarButtonItem alloc] initWithCustomView:twitterButton];
71 |
72 | UIButton *paypalButton = [UIButton buttonWithType:UIButtonTypeCustom];
73 | paypalButton.frame = CGRectMake(0,0,30,30);
74 | paypalButton.layer.cornerRadius = paypalButton.frame.size.height / 2;
75 | paypalButton.layer.masksToBounds = YES;
76 | paypalButton.backgroundColor = [UIColor colorWithRed:72/255.0f green:97/255.0f blue:112/255.0f alpha:1.0f];
77 | [paypalButton setImage:[[UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@PAYPAL.png", bundlePath]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
78 | [paypalButton addTarget:self action:@selector(paypal:) forControlEvents:UIControlEventTouchUpInside];
79 | paypalButton.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
80 |
81 | paypalButtonItem = [[UIBarButtonItem alloc] initWithCustomView:paypalButton];
82 |
83 | NSArray *rightButtons;
84 | rightButtons = @[respringButtonItem, changelogButtonItem, twitterButtonItem, paypalButtonItem];
85 | self.navigationItem.rightBarButtonItems = rightButtons;
86 | self.navigationItem.titleView = [UIView new];
87 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
88 | self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
89 | self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
90 | self.titleLabel.text = @"";
91 | self.titleLabel.textColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
92 | self.titleLabel.textAlignment = NSTextAlignmentCenter;
93 | [self.navigationItem.titleView addSubview:self.titleLabel];
94 |
95 | self.iconView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
96 | self.iconView.contentMode = UIViewContentModeScaleAspectFit;
97 | self.iconView.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@icon.png", bundlePath]];
98 | self.iconView.translatesAutoresizingMaskIntoConstraints = NO;
99 | self.iconView.alpha = 0.0;
100 | [self.navigationItem.titleView addSubview:self.iconView];
101 |
102 | [NSLayoutConstraint activateConstraints:@[
103 | [self.titleLabel.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
104 | [self.titleLabel.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
105 | [self.titleLabel.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
106 | [self.titleLabel.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
107 | [self.iconView.topAnchor constraintEqualToAnchor:self.navigationItem.titleView.topAnchor],
108 | [self.iconView.leadingAnchor constraintEqualToAnchor:self.navigationItem.titleView.leadingAnchor],
109 | [self.iconView.trailingAnchor constraintEqualToAnchor:self.navigationItem.titleView.trailingAnchor],
110 | [self.iconView.bottomAnchor constraintEqualToAnchor:self.navigationItem.titleView.bottomAnchor],
111 | ]];
112 |
113 | }
114 |
115 | return self;
116 |
117 | }
118 |
119 | - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
120 |
121 | return UIModalPresentationNone;
122 | }
123 |
124 | - (void)viewWillAppear:(BOOL)animated {
125 |
126 | [super viewWillAppear:animated];
127 |
128 | self.view.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
129 | [[UIApplication sharedApplication] keyWindow].tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
130 |
131 | CGRect frame = self.table.bounds;
132 | frame.origin.y = -frame.size.height;
133 |
134 | self.navigationController.navigationController.navigationBar.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
135 | self.navigationController.navigationController.navigationBar.translucent = YES;
136 | }
137 |
138 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
139 | tableView.tableHeaderView = self.headerView;
140 | return [super tableView:tableView cellForRowAtIndexPath:indexPath];
141 | }
142 |
143 | - (void)viewDidLoad {
144 |
145 | [super viewDidLoad];
146 |
147 | self.view.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
148 | [[UIApplication sharedApplication] keyWindow].tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
149 |
150 | self.navigationController.navigationController.navigationBar.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
151 | self.navigationController.navigationController.navigationBar.translucent = YES;
152 |
153 | self.headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)];
154 | self.headerImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,200,200)];
155 | self.headerImageView.contentMode = UIViewContentModeScaleAspectFit;
156 | self.headerImageView.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@banner.png", bundlePath]];
157 | self.headerImageView.translatesAutoresizingMaskIntoConstraints = NO;
158 |
159 | [self.headerView addSubview:self.headerImageView];
160 | [NSLayoutConstraint activateConstraints:@[
161 | [self.headerImageView.topAnchor constraintEqualToAnchor:self.headerView.topAnchor],
162 | [self.headerImageView.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor],
163 | [self.headerImageView.trailingAnchor constraintEqualToAnchor:self.headerView.trailingAnchor],
164 | [self.headerImageView.bottomAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
165 | ]];
166 |
167 | _table.tableHeaderView = self.headerView;
168 |
169 | [[NSNotificationCenter defaultCenter] addObserver:self
170 | selector:@selector(handleNoGesture:)
171 | name:UIApplicationDidEnterBackgroundNotification object:nil];
172 |
173 | }
174 |
175 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
176 | CGFloat offsetY = scrollView.contentOffset.y;
177 |
178 | if (offsetY > 40) {
179 | [UIView animateWithDuration:0.2 animations:^{
180 | self.iconView.alpha = 1.0;
181 | self.titleLabel.alpha = 0.0;
182 | }];
183 | } else {
184 | [UIView animateWithDuration:0.2 animations:^{
185 | self.iconView.alpha = 0.0;
186 | self.titleLabel.alpha = 1.0;
187 | }];
188 | }
189 |
190 | if (offsetY > 0) offsetY = 0;
191 | self.headerImageView.frame = CGRectMake(self.headerView.frame.origin.x, self.headerView.frame.origin.y, self.headerView.frame.size.width, 200 - offsetY);
192 | }
193 |
194 | - (void)viewWillDisappear:(BOOL)animated {
195 | [super viewWillDisappear:animated];
196 |
197 | [self.navigationController.navigationController.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor blackColor]}];
198 | }
199 |
200 | -(id)readPreferenceValue: (PSSpecifier *)specifier {
201 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
202 | [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:plistPath]];
203 | return settings [specifier.properties[@"key"]] ?: specifier.properties[@"default"];
204 | }
205 |
206 | -(void)setPreferenceValue:(id)value specifier: (PSSpecifier *)specifier {
207 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
208 | [settings addEntriesFromDictionary: [NSDictionary dictionaryWithContentsOfFile:plistPath]];
209 | [settings setObject:value forKey:specifier.properties [@"key"]];
210 | [settings writeToFile:plistPath atomically:YES];
211 | [super setPreferenceValue:value specifier :specifier];
212 |
213 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
214 | }
215 |
216 | - (void)apply:(UIButton *)sender {
217 |
218 | popController = [[UIViewController alloc] init];
219 | popController.modalPresentationStyle = UIModalPresentationPopover;
220 | popController.preferredContentSize = CGSizeMake(200,130);
221 | UILabel *respringLabel = [[UILabel alloc] init];
222 | respringLabel.frame = CGRectMake(20, 20, 160, 60);
223 | respringLabel.numberOfLines = 2;
224 | respringLabel.textAlignment = NSTextAlignmentCenter;
225 | respringLabel.adjustsFontSizeToFitWidth = YES;
226 | respringLabel.font = [UIFont boldSystemFontOfSize:20];
227 | respringLabel.textColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
228 | respringLabel.text = @"Are you sure you want to respring?";
229 | [popController.view addSubview:respringLabel];
230 |
231 | UIButton *yesButton = [UIButton buttonWithType:UIButtonTypeCustom];
232 | [yesButton addTarget:self
233 | action:@selector(handleYesGesture)
234 | forControlEvents:UIControlEventTouchUpInside];
235 | [yesButton setTitle:@"Yes" forState:UIControlStateNormal];
236 | yesButton.titleLabel.font = [UIFont boldSystemFontOfSize:20];
237 | [yesButton setTitleColor:[UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f] forState:UIControlStateNormal];
238 | yesButton.frame = CGRectMake(100, 100, 100, 30);
239 | [popController.view addSubview:yesButton];
240 |
241 | UIButton *noButton = [UIButton buttonWithType:UIButtonTypeCustom];
242 | [noButton addTarget:self
243 | action:@selector(handleNoGesture:)
244 | forControlEvents:UIControlEventTouchUpInside];
245 | [noButton setTitle:@"No" forState:UIControlStateNormal];
246 | noButton.titleLabel.font = [UIFont boldSystemFontOfSize:20];
247 | [noButton setTitleColor:[UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f] forState:UIControlStateNormal];
248 | noButton.frame = CGRectMake(0, 100, 100, 30);
249 | [popController.view addSubview:noButton];
250 |
251 | UIPopoverPresentationController *popover = popController.popoverPresentationController;
252 | popover.delegate = self;
253 | //[popover _setBackgroundBlurDisabled:YES];
254 | popover.permittedArrowDirections = UIPopoverArrowDirectionUp;
255 | popover.barButtonItem = respringButtonItem;
256 | popover.backgroundColor = [UIColor colorWithRed:72/255.0f green:97/255.0f blue:112/255.0f alpha:1.0f];
257 |
258 | [self presentViewController:popController animated:YES completion:nil];
259 |
260 | AudioServicesPlaySystemSound(1519);
261 |
262 | }
263 |
264 |
265 | - (void)showMenu:(id)sender {
266 |
267 | AudioServicesPlaySystemSound(1519);
268 |
269 | self.changelogController = [[OBWelcomeController alloc] initWithTitle:@"ReachPlayer" detailText:@"2.5" icon:[UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@changelogControllerIcon.png", bundlePath]]];
270 |
271 | [self.changelogController addBulletedListItemWithTitle:@"Y Offset" description:@"Allows Y Offset to be changed right away and not need a respring." image:[UIImage systemImageNamed:@"1.circle.fill"]];
272 |
273 | self.changelogController.viewIfLoaded.backgroundColor = [UIColor systemBackgroundColor];
274 | for (OBBulletedListItem *item in self.changelogController.bulletedList.items) {
275 | item.imageView.tintColor = [UIColor colorWithRed:121/255.0f green:145/255.0f blue:153/255.0f alpha:1.0f];
276 | }
277 | self.changelogController.modalPresentationStyle = UIModalPresentationPageSheet;
278 | self.changelogController.modalInPresentation = NO;
279 | [self presentViewController:self.changelogController animated:YES completion:nil];
280 | }
281 | - (void)dismissVC {
282 | [self.changelogController dismissViewControllerAnimated:YES completion:nil];
283 | }
284 |
285 | - (void)twitter:(id)sender {
286 | AudioServicesPlaySystemSound(1519);
287 |
288 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://twitter.com/EthanWhited"] options:@{} completionHandler:nil];
289 | }
290 |
291 | - (void)paypal:(id)sender {
292 | AudioServicesPlaySystemSound(1519);
293 |
294 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://paypal.me/nahtedetihw"] options:@{} completionHandler:nil];
295 | }
296 |
297 | - (void)handleYesGesture {
298 | AudioServicesPlaySystemSound(1519);
299 |
300 | [popController dismissViewControllerAnimated:YES completion:nil];
301 |
302 | pid_t pid;
303 | const char* args[] = {"killall", "SpringBoard", NULL};
304 | if ([[NSFileManager defaultManager] fileExistsAtPath:@"/usr/bin/killall"]) {
305 | posix_spawn(&pid, "usr/bin/killall", NULL, NULL, (char* const*)args, NULL);
306 | } else {
307 | posix_spawn(&pid, "/var/jb/usr/bin/killall", NULL, NULL, (char* const*)args, NULL);
308 | }
309 |
310 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
311 | }
312 |
313 | - (void)handleNoGesture:(UIButton *)sender {
314 | [popController dismissViewControllerAnimated:YES completion:nil];
315 | }
316 |
317 | @end
318 |
319 | @implementation REACHPLAYERACTIVATIONPreferencesListController
320 | - (NSArray *)specifiers {
321 | if (!_specifiers) {
322 | _specifiers = [self loadSpecifiersFromPlistName:@"ACTIVATION" target:self];
323 | }
324 |
325 | return _specifiers;
326 | }
327 |
328 | - (UITableViewStyle)tableViewStyle {
329 | return UITableViewStyleInsetGrouped;
330 | }
331 |
332 | -(id)readPreferenceValue: (PSSpecifier *)specifier {
333 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
334 | [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:plistPath]];
335 | return settings [specifier.properties[@"key"]] ?: specifier.properties[@"default"];
336 | }
337 |
338 | -(void)setPreferenceValue:(id)value specifier: (PSSpecifier *)specifier {
339 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
340 | [settings addEntriesFromDictionary: [NSDictionary dictionaryWithContentsOfFile: plistPath]];
341 | [settings setObject:value forKey:specifier.properties [@"key"]];
342 | [settings writeToFile:plistPath atomically:YES];
343 | [super setPreferenceValue:value specifier :specifier];
344 |
345 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
346 | }
347 | @end
348 |
349 |
350 | @implementation REACHPLAYERLAYOUTPreferencesListController
351 | - (NSArray *)specifiers {
352 | if (!_specifiers) {
353 | _specifiers = [self loadSpecifiersFromPlistName:@"LAYOUT" target:self];
354 | }
355 |
356 | return _specifiers;
357 | }
358 |
359 | - (UITableViewStyle)tableViewStyle {
360 | return UITableViewStyleInsetGrouped;
361 | }
362 |
363 | -(id)readPreferenceValue: (PSSpecifier *)specifier {
364 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
365 | [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:plistPath]];
366 | return settings [specifier.properties[@"key"]] ?: specifier.properties[@"default"];
367 | }
368 |
369 | -(void)setPreferenceValue:(id)value specifier: (PSSpecifier *)specifier {
370 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
371 | [settings addEntriesFromDictionary: [NSDictionary dictionaryWithContentsOfFile: plistPath]];
372 | [settings setObject:value forKey:specifier.properties [@"key"]];
373 | [settings writeToFile:plistPath atomically:YES];
374 | [super setPreferenceValue:value specifier :specifier];
375 |
376 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
377 | }
378 | @end
379 |
380 | @implementation REACHPLAYERBACKGROUNDPreferencesListController
381 | - (NSArray *)specifiers {
382 | if (!_specifiers) {
383 | _specifiers = [self loadSpecifiersFromPlistName:@"BACKGROUND" target:self];
384 | }
385 |
386 | return _specifiers;
387 | }
388 |
389 | - (UITableViewStyle)tableViewStyle {
390 | return UITableViewStyleInsetGrouped;
391 | }
392 |
393 | -(id)readPreferenceValue: (PSSpecifier *)specifier {
394 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
395 | [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:plistPath]];
396 | return settings [specifier.properties[@"key"]] ?: specifier.properties[@"default"];
397 | }
398 |
399 | -(void)setPreferenceValue:(id)value specifier: (PSSpecifier *)specifier {
400 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
401 | [settings addEntriesFromDictionary: [NSDictionary dictionaryWithContentsOfFile: plistPath]];
402 | [settings setObject:value forKey:specifier.properties [@"key"]];
403 | [settings writeToFile:plistPath atomically:YES];
404 | [super setPreferenceValue:value specifier :specifier];
405 |
406 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
407 | }
408 | @end
409 |
410 | @implementation REACHPLAYERMISCPreferencesListController
411 | - (NSArray *)specifiers {
412 | if (!_specifiers) {
413 | _specifiers = [self loadSpecifiersFromPlistName:@"MISC" target:self];
414 | }
415 |
416 | return _specifiers;
417 | }
418 |
419 | - (UITableViewStyle)tableViewStyle {
420 | return UITableViewStyleInsetGrouped;
421 | }
422 |
423 | -(id)readPreferenceValue: (PSSpecifier *)specifier {
424 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
425 | [settings addEntriesFromDictionary:[NSDictionary dictionaryWithContentsOfFile:plistPath]];
426 | return settings [specifier.properties[@"key"]] ?: specifier.properties[@"default"];
427 | }
428 |
429 | -(void)setPreferenceValue:(id)value specifier: (PSSpecifier *)specifier {
430 | NSMutableDictionary *settings = [NSMutableDictionary dictionary];
431 | [settings addEntriesFromDictionary: [NSDictionary dictionaryWithContentsOfFile: plistPath]];
432 | [settings setObject:value forKey:specifier.properties [@"key"]];
433 | [settings writeToFile:plistPath atomically:YES];
434 | [super setPreferenceValue:value specifier :specifier];
435 |
436 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef)preferencesNotification, NULL, NULL, TRUE);
437 | }
438 | @end
439 |
--------------------------------------------------------------------------------
/ReachPlayerContainerView.xm:
--------------------------------------------------------------------------------
1 | #import "ReachPlayerContainerView.h"
2 |
3 | @implementation ReachPlayerContainerView
4 | - (instancetype)init {
5 | self = [super init];
6 | if (self) {
7 | [self addBackgroundImage];
8 | [self addBackgroundBlur];
9 | [self addArtworkContainerView];
10 | [self addLabelsStackView];
11 | [self addControlsStackView];
12 | [self updateImage];
13 | [self updateTransition];
14 |
15 | if (self.nowPlayingInfoSong.text == nil) {
16 | [self setHidden:YES];
17 | } else {
18 | [self setHidden:NO];
19 | }
20 |
21 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
22 | [notificationCenter addObserver:self selector:@selector(updateImage) name:(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDidChangeNotification object:nil];
23 | [notificationCenter postNotificationName:(__bridge NSString *)kMRMediaRemoteNowPlayingInfoDidChangeNotification object:nil];
24 |
25 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playingDidChange:) name:(__bridge NSString *)kMRMediaRemoteNowPlayingApplicationPlaybackStateDidChangeNotification object:nil];
26 | [[NSNotificationCenter defaultCenter] postNotificationName:(__bridge NSString *)kMRMediaRemoteNowPlayingApplicationPlaybackStateDidChangeNotification object:nil];
27 | }
28 | return self;
29 | }
30 |
31 | - (void)addBackgroundImage {
32 | self.backgroundImageView = [[UIImageView alloc] initWithFrame:self.bounds];
33 | self.backgroundImageView.contentMode = UIViewContentModeScaleAspectFill;
34 | [self addSubview:self.backgroundImageView];
35 |
36 | self.backgroundImageView.translatesAutoresizingMaskIntoConstraints = false;
37 | [self.backgroundImageView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES;
38 | [self.backgroundImageView.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:0].active = YES;
39 | [self.backgroundImageView.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:0].active = YES;
40 | [self.backgroundImageView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES;
41 | }
42 |
43 | - (void)addBackgroundBlur {
44 | _UIBackdropViewSettings *settings;
45 | if (blurStyleRP == 0) {
46 | settings = [_UIBackdropViewSettings settingsForStyle:4005];
47 | } else if (blurStyleRP == 1) {
48 | settings = [_UIBackdropViewSettings settingsForStyle:2];
49 | } else if (blurStyleRP == 2) {
50 | settings = [_UIBackdropViewSettings settingsForStyle:4000];
51 | }
52 |
53 | self.backgroundBlurView = [[_UIBackdropView alloc] initWithSettings:settings];
54 | self.backgroundBlurView.frame = self.backgroundImageView.frame;
55 | [self insertSubview:self.backgroundBlurView aboveSubview:self.backgroundImageView];
56 |
57 | self.backgroundBlurView.translatesAutoresizingMaskIntoConstraints = false;
58 | [self.backgroundBlurView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0].active = YES;
59 | [self.backgroundBlurView.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:0].active = YES;
60 | [self.backgroundBlurView.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:0].active = YES;
61 | [self.backgroundBlurView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0].active = YES;
62 | }
63 |
64 | - (void)addArtworkContainerView {
65 | self.artworkContainerView = [[ReachPlayerArtworkContainerView alloc] initWithFrame:CGRectMake(0,0,artworkSizeRP,artworkSizeRP)];
66 | self.artworkContainerView.contentMode = UIViewContentModeScaleAspectFill;
67 | self.artworkContainerView.layer.masksToBounds = YES;
68 | self.artworkContainerView.layer.cornerCurve = kCACornerCurveContinuous;
69 | self.artworkContainerView.layer.cornerRadius = self.artworkContainerView.frame.size.height/16;
70 | [self addSubview:self.artworkContainerView];
71 |
72 | self.artworkContainerView.translatesAutoresizingMaskIntoConstraints = false;
73 | [self.artworkContainerView.widthAnchor constraintEqualToConstant:artworkSizeRP].active = true;
74 | [self.artworkContainerView.heightAnchor constraintEqualToConstant:artworkSizeRP].active = true;
75 | if (layoutStyleRP == 0) {
76 | [self.artworkContainerView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP-(artworkSizeRP/2)-15].active = true;
77 | [self.artworkContainerView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+(artworkSizeRP/2)].active = true;
78 | } else if (layoutStyleRP == 1) {
79 | [self.artworkContainerView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP].active = true;
80 | [self.artworkContainerView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+(artworkSizeRP/2)].active = true;
81 | }
82 |
83 | self.artworkContainerView.artworkView = [[UIImageView alloc] initWithFrame:CGRectMake(0,self.center.y-positionYRP,artworkSizeRP,artworkSizeRP)];
84 | self.artworkContainerView.artworkView.contentMode = UIViewContentModeScaleAspectFill;
85 | self.artworkContainerView.artworkView.layer.masksToBounds = YES;
86 | self.artworkContainerView.artworkView.layer.cornerCurve = kCACornerCurveContinuous;
87 | self.artworkContainerView.artworkView.layer.cornerRadius = self.artworkContainerView.frame.size.height/16;
88 | [self.artworkContainerView insertSubview:self.artworkContainerView.artworkView atIndex:1];
89 |
90 | self.artworkContainerView.artworkView.translatesAutoresizingMaskIntoConstraints = false;
91 | [self.artworkContainerView.artworkView.widthAnchor constraintEqualToConstant:artworkSizeRP].active = true;
92 | [self.artworkContainerView.artworkView.heightAnchor constraintEqualToConstant:artworkSizeRP].active = true;
93 | [self.artworkContainerView.artworkView.centerXAnchor constraintEqualToAnchor:self.artworkContainerView.centerXAnchor constant:0].active = true;
94 | [self.artworkContainerView.artworkView.centerYAnchor constraintEqualToAnchor:self.artworkContainerView.centerYAnchor constant:0].active = true;
95 | }
96 |
97 | - (void)addNowPlayingInfoSong {
98 | self.nowPlayingInfoSong = [[UILabel alloc] init];
99 | [self.nowPlayingInfoSong setMarqueeRunning:YES];
100 | [self.nowPlayingInfoSong setMarqueeEnabled:YES];
101 | if (layoutStyleRP == 0) {
102 | self.nowPlayingInfoSong.textAlignment = NSTextAlignmentLeft;
103 | } else if (layoutStyleRP == 1) {
104 | self.nowPlayingInfoSong.textAlignment = NSTextAlignmentCenter;
105 | }
106 | self.nowPlayingInfoSong.font = [UIFont boldSystemFontOfSize:20];
107 | self.nowPlayingInfoSong.frame = CGRectMake(0, 0, 150, 20);
108 | if (blurStyleRP == 2) {
109 | self.nowPlayingInfoSong.textColor = [UIColor blackColor];
110 | } else {
111 | self.nowPlayingInfoSong.textColor = [UIColor whiteColor];
112 | }
113 | self.nowPlayingInfoSong.clipsToBounds = NO;
114 | self.nowPlayingInfoSong.isAccessibilityElement = YES;
115 | self.nowPlayingInfoSong.accessibilityHint = @"Name of the currently playing song.";
116 | [self.labelsStackView addArrangedSubview:self.nowPlayingInfoSong];
117 |
118 | self.nowPlayingInfoSong.translatesAutoresizingMaskIntoConstraints = false;
119 | [self.nowPlayingInfoSong.widthAnchor constraintEqualToConstant:150].active = true;
120 | [self.nowPlayingInfoSong.heightAnchor constraintEqualToConstant:20].active = true;
121 | }
122 |
123 | - (void)addNowPlayingInfoArtist {
124 | self.nowPlayingInfoArtist = [[UILabel alloc] init];
125 | [self.nowPlayingInfoArtist setMarqueeRunning:YES];
126 | [self.nowPlayingInfoArtist setMarqueeEnabled:YES];
127 | if (layoutStyleRP == 0) {
128 | self.nowPlayingInfoArtist.textAlignment = NSTextAlignmentLeft;
129 | } else if (layoutStyleRP == 1) {
130 | self.nowPlayingInfoArtist.textAlignment = NSTextAlignmentCenter;
131 | }
132 | self.nowPlayingInfoArtist.font = [UIFont boldSystemFontOfSize:14];
133 | self.nowPlayingInfoArtist.frame = CGRectMake(0, 0, 150, 20);
134 | self.nowPlayingInfoArtist.alpha = 0.6;
135 | if (blurStyleRP == 2) {
136 | self.nowPlayingInfoArtist.textColor = [UIColor blackColor];
137 | } else {
138 | self.nowPlayingInfoArtist.textColor = [UIColor whiteColor];
139 | }
140 | self.nowPlayingInfoArtist.clipsToBounds = NO;
141 | self.nowPlayingInfoArtist.isAccessibilityElement = YES;
142 | self.nowPlayingInfoArtist.accessibilityHint = @"Name of the currently playing artist.";
143 | [self.labelsStackView addArrangedSubview:self.nowPlayingInfoArtist];
144 |
145 | self.nowPlayingInfoArtist.translatesAutoresizingMaskIntoConstraints = false;
146 | [self.nowPlayingInfoArtist.widthAnchor constraintEqualToConstant:150].active = true;
147 | [self.nowPlayingInfoArtist.heightAnchor constraintEqualToConstant:20].active = true;
148 | }
149 |
150 | - (void)addNowPlayingInfoAlbum {
151 | self.nowPlayingInfoAlbum = [[UILabel alloc] init];
152 | [self.nowPlayingInfoAlbum setMarqueeRunning:YES];
153 | [self.nowPlayingInfoAlbum setMarqueeEnabled:YES];
154 | if (layoutStyleRP == 0) {
155 | self.nowPlayingInfoAlbum.textAlignment = NSTextAlignmentLeft;
156 | } else if (layoutStyleRP == 1) {
157 | self.nowPlayingInfoAlbum.textAlignment = NSTextAlignmentCenter;
158 | }
159 | self.nowPlayingInfoAlbum.font = [UIFont systemFontOfSize:14];
160 | self.nowPlayingInfoAlbum.frame = CGRectMake(0, 0, 150, 20);
161 | self.nowPlayingInfoAlbum.alpha = 0.2;
162 | if (blurStyleRP == 2) {
163 | self.nowPlayingInfoAlbum.textColor = [UIColor blackColor];
164 | } else {
165 | self.nowPlayingInfoAlbum.textColor = [UIColor whiteColor];
166 | }
167 | self.nowPlayingInfoAlbum.clipsToBounds = NO;
168 | self.nowPlayingInfoAlbum.isAccessibilityElement = YES;
169 | self.nowPlayingInfoAlbum.accessibilityHint = @"Name of the currently playing album.";
170 | [self.labelsStackView addArrangedSubview:self.nowPlayingInfoAlbum];
171 |
172 | self.nowPlayingInfoAlbum.translatesAutoresizingMaskIntoConstraints = false;
173 | [self.nowPlayingInfoAlbum.widthAnchor constraintEqualToConstant:150].active = true;
174 | [self.nowPlayingInfoAlbum.heightAnchor constraintEqualToConstant:20].active = true;
175 | }
176 |
177 | - (void)addLabelsStackView {
178 | self.labelsStackView = [UIStackView new];
179 | self.labelsStackView.frame = CGRectMake(self.center.x+positionXRP+75, self.center.y+positionYRP+30, 150, 60);
180 | self.labelsStackView.transform = CGAffineTransformMakeScale(0.8, 0.8);
181 | self.labelsStackView.axis = UILayoutConstraintAxisVertical;
182 | self.labelsStackView.alignment = UIStackViewAlignmentFill;
183 | self.labelsStackView.distribution = UIStackViewDistributionEqualSpacing;
184 | self.labelsStackView.spacing = 5;
185 | self.labelsStackView.layoutMarginsRelativeArrangement = YES;
186 | [self addNowPlayingInfoSong];
187 | [self addNowPlayingInfoArtist];
188 | [self addNowPlayingInfoAlbum];
189 | self.labelsStackView.translatesAutoresizingMaskIntoConstraints = false;
190 | [self addSubview:self.labelsStackView];
191 | self.labelsStackView.translatesAutoresizingMaskIntoConstraints = false;
192 | [self.labelsStackView.heightAnchor constraintEqualToConstant:60].active = true;
193 | [self.labelsStackView.widthAnchor constraintEqualToConstant:150].active = true;
194 | if (layoutStyleRP == 0) {
195 | [self.labelsStackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP+75].active = true;
196 | [self.labelsStackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+40].active = true;
197 | } else if (layoutStyleRP == 1) {
198 | [self.labelsStackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP].active = true;
199 | [self.labelsStackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+artworkSizeRP+30+10].active = true;
200 | }
201 | }
202 |
203 | - (void)addPreviousButton {
204 | self.previousButton = [UIButton buttonWithType:UIButtonTypeCustom];
205 | self.previousButton.frame = CGRectMake(0, 0, 27, 12);
206 | [self.previousButton setTitle:@"" forState:UIControlStateNormal];
207 | [self.previousButton setImage:[[UIImage systemImageNamed:@"backward.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
208 | if (blurStyleRP == 2) {
209 | self.previousButton.tintColor = [UIColor blackColor];
210 | } else {
211 | self.previousButton.tintColor = [UIColor whiteColor];
212 | }
213 | [self.previousButton addTarget:self
214 | action:@selector(previous)
215 | forControlEvents:UIControlEventTouchUpInside];
216 | self.previousButton.isAccessibilityElement = YES;
217 | self.previousButton.accessibilityHint = @"Next Song Button.";
218 | self.previousButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
219 | self.previousButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
220 | self.previousButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
221 | [self.previousButton setContentMode:UIViewContentModeCenter];
222 | [self.controlsStackView addArrangedSubview:self.previousButton];
223 |
224 | self.previousButton.translatesAutoresizingMaskIntoConstraints = false;
225 | [self.previousButton.widthAnchor constraintEqualToConstant:32].active = true;
226 | [self.previousButton.heightAnchor constraintEqualToConstant:12].active = true;
227 | }
228 |
229 | - (void)addPlayPauseButton {
230 | self.playPauseButton = [UIButton buttonWithType:UIButtonTypeCustom];
231 | [self.playPauseButton setTitle:@"" forState:UIControlStateNormal];
232 | self.playPauseButton.frame = CGRectMake(0, 0, 20, 23);
233 | if (blurStyleRP == 2) {
234 | self.playPauseButton.tintColor = [UIColor blackColor];
235 | } else {
236 | self.playPauseButton.tintColor = [UIColor whiteColor];
237 | }
238 |
239 | [self.playPauseButton addTarget:self
240 | action:@selector(playPause)
241 | forControlEvents:UIControlEventTouchUpInside];
242 | self.playPauseButton.isAccessibilityElement = YES;
243 | self.playPauseButton.accessibilityHint = @"Play Pause Song Button.";
244 | self.playPauseButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
245 | self.playPauseButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
246 | self.playPauseButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
247 | [self.playPauseButton setContentMode:UIViewContentModeCenter];
248 | [self.controlsStackView addArrangedSubview:self.playPauseButton];
249 |
250 | self.playPauseButton.translatesAutoresizingMaskIntoConstraints = false;
251 | [self.playPauseButton.widthAnchor constraintEqualToConstant:25].active = true;
252 | [self.playPauseButton.heightAnchor constraintEqualToConstant:28].active = true;
253 | }
254 |
255 | - (void)addNextButton {
256 | self.nextButton = [UIButton buttonWithType:UIButtonTypeCustom];
257 | self.nextButton.frame = CGRectMake(0, 0, 27, 12);
258 | [self.nextButton setTitle:@"" forState:UIControlStateNormal];
259 | [self.nextButton setImage:[[UIImage systemImageNamed:@"forward.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
260 | if (blurStyleRP == 2) {
261 | self.nextButton.tintColor = [UIColor blackColor];
262 | } else {
263 | self.nextButton.tintColor = [UIColor whiteColor];
264 | }
265 | [self.nextButton addTarget:self
266 | action:@selector(next)
267 | forControlEvents:UIControlEventTouchUpInside];
268 | self.nextButton.isAccessibilityElement = YES;
269 | self.nextButton.accessibilityHint = @"Next Song Button.";
270 | self.nextButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
271 | self.nextButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
272 | self.nextButton.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
273 | [self.nextButton setContentMode:UIViewContentModeCenter];
274 | [self.controlsStackView addArrangedSubview:self.nextButton];
275 |
276 | self.nextButton.translatesAutoresizingMaskIntoConstraints = false;
277 | [self.nextButton.widthAnchor constraintEqualToConstant:32].active = true;
278 | [self.nextButton.heightAnchor constraintEqualToConstant:12].active = true;
279 | }
280 |
281 | - (void)addControlsStackView {
282 | self.controlsStackView = [UIStackView new];
283 | self.controlsStackView.frame = CGRectMake(self.center.x+positionXRP+47,self.center.y+positionYRP+28.5,94,57);
284 | self.controlsStackView.transform = CGAffineTransformMakeScale(0.8, 0.8);
285 | self.controlsStackView.axis = UILayoutConstraintAxisHorizontal;
286 | self.controlsStackView.alignment = UIStackViewAlignmentFill;
287 | self.controlsStackView.distribution = UIStackViewDistributionEqualSpacing;
288 | self.controlsStackView.spacing = 25;
289 | self.controlsStackView.layoutMarginsRelativeArrangement = YES;
290 | self.controlsStackView.translatesAutoresizingMaskIntoConstraints = false;
291 | [self addPreviousButton];
292 | [self addPlayPauseButton];
293 | [self addNextButton];
294 | [self addSubview:self.controlsStackView];
295 | self.controlsStackView.translatesAutoresizingMaskIntoConstraints = false;
296 | [self.controlsStackView.heightAnchor constraintEqualToConstant:28].active = true;
297 | [self.controlsStackView.widthAnchor constraintEqualToConstant:144].active = true;
298 | if (layoutStyleRP == 0) {
299 | [self.controlsStackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP+72].active = true;
300 | [self.controlsStackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+60+10+14].active = true;
301 | } else if (layoutStyleRP == 1) {
302 | [self.controlsStackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor constant:positionXRP].active = true;
303 | [self.controlsStackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor constant:positionYRP+artworkSizeRP+70+10+14].active = true;
304 | }
305 | }
306 |
307 | - (void)playingDidChange:(NSNotification *)notification {
308 | MRMediaRemoteGetNowPlayingApplicationIsPlaying(dispatch_get_main_queue(), ^(Boolean isPlayingNow){
309 | if (isPlayingNow == YES) {
310 | [self.playPauseButton setBackgroundImage:[[UIImage systemImageNamed:@"pause.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
311 | } else {
312 | [self.playPauseButton setBackgroundImage:[[UIImage systemImageNamed:@"play.fill"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
313 | }
314 | });
315 | }
316 |
317 | - (void)updateTransition {
318 | CATransition *transition = [CATransition animation];
319 | transition.duration = 1.0f;
320 | transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
321 | transition.type = kCATransitionFade;
322 |
323 | [self.artworkContainerView.artworkView.layer addAnimation:transition forKey:nil];
324 |
325 | CATransition *transitionBG = [CATransition animation];
326 | transitionBG.duration = 1.0f;
327 | transitionBG.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
328 | transitionBG.type = kCATransitionFade;
329 |
330 | [self.backgroundImageView.layer addAnimation:transitionBG forKey:nil];
331 | }
332 |
333 | - (void)playPause {
334 | MRMediaRemoteSendCommand(kMRTogglePlayPause, nil);
335 | AudioServicesPlaySystemSound(1519);
336 | }
337 |
338 | -(void)next {
339 | MRMediaRemoteSendCommand(kMRNextTrack, nil);
340 | AudioServicesPlaySystemSound(1519);
341 | }
342 |
343 | -(void)previous {
344 | MRMediaRemoteSendCommand(kMRPreviousTrack, nil);
345 | AudioServicesPlaySystemSound(1519);
346 | }
347 |
348 | - (void)updateImage {
349 | MRMediaRemoteGetNowPlayingInfo(dispatch_get_main_queue(), ^(CFDictionaryRef result) {
350 | if (result) {
351 | NSDictionary *dictionary = (__bridge NSDictionary *)result;
352 | NSString *songName = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoTitle];
353 | NSString *artistName = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtist];
354 | NSString *albumName = dictionary[(__bridge NSString *)kMRMediaRemoteNowPlayingInfoAlbum];
355 | NSData *artworkData = [dictionary objectForKey:(__bridge NSString *)kMRMediaRemoteNowPlayingInfoArtworkData];
356 |
357 | if (artworkData != nil) {
358 | self.artworkContainerView.artworkView.image = [UIImage imageWithData:artworkData];
359 | self.backgroundImageView.image = [UIImage imageWithData:artworkData];
360 | [self updateTransition];
361 | }
362 |
363 | if (songName != nil) {
364 | self.nowPlayingInfoSong.text = [NSString stringWithFormat:@"%@", songName];
365 | self.nowPlayingInfoSong.accessibilityLabel = [NSString stringWithFormat:@"%@", songName];
366 | [self setHidden:NO];
367 | } else {
368 | self.nowPlayingInfoSong.text = @" ";
369 | self.nowPlayingInfoSong.accessibilityLabel = @" ";
370 | [self setHidden:YES];
371 | }
372 |
373 | if (artistName != nil) {
374 | self.nowPlayingInfoArtist.text = [NSString stringWithFormat:@"%@", artistName];
375 | self.nowPlayingInfoArtist.accessibilityLabel = [NSString stringWithFormat:@"%@", songName];
376 | } else {
377 | self.nowPlayingInfoArtist.text = @" ";
378 | self.nowPlayingInfoArtist.accessibilityLabel = @" ";
379 | }
380 |
381 | if (albumName != nil) {
382 | self.nowPlayingInfoAlbum.text = [NSString stringWithFormat:@"%@", albumName];
383 | self.nowPlayingInfoAlbum.accessibilityLabel = [NSString stringWithFormat:@"%@", songName];
384 | } else {
385 | self.nowPlayingInfoAlbum.text = @" ";
386 | self.nowPlayingInfoAlbum.accessibilityLabel = @" ";
387 | }
388 | } else {
389 | self.artworkContainerView.artworkView.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@DefaultContainerArtwork.png", bundlePath]];
390 | self.backgroundImageView.image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@DefaultContainerArtwork.png", bundlePath]];
391 | }
392 | });
393 | }
394 | @end
395 |
396 | %ctor {
397 | BOOL shouldLoad = NO;
398 | NSArray *args = [[NSClassFromString(@"NSProcessInfo") processInfo] arguments];
399 | NSUInteger count = args.count;
400 | if (count != 0) {
401 | NSString *executablePath = args[0];
402 | if (executablePath) {
403 | NSString *processName = [executablePath lastPathComponent];
404 | BOOL isSpringBoard = [processName isEqualToString:@"SpringBoard"];
405 | BOOL isPreferences = [processName isEqualToString:@"Preferences"];
406 | BOOL isApplication = [executablePath rangeOfString:@"/Application/"].location != NSNotFound || [executablePath rangeOfString:@"/Applications/"].location != NSNotFound;
407 | BOOL isFileProvider = [[processName lowercaseString] rangeOfString:@"fileprovider"].location != NSNotFound;
408 | BOOL skip = [processName isEqualToString:@"AdSheet"]
409 | || [processName isEqualToString:@"CoreAuthUI"]
410 | || [processName isEqualToString:@"InCallService"]
411 | || [processName isEqualToString:@"MessagesNotificationViewService"]
412 | || [executablePath rangeOfString:@".appex/"].location != NSNotFound;
413 | if (!isFileProvider && (isSpringBoard || isApplication || isPreferences) && !skip) {
414 | shouldLoad = YES;
415 | }
416 | }
417 | }
418 | if (shouldLoad) {
419 |
420 | loadPreferences(); // Load prefs
421 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)loadPreferences, (CFStringRef)preferencesNotification, NULL, CFNotificationSuspensionBehaviorCoalesce);
422 | }
423 | }
424 |
--------------------------------------------------------------------------------