├── .gitignore ├── DragonMake ├── Headers ├── SpringBoard │ ├── SBHomeScreenViewController.h │ ├── SBMainDisplaySceneLayoutStatusBarView.h │ └── SpringBoard.h └── UIKit │ ├── UIBlurEffect+Private.h │ ├── UIKit+Private.h │ ├── UIStatusBarWindow.h │ ├── UIVisualEffectView+Private.h │ ├── _UIOverlayEffect.h │ └── _UIZoomEffect.h ├── LICENSE ├── Makefile ├── Notations.plist ├── control ├── layout └── Library │ └── Application Support │ └── Notations │ ├── delete.png │ ├── delete@2x.png │ ├── delete@3x.png │ ├── locked.png │ ├── locked@2x.png │ ├── locked@3x.png │ ├── resize.png │ ├── resize@2x.png │ ├── resize@3x.png │ ├── unlocked.png │ ├── unlocked@2x.png │ └── unlocked@3x.png └── src ├── Preferences ├── Makefile ├── NTSAppearanceTableCell.h ├── NTSAppearanceTableCell.m ├── NTSRootListController.h ├── NTSRootListController.m ├── Resources │ ├── Info.plist │ ├── Root.plist │ ├── bug.png │ ├── bug@2x.png │ ├── bug@3x.png │ ├── donate.png │ ├── donate@2x.png │ ├── donate@3x.png │ ├── icon.png │ ├── icon@2x.png │ ├── icon@3x.png │ └── styles │ │ ├── dark.png │ │ ├── default.png │ │ └── light.png └── entry.plist └── Tweak ├── Listener ├── NTSListener.h └── NTSListener.m ├── Manager ├── NTSManager.h └── NTSManager.m ├── Notations.h ├── Notations.plist ├── Notations.x ├── Objects ├── NTSNote.h └── NTSNote.m └── UI ├── Notes ├── NTSNoteView.h ├── NTSNoteView.m ├── NTSNotesViewController.h └── NTSNotesViewController.m └── Window ├── NTSWindow.h └── NTSWindow.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Theos Ignore Files 2 | .theos/ 3 | packages/ 4 | 5 | # Dragon Ignore Files 6 | .dragon/ 7 | build.ninja 8 | 9 | # Other 10 | .DS_Store 11 | .vscode/ 12 | -------------------------------------------------------------------------------- /DragonMake: -------------------------------------------------------------------------------- 1 | --- 2 | # This represents the overall project name. 3 | name: Notations 4 | icmd: sbreload 5 | 6 | all: 7 | targetvers: 13.0 8 | archs: 9 | - arm64 10 | - arm64e 11 | include: 12 | - ../../Headers/ 13 | # This represents a Tweak .dylib and .plist. 14 | Notations: 15 | dir: src/Tweak 16 | type: tweak 17 | # A list of logos files. See variables section for more info. 18 | logos_files: 19 | - '*.x' 20 | objc_files: 21 | - '**/*.m' 22 | # A list, excluding logos files, of files to compile. See variables section for more info. 23 | # Min ios 24 | # List of archs we want to build for 25 | # Now for prefs! 26 | NotationsPrefs: 27 | # Specify the directory, since it's a subproject 28 | dir: src/Preferences 29 | # Tell dragon that it's a bundle 30 | type: prefs 31 | # You can specify files from anywhere in your tweak, or use directory specific wildcards 32 | objc_files: 33 | - NTSRootListController.m 34 | - NTSAppearanceTableCell.m 35 | -------------------------------------------------------------------------------- /Headers/SpringBoard/SBHomeScreenViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface SBHomeScreenViewController : UIViewController 5 | @end 6 | -------------------------------------------------------------------------------- /Headers/SpringBoard/SBMainDisplaySceneLayoutStatusBarView.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface SBMainDisplaySceneLayoutStatusBarView : UIView 5 | @end 6 | -------------------------------------------------------------------------------- /Headers/SpringBoard/SpringBoard.h: -------------------------------------------------------------------------------- 1 | #import "./SBHomeScreenViewController.h" 2 | #import "./SBMainDisplaySceneLayoutStatusBarView.h" 3 | -------------------------------------------------------------------------------- /Headers/UIKit/UIBlurEffect+Private.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface UIBlurEffect (Private) 5 | 6 | + (id)effectWithBlurRadius:(CGFloat)blurRadius; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Headers/UIKit/UIKit+Private.h: -------------------------------------------------------------------------------- 1 | #import "./_UIOverlayEffect.h" 2 | #import "./_UIZoomEffect.h" 3 | #import "./UIBlurEffect+Private.h" 4 | #import "./UIStatusBarWindow.h" 5 | #import "./UIVisualEffectView+Private.h" 6 | -------------------------------------------------------------------------------- /Headers/UIKit/UIStatusBarWindow.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface UIStatusBarWindow : UIWindow 5 | @end 6 | -------------------------------------------------------------------------------- /Headers/UIKit/UIVisualEffectView+Private.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface UIVisualEffectView (Private) 5 | 6 | @property (nonatomic, copy) NSArray *backgroundEffects; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Headers/UIKit/_UIOverlayEffect.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface _UIOverlayEffect : UIVisualEffect 5 | 6 | @property (nonatomic, copy) NSString *filterType; 7 | @property (nonatomic, copy) UIColor *color; 8 | @property (nonatomic, assign) double alpha; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Headers/UIKit/_UIZoomEffect.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface _UIZoomEffect : UIVisualEffect 5 | 6 | + (id)zoomEffectWithMagnitude:(double)magnitude; 7 | + (id)_underlayZoomEffectWithMagnitude:(double)magnitude; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | INSTALL_TARGET_PROCESSES = SpringBoard 2 | ARCHS = arm64 arm64e 3 | TARGET = iphone:clang::11.0 4 | 5 | include $(THEOS)/makefiles/common.mk 6 | 7 | TWEAK_NAME = Notations 8 | 9 | Notations_FILES = $(wildcard src/Tweak/*.x) $(wildcard src/Tweak/*/*.m) $(wildcard src/Tweak/*/*/*.m) 10 | Notations_CFLAGS = -fobjc-arc -IHeaders 11 | 12 | include $(THEOS_MAKE_PATH)/tweak.mk 13 | 14 | SUBPROJECTS += src/Preferences 15 | include $(THEOS_MAKE_PATH)/aggregate.mk 16 | -------------------------------------------------------------------------------- /Notations.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /control: -------------------------------------------------------------------------------- 1 | Package: me.tale.notations-legacy 2 | Name: Notations 3 | Depends: mobilesubstrate, preferenceloader, firmware (>=11.0) 4 | Version: 1.0.1 5 | Architecture: iphoneos-arm 6 | Description: The "Sticky Notes" experience for iOS! 7 | Maintainer: Aarnav Tale 8 | Author: Aarnav Tale 9 | Section: Tweaks 10 | Conflicts: me.renai.notations 11 | Icon: https://apt.tale.me/api/me.tale.notations-legacy.png 12 | Depiction: https://apt.tale.me/me.tale.notations-legacy 13 | SileoDepiction: https://apt.tale.me/me.tale.notations-legacy.json 14 | -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/delete.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/delete@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/delete@2x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/delete@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/delete@3x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/locked.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/locked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/locked@2x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/locked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/locked@3x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/resize.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/resize@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/resize@2x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/resize@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/resize@3x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/unlocked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/unlocked.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/unlocked@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/unlocked@2x.png -------------------------------------------------------------------------------- /layout/Library/Application Support/Notations/unlocked@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/layout/Library/Application Support/Notations/unlocked@3x.png -------------------------------------------------------------------------------- /src/Preferences/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = iphone:clang::11.0 2 | ARCHS = arm64 arm64e 3 | 4 | include $(THEOS)/makefiles/common.mk 5 | BUNDLE_NAME = NotationsPrefs 6 | 7 | NotationsPrefs_FILES = $(wildcard *.m) $(wildcard SkittyPrefs/*.m) 8 | NotationsPrefs_INSTALL_PATH = /Library/PreferenceBundles 9 | NotationsPrefs_FRAMEWORKS = UIKit 10 | NotationsPrefs_PRIVATE_FRAMEWORKS = Preferences 11 | NotationsPrefs_CFLAGS = -fobjc-arc 12 | 13 | include $(THEOS_MAKE_PATH)/bundle.mk 14 | 15 | internal-stage:: 16 | $(ECHO_NOTHING)mkdir -p $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences$(ECHO_END) 17 | $(ECHO_NOTHING)cp entry.plist $(THEOS_STAGING_DIR)/Library/PreferenceLoader/Preferences/NotationsPrefs.plist$(ECHO_END) 18 | -------------------------------------------------------------------------------- /src/Preferences/NTSAppearanceTableCell.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | 5 | @interface UIColor (iOS13Fix) 6 | 7 | @property (class, nonatomic, readonly) UIColor *labelColor; 8 | 9 | @end 10 | 11 | @protocol PreferencesTableCustomView 12 | 13 | - (instancetype)initWithSpecifier:(PSSpecifier *)specifier; 14 | - (CGFloat)preferredHeightForWidth:(CGFloat)width; 15 | 16 | @end 17 | 18 | @interface AppearanceTypeStackView : UIView 19 | @end 20 | 21 | @interface NTSAppearanceCell : PSTableCell 22 | 23 | @property (nonatomic, retain) UIStackView *containerStackView; 24 | @property (nonatomic, retain) AppearanceTypeStackView *leftStackView; 25 | @property (nonatomic, retain) AppearanceTypeStackView *centerStackView; 26 | @property (nonatomic, retain) AppearanceTypeStackView *rightStackView; 27 | 28 | - (void)updateForType:(int)type; 29 | 30 | @end 31 | 32 | @interface AppearanceTypeStackView () 33 | 34 | @property (nonatomic, retain) UIImage *iconImage; 35 | @property (nonatomic, retain) UIImageView *iconView; 36 | @property (nonatomic, retain) UILabel *captionLabel; 37 | @property (nonatomic, retain) UIButton *checkmarkButton; 38 | @property (nonatomic, retain) UIStackView *contentStackview; 39 | @property (nonatomic, retain) NTSAppearanceCell *hostController; 40 | @property (nonatomic, retain) UIImpactFeedbackGenerator *feedbackGenerator; 41 | @property (nonatomic, retain) UITapGestureRecognizer *tapGestureRecognizer; 42 | @property (nonatomic, assign) int type; 43 | 44 | @end 45 | 46 | @interface UIImage (Private) 47 | 48 | + (UIImage*)kitImageNamed:(NSString*)name; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /src/Preferences/NTSAppearanceTableCell.m: -------------------------------------------------------------------------------- 1 | #import "./NTSAppearanceTableCell.h" 2 | 3 | NSString *leftOptionName; 4 | NSString *leftOptionImage; 5 | 6 | NSString *centerOptionName; 7 | NSString *centerOptionImage; 8 | 9 | NSString *rightOptionName; 10 | NSString *rightOptionImage; 11 | 12 | NSString *postNotification; 13 | NSString *defaults; 14 | NSString *key; 15 | 16 | UIImage *unchecked; 17 | UIImage *checked; 18 | 19 | @implementation AppearanceTypeStackView 20 | 21 | - (instancetype)initWithType:(int)type forController:(NTSAppearanceCell *)controller { 22 | self = [super init]; 23 | 24 | if (self) { 25 | self.hostController = controller; 26 | self.captionLabel = [[UILabel alloc] init]; 27 | self.checkmarkButton = [UIButton buttonWithType:UIButtonTypeCustom]; 28 | self.checkmarkButton.frame = CGRectMake(0, 0, 22, 22); 29 | 30 | self.feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:(UIImpactFeedbackStyleMedium)]; 31 | [self.feedbackGenerator prepare]; 32 | 33 | self.type = type; 34 | 35 | if (self.type == 0) { 36 | self.iconImage = [UIImage imageWithContentsOfFile:leftOptionImage]; 37 | self.captionLabel.text = leftOptionName; 38 | } else if (self.type == 1) { 39 | self.iconImage = [UIImage imageWithContentsOfFile:centerOptionImage]; 40 | self.captionLabel.text = centerOptionName; 41 | } else if (self.type == 2) { 42 | self.iconImage = [UIImage imageWithContentsOfFile:rightOptionImage]; 43 | self.captionLabel.text = rightOptionName; 44 | } 45 | 46 | NSMutableDictionary *preferences; 47 | CFArrayRef preferencesKeyList = CFPreferencesCopyKeyList(CFSTR("me.tale.notations-legacy"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 48 | if (preferencesKeyList) { 49 | preferences = (NSMutableDictionary *)CFBridgingRelease(CFPreferencesCopyMultiple(preferencesKeyList, CFSTR("me.tale.notations-legacy"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); 50 | CFRelease(preferencesKeyList); 51 | } else { 52 | preferences = nil; 53 | } 54 | 55 | if (preferences == nil) { 56 | preferences = [[NSMutableDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", @"me.tale.notations-legacy"]]; 57 | } 58 | 59 | checked = [[UIImage kitImageNamed:@"UITintedCircularButtonCheckmark.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 60 | 61 | unchecked = [[UIImage kitImageNamed:@"UIRemoveControlMultiNotCheckedImage.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 62 | 63 | NSNumber *appearanceStyle = [NSNumber numberWithInt:[([preferences objectForKey:key] ?: @(0)) integerValue]]; 64 | if ([appearanceStyle isEqualToNumber:[NSNumber numberWithInt:self.type]]) { 65 | [self.checkmarkButton setImage:checked forState:UIControlStateNormal]; 66 | self.checkmarkButton.tintColor = [UIColor systemBlueColor]; 67 | } else { 68 | [self.checkmarkButton setImage:unchecked forState:UIControlStateNormal]; 69 | self.checkmarkButton.tintColor = [UIColor systemGrayColor]; 70 | } 71 | 72 | self.iconView = [[UIImageView alloc] initWithImage:self.iconImage]; 73 | // self.iconView.contentMode = UIViewContentModeScaleAspectFit; 74 | [self.iconView.heightAnchor constraintEqualToConstant:120].active = true; 75 | [self.iconView.widthAnchor constraintEqualToConstant:60].active = true; 76 | 77 | [self.captionLabel setFont:[UIFont preferredFontForTextStyle:UIFontTextStyleBody]]; 78 | [self.captionLabel.heightAnchor constraintEqualToConstant:20].active = true; 79 | 80 | if (@available(iOS 13, *)) { 81 | [self.captionLabel setTextColor:[UIColor labelColor]]; 82 | } else { 83 | [self.captionLabel setTextColor:[UIColor blackColor]]; 84 | } 85 | 86 | [self.checkmarkButton.heightAnchor constraintEqualToConstant:22].active = true; 87 | [self.checkmarkButton.widthAnchor constraintEqualToConstant:22].active = true; 88 | [self.checkmarkButton addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside]; 89 | 90 | self.contentStackview = [[UIStackView alloc] init]; 91 | self.contentStackview.axis = UILayoutConstraintAxisVertical; 92 | self.contentStackview.alignment = UIStackViewAlignmentCenter; 93 | self.contentStackview.spacing = 8; 94 | 95 | [self.contentStackview addArrangedSubview:self.iconView]; 96 | [self.contentStackview addArrangedSubview:self.captionLabel]; 97 | [self.contentStackview addArrangedSubview:self.checkmarkButton]; 98 | 99 | self.contentStackview.translatesAutoresizingMaskIntoConstraints = false; 100 | self.translatesAutoresizingMaskIntoConstraints = false; 101 | 102 | self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(buttonTapped:)]; 103 | self.tapGestureRecognizer.numberOfTapsRequired = 1; 104 | 105 | [self addSubview:self.contentStackview]; 106 | [self.contentStackview setUserInteractionEnabled:YES]; 107 | [self.contentStackview addGestureRecognizer:self.tapGestureRecognizer]; 108 | 109 | [self.widthAnchor constraintEqualToConstant:55].active = true; 110 | [self.heightAnchor constraintEqualToConstant:140].active = true; 111 | } 112 | 113 | return self; 114 | } 115 | 116 | - (void)buttonTapped:(UILongPressGestureRecognizer *)sender { 117 | if (sender.state == UIGestureRecognizerStateBegan) { 118 | [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 119 | self.alpha = 0.5; 120 | } completion:^(BOOL finished) {}]; 121 | } else if (sender.state == UIGestureRecognizerStateEnded){ 122 | [UIView animateWithDuration:0.1 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ 123 | self.alpha = 1.0; 124 | } completion:^(BOOL finished) {}]; 125 | } 126 | 127 | [self.feedbackGenerator impactOccurred]; 128 | 129 | CFPreferencesSetValue((CFStringRef) key, CFBridgingRetain([NSNumber numberWithInt:self.type]), (CFStringRef) defaults, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 130 | 131 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (CFStringRef) postNotification, NULL, NULL, YES); 132 | 133 | [self.hostController updateForType:self.type]; 134 | } 135 | 136 | @end 137 | 138 | @implementation NTSAppearanceCell 139 | 140 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier specifier:(PSSpecifier *)specifier { 141 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier specifier:specifier]; 142 | 143 | if (self) { 144 | leftOptionName = specifier.properties[@"leftOptionName"]; 145 | centerOptionName = specifier.properties[@"centerOptionName"]; 146 | rightOptionName = specifier.properties[@"rightOptionName"]; 147 | leftOptionImage = specifier.properties[@"leftOptionImage"]; 148 | centerOptionImage = specifier.properties[@"centerOptionImage"]; 149 | rightOptionImage = specifier.properties[@"rightOptionImage"]; 150 | defaults = specifier.properties[@"defaults"]; 151 | postNotification = specifier.properties[@"PostNotification"]; 152 | key = specifier.properties[@"key"]; 153 | 154 | self.leftStackView = [[AppearanceTypeStackView alloc] initWithType:0 forController:self]; 155 | self.centerStackView =[[AppearanceTypeStackView alloc] initWithType:1 forController:self]; 156 | self.rightStackView = [[AppearanceTypeStackView alloc] initWithType:2 forController:self]; 157 | 158 | self.containerStackView = [[UIStackView alloc] init]; 159 | self.containerStackView.axis = UILayoutConstraintAxisHorizontal; 160 | self.containerStackView.alignment = UIStackViewAlignmentCenter; 161 | self.containerStackView.distribution = UIStackViewDistributionEqualSpacing; 162 | self.containerStackView.spacing = 50; 163 | self.containerStackView.translatesAutoresizingMaskIntoConstraints = NO; 164 | 165 | [self.containerStackView addArrangedSubview:self.leftStackView]; 166 | [self.containerStackView addArrangedSubview:self.centerStackView]; 167 | [self.containerStackView addArrangedSubview:self.rightStackView]; 168 | [self.contentView addSubview:self.containerStackView]; 169 | 170 | [self.containerStackView.centerXAnchor constraintEqualToAnchor:self.centerXAnchor].active = true; 171 | [self.containerStackView.centerYAnchor constraintEqualToAnchor:self.centerYAnchor].active = true; 172 | [self.heightAnchor constraintEqualToConstant:179].active = true; 173 | } 174 | 175 | return self; 176 | } 177 | 178 | - (instancetype)initWithSpecifier:(PSSpecifier *)specifier { 179 | self = [self initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"NTSAppearanceCell" specifier:specifier]; 180 | return self; 181 | } 182 | 183 | - (CGFloat)preferredHeightForWidth:(CGFloat)width { 184 | return 410.0f; 185 | } 186 | 187 | - (CGFloat)preferredHeightForWidth:(CGFloat)width inTableView:(id)tableView { 188 | return [self preferredHeightForWidth:width]; 189 | } 190 | 191 | - (void)updateForType:(int)type { 192 | AppearanceTypeStackView *notSelect1; 193 | AppearanceTypeStackView *notSelect2; 194 | AppearanceTypeStackView *toSelect; 195 | 196 | if (type == 1) { 197 | notSelect1 = self.leftStackView; 198 | notSelect2 = self.rightStackView; 199 | toSelect = self.centerStackView; 200 | } else if (type == 2) { 201 | notSelect1 = self.leftStackView; 202 | notSelect2 = self.centerStackView; 203 | toSelect = self.rightStackView; 204 | } else { 205 | notSelect1 = self.centerStackView; 206 | notSelect2 = self.rightStackView; 207 | toSelect = self.leftStackView; 208 | } 209 | 210 | [UIView transitionWithView:notSelect1.checkmarkButton duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ 211 | [notSelect1.checkmarkButton setImage:unchecked forState:UIControlStateNormal]; 212 | notSelect1.checkmarkButton.tintColor = [UIColor systemGrayColor]; 213 | } completion:^(BOOL finished) { 214 | finished = YES; 215 | }]; 216 | 217 | [UIView transitionWithView:notSelect2.checkmarkButton duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ 218 | [notSelect2.checkmarkButton setImage:unchecked forState:UIControlStateNormal]; 219 | notSelect2.checkmarkButton.tintColor = [UIColor systemGrayColor]; 220 | } completion:^(BOOL finished) { 221 | finished = YES; 222 | }]; 223 | 224 | [UIView transitionWithView:toSelect.checkmarkButton duration:0.2f options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ 225 | [toSelect.checkmarkButton setImage:checked forState:UIControlStateNormal]; 226 | toSelect.checkmarkButton.tintColor = [UIColor systemBlueColor]; 227 | } completion:^(BOOL finished) { 228 | finished = YES; 229 | }]; 230 | } 231 | 232 | @end 233 | 234 | -------------------------------------------------------------------------------- /src/Preferences/NTSRootListController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NTSRootListController : PSListController 4 | 5 | @property (nonatomic, retain) NSMutableDictionary *required; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /src/Preferences/NTSRootListController.m: -------------------------------------------------------------------------------- 1 | #import "NTSRootListController.h" 2 | #import 3 | 4 | @implementation NTSRootListController 5 | 6 | - (instancetype)init { 7 | self = [super init]; 8 | 9 | if (self) { 10 | NSMutableDictionary *preferences; 11 | CFArrayRef preferencesKeyList = CFPreferencesCopyKeyList(CFSTR("me.tale.notations-legacy"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 12 | if (preferencesKeyList) { 13 | preferences = (NSMutableDictionary *)CFBridgingRelease(CFPreferencesCopyMultiple(preferencesKeyList, CFSTR("me.tale.notations-legacy"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); 14 | CFRelease(preferencesKeyList); 15 | } else { 16 | preferences = nil; 17 | } 18 | 19 | if (preferences == nil) { 20 | preferences = [[NSMutableDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", @"me.tale.notations-legacy"]]; 21 | } 22 | 23 | UISwitch *toggleSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(0, 0, 50, 30)]; 24 | [toggleSwitch setOn:[([preferences objectForKey:@"enabled"] ?: @(YES)) boolValue] animated:NO]; 25 | [toggleSwitch addTarget:self action:@selector(updateSwitch:) forControlEvents:UIControlEventTouchUpInside]; 26 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:toggleSwitch]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (void)updateSwitch:(UISwitch *)sender { 33 | UISwitch *toggleSwitch = (UISwitch *)sender; 34 | 35 | CFPreferencesSetValue(CFSTR("enabled"), CFBridgingRetain([NSNumber numberWithBool:[toggleSwitch isOn]]), CFSTR("me.tale.notations-legacy"), kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 36 | 37 | CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), CFSTR("me.tale.notations-legacy/reload"), NULL, NULL, YES); 38 | } 39 | 40 | - (NSMutableArray *)specifiers { 41 | if (!_specifiers) { 42 | _specifiers = [self loadSpecifiersFromPlistName:@"Root" target:self]; 43 | self.required = (!self.required) ? [NSMutableDictionary new] : self.required; 44 | 45 | for (PSSpecifier *specifier in _specifiers) { 46 | if ([specifier propertyForKey:@"requires"]) { 47 | [self.required setObject:@0 forKey:[specifier propertyForKey:@"requires"]]; 48 | } 49 | } 50 | 51 | for (PSSpecifier *specifier in _specifiers) { 52 | if ([self.required objectForKey:[specifier propertyForKey:@"key"]]) { 53 | [self.required setObject:[self readPreferenceValue:specifier] forKey:[specifier propertyForKey:@"key"]]; 54 | } 55 | } 56 | } 57 | 58 | return _specifiers; 59 | } 60 | 61 | - (CGFloat)tableView:(UITableView *)view heightForRowAtIndexPath:(NSIndexPath *)path { 62 | PSSpecifier *specifier = [self specifierAtIndexPath:path]; 63 | if ([specifier propertyForKey:@"requires"]) { 64 | if (![[self.required objectForKey:[specifier propertyForKey:@"requires"]] boolValue]) { 65 | return 0.01; 66 | } 67 | } 68 | 69 | return [super tableView:view heightForRowAtIndexPath:path]; 70 | } 71 | 72 | - (void)tableView:(UITableView *)view willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)path { 73 | cell.clipsToBounds = YES; 74 | } 75 | 76 | - (void)setPreferenceValue:(id)value specifier:(PSSpecifier *)specifier { 77 | [super setPreferenceValue:value specifier:specifier]; 78 | if ([specifier propertyForKey:@"key"] && [self.required objectForKey:[specifier propertyForKey:@"key"]]) { 79 | [self.required setObject:value forKey:[specifier propertyForKey:@"key"]]; 80 | [[self valueForKey:@"_table"] beginUpdates]; 81 | [[self valueForKey:@"_table"] endUpdates]; 82 | } 83 | } 84 | 85 | - (void)submitIssue { 86 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://github.com/Renaitare/Notations/issues/new"] options:@{} completionHandler:nil]; 87 | } 88 | 89 | - (void)donate { 90 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://ko-fi.com/renai"] options:@{} completionHandler:nil]; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /src/Preferences/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | NotationsPrefs 9 | CFBundleIdentifier 10 | me.tale.notations-legacy.preferences 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 | NTSRootListController 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/Preferences/Resources/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | items 6 | 7 | 8 | cell 9 | PSGroupCell 10 | label 11 | Appearance 12 | 13 | 14 | cell 15 | PSDefaultCell 16 | cellClass 17 | NTSAppearanceCell 18 | leftOptionName 19 | Default 20 | centerOptionName 21 | Light 22 | rightOptionName 23 | Dark 24 | leftOptionImage 25 | /Library/PreferenceBundles/NotationsPrefs.bundle/styles/default.png 26 | centerOptionImage 27 | /Library/PreferenceBundles/NotationsPrefs.bundle/styles/light.png 28 | rightOptionImage 29 | /Library/PreferenceBundles/NotationsPrefs.bundle/styles/dark.png 30 | defaults 31 | me.tale.notations-legacy 32 | PostNotification 33 | me.tale.notations-legacy/reload 34 | key 35 | style 36 | height 37 | 211 38 | 39 | 40 | cell 41 | PSGroupCell 42 | label 43 | Settings 44 | 45 | 46 | cell 47 | PSLinkListCell 48 | detail 49 | PSListItemsController 50 | default 51 | 0 52 | label 53 | Gesture 54 | validTitles 55 | 56 | Long-Press Status Bar 57 | Double-Tap Home Screen 58 | Triple-Tap Home Screen 59 | Activator Gestures 60 | 61 | validValues 62 | 63 | 1 64 | 2 65 | 3 66 | 4 67 | 68 | key 69 | gesture 70 | defaults 71 | me.tale.notations-legacy 72 | PostNotification 73 | me.tale.notations-legacy/reload 74 | 75 | 76 | cell 77 | PSSwitchCell 78 | default 79 | 80 | label 81 | Custom Text Size 82 | key 83 | isCustomText 84 | defaults 85 | me.tale.notations-legacy 86 | PostNotification 87 | me.tale.notations-legacy/reload 88 | 89 | 90 | cell 91 | PSSliderCell 92 | showValue 93 | 94 | default 95 | 14 96 | min 97 | 10 98 | max 99 | 24 100 | isSegmented 101 | 102 | segmentCount 103 | 14 104 | requires 105 | isCustomText 106 | key 107 | customText 108 | defaults 109 | me.tale.notations-legacy 110 | PostNotification 111 | me.tale.notations-legacy/reload 112 | 113 | 114 | cell 115 | PSGroupCell 116 | label 117 | Text Alignment 118 | 119 | 120 | cell 121 | PSSegmentCell 122 | default 123 | 1 124 | alignment 125 | 3 126 | validValues 127 | 128 | 1 129 | 2 130 | 3 131 | 132 | validTitles 133 | 134 | Left 135 | Center 136 | Right 137 | 138 | key 139 | alignment 140 | defaults 141 | me.tale.notations-legacy 142 | PostNotification 143 | me.tale.notations-legacy/reload 144 | 145 | 146 | cell 147 | PSGroupCell 148 | label 149 | Links 150 | 151 | 152 | cell 153 | PSButtonCell 154 | action 155 | submitIssue 156 | label 157 | Report Issues 158 | icon 159 | /Library/PreferenceBundles/NotationsPrefs.bundle/bug.png 160 | 161 | 162 | cell 163 | PSButtonCell 164 | action 165 | donate 166 | label 167 | Donate / Support Me 168 | icon 169 | /Library/PreferenceBundles/NotationsPrefs.bundle/donate.png 170 | 171 | 172 | cell 173 | PSGroupCell 174 | footerText 175 | Made with ❤️ by Renaitare 176 | footerAlignment 177 | 1 178 | 179 | 180 | title 181 | Notations 182 | 183 | 184 | -------------------------------------------------------------------------------- /src/Preferences/Resources/bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/bug.png -------------------------------------------------------------------------------- /src/Preferences/Resources/bug@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/bug@2x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/bug@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/bug@3x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/donate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/donate.png -------------------------------------------------------------------------------- /src/Preferences/Resources/donate@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/donate@2x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/donate@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/donate@3x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/icon.png -------------------------------------------------------------------------------- /src/Preferences/Resources/icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/icon@2x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/icon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/icon@3x.png -------------------------------------------------------------------------------- /src/Preferences/Resources/styles/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/styles/dark.png -------------------------------------------------------------------------------- /src/Preferences/Resources/styles/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/styles/default.png -------------------------------------------------------------------------------- /src/Preferences/Resources/styles/light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tale/notations/7928a1188da90b4d75507ba063db5d571c13c546/src/Preferences/Resources/styles/light.png -------------------------------------------------------------------------------- /src/Preferences/entry.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | entry 6 | 7 | bundle 8 | NotationsPrefs 9 | cell 10 | PSLinkCell 11 | detail 12 | NTSRootListController 13 | icon 14 | icon.png 15 | isController 16 | 17 | label 18 | Notations 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Tweak/Listener/NTSListener.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NTSListener : NSObject 4 | @end 5 | -------------------------------------------------------------------------------- /src/Tweak/Listener/NTSListener.m: -------------------------------------------------------------------------------- 1 | #import "NTSListener.h" 2 | #import "../Manager/NTSManager.h" 3 | 4 | @implementation NTSListener 5 | 6 | - (NSString *)activator:(LAActivator *)activator requiresLocalizedTitleForListenerName:(NSString *)listenerName { 7 | return @"Notations"; 8 | } 9 | 10 | - (NSString *)activator:(LAActivator *)activator requiresLocalizedDescriptionForListenerName:(NSString *)listenerName { 11 | return @"Toggle the notes view visibility"; 12 | } 13 | 14 | - (NSArray *)activator:(LAActivator *)activator requiresCompatibleEventModesForListenerWithName:(NSString *)listenerName { 15 | return [NSArray arrayWithObjects:@"springboard", @"lockscreen", @"application", nil]; 16 | } 17 | 18 | - (UIImage *)activator:(LAActivator *)activator requiresIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale { 19 | return [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/NotationsPrefs.bundle/icon.png"]; 20 | } 21 | 22 | - (UIImage *)activator:(LAActivator *)activator requiresSmallIconForListenerName:(NSString *)listenerName scale:(CGFloat)scale { 23 | return [UIImage imageWithContentsOfFile:@"/Library/PreferenceBundles/NotationsPrefs.bundle/icon.png"]; 24 | } 25 | 26 | - (void)activator:(LAActivator *)activator receiveEvent:(LAEvent *)event { 27 | if ([NTSManager sharedInstance].gesture == 4) { 28 | [[NTSManager sharedInstance] toggleNotesShown]; 29 | } 30 | 31 | [event setHandled:YES]; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /src/Tweak/Manager/NTSManager.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class NTSNote, NTSWindow, NTSNotesView; 4 | 5 | @interface NTSManager : NSObject 6 | 7 | @property (nonatomic, retain) UIView *notesView; 8 | @property (nonatomic, retain) NSMutableArray *notes; 9 | @property (nonatomic, retain) NTSWindow *window; 10 | @property (nonatomic) BOOL windowVisible; 11 | @property (nonatomic) BOOL enabled; 12 | @property (nonatomic) BOOL isCustomText; 13 | @property (nonatomic) NSInteger gesture; 14 | @property (nonatomic) NSInteger textSize; 15 | @property (nonatomic) NSInteger textAlignment; 16 | @property (nonatomic) NSInteger colorStyle; 17 | 18 | + (instancetype)sharedInstance; 19 | - (id)init; 20 | - (void)loadView; 21 | - (void)removeNote:(NTSNote *)note; 22 | - (void)createNote:(UILongPressGestureRecognizer *)sender; 23 | - (void)loadNotes; 24 | - (void)updateNotes; 25 | - (void)toggleNotesShown; 26 | - (void)showNotes; 27 | - (void)hideNotes; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /src/Tweak/Manager/NTSManager.m: -------------------------------------------------------------------------------- 1 | #import "NTSManager.h" 2 | #import "../Objects/NTSNote.h" 3 | #import "../UI/Notes/NTSNoteView.h" 4 | #import "../UI/Window/NTSWindow.h" 5 | 6 | @implementation NTSManager 7 | 8 | + (instancetype)sharedInstance { 9 | static NTSManager *instance = nil; 10 | static dispatch_once_t onceToken; 11 | 12 | dispatch_once(&onceToken, ^{ 13 | instance = [NTSManager alloc]; 14 | instance.notes = [NSMutableArray new]; 15 | }); 16 | 17 | return instance; 18 | } 19 | 20 | - (instancetype)init { 21 | return [NTSManager sharedInstance]; 22 | } 23 | 24 | - (void)loadView { 25 | if (!self.window) { 26 | self.window = [[NTSWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 27 | } 28 | if (!self.notesView) { 29 | self.notesView = self.window.rootViewController.view; 30 | self.notesView.userInteractionEnabled = YES; 31 | } 32 | 33 | [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 34 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:[UIDevice currentDevice]]; 35 | } 36 | 37 | - (void)removeNote:(NTSNote *)note { 38 | [note willHideView]; 39 | [self.notes removeObject:note]; 40 | 41 | NSError *error; 42 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.notes requiringSecureCoding:NO error:&error]; 43 | 44 | [data writeToFile:@"/var/mobile/Documents/NotationsData.plist" atomically:NO]; 45 | 46 | [self updateNotes]; 47 | } 48 | 49 | - (void)loadNotes { 50 | NSData *notesArrayData = [NSData dataWithContentsOfFile:@"/var/mobile/Documents/NotationsData.plist"]; 51 | 52 | if (notesArrayData) { 53 | // NSError *error; 54 | // NSArray *savedNotesArray = [NSKeyedUnarchiver unarchivedObjectOfClass:[NTSNote class] fromData:notesArrayData error:&error]; 55 | NSArray *savedNotesArray = [NSKeyedUnarchiver unarchiveObjectWithData:notesArrayData]; 56 | if (savedNotesArray) { 57 | self.notes = [[NSMutableArray alloc] initWithArray:savedNotesArray]; 58 | } else { 59 | self.notes = [[NSMutableArray alloc] init]; 60 | } 61 | } 62 | 63 | for (NTSNote *note in self.notes) { 64 | note.presented = NO; 65 | } 66 | 67 | [self updateNotes]; 68 | } 69 | 70 | - (void)updateNotes { 71 | if (self.notes.count == 0) { 72 | } else { 73 | for (NTSNote *note in self.notes) { 74 | [note loadView]; 75 | [note.view removeFromSuperview]; 76 | [self.notesView addSubview:note.view]; 77 | note.presented = YES; 78 | } 79 | } 80 | } 81 | 82 | - (void)createNote:(UILongPressGestureRecognizer *)sender { 83 | if (sender.state == UIGestureRecognizerStateBegan) { 84 | if (self.windowVisible) { 85 | CGPoint position = [sender locationInView:self.notesView]; 86 | NTSNote *note = [[NTSNote alloc] init]; 87 | note.text = @""; 88 | note.center = CGPointMake(position.x, position.y); 89 | note.size = CGSizeMake(200, 200); 90 | note.interactive = YES; 91 | 92 | [self.notes addObject:note]; 93 | [self updateNotes]; 94 | [note willShowView]; 95 | [self.notesView addSubview:note.view]; 96 | [note didShowView]; 97 | 98 | NSError *error; 99 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.notes requiringSecureCoding:NO error:&error]; 100 | 101 | [data writeToFile:@"/var/mobile/Documents/NotationsData.plist" atomically:NO]; 102 | } 103 | } 104 | } 105 | 106 | - (void)toggleNotesShown { 107 | if (self.enabled) { 108 | if (self.windowVisible) { 109 | [self hideNotes]; 110 | } else { 111 | [self showNotes]; 112 | } 113 | } 114 | } 115 | 116 | - (void)showNotes { 117 | for (NTSNote *note in self.notes) { 118 | [note willShowView]; 119 | } 120 | [self updateNotes]; 121 | 122 | self.window.windowLevel = UIWindowLevelStatusBar + 99.0; 123 | self.window.hidden = NO; 124 | self.windowVisible = YES; 125 | 126 | for (NTSNote *note in self.notes) { 127 | [note didShowView]; 128 | } 129 | } 130 | 131 | - (void)hideNotes { 132 | for (NTSNote *note in self.notes) { 133 | [note willHideView]; 134 | } 135 | self.window.hidden = YES; 136 | self.windowVisible = NO; 137 | } 138 | 139 | - (void) orientationChanged:(NSNotification *)sender { 140 | UIDevice * device = sender.object; 141 | switch (device.orientation) { 142 | case UIInterfaceOrientationLandscapeLeft: 143 | for (NTSNote *note in self.notes) { 144 | [UIView animateWithDuration:0.25 animations:^{ 145 | note.view.transform = CGAffineTransformMakeRotation(-90 * M_PI / 180.0); 146 | } completion:nil]; 147 | } 148 | break; 149 | case UIInterfaceOrientationLandscapeRight: 150 | for (NTSNote *note in self.notes) { 151 | [UIView animateWithDuration:0.25 animations:^{ 152 | note.view.transform = CGAffineTransformMakeRotation(90 * M_PI / 180.0); 153 | } completion:nil]; 154 | } 155 | break; 156 | case UIInterfaceOrientationPortraitUpsideDown: 157 | for (NTSNote *note in self.notes) { 158 | [UIView animateWithDuration:0.25 animations:^{ 159 | note.view.transform = CGAffineTransformMakeRotation(180 * M_PI / 180.0); 160 | } completion:nil]; 161 | } 162 | break; 163 | case UIInterfaceOrientationPortrait: 164 | default: 165 | for (NTSNote *note in self.notes) { 166 | [UIView animateWithDuration:0.25 animations:^{ 167 | note.view.transform = CGAffineTransformMakeRotation(0 * M_PI / 180.0); 168 | } completion:nil]; 169 | } 170 | break; 171 | } 172 | } 173 | 174 | @end 175 | -------------------------------------------------------------------------------- /src/Tweak/Notations.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "UIKit/UIStatusBarWindow.h" 4 | #import 5 | 6 | #define SYSTEM_VERSION(version) ([[[UIDevice currentDevice] systemVersion] compare:version options:NSNumericSearch] != NSOrderedAscending) 7 | 8 | extern CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); 9 | 10 | @interface SBHomeScreenViewController (Notations) 11 | @property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 12 | - (void)updateNotations; 13 | - (void)toggleNotesShown; 14 | @end 15 | 16 | @interface SBMainDisplaySceneLayoutStatusBarView (Notations) 17 | @property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 18 | - (void)updateNotations; 19 | - (void)toggleNotesShown; 20 | @end 21 | 22 | @interface UIStatusBarWindow (Notations) 23 | @property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 24 | - (void)updateNotations; 25 | - (void)toggleNotesShown; 26 | @end 27 | -------------------------------------------------------------------------------- /src/Tweak/Notations.plist: -------------------------------------------------------------------------------- 1 | { Filter = { Bundles = ( "com.apple.springboard" ); }; } 2 | -------------------------------------------------------------------------------- /src/Tweak/Notations.x: -------------------------------------------------------------------------------- 1 | #import "Notations.h" 2 | #import "Manager/NTSManager.h" 3 | #import "Objects/NTSNote.h" 4 | #import "UI/Window/NTSWindow.h" 5 | #import "Listener/NTSListener.h" 6 | 7 | static NSString *bundleIdentifier = @"me.tale.notations-legacy"; 8 | 9 | static NSMutableDictionary *preferences; 10 | static NSMutableArray *viewUpdateQueue; 11 | 12 | // Hide notes on power button press 13 | %hook SBLockHardwareButton 14 | 15 | - (void)singlePress:(id)arg1 { 16 | if ([NTSManager sharedInstance].windowVisible) { 17 | [[NTSManager sharedInstance] hideNotes]; 18 | return; 19 | } 20 | %orig; 21 | } 22 | 23 | %end 24 | 25 | // Hide notes on home button press 26 | %hook SBHomeHardwareButton 27 | 28 | - (void)singlePressUp:(id)arg1 { 29 | if ([NTSManager sharedInstance].windowVisible) { 30 | [[NTSManager sharedInstance] hideNotes]; 31 | return; 32 | } 33 | %orig; 34 | } 35 | 36 | %end 37 | 38 | // Hide notes when switcher opens 39 | %hook SBFluidSwitcherViewController 40 | 41 | - (void)viewWillAppear:(BOOL)arg1 { 42 | %orig; 43 | [[NTSManager sharedInstance] hideNotes]; 44 | } 45 | 46 | %end 47 | 48 | // Initialize notes view 49 | %hook SpringBoard 50 | 51 | - (void)applicationDidFinishLaunching:(id)arg1 { 52 | %orig; 53 | [[NTSManager sharedInstance] loadView]; 54 | [[NTSManager sharedInstance] loadNotes]; 55 | } 56 | 57 | %end 58 | 59 | // Home screen gestures 60 | %hook SBHomeScreenViewController 61 | %property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 62 | 63 | - (void)viewDidLoad { 64 | %orig; 65 | [self updateNotations]; 66 | if (![viewUpdateQueue containsObject:self]) { 67 | [viewUpdateQueue addObject:self]; 68 | } 69 | } 70 | 71 | %new 72 | - (void)updateNotations { 73 | if (self.notationsGesture) [self.view removeGestureRecognizer:self.notationsGesture]; 74 | if ([NTSManager sharedInstance].gesture == 2) { 75 | self.notationsGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleNotesShown)]; 76 | ((UITapGestureRecognizer *)self.notationsGesture).numberOfTapsRequired = 2; 77 | [self.view addGestureRecognizer:self.notationsGesture]; 78 | } else if ([NTSManager sharedInstance].gesture == 3) { 79 | self.notationsGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleNotesShown)]; 80 | ((UITapGestureRecognizer *)self.notationsGesture).numberOfTapsRequired = 3; 81 | [self.view addGestureRecognizer:self.notationsGesture]; 82 | } 83 | } 84 | 85 | %new 86 | - (void)toggleNotesShown { 87 | CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("me.tale.notations-legacy/toggle"), NULL, NULL, true); 88 | } 89 | 90 | %end 91 | 92 | // Status bar gestures 93 | %hook UIStatusBarWindow 94 | %property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 95 | 96 | - (instancetype)initWithFrame:(CGRect)frame { 97 | self = %orig; 98 | [self updateNotations]; 99 | if (![viewUpdateQueue containsObject:self]) { 100 | [viewUpdateQueue addObject:self]; 101 | } 102 | return self; 103 | } 104 | 105 | %new 106 | - (void)updateNotations { 107 | if (self.notationsGesture) [self removeGestureRecognizer:self.notationsGesture]; 108 | if ([NTSManager sharedInstance].gesture == 0) { 109 | self.notationsGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleNotesShown)]; 110 | ((UITapGestureRecognizer *)self.notationsGesture).numberOfTapsRequired = 2; 111 | [self addGestureRecognizer:self.notationsGesture]; 112 | } else if ([NTSManager sharedInstance].gesture == 1) { 113 | self.notationsGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressStatusBar:)]; 114 | [self addGestureRecognizer:self.notationsGesture]; 115 | } 116 | } 117 | 118 | %new 119 | - (void)longPressStatusBar:(UILongPressGestureRecognizer *)sender { 120 | if (sender.state == UIGestureRecognizerStateBegan) { 121 | [self toggleNotesShown]; 122 | } 123 | } 124 | 125 | %new 126 | - (void)toggleNotesShown { 127 | CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("me.tale.notations-legacy/toggle"), NULL, NULL, true); 128 | } 129 | 130 | %end 131 | 132 | %group iOS13StatusBar 133 | 134 | %hook SBMainDisplaySceneLayoutStatusBarView 135 | %property (nonatomic, retain) UIGestureRecognizer *notationsGesture; 136 | 137 | - (void)_addStatusBarIfNeeded { 138 | %orig; 139 | [self updateNotations]; 140 | if (![viewUpdateQueue containsObject:self]) { 141 | [viewUpdateQueue addObject:self]; 142 | } 143 | } 144 | 145 | %new 146 | - (void)updateNotations { 147 | UIView *statusBar = [self valueForKey:@"_statusBar"]; 148 | if (self.notationsGesture) [statusBar removeGestureRecognizer:self.notationsGesture]; 149 | if ([NTSManager sharedInstance].gesture == 0) { 150 | self.notationsGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleNotesShown)]; 151 | ((UITapGestureRecognizer *)self.notationsGesture).numberOfTapsRequired = 2; 152 | [statusBar addGestureRecognizer:self.notationsGesture]; 153 | } else if ([NTSManager sharedInstance].gesture == 1) { 154 | self.notationsGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressStatusBar:)]; 155 | [statusBar addGestureRecognizer:self.notationsGesture]; 156 | } 157 | } 158 | 159 | %new 160 | - (void)longPressStatusBar:(UILongPressGestureRecognizer *)sender { 161 | if (sender.state == UIGestureRecognizerStateBegan) { 162 | [self toggleNotesShown]; 163 | } 164 | } 165 | 166 | %new 167 | - (void)toggleNotesShown { 168 | CFNotificationCenterPostNotification(CFNotificationCenterGetDistributedCenter(), CFSTR("me.tale.notations-legacy/toggle"), NULL, NULL, true); 169 | } 170 | 171 | %end 172 | 173 | %end 174 | 175 | static void NTSToggleNotes() { 176 | if (![[[NSBundle mainBundle] bundleIdentifier] isEqual:@"com.apple.springboard"]) return; 177 | [[NTSManager sharedInstance] toggleNotesShown]; 178 | } 179 | 180 | static void NTSPreferencesUpdate() { 181 | CFArrayRef preferencesKeyList = CFPreferencesCopyKeyList((CFStringRef)bundleIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); 182 | if (preferencesKeyList) { 183 | preferences = (NSMutableDictionary *)CFBridgingRelease(CFPreferencesCopyMultiple(preferencesKeyList, (CFStringRef)bundleIdentifier, kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); 184 | CFRelease(preferencesKeyList); 185 | } else { 186 | preferences = nil; 187 | } 188 | 189 | if (preferences == nil) { 190 | preferences = [[NSMutableDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"/var/mobile/Library/Preferences/%@.plist", bundleIdentifier]]; 191 | } 192 | 193 | [NTSManager sharedInstance].enabled = [([preferences objectForKey:@"enabled"] ?: @(YES)) boolValue]; 194 | [NTSManager sharedInstance].gesture = [([preferences objectForKey:@"gesture"] ?: @(0)) integerValue]; 195 | [NTSManager sharedInstance].colorStyle = [([preferences objectForKey:@"style"] ?: @(0)) integerValue]; 196 | [NTSManager sharedInstance].textAlignment = [([preferences objectForKey:@"alignment"] ?: @(1)) integerValue]; 197 | [NTSManager sharedInstance].isCustomText = [([preferences objectForKey:@"isCustomText"] ?: @(NO)) boolValue]; 198 | 199 | if ([NTSManager sharedInstance].isCustomText) { 200 | [NTSManager sharedInstance].textSize = [([preferences objectForKey:@"customText"] ?: @([UIFont systemFontSize])) integerValue]; 201 | } else { 202 | [NTSManager sharedInstance].textSize = [UIFont systemFontSize]; 203 | } 204 | 205 | for (SBMainDisplaySceneLayoutStatusBarView *view in viewUpdateQueue) { 206 | if ([view respondsToSelector:@selector(updateNotations)]) [view updateNotations]; 207 | } 208 | } 209 | 210 | %ctor { 211 | NSArray *arguments = [[NSProcessInfo processInfo] arguments]; 212 | if (arguments != nil && arguments.count != 0) { 213 | NSString *executablePath = arguments[0]; 214 | BOOL isSpringBoard = [[executablePath lastPathComponent] isEqualToString:@"SpringBoard"]; 215 | BOOL isApplication = [executablePath rangeOfString:@"/Application"].location != NSNotFound; 216 | 217 | if (isSpringBoard || isApplication) { 218 | if (%c(UIStatusBarManager)) { 219 | %init(iOS13StatusBar) 220 | } 221 | 222 | %init; 223 | viewUpdateQueue = [NSMutableArray new]; 224 | 225 | NTSPreferencesUpdate(); 226 | 227 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback) NTSPreferencesUpdate, CFSTR("me.tale.notations-legacy/reload"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 228 | 229 | CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), NULL, (CFNotificationCallback) NTSToggleNotes, CFSTR("me.tale.notations-legacy/toggle"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 230 | 231 | if (isSpringBoard) { 232 | dlopen("/usr/lib/libactivator.dylib", RTLD_LAZY); 233 | id la = %c(LAActivator); 234 | if (la) { 235 | [[la sharedInstance] registerListener:[NTSListener new] forName:@"me.tale.notations-legacy/toggle"]; 236 | } 237 | } 238 | } 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/Tweak/Objects/NTSNote.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class NTSNoteView; 4 | 5 | @interface NTSNote : NSObject 6 | 7 | @property (nonatomic, retain) NTSNoteView *view; 8 | @property (nonatomic, retain) NSString *text; 9 | @property (nonatomic) CGPoint center; 10 | @property (nonatomic) CGSize size; 11 | @property (nonatomic) BOOL presented; 12 | @property (nonatomic) BOOL interactive; 13 | 14 | - (instancetype)initWithCoder:(NSCoder *)decoder; 15 | - (void)encodeWithCoder:(NSCoder *)encoder; 16 | - (void)loadView; 17 | - (void)willShowView; 18 | - (void)willHideView; 19 | - (void)didShowView; 20 | - (void)keyboardDidShow:(NSNotification *)notification; 21 | - (void)keyboardDidHide:(NSNotification *)notification; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /src/Tweak/Objects/NTSNote.m: -------------------------------------------------------------------------------- 1 | #import "NTSNote.h" 2 | #import "../Manager/NTSManager.h" 3 | #import "../UI/Notes/NTSNoteView.h" 4 | 5 | @implementation NTSNote 6 | 7 | - (instancetype)initWithCoder:(NSCoder *)decoder { 8 | self = [super init]; 9 | 10 | if (self) { 11 | self.text = [decoder decodeObjectForKey:@"text"]; 12 | self.center = CGPointFromString([decoder decodeObjectForKey:@"center"]); 13 | self.size = CGSizeFromString([decoder decodeObjectForKey:@"size"]); 14 | self.presented = [decoder decodeBoolForKey:@"presented"]; 15 | self.interactive = [decoder decodeBoolForKey:@"interactive"]; 16 | } 17 | 18 | return self; 19 | } 20 | 21 | - (void)encodeWithCoder:(NSCoder *)encoder { 22 | [encoder encodeObject:self.text forKey:@"text"]; 23 | [encoder encodeObject:NSStringFromCGPoint(self.view.center) forKey:@"center"]; 24 | [encoder encodeObject:NSStringFromCGSize(self.size) forKey:@"size"]; 25 | [encoder encodeBool:self.presented forKey:@"presented"]; 26 | [encoder encodeBool:self.interactive forKey:@"interactive"]; 27 | } 28 | 29 | - (void)loadView { 30 | if (!self.presented) { 31 | self.view = [[NTSNoteView alloc] initWithFrame:CGRectMake(0, 0, self.size.width, self.size.height)]; 32 | self.view.translatesAutoresizingMaskIntoConstraints = YES; 33 | self.view.center = self.center; 34 | 35 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; 36 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; 37 | 38 | 39 | [self.view.lockButton addTarget:self action:@selector(disableActions) forControlEvents:UIControlEventTouchUpInside]; 40 | [self.view.deleteButton addTarget:self action:@selector(deleteNote) forControlEvents:UIControlEventTouchUpInside]; 41 | 42 | UIPanGestureRecognizer *resize = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(resizeView:)]; 43 | [self.view.resizeGrabber addGestureRecognizer:resize]; 44 | 45 | UIPanGestureRecognizer *drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragView:)]; 46 | [self.view addGestureRecognizer:drag]; 47 | 48 | if (self.interactive) { 49 | [self.view.lockButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/unlocked.png"] forState:UIControlStateNormal]; 50 | } else { 51 | [self.view.lockButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/notations/locked.png"] forState:UIControlStateNormal]; 52 | } 53 | 54 | UIToolbar *keyboardBar = [[UIToolbar alloc] init]; 55 | [keyboardBar sizeToFit]; 56 | 57 | UIBarButtonItem *flexBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; 58 | 59 | UIBarButtonItem *doneBarButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(dismissKeyboard)]; 60 | 61 | keyboardBar.items = @[flexBarButton, doneBarButton]; 62 | self.view.textView.inputAccessoryView = keyboardBar; 63 | 64 | if (self.text != nil) { 65 | self.view.textView.text = self.text; 66 | } 67 | 68 | CGFloat pointX = self.view.center.x; 69 | CGFloat pointY = self.view.center.y; 70 | CGRect screen = [[UIScreen mainScreen] bounds]; 71 | 72 | if (CGRectGetMinX(self.view.frame) < screen.origin.x) { 73 | pointX = self.view.frame.size.width / 2; 74 | } 75 | 76 | if (CGRectGetMaxX(self.view.frame) > screen.size.width) { 77 | pointX = screen.size.width - self.view.frame.size.width / 2; 78 | } 79 | 80 | if (CGRectGetMinY(self.view.frame) < screen.origin.y) { 81 | pointY = self.view.frame.size.height / 2; 82 | } 83 | 84 | if (CGRectGetMaxY(self.view.frame) > screen.size.height) { 85 | pointY = screen.size.height - self.view.frame.size.height / 2; 86 | } 87 | 88 | [self.view setCenter:CGPointMake(pointX, pointY)]; 89 | [self saveNote]; 90 | } 91 | } 92 | 93 | - (void)willShowView { 94 | [self.view updateEffect]; 95 | } 96 | 97 | - (void)willHideView { 98 | self.view.hidden = YES; 99 | } 100 | 101 | - (void)didShowView { 102 | self.view.hidden = NO; 103 | } 104 | 105 | - (void)disableActions { 106 | if (self.interactive) { 107 | self.interactive = NO; 108 | [self.view.lockButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/locked.png"] forState:UIControlStateNormal]; 109 | [self.view lockNote]; 110 | } else { 111 | self.interactive = YES; 112 | [self.view.lockButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/unlocked.png"] forState:UIControlStateNormal]; 113 | [self.view unlockNote]; 114 | } 115 | 116 | [self saveNote]; 117 | } 118 | 119 | - (void)deleteNote { 120 | if (self.interactive) { 121 | [[NTSManager sharedInstance] removeNote:self]; 122 | } 123 | } 124 | 125 | - (void)resizeView:(UIPanGestureRecognizer *)sender { 126 | CGPoint translatedPoint = [sender translationInView:sender.view]; 127 | [sender setTranslation:CGPointZero inView:sender.view]; 128 | [self.view.superview bringSubviewToFront:sender.view]; 129 | 130 | CGFloat x = self.view.frame.origin.x; 131 | CGFloat y = self.view.frame.origin.y; 132 | 133 | CGFloat width = fabs(self.view.frame.size.width + translatedPoint.x); 134 | CGFloat height = fabs(self.view.frame.size.height + translatedPoint.y); 135 | CGRect screen = [[UIScreen mainScreen] bounds]; 136 | 137 | if (self.view.frame.size.width + translatedPoint.x < 200) { 138 | width = 200; 139 | } 140 | 141 | if (CGRectGetMaxX(self.view.frame) > screen.size.width) { 142 | width -= fabs(screen.size.width - CGRectGetMaxX(self.view.frame)); 143 | } 144 | 145 | if (self.view.frame.size.height + translatedPoint.y < 200) { 146 | height = 200; 147 | } 148 | 149 | if (CGRectGetMaxY(self.view.frame) > screen.size.height) { 150 | height -= fabs(screen.size.height - CGRectGetMaxY(self.view.frame)); 151 | } 152 | 153 | self.view.frame = CGRectMake(x, y, width, height); 154 | self.size = CGSizeMake(width, height); 155 | 156 | [self saveNote]; 157 | } 158 | 159 | - (void)dragView:(UIPanGestureRecognizer *)sender { 160 | if (self.interactive) { 161 | CGPoint translatedPoint = CGPointMake(sender.view.center.x + [sender translationInView:sender.view.superview].x, sender.view.center.y + [sender translationInView:sender.view.superview].y); 162 | 163 | [self.view.superview bringSubviewToFront:sender.view]; 164 | [sender.view setCenter:translatedPoint]; 165 | [sender setTranslation:CGPointZero inView:sender.view]; 166 | 167 | if (sender.state == UIGestureRecognizerStateEnded) { 168 | BOOL corrected = NO; 169 | CGFloat pointX = translatedPoint.x; 170 | CGFloat pointY = translatedPoint.y; 171 | CGRect screen = [[UIScreen mainScreen] bounds]; 172 | 173 | if (CGRectGetMinX(self.view.frame) < screen.origin.x) { 174 | pointX = self.view.frame.size.width / 2; 175 | corrected = YES; 176 | } 177 | 178 | if (CGRectGetMaxX(self.view.frame) > screen.size.width) { 179 | pointX = screen.size.width - self.view.frame.size.width / 2; 180 | corrected = YES; 181 | } 182 | 183 | if (CGRectGetMinY(self.view.frame) < screen.origin.y) { 184 | pointY = self.view.frame.size.height / 2; 185 | corrected = YES; 186 | } 187 | 188 | if (CGRectGetMaxY(self.view.frame) > screen.size.height) { 189 | pointY = screen.size.height - self.view.frame.size.height / 2; 190 | corrected = YES; 191 | } 192 | 193 | if (corrected) { 194 | [UIView animateWithDuration:0.25 animations:^{ 195 | [[sender view] setCenter:CGPointMake(pointX, pointY)]; 196 | }]; 197 | } else { 198 | [[sender view] setCenter:CGPointMake(pointX, pointY)]; 199 | } 200 | } 201 | } 202 | 203 | [self saveNote]; 204 | } 205 | 206 | - (void)dismissKeyboard { 207 | [self.view.textView resignFirstResponder]; 208 | self.text = self.view.textView.text; 209 | 210 | [self saveNote]; 211 | } 212 | 213 | - (void)saveNote { 214 | NSError *error; 215 | NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[NTSManager sharedInstance].notes requiringSecureCoding:NO error:&error]; 216 | 217 | [data writeToFile:@"/var/mobile/Documents/NotationsData.plist" atomically:NO]; 218 | } 219 | 220 | - (void)keyboardDidShow:(NSNotification *)notification { 221 | CGRect screen = [[UIScreen mainScreen] bounds]; 222 | CGFloat boardHeight = fabs(screen.size.height - [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height); 223 | 224 | if ([self.view.textView isFirstResponder] && CGRectGetMaxY(self.view.frame) > boardHeight) { 225 | if (self.view.frame.size.height - 30 > boardHeight) { 226 | [UIView animateWithDuration:0.25 animations:^{ 227 | [self.view.superview bringSubviewToFront:self.view]; 228 | self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.view.frame.size.width, boardHeight - 30); 229 | }]; 230 | } 231 | 232 | CGFloat translationX; 233 | if (self.view.center.x < screen.size.width / 2) { 234 | translationX = fabs(self.view.center.x - screen.size.width / 2); 235 | } else if (self.view.center.x > screen.size.width / 2) { 236 | translationX = -fabs(self.view.center.x - screen.size.width / 2); 237 | } else { 238 | translationX = self.view.center.x; 239 | } 240 | 241 | CGFloat translationY = -fabs(self.view.center.y - (boardHeight - self.view.frame.size.height / 2 - 30)); 242 | 243 | // [self saveNote]; 244 | [UIView animateWithDuration:0.25 animations:^{ 245 | self.view.transform = CGAffineTransformMakeTranslation(translationX, translationY); 246 | }]; 247 | } 248 | } 249 | 250 | - (void)keyboardDidHide:(NSNotification *)notification { 251 | [UIView animateWithDuration:0.25 animations:^{ 252 | self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y, self.size.width, self.size.height); 253 | self.view.transform = CGAffineTransformIdentity; 254 | }]; 255 | 256 | [self saveNote]; 257 | } 258 | 259 | @end 260 | -------------------------------------------------------------------------------- /src/Tweak/UI/Notes/NTSNoteView.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NTSNoteView : UIView 4 | 5 | @property (nonatomic, retain) UIVisualEffectView *blurEffectView; 6 | @property (nonatomic, retain) UIView *resizeGrabber; 7 | @property (nonatomic, retain) UITextView *textView; 8 | @property (nonatomic, retain) UIButton *lockButton; 9 | @property (nonatomic, retain) UIButton *deleteButton; 10 | 11 | - (void)updateEffect; 12 | - (void)lockNote; 13 | - (void)unlockNote; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /src/Tweak/UI/Notes/NTSNoteView.m: -------------------------------------------------------------------------------- 1 | #import "NTSNoteView.h" 2 | #import "../../Manager/NTSManager.h" 3 | // #import "../../../Tweak.h" 4 | 5 | @implementation NTSNoteView 6 | 7 | - (instancetype)initWithFrame:(CGRect)frame { 8 | self = [super initWithFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height)]; 9 | 10 | if (self) { 11 | self.backgroundColor = [UIColor clearColor]; 12 | self.userInteractionEnabled = YES; 13 | self.layer.cornerRadius = 20; 14 | 15 | // Background blur 16 | UIBlurEffect *blurEffect; 17 | 18 | if ([NTSManager sharedInstance].colorStyle == 0) { 19 | if (@available(iOS 13, *)) { 20 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]; 21 | } else { 22 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; 23 | } 24 | } else if ([NTSManager sharedInstance].colorStyle == 2) { 25 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 26 | } else { 27 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; 28 | } 29 | 30 | self.blurEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; 31 | self.blurEffectView.layer.cornerRadius = 20; 32 | self.blurEffectView.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); 33 | self.blurEffectView.layer.masksToBounds = YES; 34 | self.blurEffectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 35 | [self addSubview:self.blurEffectView]; 36 | 37 | // Buttons 38 | UIColor *buttonColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.5]; 39 | 40 | self.lockButton = [UIButton buttonWithType:UIButtonTypeCustom]; 41 | self.lockButton.backgroundColor = buttonColor; 42 | self.lockButton.layer.cornerRadius = 15.0; 43 | self.lockButton.translatesAutoresizingMaskIntoConstraints = NO; 44 | [self.lockButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/unlocked.png"] forState:UIControlStateNormal]; 45 | [self addSubview:self.lockButton]; 46 | 47 | [self.lockButton.widthAnchor constraintEqualToConstant:30].active = YES; 48 | [self.lockButton.heightAnchor constraintEqualToConstant:30].active = YES; 49 | [self.lockButton.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; 50 | [self.lockButton.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:5].active = YES; 51 | 52 | self.deleteButton = [UIButton buttonWithType:UIButtonTypeCustom]; 53 | self.deleteButton.backgroundColor = buttonColor; 54 | self.deleteButton.layer.cornerRadius = 15.0; 55 | self.deleteButton.translatesAutoresizingMaskIntoConstraints = NO; 56 | [self.deleteButton setImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/delete.png"] forState:UIControlStateNormal]; 57 | [self addSubview:self.deleteButton]; 58 | 59 | [self.deleteButton.widthAnchor constraintEqualToConstant:30].active = YES; 60 | [self.deleteButton.heightAnchor constraintEqualToConstant:30].active = YES; 61 | [self.deleteButton.topAnchor constraintEqualToAnchor:self.topAnchor constant:5].active = YES; 62 | [self.deleteButton.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5].active = YES; 63 | 64 | self.resizeGrabber = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 15, 15)]; 65 | UIImageView *resizeImage = [[UIImageView alloc] initWithImage:[[UIImage alloc] initWithContentsOfFile:@"/Library/Application Support/Notations/resize.png"]]; 66 | resizeImage.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin); 67 | 68 | self.resizeGrabber.backgroundColor = buttonColor; 69 | self.resizeGrabber.layer.cornerRadius = 15.0; 70 | self.resizeGrabber.translatesAutoresizingMaskIntoConstraints = NO; 71 | [self.resizeGrabber addSubview:resizeImage]; 72 | [self addSubview:self.resizeGrabber]; 73 | 74 | [self.resizeGrabber.widthAnchor constraintEqualToConstant:30].active = YES; 75 | [self.resizeGrabber.heightAnchor constraintEqualToConstant:30].active = YES; 76 | [self.resizeGrabber.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-5].active = YES; 77 | [self.resizeGrabber.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-5].active = YES; 78 | 79 | UIPanGestureRecognizer *dragResize = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(resizeView:)]; 80 | [self.resizeGrabber addGestureRecognizer:dragResize]; 81 | 82 | // Text view 83 | self.textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 50, self.frame.size.width - 20, self.frame.size.height - 80)]; 84 | self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 85 | self.textView.backgroundColor = [UIColor clearColor]; 86 | self.textView.font = [UIFont systemFontOfSize:[NTSManager sharedInstance].textSize]; 87 | 88 | if ([NTSManager sharedInstance].textAlignment == 1) { 89 | self.textView.textAlignment = NSTextAlignmentLeft; 90 | } else if ([NTSManager sharedInstance].textAlignment == 2) { 91 | self.textView.textAlignment = NSTextAlignmentCenter; 92 | } else if ([NTSManager sharedInstance].textAlignment == 3) { 93 | self.textView.textAlignment = NSTextAlignmentRight; 94 | } else { 95 | self.textView.textAlignment = NSTextAlignmentNatural; 96 | } 97 | 98 | [self addSubview:self.textView]; 99 | } 100 | 101 | return self; 102 | } 103 | 104 | - (void)updateEffect { 105 | UIBlurEffect *blurEffect; 106 | 107 | if ([NTSManager sharedInstance].colorStyle == 0) { 108 | if (@available(iOS 13, *)) { 109 | self.textView.textColor = [UIColor labelColor]; 110 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]; 111 | } else { 112 | self.textView.textColor = [UIColor blackColor]; 113 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; 114 | } 115 | } else if ([NTSManager sharedInstance].colorStyle == 2) { 116 | self.textView.textColor = [UIColor whiteColor]; 117 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark]; 118 | } else { 119 | self.textView.textColor = [UIColor blackColor]; 120 | blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; 121 | } 122 | 123 | self.blurEffectView.effect = blurEffect; 124 | 125 | self.textView.font = [UIFont systemFontOfSize:[NTSManager sharedInstance].textSize]; 126 | if ([NTSManager sharedInstance].textAlignment == 1) { 127 | self.textView.textAlignment = NSTextAlignmentLeft; 128 | } else if ([NTSManager sharedInstance].textAlignment == 2) { 129 | self.textView.textAlignment = NSTextAlignmentCenter; 130 | } else if ([NTSManager sharedInstance].textAlignment == 3) { 131 | self.textView.textAlignment = NSTextAlignmentRight; 132 | } else { 133 | self.textView.textAlignment = NSTextAlignmentNatural; 134 | } 135 | } 136 | 137 | - (void)setHidden:(BOOL)hidden { 138 | if (!hidden) { 139 | self.transform = CGAffineTransformMakeScale(0, 0); 140 | [super setHidden:hidden]; 141 | [UIView animateWithDuration:0.2 animations:^{ 142 | self.transform = CGAffineTransformMakeScale(1, 1); 143 | } completion:nil]; 144 | } else { 145 | self.transform = CGAffineTransformMakeScale(1, 1); 146 | [UIView animateWithDuration:0.2 animations:^{ 147 | self.transform = CGAffineTransformMakeScale(0.01, 0.01); // Not possible to animate scale to 0 148 | } completion:^(BOOL finished) { 149 | [super setHidden:hidden]; 150 | [self removeFromSuperview]; 151 | }]; 152 | } 153 | } 154 | 155 | - (void)lockNote { 156 | [UIView animateWithDuration:0.2 animations:^{ 157 | self.resizeGrabber.alpha = 0; 158 | self.deleteButton.alpha = 0; 159 | self.textView.frame = CGRectMake(20, 50, self.frame.size.width - 20, self.frame.size.height - 50); 160 | } completion:nil]; 161 | } 162 | 163 | - (void)unlockNote { 164 | [UIView animateWithDuration:0.2 animations:^{ 165 | self.resizeGrabber.alpha = 1; 166 | self.deleteButton.alpha = 1; 167 | self.textView.frame = CGRectMake(20, 50, self.frame.size.width - 20, self.frame.size.height - 80); 168 | } completion:nil]; 169 | } 170 | 171 | - (void)resizeView:(UIPanGestureRecognizer *)gesture { 172 | CGPoint translatedPoint = [gesture translationInView:gesture.view]; 173 | [gesture setTranslation:CGPointZero inView:gesture.view]; 174 | 175 | CGFloat x = self.frame.origin.x; 176 | CGFloat y = self.frame.origin.y; 177 | CGFloat width = self.frame.size.width; 178 | CGFloat height = self.frame.size.height; 179 | 180 | CGFloat minHeight = 200; 181 | CGFloat minWidth = 200; 182 | 183 | if (height + translatedPoint.y <= minHeight) height = minHeight - translatedPoint.y; 184 | if (width+translatedPoint.x <= minWidth) width = minWidth - translatedPoint.x; 185 | self.frame = CGRectMake(x, y, width + translatedPoint.x, height + translatedPoint.y); 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /src/Tweak/UI/Notes/NTSNotesViewController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NTSNotesViewController : UIViewController 4 | 5 | @property (nonatomic, retain) UIVisualEffectView *effectView; 6 | @property (nonatomic, retain) UILabel *titleLabel; 7 | @property (nonatomic, retain) UIButton *addButton; 8 | @property (nonatomic, retain) UILabel *addLabel; 9 | 10 | - (void)present; 11 | - (void)dismiss; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /src/Tweak/UI/Notes/NTSNotesViewController.m: -------------------------------------------------------------------------------- 1 | #import "NTSNotesViewController.h" 2 | #import "../../Manager/NTSManager.h" 3 | #import "../Window/NTSWindow.h" 4 | #import 5 | 6 | @implementation NTSNotesViewController 7 | 8 | - (void)viewDidLoad { 9 | [super viewDidLoad]; 10 | self.view.userInteractionEnabled = YES; 11 | 12 | // Blurry background view 13 | self.effectView = [[UIVisualEffectView alloc] init]; 14 | self.effectView.frame = self.view.bounds; 15 | self.effectView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 16 | [self.view addSubview:self.effectView]; 17 | 18 | // Gestures 19 | UILongPressGestureRecognizer *pressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:[NTSManager sharedInstance] action:@selector(createNote:)]; 20 | [self.view addGestureRecognizer:pressRecognizer]; 21 | 22 | UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:[NTSManager sharedInstance] action:@selector(hideNotes)]; 23 | [self.view addGestureRecognizer:tapRecognizer]; 24 | } 25 | 26 | - (void)viewWillAppear:(BOOL)animated { 27 | [super viewWillAppear:animated]; 28 | [self present]; 29 | } 30 | 31 | - (void)present { 32 | // Background effects 33 | UIBlurEffect *blurEffect = [UIBlurEffect effectWithBlurRadius:10]; 34 | _UIZoomEffect *zoomEffect = [NSClassFromString(@"_UIZoomEffect") _underlayZoomEffectWithMagnitude:0.024]; 35 | _UIOverlayEffect *overlayEffect = [[NSClassFromString(@"_UIOverlayEffect") alloc] init]; 36 | overlayEffect.filterType = @"multiplyBlendMode"; 37 | overlayEffect.color = [UIColor blackColor]; 38 | overlayEffect.alpha = 0.088; 39 | 40 | [UIView animateWithDuration:0.2 animations:^{ 41 | self.effectView.backgroundEffects = @[zoomEffect, overlayEffect, blurEffect]; 42 | self.effectView.backgroundColor = [UIColor colorWithRed:0.086 green:0.082 blue:0.1647 alpha:0.21]; 43 | } completion:nil]; 44 | } 45 | 46 | - (void)dismiss { 47 | CABasicAnimation *colorAnimation = [CABasicAnimation animation]; 48 | colorAnimation.keyPath = @"backgroundColor"; 49 | colorAnimation.fromValue = (id)[UIColor colorWithRed:0.086 green:0.082 blue:0.1647 alpha:0.21].CGColor; 50 | colorAnimation.toValue = (id)[UIColor clearColor].CGColor; 51 | colorAnimation.duration = 0.3; 52 | 53 | [self.effectView.layer addAnimation:colorAnimation forKey:@"backgroundColor"]; 54 | 55 | [UIView animateWithDuration:0.2 animations:^{ 56 | self.effectView.backgroundEffects = nil; 57 | } completion:nil]; 58 | } 59 | 60 | - (BOOL)_canShowWhileLocked { 61 | return YES; 62 | } 63 | 64 | -(BOOL)shouldAutorotate { 65 | return NO; 66 | } 67 | 68 | - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { 69 | return NO; 70 | } 71 | 72 | - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { 73 | return UIInterfaceOrientationPortrait; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /src/Tweak/UI/Window/NTSWindow.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NTSWindow : UIWindow 4 | @end 5 | -------------------------------------------------------------------------------- /src/Tweak/UI/Window/NTSWindow.m: -------------------------------------------------------------------------------- 1 | #import "NTSWindow.h" 2 | #import "../../Manager/NTSManager.h" 3 | #import "../Notes/NTSNotesViewController.h" 4 | 5 | @implementation NTSWindow : UIWindow 6 | 7 | - (id)initWithFrame:(CGRect)frame { 8 | self = [super initWithFrame:frame]; 9 | 10 | if (self) { 11 | self.rootViewController = [[NTSNotesViewController alloc] init]; 12 | } 13 | 14 | return self; 15 | } 16 | 17 | - (void)setHidden:(BOOL)hidden { 18 | if (![self.rootViewController isKindOfClass:[NTSNotesViewController class]]) { 19 | self.rootViewController = [[NTSNotesViewController alloc] init]; 20 | } 21 | 22 | if (!hidden) { 23 | [super setHidden:hidden]; 24 | [(NTSNotesViewController *)self.rootViewController present]; 25 | } else { 26 | [(NTSNotesViewController *)self.rootViewController dismiss]; 27 | self.backgroundColor = nil; 28 | [UIView animateWithDuration:0.2 animations:^{ 29 | self.backgroundColor = [UIColor clearColor]; 30 | } completion:^(BOOL finished) { 31 | [super setHidden:hidden]; 32 | }]; 33 | } 34 | } 35 | 36 | - (BOOL)_canShowWhileLocked { 37 | return YES; 38 | } 39 | 40 | - (BOOL)_shouldCreateContextAsSecure { 41 | return YES; 42 | } 43 | 44 | @end 45 | --------------------------------------------------------------------------------