├── Releases ├── 1.0 │ ├── Remindly.app │ │ ├── PkgInfo │ │ ├── CodeResources │ │ ├── Icon.png │ │ ├── Info.plist │ │ ├── Remindly │ │ ├── alarm.png │ │ ├── blank.png │ │ ├── Default.png │ │ ├── Icon@2x.png │ │ ├── alarm@2X.png │ │ ├── empty.plist │ │ ├── draw-icon.png │ │ ├── erase-icon.png │ │ ├── photos_icon.png │ │ ├── alarm_times.plist │ │ ├── erase-icon@2x.png │ │ ├── alarm-clock-icon.png │ │ ├── embedded.mobileprovision │ │ ├── ResourceRules.plist │ │ └── _CodeSignature │ │ │ └── CodeResources │ ├── Remindly.zip │ └── Remindly.app.dSYM │ │ └── Contents │ │ ├── Resources │ │ └── DWARF │ │ │ └── Remindly │ │ └── Info.plist └── 2.0 │ └── app.ipa ├── blank.png ├── Sounds ├── 0.caf ├── 1.caf ├── 2.caf ├── 3.caf ├── 4.caf ├── 5.caf ├── 6.caf ├── 7.caf ├── v3.caf ├── v5.caf ├── v10.caf ├── v120.caf ├── v1440.caf ├── v15.caf ├── v180.caf ├── v240.caf ├── v2880.caf ├── v30.caf ├── v360.caf ├── v420.caf ├── v4320.caf ├── v45.caf ├── v51.caf ├── v60.caf ├── v720.caf ├── v90.caf ├── v10080.caf ├── its-time.caf ├── alarm-area-departed.caf └── alarm-area-entered.caf ├── Images ├── Icon.png ├── play.png ├── stop.png ├── Default.png ├── Icon@2x.png ├── play@2x.png ├── stop@2x.png ├── Default@2x.png ├── alarm_icon.png ├── departing2.png ├── draw_icon.png ├── erase_icon.png ├── text_icon.png ├── delete_icon.png ├── draw_icon@2x.png ├── photos_icon.png ├── text_icon@2x.png ├── alarm_icon@2x.png ├── arriving_icon.png ├── delete_icon@2x.png ├── departing2@2x.png ├── departing_icon.png ├── erase_icon@2x.png ├── arriving_icon@2x.png ├── departing_icon@2x.png ├── text_icon@2x copy.png ├── brush_large_picker.png ├── brush_medium_picker.png ├── brush_small_picker.png ├── brush_xlarge_picker.png ├── brush_large_picker@2x.png ├── brush_medium_picker@2x.png ├── brush_small_picker@2x.png └── brush_xlarge_picker@2x.png ├── Assets ├── InApp_7.png ├── InApp_8.png ├── InApp_9.png ├── InApp_10.png ├── Screenshot_1.png ├── Screenshot_2.png ├── Screenshot_3.png ├── Screenshot_4.png ├── Screenshot_5.png ├── Screenshot_6.png ├── Screenshot_7.png ├── delete-icon.psd ├── notepad-512.png ├── notepad-512-2.png ├── notepad-512-3.png ├── notepad-512-4.png ├── notepad-512bk.png ├── alarm-clock-icon.psd ├── alarm-clock-icon2.psd ├── notepad-512-final.png └── play.svg ├── Remindly_Prefix.pch ├── Remindly.xcodeproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── nas.xcuserdatad │ └── xcschemes │ ├── xcschememanagement.plist │ └── Remindly.xcscheme ├── .gitignore ├── empty.plist ├── Classes ├── HPTextViewInternal.h ├── PickerSelectionIndicator.h ├── DrawingPaletteView.h ├── NSDate+HumanInterval.h ├── DrawingPaletteTool.h ├── AlarmAnnotationLabel.h ├── ColorButton.h ├── DrawingPaletteController.h ├── AlarmSounds.h ├── CountingButton.h ├── MainToolBar.h ├── LocationAlarmManager.h ├── NoteThumbnailView.h ├── AlarmAbsoluteTimes.h ├── DrawingTextBox.h ├── AlarmAnnotationLabel.m ├── ToggleButton.h ├── StoreView.h ├── AppDelegate.h ├── AlarmAnnotationPin.h ├── AlarmMapView.h ├── AlarmQuickTimes.h ├── HPTextViewInternal.m ├── PurchaseManager.h ├── AlarmPopUpController.h ├── AlarmTitleButton.h ├── NotesManager.h ├── NotesScrollView.h ├── MainViewController.h ├── DrawingViewController.h ├── GradientButton.h ├── PickerSelectionIndicator.m ├── AlarmAnnotationPin.m ├── NoteSelectorController.h ├── AlarmAbsoluteTimes.m ├── CountingButton.m ├── ToggleButton.m ├── DrawingPaletteTool.m ├── DrawingPaletteView.m ├── UIColor+Expanded.h ├── HPGrowingTextView.h ├── AlarmTitleButton.m ├── NoteThumbnailView.m ├── Note.h ├── ColorButton.m ├── NSDate+HumanInterval.m ├── NoteSelectorController.m ├── PurchaseManager.m ├── DrawingTextBox.m ├── AlarmMapView.m ├── AlarmSounds.m ├── MainViewController.m ├── DrawingPaletteController.m ├── AlarmQuickTimes.m ├── AppDelegate.m ├── NotesScrollView.m ├── Appirater.h ├── AlarmPopUpController.m ├── LocationAlarmManager.m ├── MainToolBar.m ├── NotesManager.m └── DrawingViewController.m ├── main.m ├── Remindly-Info.plist ├── alarm_times.plist └── README.markdown /Releases/1.0/Remindly.app/PkgInfo: -------------------------------------------------------------------------------- 1 | APPL???? -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/CodeResources: -------------------------------------------------------------------------------- 1 | _CodeSignature/CodeResources -------------------------------------------------------------------------------- /blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/blank.png -------------------------------------------------------------------------------- /Sounds/0.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/0.caf -------------------------------------------------------------------------------- /Sounds/1.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/1.caf -------------------------------------------------------------------------------- /Sounds/2.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/2.caf -------------------------------------------------------------------------------- /Sounds/3.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/3.caf -------------------------------------------------------------------------------- /Sounds/4.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/4.caf -------------------------------------------------------------------------------- /Sounds/5.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/5.caf -------------------------------------------------------------------------------- /Sounds/6.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/6.caf -------------------------------------------------------------------------------- /Sounds/7.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/7.caf -------------------------------------------------------------------------------- /Sounds/v3.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v3.caf -------------------------------------------------------------------------------- /Sounds/v5.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v5.caf -------------------------------------------------------------------------------- /Images/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/Icon.png -------------------------------------------------------------------------------- /Images/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/play.png -------------------------------------------------------------------------------- /Images/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/stop.png -------------------------------------------------------------------------------- /Sounds/v10.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v10.caf -------------------------------------------------------------------------------- /Sounds/v120.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v120.caf -------------------------------------------------------------------------------- /Sounds/v1440.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v1440.caf -------------------------------------------------------------------------------- /Sounds/v15.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v15.caf -------------------------------------------------------------------------------- /Sounds/v180.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v180.caf -------------------------------------------------------------------------------- /Sounds/v240.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v240.caf -------------------------------------------------------------------------------- /Sounds/v2880.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v2880.caf -------------------------------------------------------------------------------- /Sounds/v30.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v30.caf -------------------------------------------------------------------------------- /Sounds/v360.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v360.caf -------------------------------------------------------------------------------- /Sounds/v420.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v420.caf -------------------------------------------------------------------------------- /Sounds/v4320.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v4320.caf -------------------------------------------------------------------------------- /Sounds/v45.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v45.caf -------------------------------------------------------------------------------- /Sounds/v51.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v51.caf -------------------------------------------------------------------------------- /Sounds/v60.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v60.caf -------------------------------------------------------------------------------- /Sounds/v720.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v720.caf -------------------------------------------------------------------------------- /Sounds/v90.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v90.caf -------------------------------------------------------------------------------- /Assets/InApp_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/InApp_7.png -------------------------------------------------------------------------------- /Assets/InApp_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/InApp_8.png -------------------------------------------------------------------------------- /Assets/InApp_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/InApp_9.png -------------------------------------------------------------------------------- /Images/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/Default.png -------------------------------------------------------------------------------- /Images/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/Icon@2x.png -------------------------------------------------------------------------------- /Images/play@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/play@2x.png -------------------------------------------------------------------------------- /Images/stop@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/stop@2x.png -------------------------------------------------------------------------------- /Sounds/v10080.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/v10080.caf -------------------------------------------------------------------------------- /Assets/InApp_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/InApp_10.png -------------------------------------------------------------------------------- /Images/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/Default@2x.png -------------------------------------------------------------------------------- /Images/alarm_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/alarm_icon.png -------------------------------------------------------------------------------- /Images/departing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/departing2.png -------------------------------------------------------------------------------- /Images/draw_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/draw_icon.png -------------------------------------------------------------------------------- /Images/erase_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/erase_icon.png -------------------------------------------------------------------------------- /Images/text_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/text_icon.png -------------------------------------------------------------------------------- /Releases/2.0/app.ipa: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/2.0/app.ipa -------------------------------------------------------------------------------- /Sounds/its-time.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/its-time.caf -------------------------------------------------------------------------------- /Assets/Screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_1.png -------------------------------------------------------------------------------- /Assets/Screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_2.png -------------------------------------------------------------------------------- /Assets/Screenshot_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_3.png -------------------------------------------------------------------------------- /Assets/Screenshot_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_4.png -------------------------------------------------------------------------------- /Assets/Screenshot_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_5.png -------------------------------------------------------------------------------- /Assets/Screenshot_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_6.png -------------------------------------------------------------------------------- /Assets/Screenshot_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/Screenshot_7.png -------------------------------------------------------------------------------- /Assets/delete-icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/delete-icon.psd -------------------------------------------------------------------------------- /Assets/notepad-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512.png -------------------------------------------------------------------------------- /Images/delete_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/delete_icon.png -------------------------------------------------------------------------------- /Images/draw_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/draw_icon@2x.png -------------------------------------------------------------------------------- /Images/photos_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/photos_icon.png -------------------------------------------------------------------------------- /Images/text_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/text_icon@2x.png -------------------------------------------------------------------------------- /Assets/notepad-512-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512-2.png -------------------------------------------------------------------------------- /Assets/notepad-512-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512-3.png -------------------------------------------------------------------------------- /Assets/notepad-512-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512-4.png -------------------------------------------------------------------------------- /Assets/notepad-512bk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512bk.png -------------------------------------------------------------------------------- /Images/alarm_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/alarm_icon@2x.png -------------------------------------------------------------------------------- /Images/arriving_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/arriving_icon.png -------------------------------------------------------------------------------- /Images/delete_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/delete_icon@2x.png -------------------------------------------------------------------------------- /Images/departing2@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/departing2@2x.png -------------------------------------------------------------------------------- /Images/departing_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/departing_icon.png -------------------------------------------------------------------------------- /Images/erase_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/erase_icon@2x.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.zip -------------------------------------------------------------------------------- /Assets/alarm-clock-icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/alarm-clock-icon.psd -------------------------------------------------------------------------------- /Assets/alarm-clock-icon2.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/alarm-clock-icon2.psd -------------------------------------------------------------------------------- /Assets/notepad-512-final.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Assets/notepad-512-final.png -------------------------------------------------------------------------------- /Images/arriving_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/arriving_icon@2x.png -------------------------------------------------------------------------------- /Images/departing_icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/departing_icon@2x.png -------------------------------------------------------------------------------- /Images/text_icon@2x copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/text_icon@2x copy.png -------------------------------------------------------------------------------- /Images/brush_large_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_large_picker.png -------------------------------------------------------------------------------- /Images/brush_medium_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_medium_picker.png -------------------------------------------------------------------------------- /Images/brush_small_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_small_picker.png -------------------------------------------------------------------------------- /Images/brush_xlarge_picker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_xlarge_picker.png -------------------------------------------------------------------------------- /Sounds/alarm-area-departed.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/alarm-area-departed.caf -------------------------------------------------------------------------------- /Sounds/alarm-area-entered.caf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Sounds/alarm-area-entered.caf -------------------------------------------------------------------------------- /Images/brush_large_picker@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_large_picker@2x.png -------------------------------------------------------------------------------- /Images/brush_medium_picker@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_medium_picker@2x.png -------------------------------------------------------------------------------- /Images/brush_small_picker@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_small_picker@2x.png -------------------------------------------------------------------------------- /Images/brush_xlarge_picker@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Images/brush_xlarge_picker@2x.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/Icon.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/Info.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/Info.plist -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/Remindly: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/Remindly -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/alarm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/alarm.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/blank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/blank.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/Default.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/Icon@2x.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/alarm@2X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/alarm@2X.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/empty.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/empty.plist -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/draw-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/draw-icon.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/erase-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/erase-icon.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/photos_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/photos_icon.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/alarm_times.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/alarm_times.plist -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/erase-icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/erase-icon@2x.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/alarm-clock-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/alarm-clock-icon.png -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/embedded.mobileprovision: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app/embedded.mobileprovision -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app.dSYM/Contents/Resources/DWARF/Remindly: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nathanstitt/Remindly/HEAD/Releases/1.0/Remindly.app.dSYM/Contents/Resources/DWARF/Remindly -------------------------------------------------------------------------------- /Remindly_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'IoGee' target in the 'IoGee' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import 8 | #endif 9 | -------------------------------------------------------------------------------- /Remindly.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Remindly.xcodeproj/xcuserdata/*.xcuserdatad 2 | Remindly.xcodeproj/xcuserdata/* 3 | Remindly.xcodeproj/project.xcworkspace/xcuserdata/* 4 | *~ 5 | .#* 6 | build/ 7 | .DS_Store 8 | **/*.pbxuser 9 | *.mode2v3 10 | *.mode1v3 11 | **/*.perspectivev* 12 | 13 | -------------------------------------------------------------------------------- /empty.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Classes/HPTextViewInternal.h: -------------------------------------------------------------------------------- 1 | // 2 | // HPTextViewInternal.h 3 | // Cupido 4 | // 5 | // Created by Hans Pinckaers on 30-06-10. 6 | // Copyright 2010 Hans Pinckaers. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface HPTextViewInternal : UITextView { 13 | } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Classes/PickerSelectionIndicator.h: -------------------------------------------------------------------------------- 1 | // 2 | // PickerSelectionIndicator.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/11/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface PickerSelectionIndicator : UIView { 13 | 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingPalletteView.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/14/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface DrawingPaletteView : UIView { 13 | 14 | } 15 | 16 | - (id)initWithFrame:(CGRect)frame; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Classes/NSDate+HumanInterval.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+HumanInterval.h 3 | // Copyright 2011 Nathan Stitt, 4 | // Distributed under the terms of the GNU General Public License version 3. 5 | // 6 | // A category adding a humanIntervalFromNow method to NSDate 7 | 8 | #import 9 | 10 | @interface NSDate (HumanInterval) 11 | - (NSString *) humanIntervalFromNow; 12 | @end 13 | -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // IoGee 4 | // 5 | // Created by Nathan Stitt on 11/6/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) { 12 | NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 13 | int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate"); 14 | [pool release]; 15 | return retVal; 16 | } 17 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteTool.h: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingPaletteTool.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/3/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface DrawingPaletteTool : UIButton { 13 | NSInteger drawingWidth; 14 | } 15 | 16 | +(id)withImage:(UIImage*)image frame:(CGRect)frame; 17 | 18 | @property (nonatomic) NSInteger drawingWidth; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Classes/AlarmAnnotationLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAnnotation.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "AlarmAnnotationPin.h" 12 | 13 | @class AlarmAnnotationPin; 14 | 15 | @interface AlarmAnnotationLabel : NSObject { 16 | CLLocationCoordinate2D coordinate; 17 | BOOL entering; 18 | } 19 | 20 | @property (nonatomic) CLLocationCoordinate2D coordinate; 21 | @property (nonatomic) BOOL entering; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Classes/ColorButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // ColorButton.h 3 | // Created by Nathan Stitt on 11/30/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | // 7 | // A UIButton with a rounded center set to a given color 8 | 9 | #import 10 | 11 | 12 | @interface ColorButton : UIButton { 13 | UIColor *color; 14 | BOOL marked; 15 | UIImage *image; 16 | } 17 | 18 | - (id)initWithButtonColor:(UIColor*)c; 19 | - (void)setBrushImage:(UIImage*)image; 20 | 21 | @property (retain,nonatomic) UIColor *color; 22 | @property (nonatomic) BOOL marked; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/ResourceRules.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | rules 6 | 7 | .* 8 | 9 | Info.plist 10 | 11 | omit 12 | 13 | weight 14 | 10 15 | 16 | ResourceRules.plist 17 | 18 | omit 19 | 20 | weight 21 | 100 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Remindly.xcodeproj/xcuserdata/nas.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Remindly.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 1D6058900D05DD3D006BFB54 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingToolsPanel.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/1/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @class DrawingPaletteTool; 13 | 14 | @interface DrawingPaletteController : UIViewController { 15 | CGRect buttonFrame; 16 | NSMutableArray *colorButtons; 17 | UIColor *color; 18 | NSArray *tools; 19 | DrawingPaletteTool *tool; 20 | } 21 | 22 | 23 | @property (nonatomic) BOOL isShowing; 24 | @property (nonatomic, assign ) DrawingPaletteTool *tool; 25 | @property (nonatomic, retain ) UIColor *color; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Classes/AlarmSounds.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmSoundsView.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/20/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "Note.h" 11 | #import 12 | 13 | @class AlarmPopUpController,ToggleButton; 14 | 15 | 16 | @interface AlarmSounds : UITableViewController < AVAudioPlayerDelegate > { 17 | NoteSoundType snd; 18 | ToggleButton *playingBtn; 19 | AVAudioPlayer *player; 20 | } 21 | 22 | -(id)initWithAlarmView:(AlarmPopUpController*)view; 23 | 24 | -(void) setFromNote:(Note*)note; 25 | -(void) saveToNote: (Note*)note; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app.dSYM/Contents/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleIdentifier 8 | com.apple.xcode.dsym.com.iogee.remindly 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundlePackageType 12 | dSYM 13 | CFBundleSignature 14 | ???? 15 | CFBundleVersion 16 | 1.0 17 | 18 | 19 | -------------------------------------------------------------------------------- /Classes/CountingButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // CountingButton.h 3 | // Created by Nathan Stitt on 12/3/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // The CountingButton emulates the Button in safari which 8 | // shows the number of webviews open 9 | 10 | #import 11 | 12 | 13 | @interface CountingButton : UIBarButtonItem { 14 | UIButton *button; 15 | UIImage *icon; 16 | UIFont *font; 17 | NSInteger count; 18 | } 19 | 20 | // the count to start with 21 | -(id)initWithCount:(NSInteger)count; 22 | 23 | @property (nonatomic) NSInteger count; 24 | 25 | @property (nonatomic,readonly) UIButton *button; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Classes/MainToolBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainToolBar.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ColorButton.h" 11 | #import "CountingButton.h" 12 | #import "ToggleButton.h" 13 | 14 | @class MainViewController,DrawingPaletteController; 15 | 16 | @interface MainToolBar : UIToolbar { 17 | 18 | MainViewController *mvc; 19 | 20 | NSArray *drawButtons; 21 | NSArray *selButtons; 22 | ToggleButton *eraseBtn; 23 | UIBarButtonItem *pickerBtn; 24 | CountingButton *countBtn; 25 | 26 | } 27 | 28 | 29 | -(void) setDrawingMode:(BOOL)draw; 30 | 31 | -(id)initWithController:(MainViewController*)m; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Classes/LocationAlarmManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // LocationManager.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/25/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "Note.h" 12 | 13 | #define ALARM_METER_RADIUS 750.0f 14 | 15 | @interface LocationAlarmManager : NSObject { 16 | CLLocationManager *manager; 17 | NSMutableDictionary *notes; 18 | CLLocation *lastLocation; 19 | } 20 | 21 | + (void)startup; 22 | + (void)registerNote:(Note*)note; 23 | + (void)unregisterNote:(Note*)note; 24 | + (CLLocation*)lastCoord; 25 | + (NSString*)distanceStringFrom:(CLLocationCoordinate2D)coord isEnter:(BOOL)isEnter; 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/NoteThumbnailView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotePreviewView.h 3 | // Created by Nathan Stitt 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // NotesScrollView handles hit detection and feeding the UIScrollView 8 | // data in the form of NotePreviewViews 9 | 10 | #import 11 | #import "Note.h" 12 | 13 | @class NotesScrollView; 14 | 15 | @interface NoteThumbnailView : UIView { 16 | Note *note; 17 | UIImageView *imageView; 18 | NotesScrollView *scroller; 19 | UIButton *deleteBtn; 20 | } 21 | 22 | -(id)initWithNote:(Note*)n frame:(CGRect)frame scroller:(NotesScrollView*)sc; 23 | 24 | @property ( nonatomic ) BOOL focused; 25 | @property ( nonatomic, readonly ) Note *note; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Classes/AlarmAbsoluteTimes.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAbsoluteTimes.h 3 | // Created by Nathan Stitt on 11/14/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // The AlarmAbsoluteTimes is a UIDatePicker which 8 | // allows setting the alarm to an arbitrary date/time 9 | 10 | #import 11 | 12 | @class Note,AlarmPopUpController; 13 | 14 | @interface AlarmAbsoluteTimes : NSObject { 15 | UIDatePicker *picker; 16 | AlarmPopUpController *controller; 17 | } 18 | 19 | -(id)initWithAlarmView:(AlarmPopUpController*)controller frame:(CGRect)frame; 20 | -(void)reset; 21 | -(void)saveToNote:(Note*)note; 22 | 23 | @property (readonly,nonatomic) UIView *view; 24 | @property (nonatomic,assign) NSDate *date; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Classes/DrawingTextBox.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #import "HPGrowingTextView.h" 5 | #import "Note.h" 6 | 7 | @class DrawingViewController; 8 | 9 | @interface DrawingTextBox : HPGrowingTextView { 10 | UIImage *placardImage; 11 | NSString *currentDisplayString; 12 | CGFloat fontSize; 13 | CGSize textSize; 14 | DrawingViewController *dvc; 15 | // RoundedTextView *textView; 16 | NSArray *displayStrings; 17 | NSUInteger displayStringsIndex; 18 | CGPoint displacedFrom; 19 | NoteTextBlob *ntb; 20 | UIButton *deleteBtn; 21 | } 22 | 23 | @property (nonatomic) BOOL isEditing; 24 | 25 | // Initializer for this object 26 | - (id)initWithTextBlob:(NoteTextBlob*)ntb Controller:(DrawingViewController*)dcm; 27 | 28 | - (void)liftUp; 29 | - (void)moveTo:(CGPoint)point; 30 | - (void)moveToAndDrop:(CGPoint)point; 31 | @end 32 | -------------------------------------------------------------------------------- /Classes/AlarmAnnotationLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAnnotation.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AlarmAnnotationLabel.h" 10 | 11 | 12 | @implementation AlarmAnnotationLabel 13 | 14 | @synthesize coordinate,entering; 15 | 16 | -init { 17 | self = [super init]; 18 | if ( ! self ){ 19 | return nil; 20 | } 21 | entering = NO; 22 | coordinate.latitude = 37.810000; 23 | coordinate.longitude = -122.477989; 24 | return self; 25 | 26 | } 27 | 28 | -(void)setEntering:(BOOL)v{ 29 | entering = v; 30 | } 31 | 32 | - (NSString *)title { 33 | return entering ? @"Entering" : @"Exiting"; 34 | } 35 | 36 | -(NSString*)subtitle { 37 | return @"Press & Hold to drag"; 38 | } 39 | // optional 40 | 41 | @end 42 | 43 | -------------------------------------------------------------------------------- /Classes/ToggleButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // EraseButton.h 3 | // Created by Nathan Stitt on 12/4/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // a simple UIButton that toggles between an array of images when pressed 8 | 9 | 10 | #import 11 | 12 | 13 | @interface ToggleButton : UIButton { 14 | NSArray *choices; 15 | BOOL toggleOnTouch; 16 | } 17 | 18 | -(id)initWithImages:(NSArray*)images Frame:(CGRect)frame; 19 | 20 | // advance to next image 21 | -(void)toggle; 22 | 23 | // the currently selected image's index 24 | @property (nonatomic) NSInteger selectedIndex; 25 | 26 | @property (nonatomic) BOOL toggleOnTouch; 27 | 28 | // anything other than the first image returns true 29 | @property (nonatomic) BOOL boolValue; 30 | 31 | 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Classes/StoreView.h: -------------------------------------------------------------------------------- 1 | // 2 | // StoreView.h 3 | // Created by Nathan Stitt on 12/24/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // StoreView initiates an InApp purchase 8 | 9 | #import 10 | #import 11 | 12 | @class GradientButton; 13 | 14 | @interface StoreView : UIView 18 | { 19 | UITableView *tableView; 20 | UILabel *message; 21 | 22 | UITableViewCell *firstOption; 23 | UILabel *firstDesc; 24 | 25 | UITableViewCell *secondOption; 26 | UILabel *secondDesc; 27 | 28 | GradientButton *closeButton; 29 | 30 | NSNumberFormatter *priceFormatter; 31 | } 32 | 33 | -(id)initAndShowInto:(UIView*)view; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Classes/AppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | // AppDelegate.h 3 | 4 | // Created by Nathan Stitt on 11/6/10. 5 | // Copyright 2011. 6 | // Distributed under the terms of the GNU General Public License version 3. 7 | 8 | // Since I dislike Interface builder's Xib's the 9 | // app is composed entirely from code. Accordingly the ApplicationDelegate is 10 | // a bit more complex than normal, as it handles creating the window and views 11 | 12 | 13 | #import 14 | #import "MainViewController.h" 15 | #import "Note.h" 16 | #import "PurchaseManager.h" 17 | #import 18 | 19 | @interface AppDelegate : NSObject 21 | { 22 | AVAudioPlayer *player; 23 | UIWindow *window; 24 | MainViewController *mvc; 25 | Note *pendingNote; 26 | } 27 | 28 | @end 29 | 30 | -------------------------------------------------------------------------------- /Classes/AlarmAnnotationPin.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAnnotationView.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @class ToggleButton,AlarmMapView,AlarmAnnotationLabel; 14 | 15 | @interface AlarmAnnotationPin : MKPinAnnotationView { 16 | id delegate; 17 | MKAnnotationViewDragState dragState; 18 | ToggleButton *button; 19 | AlarmAnnotationLabel *label; 20 | } 21 | 22 | -initWithMap:(AlarmMapView*)map; 23 | @property (nonatomic,readonly) ToggleButton *button; 24 | @property (nonatomic,readonly) AlarmAnnotationLabel *label; 25 | @property (nonatomic) BOOL onEnter; 26 | @property (nonatomic, assign) id delegate; 27 | @property (nonatomic, assign) MKAnnotationViewDragState dragState; 28 | @property (nonatomic, assign) AlarmMapView *map; 29 | 30 | @end 31 | 32 | -------------------------------------------------------------------------------- /Classes/AlarmMapView.h: -------------------------------------------------------------------------------- 1 | // 2 | // MapView.h 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "AlarmAnnotationPin.h" 12 | #import "Note.h" 13 | 14 | @class AlarmPopUpController; 15 | 16 | @interface AlarmMapView : NSObject { 17 | AlarmPopUpController *alarmView; 18 | MKMapView *map; 19 | MKCircle* circle; 20 | AlarmAnnotationPin *pin; 21 | BOOL dirty; 22 | } 23 | 24 | -(id) initWithAlarmView:(AlarmPopUpController*)view frame:(CGRect)frame; 25 | -(void) setFromNote:(Note*)note; 26 | -(void) saveToNote: (Note*)note; 27 | -(void) didChangeDragState:(MKAnnotationViewDragState)newDragState fromOldState:(MKAnnotationViewDragState)dragState; 28 | -(void) reset; 29 | 30 | @property (readonly,nonatomic) UIView *view; 31 | @property (readonly,nonatomic) MKMapView *map; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Classes/AlarmQuickTimes.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmQuickTimes.h 3 | // Created by Nathan Stitt on 11/18/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // The AlarmQuickTimes view holds a UIPicker which contains 8 | // shortcut times such as 3 minutes, 10 minutes, half hour, etc. 9 | // it's populated from the alarm_times.plist file 10 | 11 | #import 12 | 13 | @class AlarmPopUpController,Note; 14 | 15 | @interface AlarmQuickTimes : NSObject { 16 | UIPickerView *picker; 17 | AlarmPopUpController *alarmView; 18 | NSDictionary *choicesTimes; 19 | NSArray *quickChoices; 20 | } 21 | 22 | -(id)initWithAlarmView:(AlarmPopUpController*)view frame:(CGRect)frame; 23 | -(void)setFromNote:(Note*)note; 24 | -(void)saveToNote:(Note*)note; 25 | -(NSDate*)date; 26 | -(void)reset; 27 | -(BOOL)hasDateType:(NSString*)name; 28 | 29 | 30 | @property (readonly,nonatomic) UIView *view; 31 | -(void)selectBlank; 32 | -(BOOL)isSet; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /Classes/HPTextViewInternal.m: -------------------------------------------------------------------------------- 1 | // 2 | // HPTextViewInternal.m 3 | // Cupido 4 | // 5 | // Created by Hans Pinckaers on 30-06-10. 6 | // Copyright 2010 Hans Pinckaers. All rights reserved. 7 | // 8 | 9 | #import "HPTextViewInternal.h" 10 | 11 | 12 | @implementation HPTextViewInternal 13 | 14 | -(void)setContentOffset:(CGPoint)s 15 | { 16 | if(self.tracking || self.decelerating){ 17 | //initiated by user... 18 | self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); 19 | } else { 20 | 21 | float bottomOffset = (self.contentSize.height - self.frame.size.height + self.contentInset.bottom); 22 | if(s.y < bottomOffset && self.scrollEnabled){ 23 | self.contentInset = UIEdgeInsetsMake(0, 0, 8, 0); //maybe use scrollRangeToVisible? 24 | } 25 | 26 | } 27 | 28 | [super setContentOffset:s]; 29 | } 30 | 31 | -(void)setContentInset:(UIEdgeInsets)s 32 | { 33 | UIEdgeInsets insets = s; 34 | 35 | if(s.bottom>8) insets.bottom = 0; 36 | insets.top = 0; 37 | 38 | [super setContentInset:insets]; 39 | } 40 | 41 | 42 | - (void)dealloc { 43 | [super dealloc]; 44 | } 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Classes/PurchaseManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // PurchaseManager.h 3 | // Created by Nathan Stitt on 12/19/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // PurchaseManger listens for notification from Apple to in-app purchase requests. 8 | // once it recieves a notification, it marks the product as being purchased. 9 | 10 | #import 11 | #import 12 | 13 | // these are our sku ID's that we listen for 14 | #define LIMITED_PRODUCT_ID @"com.iogee.remindly.limited" 15 | #define UNLIMITED_PRODUCT_ID @"com.iogee.remindly.unlimited" 16 | #define PRIOR_TO_UNLIMITED_PRODUCT_ID @"com.iogee.remindly.prior_to_unlimited" 17 | 18 | // we broadcast these notifications once a notificaiton is receieved 19 | // using NSNotificationCenter defaultCenter 20 | #define IN_APP_PURCHASE_MADE @"InAppPurchaseMade" 21 | #define IN_APP_PURCHASE_CANCELED @"InAppPurchaseCanceled" 22 | 23 | 24 | @interface PurchaseManager : NSObject { 25 | 26 | } 27 | 28 | // this is called from the App delegate 29 | +(void)startup; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /Remindly-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIconFile 12 | Icon 13 | CFBundleIdentifier 14 | com.iogee.remindly 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | Remindly 19 | CFBundlePackageType 20 | APPL 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 3.2 25 | LSRequiresIPhoneOS 26 | 27 | UIPrerenderedIcon 28 | 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationPortraitUpsideDown 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Classes/AlarmPopUpController.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmView.h 3 | // Created by Nathan Stitt on 11/14/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // The AlarmViewController handles setting an alarm. 8 | // it has a button which will toggle sliding the view up & down 9 | // calls AlarmViewDelegate to set alarm after save button is pressed 10 | 11 | 12 | #import 13 | #import "Note.h" 14 | #import "AlarmQuickTimes.h" 15 | #import "AlarmAbsoluteTimes.h" 16 | #import "AlarmMapView.h" 17 | #import "AlarmSounds.h" 18 | 19 | @class AlarmPopUpController,GradientButton; 20 | 21 | 22 | @interface AlarmPopUpController : UIViewController { 23 | AlarmQuickTimes *quickTimes; 24 | AlarmAbsoluteTimes *absTimes; 25 | AlarmMapView *mapView; 26 | AlarmSounds *sounds; 27 | GradientButton *saveBtn; 28 | BOOL wasSet; 29 | UISegmentedControl *typeCtrl; 30 | NSInteger lastTab; 31 | UITabBar *tabBar; 32 | Note *currentNote; 33 | 34 | NSMutableArray *panels; 35 | } 36 | 37 | -(void)showWithNote:(Note*)note; 38 | -(void)quickSelectionMade; 39 | -(void)absSelectionMade; 40 | 41 | @property (nonatomic,readonly ) BOOL wasSet; 42 | @property (nonatomic) BOOL isShowing; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Classes/AlarmTitleButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmTitleButton.h 3 | // Created by Nathan Stitt on 11/29/10. 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // the AlarmTitleButton was originally a UILabel with rounded 8 | // bottom border and drop shadow to make it appear offset 9 | // on the DrawingView. 10 | 11 | // However after observing people using Remindly, I noticed that they consistently 12 | // tapped the label expecting it to set the alarm. Rather than fight it, I gave them what 13 | // they expected and changed it to a UIButton and pop up the alarm on TouchUpInside 14 | 15 | #import 16 | 17 | @interface AlarmTitleButton : UIButton { 18 | CGFloat borderWidth; 19 | CGFloat borderRadius; 20 | UIColor *borderColor; 21 | // super's backgroundColor seems to always draw and I 22 | // couldn't figure out how to stop that. Use this instead 23 | UIColor *fillColor; 24 | 25 | } 26 | @property (nonatomic, copy) NSString*text; 27 | 28 | @property (nonatomic, assign) CGFloat borderWidth; 29 | @property (nonatomic, assign) CGFloat borderRadius; 30 | @property (nonatomic, retain) UIColor *borderColor; 31 | @property (nonatomic, retain) UIColor *fillColor; 32 | 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /alarm_times.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 0 7 | 1 Day 8 | 1440 9 | 10 Min. 10 | 10 11 | 12 Hour 12 | 720 13 | 15 Min. 14 | 15 15 | 2 Days 16 | 2880 17 | 2 Hour 18 | 120 19 | 3 Days 20 | 4320 21 | 3 Hour 22 | 180 23 | 3 Min. 24 | 3 25 | 4 Hour 26 | 240 27 | 45 Min. 28 | 45 29 | 5 Min. 30 | 5 31 | 6 Hour 32 | 360 33 | 8 Hour 34 | 420 35 | 1/2 Hour 36 | 30 37 | Hour & 1/2 38 | 90 39 | One Hour 40 | 60 41 | 7 Days 42 | 10080 43 | Next Hour 44 | 51 45 | 46 | 47 | -------------------------------------------------------------------------------- /Classes/NotesManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nathan Stitt on 11/10/10 3 | // Copyright 2011. 4 | // Distributed under the terms of the GNU General Public License version 3. 5 | 6 | // NotesManager, manages, wait for it.... Notes 7 | // On startup, it reads in the directories, sorts 8 | // them by date created, and caches them. 9 | // then when a client requests Note at an index, it c 10 | // requests it from [ Note noteWithDirectory] and returns it 11 | // it also keeps a cache of pending notifications 12 | 13 | 14 | #import 15 | #import "Note.h" 16 | 17 | #define NOTES_COUNT_CHANGED_NOTICE @"NoteCountChange" 18 | 19 | 20 | @interface NotesManager : NSObject { 21 | NSMutableArray *dirs; 22 | NSMutableDictionary *alerts; 23 | NSString *path; 24 | } 25 | 26 | +(void)startup; 27 | +(NotesManager*)instance; 28 | +(NSInteger)count; 29 | +(Note*)noteAtIndex:(NSUInteger)index; 30 | +(NSArray*)notesWithLocationAlarms; 31 | 32 | -(Note*)addNote; 33 | -(BOOL)isAllowedMoreNotes; 34 | -(BOOL)hasBeenUpgraded; 35 | -(void)upgradeAllowedNoteCount:(BOOL)unlimited; 36 | 37 | -(Note*)deleteNote:(Note*)note; 38 | -(Note*)noteWithDirectory:(NSString*)dir; 39 | -(BOOL)hasNoteWithDirectory:(NSString*)dir; 40 | 41 | @property (readonly,nonatomic) NSString*path; 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Classes/NotesScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotesScrollView.h 3 | // Created by Nathan Stitt 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // NotesScrollView handles hit detection and feeding the UIScrollView 8 | // data in the form of NotePreviewViews 9 | 10 | #import 11 | #import 12 | 13 | 14 | @class Note, NoteSelectorController,NoteThumbnailView; 15 | 16 | 17 | @interface NotesScrollView : UIView { 18 | UIScrollView *scrollView; 19 | NSUInteger currentPage; 20 | BOOL firstLayout; 21 | NoteSelectorController *controller; 22 | NSMutableDictionary *previews; 23 | } 24 | 25 | @property (nonatomic,readonly) NSUInteger currentPage; 26 | 27 | - (id)initWithController:(NoteSelectorController*)cntr frame:(CGRect)frame; 28 | 29 | -(NoteThumbnailView*)loadPage:(NSUInteger)page; 30 | 31 | // called by a preview when it's tapped, 32 | // the notification is then passed on to the selection controller 33 | - (void)noteWasSelected:(Note*)note; 34 | 35 | // move to the specified index 36 | - (void)selectNoteIndex:(NSInteger)index; 37 | 38 | // remove specified thumbnail 39 | - (void)deleteThumbnail:(NoteThumbnailView*)tn; 40 | 41 | // clears all notes, moves to the first index 42 | // and then loads the first and second note previews 43 | - (void)reload; 44 | 45 | // clears all notes 46 | - (void)clear; 47 | 48 | 49 | @end -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # Remindly 2 | 3 | The quickest way to create a reminder on your iPhone™. It starts up quickly, allows you to scribble a letter, word, or figure on the screen, enter a time (with convienent shortcuts) and then get on with your day. 4 | 5 | ## About: 6 | * Enter a reminder in just a few seconds 7 | * Uses the UILocalNotification features found in iOs 4.0, allowing reminders to continue to fire even if Remindly isn't running 8 | * Can choose between multiple different sounding alarms, including voice. 9 | * Created by [IoGee](http://iogee.com/remindly) 10 | * Inspired by Palm application Diddlebug. 11 | * Available from [App Store](http://itunes.apple.com/us/app/remindly/id411254165?mt=8&uo=4) 12 | 13 | ## Source code includes: 14 | * Bezier curves for smoothing lines while drawing. Many drawing apps don't seem to do this, they really should. 15 | * Background locaiton updates which fire geographical alarms when leaving or nearing a location 16 | * Xibless design with application created only in code. 17 | * Uses in-app purchase, a good reference for a often-confusing subject. When building for yourself, you probably want to modify method -(BOOL)isAllowedMoreNotes in [NotesManager.m](https://github.com/nathanstitt/Remindly/blob/master/Classes/NotesManager.m) to always return true. 18 | 19 | ## License 20 | * Source code is released under the GPL v3. 21 | * Images, Sounds and other assets are licensed under the Creative Commons Attribution-NonCommercial license. 22 | 23 | -------------------------------------------------------------------------------- /Classes/MainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nathan Stitt on 11/10/10 3 | // Copyright 2011. 4 | // Distributed under the terms of the GNU General Public License version 3. 5 | 6 | // As the name says, this is the MainViewController. 7 | // It is responsible for laying out the toolbar, 8 | // DrawingController and NoteSelector 9 | // and then handling the interactions between them. 10 | 11 | // FIXME - move the toolbar into 12 | // it's own class and have it be responsible for 13 | // calling actions, which would neaten this up quite a bit 14 | 15 | #import 16 | #import "AlarmPopUpController.h" 17 | #import "MainToolBar.h" 18 | 19 | @class DrawingViewController, NoteSelectorController, DrawingPaletteController; 20 | 21 | @interface MainViewController : UIViewController { 22 | NoteSelectorController *selector; 23 | MainToolBar *toolbar; 24 | 25 | DrawingPaletteController *drawTools; 26 | DrawingViewController *drawing; 27 | AlarmPopUpController *alarm; 28 | } 29 | 30 | -(void) toggleDrawingMode; 31 | -(void) selectNote:(Note*)note; 32 | 33 | @property (nonatomic) BOOL isAlarmShowing; 34 | @property (nonatomic) BOOL isDrawToolsShowing; 35 | @property (nonatomic) BOOL drawingMode; 36 | @property (readonly,nonatomic) DrawingPaletteController *drawTools; 37 | @property (readonly,nonatomic) DrawingViewController *drawing; 38 | @property (readonly,nonatomic) AlarmPopUpController *alarm; 39 | @property (readonly,nonatomic) NoteSelectorController *selector; 40 | 41 | 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /Classes/DrawingViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingViewController.h 3 | // Created by Nathan Stitt on 11/10/10 4 | // Copyright 2011. 5 | // Distributed under the terms of the GNU General Public License version 3. 6 | 7 | // Tracks touches on a view and draws lines between 8 | // them using bezier curves 9 | 10 | #import 11 | #import "GradientButton.h" 12 | #import "DrawingTextBox.h" 13 | 14 | @class MainViewController,AlarmTitleButton,Note; 15 | 16 | #define DRAWING_BEGAN_NOTIFICATION @"DrawingBeganNotification" 17 | 18 | @interface DrawingViewController : UIViewController { 19 | CGPoint lastPoint; 20 | CGPoint points[4]; 21 | MainViewController *mainView; 22 | UIImageView *drawImage; 23 | Note *note; 24 | BOOL isErasing; 25 | BOOL wasMoved; 26 | AlarmTitleButton *alarmTitle; 27 | DrawingTextBox *currentTextEditBox; 28 | UIColor *color; 29 | } 30 | 31 | // keep a pointer to the mainview 32 | - (id)initWithMainView:(MainViewController*)mv; 33 | 34 | // erase image 35 | - (void)clear; 36 | 37 | // are we hidden 38 | @property (nonatomic) BOOL hidden; 39 | 40 | // the current color 41 | @property (retain,nonatomic) UIColor *color; 42 | 43 | // how thick the line should be 44 | @property (nonatomic) CGFloat lineWidth; 45 | 46 | // which note we're working from, with current 47 | // work saved to it. 48 | @property (nonatomic,retain) Note* note; 49 | 50 | // which note we're working from, without 51 | // saving current image to it 52 | @property (nonatomic,readonly) Note* unSavedNote; 53 | 54 | // is the erasing tool active 55 | @property (nonatomic) BOOL isErasing; 56 | 57 | // expose this so MainView can hang actions on it 58 | @property (nonatomic,readonly) AlarmTitleButton *alarmTitle; 59 | 60 | // add a text bubble 61 | -(void) addText; 62 | 63 | // remove a text bubble 64 | -(void) removeText:(DrawingTextBox*)ntb; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Classes/GradientButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // GradientButton is from 4 | // http://code.google.com/p/iphonegradientbuttons 5 | // 6 | // I've added a few new colors 7 | // it seems to find it's way into most 8 | // of my projects somehow. 9 | // 10 | // Created by jeff on 5/17/10. 11 | // 12 | 13 | #import 14 | #import 15 | #import 16 | 17 | @interface GradientButton : UIButton { 18 | // These two arrays define the gradient that will be used 19 | // when the button is in UIControlStateNormal 20 | NSArray *normalGradientColors; // Colors 21 | NSArray *normalGradientLocations; // Relative locations 22 | 23 | // These two arrays define the gradient that will be used 24 | // when the button is in UIControlStateHighlighted 25 | NSArray *highlightGradientColors; // Colors 26 | NSArray *highlightGradientLocations; // Relative locations 27 | 28 | // This defines the corner radius of the button 29 | CGFloat cornerRadius; 30 | 31 | // This defines the size and color of the stroke 32 | CGFloat strokeWeight; 33 | UIColor *strokeColor; 34 | 35 | @private 36 | CGGradientRef normalGradient; 37 | CGGradientRef highlightGradient; 38 | } 39 | @property (nonatomic, retain) NSArray *normalGradientColors; 40 | @property (nonatomic, retain) NSArray *normalGradientLocations; 41 | @property (nonatomic, retain) NSArray *highlightGradientColors; 42 | @property (nonatomic, retain) NSArray *highlightGradientLocations; 43 | @property (nonatomic) CGFloat cornerRadius; 44 | @property (nonatomic) CGFloat strokeWeight; 45 | @property (nonatomic, retain) UIColor *strokeColor; 46 | - (void)useAlertStyle; 47 | - (void)useRedDeleteStyle; 48 | - (void)useWhiteStyle; 49 | - (void)useBlackStyle; 50 | - (void)useBlueStyle; 51 | - (void)useWhiteActionSheetStyle; 52 | - (void)useBlackActionSheetStyle; 53 | - (void)useSimpleOrangeStyle; 54 | - (void)useGreenConfirmStyle; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /Classes/PickerSelectionIndicator.m: -------------------------------------------------------------------------------- 1 | // 2 | // PickerSelectionIndicator.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/11/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "PickerSelectionIndicator.h" 10 | #import 11 | 12 | @implementation PickerSelectionIndicator 13 | 14 | - (id)initWithFrame:(CGRect)frame 15 | { 16 | self = [super initWithFrame:frame]; 17 | if (self) { 18 | [self setUserInteractionEnabled:NO]; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)drawRect:(CGRect)rect { 24 | CGRect f = self.frame; 25 | CGContextRef context = UIGraphicsGetCurrentContext(); 26 | double perc = 0.18; 27 | 28 | CGContextMoveToPoint(context, f.size.width/2, f.size.height*perc ); 29 | 30 | CGContextAddCurveToPoint(context, 31 | f.size.width/2, f.size.height*perc, 32 | f.size.width/2, 0.0, 33 | 0.0, 0.0 ); 34 | 35 | CGContextAddLineToPoint(context, f.size.width, 0.0 ); 36 | 37 | CGContextAddCurveToPoint(context, 38 | f.size.width, 0.0, 39 | f.size.width/2, 0.0, 40 | f.size.width/2, f.size.height*perc ); 41 | 42 | 43 | CGContextMoveToPoint(context, f.size.width/2, f.size.height*(1.0-perc) ); 44 | 45 | CGContextAddCurveToPoint(context, 46 | f.size.width/2, f.size.height*(1.0-perc), 47 | f.size.width/2, f.size.height, 48 | f.size.width, f.size.height ); 49 | 50 | CGContextAddLineToPoint(context, 0.0, f.size.height ); 51 | 52 | CGContextAddCurveToPoint(context, 53 | 0.0, f.size.height, 54 | f.size.width/2, f.size.height, 55 | f.size.width/2, f.size.height*(1.0-perc) ); 56 | 57 | CGContextSetLineWidth(context, 1.0); 58 | CGContextSetFillColorWithColor(context, [ UIColor blackColor ].CGColor ); 59 | CGContextDrawPath(context, kCGPathFillStroke); 60 | CGContextFillPath(context); 61 | } 62 | 63 | 64 | - (void)dealloc 65 | { 66 | [super dealloc]; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Classes/AlarmAnnotationPin.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAnnotationView.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AlarmAnnotationPin.h" 10 | #import "ToggleButton.h" 11 | #import "AlarmMapView.h" 12 | 13 | #import "AlarmAnnotationLabel.h" 14 | 15 | @implementation AlarmAnnotationPin 16 | 17 | 18 | @synthesize delegate, dragState, map, button, label; 19 | 20 | -initWithMap:(AlarmMapView*)m { 21 | map = m; 22 | AlarmAnnotationLabel *l = [[ AlarmAnnotationLabel alloc ] init ]; 23 | self=[super initWithAnnotation: l reuseIdentifier:@"alarmIdentifier" ]; 24 | if ( ! self ){ 25 | [ l release ]; 26 | return nil; 27 | } 28 | button = [ [ ToggleButton alloc ] initWithImages: [ NSArray arrayWithObjects: 29 | [ UIImage imageNamed:@"departing2"], 30 | [ UIImage imageNamed:@"arriving_icon" ],nil ] 31 | Frame: CGRectMake(0, 0, 30, 30 ) ]; 32 | label = l; 33 | button.toggleOnTouch = NO; 34 | self.leftCalloutAccessoryView = button; 35 | self.draggable = YES; 36 | self.canShowCallout = YES; 37 | return self; 38 | } 39 | 40 | 41 | - (void)setDragState:(MKAnnotationViewDragState)newDragState animated:(BOOL)animated { 42 | [ map didChangeDragState:newDragState fromOldState:dragState]; 43 | if (newDragState == MKAnnotationViewDragStateStarting) { 44 | dragState = MKAnnotationViewDragStateDragging; 45 | } else if (newDragState == MKAnnotationViewDragStateEnding) { 46 | dragState = MKAnnotationViewDragStateNone; 47 | } else if (newDragState == MKAnnotationViewDragStateCanceling) { 48 | dragState = MKAnnotationViewDragStateNone; 49 | } 50 | } 51 | 52 | 53 | -(BOOL)onEnter{ 54 | return [ button boolValue ]; 55 | } 56 | 57 | -(void)setOnEnter:(BOOL)v{ 58 | self.label.entering = button.boolValue = v; 59 | } 60 | 61 | - (void)dealloc { 62 | [ label release ]; 63 | [ button release ]; 64 | [ super dealloc ]; 65 | } 66 | 67 | @end 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /Releases/1.0/Remindly.app/_CodeSignature/CodeResources: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | files 6 | 7 | Default.png 8 | 9 | XHwnkTXo5jsb+ZQdM6+2R8gZT1Y= 10 | 11 | Icon.png 12 | 13 | sclpDV96WVRlfcdA5VGdCpvDQiE= 14 | 15 | Icon@2x.png 16 | 17 | vflWCGmsbThik8T3elhcwPasocg= 18 | 19 | PkgInfo 20 | 21 | n57qDP4tZfLD1rCS43W0B4LQjzE= 22 | 23 | alarm-clock-icon.png 24 | 25 | +e/YtQ9bYJd+ZEx0C/4Kiaumb78= 26 | 27 | alarm.png 28 | 29 | ow1Sd5OBoRg01VpuIY716w8NmuI= 30 | 31 | alarm@2X.png 32 | 33 | rP7EnPHxD6WozziZo7gLLAOlPz8= 34 | 35 | alarm_times.plist 36 | 37 | hrxv5PAhTrZxWNSgvO+Vg9kCMKw= 38 | 39 | blank.png 40 | 41 | KANs2kGHZ1zGvo/9gdCbwLnjePk= 42 | 43 | draw-icon.png 44 | 45 | fvDJ3pTG2tjFhTB2CNkUAgbDKmY= 46 | 47 | embedded.mobileprovision 48 | 49 | v/FGBU7oDmQ9SLRbQQh6CZtZKUs= 50 | 51 | empty.plist 52 | 53 | zmV6UqBSo6r1NOz798vd5O4zTBA= 54 | 55 | erase-icon.png 56 | 57 | 3O/4ppHzf4tKtnnxfS4nq6gnqRE= 58 | 59 | erase-icon@2x.png 60 | 61 | mz5vp4BFcW1R0TuajbXrTwQnt+Q= 62 | 63 | photos_icon.png 64 | 65 | z97czqN/hwSB75XHZhYqC1q168Q= 66 | 67 | 68 | rules 69 | 70 | .* 71 | 72 | Info.plist 73 | 74 | omit 75 | 76 | weight 77 | 10 78 | 79 | ResourceRules.plist 80 | 81 | omit 82 | 83 | weight 84 | 100 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /Classes/NoteSelectorController.h: -------------------------------------------------------------------------------- 1 | // 2 | // NoteSelectorController.h 3 | // 4 | // I've taken the initial concept for this from Björn Sållarp 5 | // and tweaked it a good bit to take it's data directly from 6 | // the NotesManager instead of the delegate. 7 | // 8 | // Since he provided the initial concept, I'm leaving his notices 9 | // intact below 10 | // 11 | // Created by Björn Sållarp on 7/14/10. 12 | // NO Copyright 2010 MightyLittle Industries. NO rights reserved. 13 | // 14 | // Use this code any way you like. If you do like it, please 15 | // link to my blog and/or write a friendly comment. Thank you! 16 | // 17 | // Read my blog @ http://blog.sallarp.com 18 | // 19 | 20 | #import 21 | #import "NotesScrollView.h" 22 | #import "NoteThumbnailView.h" 23 | #import "Note.h" 24 | 25 | @class MainViewController; 26 | 27 | @interface NoteSelectorController : UIViewController { 28 | NotesScrollView *scroller; 29 | UILabel *noteHeader; 30 | UIPageControl *dots; 31 | MainViewController *mainView; 32 | } 33 | 34 | // init and remember the pointer to the MainView as we 35 | // use that for callbacks 36 | -(id) initWithMainView:(MainViewController*)mv; 37 | 38 | 39 | // where we are 40 | -(NSUInteger) currentIndex; 41 | 42 | 43 | // the scroller is started moving we hide the header 44 | -(void) startScrolling; 45 | 46 | 47 | // clears all thumbnails previews 48 | // called before view will become active 49 | -(void)reload; 50 | 51 | // move scroller & other data (header, dots, etc) to correspond to index 52 | -(void) selectNoteIndex:(NSInteger)index; 53 | 54 | // add a note, will also go to first index 55 | // as that's where the note will be 56 | -(void) addNote:(Note*)note; 57 | 58 | // the scroller has stopped moving - show the header 59 | -(void) endScrolling; 60 | 61 | // remove a note from the scroller, and switch to index 62 | -(void) deleteNote:(Note*)note newIndex:(NSUInteger)index; 63 | 64 | // notification that the page has changed 65 | -(void) pageChanged:(NSInteger)index; 66 | 67 | // a note was selected 68 | -(void) noteWasSelected:(Note*)note; 69 | 70 | @end 71 | 72 | -------------------------------------------------------------------------------- /Classes/AlarmAbsoluteTimes.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmAbsoluteTimes.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "AlarmAbsoluteTimes.h" 19 | #import "AlarmPopUpController.h" 20 | #import "Note.h" 21 | 22 | @implementation AlarmAbsoluteTimes 23 | 24 | @synthesize view=picker; 25 | 26 | -(id)initWithAlarmView:(AlarmPopUpController*)c frame:(CGRect)frame { 27 | self = [ super init ]; 28 | if ( ! self ){ 29 | return nil; 30 | } 31 | controller = c; 32 | picker = [[ UIDatePicker alloc ] initWithFrame: frame ]; 33 | [ picker addTarget:self action:@selector(datePickerChanged:) forControlEvents:UIControlEventValueChanged]; 34 | 35 | return self; 36 | } 37 | 38 | 39 | -(void)datePickerChanged:(id)picker { 40 | [ controller absSelectionMade ]; 41 | } 42 | 43 | -(void)reset { 44 | picker.date = [ NSDate date ]; 45 | } 46 | 47 | -(NSDate*)date{ 48 | return picker.date; 49 | } 50 | 51 | 52 | -(void)setDate:(NSDate*)date{ 53 | if ( date ){ 54 | picker.date = date; 55 | } 56 | } 57 | 58 | 59 | - (void)dealloc { 60 | [super dealloc]; 61 | } 62 | 63 | 64 | -(void)saveToNote:(Note*)note{ 65 | static NSDateFormatter *formmatter; 66 | if ( ! formmatter ){ 67 | formmatter = [[NSDateFormatter alloc] init]; 68 | [ formmatter setFormatterBehavior:NSDateFormatterBehavior10_4]; 69 | [ formmatter setDateFormat:@"hh:mm a EEE, MMM dd, YYYY" ]; 70 | } 71 | note.alarmTag = 1; 72 | [ note setFireDate: self.date ]; 73 | [ note setAlarmType:[ formmatter stringFromDate: self.date ] ]; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Classes/CountingButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // CountingButton.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "CountingButton.h" 19 | 20 | 21 | @implementation CountingButton 22 | 23 | @synthesize button,count; 24 | 25 | -(id)initWithCount:(NSInteger)c{ 26 | 27 | font = [UIFont boldSystemFontOfSize:13]; 28 | icon = [ UIImage imageNamed:@"photos_icon.png" ]; 29 | 30 | button = [ UIButton buttonWithType: UIButtonTypeCustom ]; 31 | button.titleLabel.font = font; 32 | button.titleLabel.shadowOffset = CGSizeMake(0, -1); 33 | 34 | [ button setImage:icon forState:UIControlStateNormal ]; 35 | [ button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 36 | [ button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted]; 37 | [ button setTitleShadowColor:[[UIColor blackColor] colorWithAlphaComponent:0.5] forState:UIControlStateNormal]; 38 | [ button setBackgroundImage:[UIImage imageNamed:@"bar-button-item-background.png"] forState:UIControlStateNormal]; 39 | 40 | button.frame = CGRectMake( 0, 0, icon.size.width + 15 + [ @" " sizeWithFont:font].width, 30 ); 41 | 42 | self = [ super initWithCustomView: button ]; 43 | [ self setCount: c ]; 44 | return self; 45 | } 46 | 47 | -(void)setCount:(NSInteger)c { 48 | NSString *cnt = [ NSString stringWithFormat:@"%ld", c ]; 49 | CGSize size = [ cnt sizeWithFont: button.titleLabel.font ]; 50 | button.titleEdgeInsets = UIEdgeInsetsMake( 0, ( -23 - size.width), 0, 0); 51 | [ button setTitle: cnt forState:UIControlStateNormal ]; 52 | } 53 | 54 | - (void)dealloc { 55 | [ button release ]; 56 | [super dealloc]; 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Classes/ToggleButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // DrawEraseButton.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "ToggleButton.h" 19 | 20 | @implementation ToggleButton 21 | 22 | @synthesize toggleOnTouch; 23 | 24 | -(id)initWithImages:(NSArray*)images Frame:(CGRect)frame{ 25 | self = [ super initWithFrame: frame ]; 26 | if ( ! self ){ 27 | return nil; 28 | } 29 | choices = images; 30 | [ choices retain ]; 31 | self.selectedIndex = 0; 32 | [ self setToggleOnTouch:YES ]; 33 | 34 | return self; 35 | } 36 | 37 | -(void)setToggleOnTouch:(BOOL)v { 38 | if ( v != toggleOnTouch ){ 39 | if ( v ){ 40 | [ self addTarget:self action:@selector(moveNext:) forControlEvents:UIControlEventTouchUpInside]; 41 | } else { 42 | [ self removeTarget:self action:@selector(moveNext:) forControlEvents:UIControlEventTouchUpInside ]; 43 | } 44 | } 45 | toggleOnTouch = v; 46 | } 47 | 48 | 49 | -(void)moveNext:(id)sel { 50 | [ self toggle ]; 51 | } 52 | 53 | 54 | -(NSInteger)selectedIndex { 55 | return [ choices indexOfObject: [ self imageForState: UIControlStateNormal ] ]; 56 | } 57 | 58 | 59 | -(void) setSelectedIndex:(NSInteger)index { 60 | [ self setImage: [ choices objectAtIndex:index ] forState:UIControlStateNormal ]; 61 | } 62 | 63 | 64 | -(void) setBoolValue:(BOOL)v{ 65 | self.selectedIndex=v; 66 | } 67 | 68 | 69 | -(BOOL)boolValue{ 70 | return self.selectedIndex; 71 | } 72 | 73 | 74 | -(void)toggle { 75 | if ( self.selectedIndex + 1 >= choices.count ){ 76 | self.selectedIndex = 0; 77 | } else { 78 | self.selectedIndex = self.selectedIndex + 1; 79 | } 80 | } 81 | 82 | - (void)dealloc { 83 | [ choices release ]; 84 | [super dealloc]; 85 | } 86 | 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteTool.m: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingPaletteTool.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/3/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "DrawingPaletteTool.h" 10 | #import 11 | 12 | @implementation DrawingPaletteTool 13 | 14 | @synthesize drawingWidth; 15 | 16 | 17 | - (void)setupLayers { 18 | self.layer.cornerRadius = 10.0; 19 | // self.layer.borderColor = [UIColor redColor].CGColor; 20 | // self.layer.borderWidth = 1.0f; 21 | self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f); 22 | self.layer.shadowOpacity = 1.5f; 23 | 24 | self.layer.shadowRadius = 2.5f; 25 | self.layer.anchorPoint = CGPointMake(0.5f, 0.5f); 26 | 27 | CAGradientLayer *gradient = [CAGradientLayer layer]; 28 | gradient.anchorPoint = CGPointMake(0.0f, 0.0f); 29 | gradient.position = CGPointMake(0.0f, 0.0f); 30 | gradient.bounds = self.layer.bounds; 31 | gradient.cornerRadius = 10.0; 32 | gradient.colors = [NSArray arrayWithObjects: 33 | (id)[UIColor colorWithRed:0.82f 34 | green:0.82f 35 | blue:0.82f 36 | alpha:1.0].CGColor, 37 | (id)[UIColor colorWithRed:0.52f 38 | green:0.52f 39 | blue:0.52f 40 | alpha:1.0].CGColor, 41 | nil]; 42 | 43 | [self.layer addSublayer:gradient]; 44 | } 45 | 46 | 47 | -(void)setSelected:(BOOL)selected{ 48 | [ super setSelected:selected ]; 49 | if ( selected ){ 50 | self.layer.shadowColor = [UIColor blackColor ].CGColor; 51 | self.layer.borderWidth = 2.0; 52 | } else { 53 | self.layer.shadowColor = [UIColor whiteColor ].CGColor; 54 | self.layer.borderWidth = 0.0; 55 | } 56 | } 57 | 58 | 59 | +(id)withImage:(UIImage*)image frame:(CGRect)frame { 60 | DrawingPaletteTool *btn = [ DrawingPaletteTool buttonWithType:UIButtonTypeCustom ]; 61 | [ btn setImage:image forState:UIControlStateNormal ]; 62 | [ btn setupLayers ]; 63 | btn.frame = frame; 64 | return btn; 65 | } 66 | 67 | 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingPalletteView.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/14/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "DrawingPaletteView.h" 10 | #import 11 | #import "UIColor+Expanded.h" 12 | 13 | @implementation DrawingPaletteView 14 | 15 | 16 | - (id)initWithFrame:(CGRect)frame 17 | { 18 | self = [super initWithFrame:frame]; 19 | if (self) { 20 | self.backgroundColor = [ UIColor clearColor ]; 21 | } 22 | return self; 23 | } 24 | 25 | 26 | // Only override drawRect: if you perform custom drawing. 27 | // An empty implementation adversely affects performance during animation. 28 | - (void)drawRect:(CGRect)rect { 29 | CGContextRef context = UIGraphicsGetCurrentContext(); 30 | CGContextSaveGState(context); 31 | CGRect f = self.frame; 32 | NSInteger radius = 40.0; 33 | 34 | CGContextMoveToPoint(context, 0.0, f.size.height ); 35 | 36 | CGContextAddLineToPoint(context, 0.0, radius ); 37 | 38 | CGContextAddCurveToPoint(context, 39 | 0.0, radius, 40 | 0.0, 0.0, 41 | radius, 0.0 ); 42 | 43 | CGContextAddLineToPoint(context, f.size.width-radius, 0.0 ); 44 | 45 | CGContextAddCurveToPoint(context, 46 | f.size.width-radius, 0.0, 47 | f.size.width, 0.0, 48 | f.size.width, radius ); 49 | 50 | CGContextAddLineToPoint(context, f.size.width, f.size.height ); 51 | 52 | CGContextAddLineToPoint(context, 0.0, f.size.height ); 53 | 54 | // [self.fillColor [ UIColor colorWithHexString:@"9a9a9a" ] ]; 55 | // [self.borderColor setStroke ]; 56 | CGContextSetFillColorWithColor( context, [ UIColor colorWithHexString:@"9a9a9a" ].CGColor ); 57 | CGContextSetLineWidth(context, 1.0 ); 58 | 59 | CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 1.0, [UIColor grayColor ].CGColor ); 60 | 61 | CGContextDrawPath(context, kCGPathFillStroke); 62 | 63 | CGContextRestoreGState(context); 64 | [ UIColor colorWithHexString:@"9a9a9a" ]; 65 | [ super drawRect:rect ]; 66 | } 67 | 68 | 69 | - (void)dealloc 70 | { 71 | [super dealloc]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Classes/UIColor+Expanded.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor utilities published by Erica Sadun at 3 | // http://arstechnica.com/apple/guides/2009/02/iphone-development-accessing-uicolor-components.ars 4 | // used to record which color was last in userprefs by MainToolBar 5 | // so that it can be selected on startup 6 | 7 | #import 8 | 9 | 10 | #define SUPPORTS_UNDOCUMENTED_API 0 11 | 12 | @interface UIColor (UIColor_Expanded) 13 | @property (nonatomic, readonly) CGColorSpaceModel colorSpaceModel; 14 | @property (nonatomic, readonly) BOOL canProvideRGBComponents; 15 | @property (nonatomic, readonly) CGFloat red; // Only valid if canProvideRGBComponents is YES 16 | @property (nonatomic, readonly) CGFloat green; // Only valid if canProvideRGBComponents is YES 17 | @property (nonatomic, readonly) CGFloat blue; // Only valid if canProvideRGBComponents is YES 18 | @property (nonatomic, readonly) CGFloat white; // Only valid if colorSpaceModel == kCGColorSpaceModelMonochrome 19 | @property (nonatomic, readonly) CGFloat alpha; 20 | @property (nonatomic, readonly) UInt32 rgbHex; 21 | 22 | - (NSString *)colorSpaceString; 23 | 24 | - (NSArray *)arrayFromRGBAComponents; 25 | 26 | - (BOOL)red:(CGFloat *)r green:(CGFloat *)g blue:(CGFloat *)b alpha:(CGFloat *)a; 27 | 28 | - (UIColor *)colorByLuminanceMapping; 29 | 30 | - (UIColor *)colorByMultiplyingByRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; 31 | - (UIColor *) colorByAddingRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; 32 | - (UIColor *) colorByLighteningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; 33 | - (UIColor *) colorByDarkeningToRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; 34 | 35 | - (UIColor *)colorByMultiplyingBy:(CGFloat)f; 36 | - (UIColor *) colorByAdding:(CGFloat)f; 37 | - (UIColor *) colorByLighteningTo:(CGFloat)f; 38 | - (UIColor *) colorByDarkeningTo:(CGFloat)f; 39 | 40 | - (UIColor *)colorByMultiplyingByColor:(UIColor *)color; 41 | - (UIColor *) colorByAddingColor:(UIColor *)color; 42 | - (UIColor *) colorByLighteningToColor:(UIColor *)color; 43 | - (UIColor *) colorByDarkeningToColor:(UIColor *)color; 44 | 45 | - (NSString *)stringFromColor; 46 | - (NSString *)hexStringFromColor; 47 | 48 | + (UIColor *)randomColor; 49 | + (UIColor *)colorWithString:(NSString *)stringToConvert; 50 | + (UIColor *)colorWithRGBHex:(UInt32)hex; 51 | + (UIColor *)colorWithHexString:(NSString *)stringToConvert; 52 | 53 | + (UIColor *)colorWithName:(NSString *)cssColorName; 54 | 55 | @end 56 | 57 | #if SUPPORTS_UNDOCUMENTED_API 58 | // UIColor_Undocumented_Expanded 59 | // Methods which rely on undocumented methods of UIColor 60 | @interface UIColor (UIColor_Undocumented_Expanded) 61 | - (NSString *)fetchStyleString; 62 | - (UIColor *)rgbColor; // Via Poltras 63 | @end 64 | #endif // SUPPORTS_UNDOCUMENTED_API 65 | -------------------------------------------------------------------------------- /Classes/HPGrowingTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HPTextView.h 3 | // Cupido 4 | // 5 | // Created by Hans Pinckaers on 29-06-10. 6 | // Copyright 2010 Hans Pinckaers. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class HPGrowingTextView; 12 | @class HPTextViewInternal; 13 | 14 | @protocol HPGrowingTextViewDelegate 15 | 16 | @optional 17 | - (BOOL)growingTextViewShouldBeginEditing:(HPGrowingTextView *)growingTextView; 18 | - (BOOL)growingTextViewShouldEndEditing:(HPGrowingTextView *)growingTextView; 19 | 20 | - (void)growingTextViewDidBeginEditing:(HPGrowingTextView *)growingTextView; 21 | - (void)growingTextViewDidEndEditing:(HPGrowingTextView *)growingTextView; 22 | 23 | - (BOOL)growingTextView:(HPGrowingTextView *)growingTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text; 24 | - (void)growingTextViewDidChange:(HPGrowingTextView *)growingTextView; 25 | 26 | - (void)growingTextView:(HPGrowingTextView *)growingTextView willChangeHeight:(float)height; 27 | - (void)growingTextView:(HPGrowingTextView *)growingTextView didChangeHeight:(float)height; 28 | 29 | - (void)growingTextViewDidChangeSelection:(HPGrowingTextView *)growingTextView; 30 | - (BOOL)growingTextViewShouldReturn:(HPGrowingTextView *)growingTextView; 31 | @end 32 | 33 | @interface HPGrowingTextView : UIView { 34 | HPTextViewInternal *internalTextView; 35 | 36 | int minHeight; 37 | int maxHeight; 38 | 39 | //class properties 40 | int maxNumberOfLines; 41 | int minNumberOfLines; 42 | 43 | BOOL animateHeightChange; 44 | 45 | //uitextview properties 46 | NSObject *delegate; 47 | NSString *text; 48 | UIFont *font; 49 | UIColor *textColor; 50 | UITextAlignment textAlignment; 51 | NSRange selectedRange; 52 | BOOL editable; 53 | UIDataDetectorTypes dataDetectorTypes; 54 | UIReturnKeyType returnKeyType; 55 | } 56 | 57 | //real class properties 58 | @property (nonatomic) int maxNumberOfLines; 59 | @property (nonatomic) int minNumberOfLines; 60 | @property (nonatomic) BOOL animateHeightChange; 61 | @property (retain) UITextView *internalTextView; 62 | 63 | 64 | //uitextview properties 65 | @property(assign) NSObject *delegate; 66 | @property(nonatomic,assign) NSString *text; 67 | @property(nonatomic,assign) UIFont *font; 68 | @property(nonatomic,assign) UIColor *textColor; 69 | @property(nonatomic) UITextAlignment textAlignment; // default is UITextAlignmentLeft 70 | @property(nonatomic) NSRange selectedRange; // only ranges of length 0 are supported 71 | @property(nonatomic,getter=isEditable) BOOL editable; 72 | @property(nonatomic) UIDataDetectorTypes dataDetectorTypes __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_3_0); 73 | @property (nonatomic) UIReturnKeyType returnKeyType; 74 | 75 | 76 | //uitextview methods 77 | - (BOOL)hasText; 78 | - (void)scrollRangeToVisible:(NSRange)range; 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Remindly.xcodeproj/xcuserdata/nas.xcuserdatad/xcschemes/Remindly.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 14 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 40 | 41 | 47 | 48 | 49 | 50 | 51 | 52 | 59 | 60 | 66 | 67 | 68 | 69 | 71 | 72 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Classes/AlarmTitleButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmTitleLabel.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "AlarmTitleButton.h" 19 | #import 20 | 21 | @implementation AlarmTitleButton 22 | 23 | @synthesize borderWidth, borderRadius, borderColor, fillColor; 24 | 25 | - (id)initWithFrame:(CGRect)frame { 26 | self = [super initWithFrame:frame]; 27 | 28 | self.backgroundColor = [UIColor clearColor]; 29 | self.contentHorizontalAlignment=UIControlContentHorizontalAlignmentCenter; 30 | [ self setTitleColor:[UIColor blackColor ] forState: UIControlStateNormal]; 31 | 32 | self.borderColor = [UIColor colorWithWhite:0.65 alpha:1.0]; 33 | self.fillColor = [ UIColor colorWithRed: 241.0/255.0 34 | green:241.0/255.0 35 | blue:241.0/255.0 36 | alpha:1.0 ]; 37 | 38 | 39 | return self; 40 | } 41 | 42 | #define borderWidth 1.0 43 | #define borderRadius 10.0 44 | #define PADDING 8.0 45 | 46 | -(void)setText:(NSString*)text{ 47 | if ( self.text.length != text.length ){ 48 | [ self setNeedsDisplay ]; 49 | } 50 | [ self setTitle:text forState:UIControlStateNormal ]; 51 | } 52 | 53 | -(NSString*)text{ 54 | return [ self titleForState:UIControlStateNormal ]; 55 | } 56 | 57 | - (void)drawRect:(CGRect)rect { 58 | 59 | CGSize size = [[self text] sizeWithFont: self.titleLabel.font ]; 60 | 61 | CGRect localRect = CGRectInset(rect, borderWidth / 2, borderWidth / 2); 62 | 63 | CGContextRef context = UIGraphicsGetCurrentContext(); 64 | CGContextSaveGState(context); 65 | 66 | NSInteger leftBorder = (160-PADDING)-(size.width/2); 67 | NSInteger bottom = localRect.size.height-5; 68 | NSInteger rightBorder = 320-leftBorder; 69 | CGContextTranslateCTM(context, borderWidth / 2, borderWidth / 2); 70 | 71 | CGContextMoveToPoint(context, leftBorder, 0.0 ); 72 | CGContextAddLineToPoint(context, leftBorder, ( - borderRadius)); 73 | 74 | CGContextAddCurveToPoint(context, 75 | leftBorder, bottom-borderRadius, 76 | leftBorder, bottom, 77 | leftBorder + borderRadius, bottom ); 78 | 79 | CGContextAddLineToPoint(context, rightBorder-borderRadius, bottom); 80 | 81 | CGContextAddCurveToPoint(context, 82 | rightBorder-borderRadius, bottom, 83 | rightBorder, bottom, 84 | rightBorder, bottom - borderRadius ); 85 | 86 | CGContextAddLineToPoint(context, rightBorder, 0 ); 87 | 88 | [self.fillColor setFill ]; 89 | [self.borderColor setStroke ]; 90 | CGContextSetLineWidth(context, borderWidth); 91 | 92 | CGContextSetShadowWithColor(context, CGSizeMake(0, 2), 1.0, [UIColor grayColor ].CGColor ); 93 | 94 | CGContextDrawPath(context, kCGPathFillStroke); 95 | 96 | CGContextRestoreGState(context); 97 | 98 | [ super drawRect:rect ]; 99 | 100 | } 101 | 102 | 103 | - (void)dealloc { 104 | [super dealloc]; 105 | } 106 | 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Classes/NoteThumbnailView.m: -------------------------------------------------------------------------------- 1 | /* This file is part of Remindly. 2 | 3 | Remindly is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, version 3. 6 | 7 | Remindly is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with Remindly. If not, see . 14 | */ 15 | 16 | #import "NoteThumbnailView.h" 17 | #import "NoteSelectorController.h" 18 | 19 | #import 20 | 21 | @implementation NoteThumbnailView 22 | 23 | @synthesize note; 24 | 25 | -(id)initWithNote:(Note*)n frame:(CGRect)frame scroller:(NotesScrollView*)sc { 26 | scroller = sc; 27 | self = [ super initWithFrame:frame ]; 28 | note = [ n retain ]; 29 | imageView = [[UIImageView alloc ] initWithFrame:CGRectMake(10, 10, frame.size.width-20, self.frame.size.height-20) ]; 30 | imageView.backgroundColor = [ UIColor whiteColor ]; 31 | imageView.image = [ note thumbnail ]; 32 | [imageView.layer setBorderColor: [[UIColor blackColor] CGColor]]; 33 | [imageView.layer setBorderWidth: 1.0]; 34 | imageView.layer.shadowColor = [[UIColor blackColor] CGColor]; 35 | imageView.layer.shadowOffset = CGSizeMake(10.0f, 10.0f); 36 | imageView.layer.shadowOpacity = 1.0f; 37 | imageView.layer.shadowRadius = 10.0f; 38 | [self addSubview:imageView]; 39 | 40 | deleteBtn = [ UIButton buttonWithType: UIButtonTypeCustom ]; 41 | deleteBtn.frame = CGRectMake( frame.size.width-28, 0, 33, 33 ); 42 | // deleteBtn.hidden = YES; 43 | [ self addSubview:deleteBtn ]; 44 | 45 | [ deleteBtn retain ]; 46 | [ deleteBtn setImage:[ UIImage imageNamed:@"delete_icon" ] forState:UIControlStateNormal ] ; 47 | [ deleteBtn addTarget:self action:@selector(deletePressed:) forControlEvents:UIControlEventTouchUpInside ]; 48 | [ self addSubview:deleteBtn ]; 49 | 50 | self.userInteractionEnabled = YES; 51 | 52 | self.contentMode = UIViewContentModeScaleToFill; 53 | 54 | [ note addObserver:self forKeyPath:@"thumbnail" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:NULL]; 55 | 56 | return self; 57 | } 58 | 59 | 60 | -(void) setFocused:(BOOL) s { 61 | if ( s ){ 62 | deleteBtn.hidden = NO; 63 | } else { 64 | deleteBtn.hidden = YES; 65 | } 66 | } 67 | 68 | 69 | -(BOOL) focused { 70 | return ! deleteBtn.hidden; 71 | } 72 | 73 | 74 | -(void)deletePressed:(id)btn{ 75 | [ scroller deleteThumbnail:self ]; 76 | } 77 | 78 | 79 | -(void) setNote:(Note*)n { 80 | if ( n != note ){ 81 | [ note release ]; 82 | [ n retain ]; 83 | note=n; 84 | } 85 | imageView.image = [note thumbnail]; 86 | } 87 | 88 | 89 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 90 | [ scroller noteWasSelected: note ]; 91 | } 92 | 93 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 94 | if ( [ keyPath isEqual:@"thumbnail" ] ) { 95 | imageView.image = note.thumbnail; 96 | } 97 | } 98 | 99 | #pragma mark - 100 | #pragma mark Memory management 101 | 102 | - (void)dealloc { 103 | [ note removeObserver:self forKeyPath:@"thumbnail" ]; 104 | [ note release ]; 105 | [ deleteBtn release ]; 106 | [ imageView release ]; 107 | [ super dealloc ]; 108 | } 109 | 110 | @end 111 | 112 | -------------------------------------------------------------------------------- /Classes/Note.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Nathan Stitt on 11/10/10 3 | // Copyright 2011. 4 | // Distributed under the terms of the GNU General Public License version 3. 5 | 6 | // A Note is comprised of an image and an alarm. 7 | // Each note has it's own directory 8 | // It consists of a PNG image and a dictionary encoded into a plist 9 | 10 | #import 11 | #import 12 | 13 | @class Note; 14 | 15 | @interface NoteTextBlob : NSObject { 16 | NSString *text; 17 | CGRect frame; 18 | Note *note; 19 | } 20 | -(void)remove; 21 | @property (nonatomic,assign) Note* note; 22 | @property (retain,nonatomic) NSString *text; 23 | @property (nonatomic) CGRect frame; 24 | @end 25 | 26 | typedef enum { 27 | ALARM_QUICK_TIME_TYPE = 0, 28 | ALARM_ABS_TIME_TYPE = 1, 29 | ALARM_MAP_TYPE = 2 30 | } NoteAlarmType; 31 | 32 | typedef enum { 33 | SOUND_VOICE_TYPE, 34 | SOUND_SYSTEM_DEF_TYPE, 35 | SOUND_BELL_TYPE, 36 | SOUND_MELODY_TYPE, 37 | SOUND_CHIRP_TYPE, 38 | SOUND_ROBOT_TYPE, 39 | SOUND_TIMER_TYPE, 40 | SOUND_KLAXOM_TYPE, 41 | SOUND_TYPE_MAX 42 | } NoteSoundType; 43 | 44 | @interface Note : NSObject { 45 | NSMutableDictionary *plist; 46 | UIImage *image; 47 | UIImage *thumbnail; 48 | NSMutableArray *texts; 49 | NSString *directory; 50 | UILocalNotification *notification; 51 | NSUInteger index; 52 | } 53 | 54 | // we keep an internal cache so we don't have to reload 55 | // the PNGS all the time 56 | +(void)primeCache; 57 | 58 | // return a note either from the cache or by creating a new one 59 | // is not intended to be called directly, instead by NotesManager 60 | +(Note*)noteWithDirectory:(NSString*)dir; 61 | 62 | // save our plist to 'disk' 63 | -(void)save; 64 | 65 | // scedules the alarm 66 | -(void)scedule; 67 | 68 | // a thumbnail representation 69 | // of the image 70 | @property (nonatomic,retain) UIImage* thumbnail; 71 | 72 | // the actual drawing 73 | @property (retain, nonatomic) UIImage *image; 74 | 75 | // does this note have a UILocalNotification set yet? 76 | -(BOOL)hasNotification; 77 | 78 | // does this note have a coordinate set? 79 | -(BOOL)hasCoordinate; 80 | 81 | // set coordinate and entering/leaving geo based alarm 82 | -(void)setCoordinate:(CLLocationCoordinate2D)coordinate onEnterRegion:(BOOL)enter; 83 | -(void)unScedule; 84 | -(BOOL)onEnterRegion; 85 | -(CLLocationCoordinate2D)coordinate; 86 | 87 | // path for sound that should be played when alarm is fired 88 | // returns nil if default sound should be played 89 | -(NSString*)soundPath; 90 | 91 | // remove the note from storage and cache 92 | -(void)removeSelf; 93 | 94 | // the absolute path to the note's directory 95 | -(NSString*)fullDirectoryPath; 96 | 97 | -(NoteTextBlob*)addTextBlob; 98 | -(void)removeTextBlob:(NoteTextBlob*)blob; 99 | 100 | @property (readonly,nonatomic) NSArray *textBlobs; 101 | 102 | // the order that the note should appear in. 103 | // Is set by NotesManager 104 | @property (readonly, nonatomic ) NSUInteger index; 105 | 106 | // how was this alarm set 107 | @property (nonatomic) NoteAlarmType alarmTag; 108 | 109 | @property (nonatomic) NoteSoundType soundTag; 110 | 111 | // the title is what appears above the drawing & selector controllers 112 | @property ( readonly, nonatomic ) NSString* alarmTitle; 113 | 114 | // the type could be 'Half Hour', '3 Minutes', etc 115 | @property (assign, nonatomic ) NSString *alarmType; 116 | 117 | @property (nonatomic, readonly ) NSString *alarmText; 118 | 119 | @property (assign, nonatomic ) NSDate *fireDate; 120 | 121 | @property (retain, nonatomic) UILocalNotification *notification; 122 | 123 | @property (readonly, nonatomic) NSString *directory; 124 | 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /Classes/ColorButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // ColorButton.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "ColorButton.h" 19 | #import 20 | 21 | @implementation ColorButton 22 | 23 | @synthesize color,marked; 24 | 25 | - (id)initWithButtonColor:(UIColor*)c { 26 | self = [ super initWithFrame:CGRectMake(0, 0, 25, 25) ]; 27 | if ( ! self ) { 28 | return nil; 29 | } 30 | self.color = c; 31 | self.backgroundColor = [ UIColor clearColor ]; 32 | 33 | self.layer.shadowOffset = CGSizeMake(0.0f, 2.0f); 34 | self.layer.shadowOpacity = 1.5f; 35 | self.layer.shadowColor = [UIColor clearColor].CGColor; 36 | self.layer.shadowRadius = 2.5f; 37 | self.layer.anchorPoint = CGPointMake(0.5f, 0.5f); 38 | 39 | return self; 40 | } 41 | 42 | 43 | -(void)setColor:(UIColor*)c{ 44 | if ( color != c ) { 45 | [ c retain ]; 46 | [ color release ]; 47 | color = c; 48 | } 49 | [self setNeedsDisplay]; 50 | } 51 | 52 | -(void)setMarked:(BOOL)m { 53 | if ( m != marked ){ 54 | marked = m; 55 | if ( marked ){ 56 | self.frame = CGRectMake(self.frame.origin.x - 2, self.frame.origin.y - 2, 57 | self.frame.size.width+4, self.frame.size.height+4); 58 | self.layer.shadowColor = [UIColor blackColor].CGColor; 59 | 60 | } else { 61 | self.frame = CGRectMake(self.frame.origin.x + 2, self.frame.origin.y + 2, 62 | self.frame.size.width-4, self.frame.size.height-4); 63 | self.layer.shadowColor = [UIColor clearColor].CGColor; 64 | } 65 | [ self setNeedsDisplay ]; 66 | } 67 | } 68 | 69 | - (void)setBrushImage:(UIImage*)img { 70 | if ( img != image ){ 71 | [ image release ]; 72 | image = [img retain]; 73 | [ self setNeedsDisplay ]; 74 | } 75 | 76 | } 77 | 78 | - (void)drawRect:(CGRect)rect { 79 | 80 | 81 | CGContextRef context = UIGraphicsGetCurrentContext(); 82 | 83 | CGContextBeginPath(context); 84 | 85 | CGContextSetFillColorWithColor(context, color.CGColor ); 86 | NSInteger radius = self.frame.size.width / 2; 87 | CGContextMoveToPoint(context, CGRectGetMinX(rect) + self.frame.size.width, CGRectGetMinY(rect)); 88 | CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect) + radius, radius, 3 * M_PI / 2, 0, 0); 89 | CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect) - radius, radius, 0, M_PI / 2, 0); 90 | CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect) - radius, radius, M_PI / 2, M_PI, 0); 91 | CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) + radius, radius, M_PI, 3 * M_PI / 2, 0); 92 | 93 | CGContextClosePath(context); 94 | CGContextFillPath(context); 95 | 96 | if ( image ){ 97 | rect.size.height = rect.size.height - 4; 98 | rect.origin.y = rect.origin.y + 4; 99 | rect.origin.x = rect.origin.x + 3; 100 | [image drawInRect:rect]; 101 | } 102 | 103 | } 104 | 105 | - (void)dealloc { 106 | [ color release ]; 107 | [ super dealloc ]; 108 | } 109 | 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /Classes/NSDate+HumanInterval.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+HumanInterval.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | // The HumanInterval category adds a single method to 19 | // NSDate: humanIntervalFromNow 20 | // this method returns an english string listing the date interval 21 | // in an easy to read manner. 22 | 23 | #import "NSDate+HumanInterval.h" 24 | 25 | #define SECOND 1 26 | #define MINUTE ( 60 * SECOND ) 27 | #define HOUR ( 60 * MINUTE ) 28 | #define DAY ( 24 * HOUR ) 29 | #define WEEK ( 7 * DAY ) 30 | #define MONTH ( 30 * DAY ) 31 | #define YEAR ( 365 * DAY ) 32 | 33 | @implementation NSDate (HumanInterval) 34 | 35 | - (NSString *) humanIntervalFromNow { 36 | NSMutableArray *segments = [ NSMutableArray arrayWithCapacity:1 ]; 37 | int secs = [self timeIntervalSinceNow]; 38 | 39 | int delta = secs < 0 ? secs * -1 : secs; 40 | int remain = delta; 41 | 42 | if ( remain > 2 * YEAR) { 43 | [ segments addObject: [ NSString stringWithFormat:@"%u years", remain / YEAR ] ]; 44 | } else if ( remain > 1 * YEAR ){ 45 | [ segments addObject: [ NSString stringWithFormat:@"1 year" ] ]; 46 | } 47 | 48 | remain -= ( remain / YEAR ) * YEAR; 49 | 50 | if ( remain > 2 * MONTH ){ 51 | [ segments addObject: [ NSString stringWithFormat:@"%u months", remain / MONTH ] ]; 52 | } else if ( remain > 1 * MONTH ){ 53 | [ segments addObject: [ NSString stringWithFormat:@"1 month"] ]; 54 | } 55 | 56 | remain -= ( remain / MONTH ) * MONTH; 57 | 58 | if ( remain > 2 * DAY ){ 59 | [ segments addObject: [ NSString stringWithFormat:@"%u days", remain / DAY ] ]; 60 | } else if ( remain > 1 * DAY ){ 61 | [ segments addObject: [ NSString stringWithFormat:@"1 day"] ]; 62 | } 63 | 64 | remain -= ( remain / DAY ) * DAY; 65 | 66 | if ( delta < MONTH ){ 67 | if ( remain > 2 * HOUR ){ 68 | [ segments addObject: [ NSString stringWithFormat:@"%u hours", remain / HOUR ] ]; 69 | } else if ( remain > 1 * HOUR ){ 70 | [ segments addObject: [ NSString stringWithFormat:@"1 hour"] ]; 71 | } 72 | 73 | remain -= ( remain / HOUR ) * HOUR; 74 | 75 | if ( remain > 2 * MINUTE ){ 76 | [ segments addObject: [ NSString stringWithFormat:@"%u minutes", remain / MINUTE ] ]; 77 | } else if ( remain > 1 * MINUTE ) { 78 | [ segments addObject: [ NSString stringWithFormat:@"1 minute"] ]; 79 | } 80 | 81 | if ( delta < 10 * MINUTE ){ 82 | remain -= ( remain / MINUTE ) * MINUTE; 83 | if ( remain ){ 84 | [ segments addObject: [ NSString stringWithFormat:@"%u seconds", remain ] ]; 85 | } 86 | } 87 | } 88 | 89 | NSString *ret; 90 | if ( [ segments count ] > 1 ){ 91 | NSString *last = [ segments lastObject ]; 92 | [ segments removeLastObject ]; 93 | ret = [ NSString stringWithFormat:@"%@,%@", 94 | [ segments componentsJoinedByString:@"," ], 95 | last ]; 96 | } else if ( [ segments count ] ){ 97 | ret = [ segments lastObject ]; 98 | } else { 99 | ret = @"a few seconds"; 100 | } 101 | 102 | if ( delta > MONTH ){ 103 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 104 | [formatter setDateFormat:@"h:mm a"]; 105 | ret = [ NSString stringWithFormat:@"%@ %@", [formatter stringFromDate:self], ret ]; 106 | [ formatter release ]; 107 | } 108 | 109 | return [ NSString stringWithFormat:@"%@ %@", ret, 110 | secs < 0 ? @"ago" : @"from now" ]; 111 | } 112 | 113 | @end -------------------------------------------------------------------------------- /Classes/NoteSelectorController.m: -------------------------------------------------------------------------------- 1 | // 2 | // NoteSelectorController.m 3 | // 4 | // Created by Björn Sållarp on 7/14/10. 5 | // NO Copyright 2010 MightyLittle Industries. NO rights reserved. 6 | // 7 | // Use this code any way you like. If you do like it, please 8 | // link to my blog and/or write a friendly comment. Thank you! 9 | // 10 | // Read my blog @ http://blog.sallarp.com 11 | // 12 | 13 | #import "NoteSelectorController.h" 14 | #import "MainViewController.h" 15 | #import "NotesManager.h" 16 | #import "NoteThumbnailView.h" 17 | 18 | @implementation NoteSelectorController 19 | 20 | -(id) initWithMainView:(MainViewController*)mv { 21 | self = [ super init ]; 22 | if ( ! self ){ 23 | return nil; 24 | } 25 | mainView = mv; 26 | 27 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countChanged:) name:NOTES_COUNT_CHANGED_NOTICE object:nil]; 28 | 29 | return self; 30 | } 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | self.view.backgroundColor = [ UIColor grayColor ]; 35 | 36 | scroller = [ [NotesScrollView alloc] 37 | initWithController:self 38 | frame:CGRectMake(0, 40, 320, 320) ]; 39 | [ scroller setBackgroundColor: [ UIColor grayColor ] ]; 40 | 41 | noteHeader = [[ UILabel alloc ] initWithFrame:CGRectMake( 0, 0, 320, 40 ) ]; 42 | noteHeader.lineBreakMode = UILineBreakModeWordWrap; 43 | noteHeader.numberOfLines = 0; 44 | noteHeader.textColor = [ UIColor whiteColor ]; 45 | noteHeader.font = [ UIFont systemFontOfSize:18.0]; 46 | noteHeader.backgroundColor = [ UIColor clearColor ]; 47 | noteHeader.textAlignment = UITextAlignmentCenter; 48 | [ self.view addSubview:noteHeader ]; 49 | 50 | [self.view addSubview:scroller]; 51 | 52 | NoteThumbnailView *tn = [ scroller loadPage: 0 ]; 53 | tn.focused = YES; 54 | 55 | dots = [[ UIPageControl alloc ] init ]; 56 | dots.backgroundColor = [ UIColor grayColor ]; 57 | dots.frame = CGRectMake( 0, 360, 320, 30 ); 58 | dots.numberOfPages = [ NotesManager count ]; 59 | [dots addTarget:self action:@selector(dotsMoved:) forControlEvents:UIControlEventValueChanged]; 60 | 61 | [ self.view addSubview:dots ]; 62 | 63 | [ self pageChanged:0 ]; 64 | } 65 | 66 | 67 | -(void)reload { 68 | [ scroller reload ]; 69 | } 70 | 71 | 72 | -(void) selectNoteIndex:(NSInteger)index{ 73 | if ( index >= 0 && index <= dots.numberOfPages ){ 74 | [ scroller selectNoteIndex: index ]; 75 | dots.currentPage = index; 76 | } 77 | } 78 | 79 | -(NSUInteger)currentIndex { 80 | return dots.currentPage; 81 | } 82 | 83 | -(void)dotsMoved:(id)ctrl{ 84 | [ scroller selectNoteIndex: dots.currentPage ]; 85 | 86 | } 87 | 88 | -(void)countChanged:(NSNotification*)notif { 89 | dots.numberOfPages = [ NotesManager count ]; 90 | dots.currentPage = scroller.currentPage-1; 91 | Note *note = [ NotesManager noteAtIndex: dots.currentPage ]; 92 | noteHeader.text = [ note alarmTitle ]; 93 | } 94 | 95 | -(void)refresh { 96 | dots.numberOfPages = [ NotesManager count ]; 97 | dots.currentPage = 0; 98 | [ scroller reload ]; 99 | } 100 | 101 | 102 | -(void)deleteNote:(Note*)note newIndex:(NSUInteger)index{ 103 | dots.numberOfPages = dots.numberOfPages-1; 104 | dots.currentPage = index; 105 | [ scroller clear ]; 106 | [ scroller selectNoteIndex:index ]; 107 | } 108 | 109 | 110 | -(void) addNote:(Note*) note { 111 | [ self refresh ]; 112 | } 113 | 114 | 115 | 116 | -(void) noteWasSelected:(Note*)note{ 117 | [ mainView selectNote:note ]; 118 | } 119 | 120 | 121 | -(void)pageChanged:(NSInteger)noteIndex{ 122 | Note *note = [ NotesManager noteAtIndex:noteIndex]; 123 | noteHeader.text = [ note alarmTitle ]; 124 | dots.currentPage = noteIndex; 125 | } 126 | 127 | 128 | 129 | #pragma mark - 130 | #pragma mark PreviewScrollViewDelegate methods 131 | 132 | 133 | 134 | -(void)startScrolling{ 135 | noteHeader.hidden = YES; 136 | } 137 | 138 | -(void)endScrolling{ 139 | noteHeader.hidden = NO; 140 | } 141 | 142 | #pragma mark - 143 | #pragma mark Memory management 144 | 145 | - (void)didReceiveMemoryWarning { 146 | // Releases the view if it doesn't have a superview. 147 | [ super didReceiveMemoryWarning ]; 148 | 149 | // if we aren't shown, clear the scroller 150 | if ( ! self.view.superview ){ 151 | [ scroller clear ]; 152 | 153 | } 154 | } 155 | 156 | - (void)dealloc { 157 | [[NSNotificationCenter defaultCenter] removeObserver:self ]; 158 | [ scroller release]; 159 | [ super dealloc]; 160 | } 161 | 162 | @end 163 | -------------------------------------------------------------------------------- /Classes/PurchaseManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // InAppPurchaseManager.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "PurchaseManager.h" 19 | #import "NotesManager.h" 20 | 21 | @implementation PurchaseManager 22 | 23 | 24 | PurchaseManager *_instance; 25 | 26 | 27 | +(void)startup{ 28 | if ( ! _instance ){ 29 | _instance = [[PurchaseManager alloc] init ]; 30 | } 31 | } 32 | 33 | -(id)init { 34 | self = [ super init ]; 35 | [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; 36 | return self; 37 | } 38 | 39 | -(void)unlockReminders:(NSString*)productIdentifier{ 40 | if ( [ productIdentifier isEqualToString: LIMITED_PRODUCT_ID ] ) { 41 | [[ NotesManager instance ] upgradeAllowedNoteCount: NO ]; 42 | } else if ( [ productIdentifier isEqualToString: UNLIMITED_PRODUCT_ID ] || 43 | [ productIdentifier isEqualToString: PRIOR_TO_UNLIMITED_PRODUCT_ID ] ) { 44 | [[ NotesManager instance ] upgradeAllowedNoteCount: YES ]; 45 | } else { 46 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unknown Appstore Response" 47 | message:[ NSString stringWithFormat: @"Received an unknown response: %@, please report to IoGee Support", productIdentifier ] 48 | delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 49 | [alert show]; 50 | [alert release]; 51 | } 52 | } 53 | 54 | 55 | - (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful 56 | { 57 | // remove the transaction from the payment queue. 58 | [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; 59 | 60 | NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil]; 61 | if (wasSuccessful) { 62 | // send out a notification that we’ve finished the transaction 63 | [[NSNotificationCenter defaultCenter] postNotificationName:IN_APP_PURCHASE_MADE object:self userInfo:userInfo]; 64 | } else { 65 | // send out a notification for the failed transaction 66 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Purchase Error" 67 | message:@"Received an unknown error from Apple, please contact IoGee Support at help@iogee.com" 68 | delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 69 | [alert show]; 70 | [alert release]; 71 | } 72 | } 73 | 74 | 75 | - (void)completeTransaction:(SKPaymentTransaction *)transaction { 76 | [ self unlockReminders:transaction.payment.productIdentifier]; 77 | [ self finishTransaction:transaction wasSuccessful:YES]; 78 | } 79 | 80 | 81 | - (void)restoreTransaction:(SKPaymentTransaction *)transaction { 82 | [self unlockReminders:transaction.originalTransaction.payment.productIdentifier]; 83 | [self finishTransaction:transaction wasSuccessful:YES]; 84 | } 85 | 86 | 87 | 88 | 89 | - (void)failedTransaction:(SKPaymentTransaction *)transaction { 90 | if ( transaction.error.code != SKErrorPaymentCancelled ) { 91 | // error! 92 | [self finishTransaction:transaction wasSuccessful:NO]; 93 | } else { 94 | [[NSNotificationCenter defaultCenter] postNotificationName:IN_APP_PURCHASE_CANCELED object:self userInfo:NULL]; 95 | } 96 | } 97 | 98 | 99 | #pragma mark SKPaymentTransactionObserver methods 100 | 101 | 102 | - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{ 103 | for (SKPaymentTransaction *transaction in transactions) { 104 | switch (transaction.transactionState) { 105 | case SKPaymentTransactionStatePurchased: 106 | [self completeTransaction:transaction]; 107 | break; 108 | case SKPaymentTransactionStateFailed: 109 | [self failedTransaction:transaction]; 110 | break; 111 | case SKPaymentTransactionStateRestored: 112 | [self restoreTransaction:transaction]; 113 | break; 114 | default: 115 | break; 116 | } 117 | } 118 | } 119 | 120 | 121 | 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /Classes/DrawingTextBox.m: -------------------------------------------------------------------------------- 1 | 2 | #import "DrawingTextBox.h" 3 | #import 4 | #import "DrawingViewController.h" 5 | #import "NotesManager.h" 6 | 7 | #define ANIMATION_DURATION_SECONDS 0.5f 8 | 9 | @implementation DrawingTextBox 10 | 11 | - (id)initWithTextBlob:(NoteTextBlob*)n Controller:(DrawingViewController*)d { 12 | 13 | CGRect frame = CGRectEqualToRect(CGRectZero, n.frame) ? CGRectMake( 80, 30 * n.note.textBlobs.count, 160, 28 ) : n.frame; 14 | 15 | if ( ( self = [self initWithFrame: frame ]) ) { 16 | ntb = n; 17 | dvc = d; 18 | [ ntb retain ]; 19 | 20 | deleteBtn = [ UIButton buttonWithType: UIButtonTypeCustom ]; 21 | [ deleteBtn retain ]; 22 | deleteBtn.frame = CGRectMake( frame.size.width-24, 0, 65, 65 ); 23 | [ deleteBtn setImage:[ UIImage imageNamed:@"delete_icon" ] forState:UIControlStateNormal ] ; 24 | [ deleteBtn addTarget:self action:@selector(deletePressed:) forControlEvents:UIControlEventTouchUpInside ]; 25 | 26 | self.internalTextView.userInteractionEnabled = NO; 27 | self.internalTextView.font = [ UIFont systemFontOfSize: 22 ]; 28 | self.internalTextView.textAlignment = UITextAlignmentCenter; 29 | self.maxNumberOfLines = 20; 30 | self.minNumberOfLines = 1; 31 | 32 | self.internalTextView.backgroundColor = [ UIColor clearColor ]; 33 | self.layer.borderWidth = 1.0; 34 | self.layer.cornerRadius =10; 35 | [ self.layer setBorderColor: [[UIColor grayColor] CGColor]]; 36 | [ self.layer setBorderWidth:2.75]; 37 | self.backgroundColor = [ UIColor whiteColor ]; 38 | self.opaque = NO; 39 | 40 | self.text = ntb.text; 41 | self.animateHeightChange = YES; 42 | [ self textViewDidChange:self.internalTextView ]; 43 | self.animateHeightChange = NO; 44 | } 45 | return self; 46 | } 47 | 48 | -(void)deletePressed:(id)sel { 49 | [ dvc removeText: self ]; 50 | [ ntb remove ]; 51 | } 52 | 53 | 54 | 55 | - (void)liftUp { 56 | 57 | [self setAlpha:1]; 58 | [[self layer] setShadowColor:[UIColor blackColor].CGColor]; 59 | [[self layer] setShadowOpacity:1.0f]; 60 | [[self layer] setShadowRadius:6.0f]; 61 | [[self layer] setShadowOffset:CGSizeMake(0, 3)]; 62 | 63 | } 64 | 65 | -(void)drop { 66 | 67 | ntb.frame = self.frame; 68 | 69 | } 70 | 71 | 72 | #define KEYBOARD_SIZE 200 73 | 74 | -(BOOL)isEditing{ 75 | return self.isEditable; 76 | } 77 | 78 | -(void)showDelButton { 79 | CGRect frame = CGRectMake( self.frame.origin.x+self.frame.size.width-14, self.frame.origin.y-10, 30, 30 ); 80 | [UIView animateWithDuration:ANIMATION_DURATION_SECONDS 81 | animations:^{ deleteBtn.frame = frame; } 82 | completion:^(BOOL finished) 83 | { [ self.superview addSubview: deleteBtn ]; } ]; 84 | } 85 | 86 | -(void) setIsEditing:(BOOL)v { 87 | if ( v ){ 88 | if ( ( self.frame.origin.y + self.frame.size.height ) > KEYBOARD_SIZE ){ 89 | displacedFrom = self.center; 90 | CGRect f = self.frame; 91 | f.origin.y = 100; 92 | [UIView animateWithDuration:ANIMATION_DURATION_SECONDS 93 | animations:^{ self.frame = f; } 94 | completion:^(BOOL finished) 95 | { [ self showDelButton ]; }]; 96 | } else { 97 | 98 | [ self showDelButton ]; 99 | 100 | } 101 | 102 | self.internalTextView.userInteractionEnabled = YES; 103 | [ self.internalTextView becomeFirstResponder ]; 104 | } else { 105 | if ( ! CGPointEqualToPoint(CGPointZero, displacedFrom ) ){ 106 | 107 | [UIView animateWithDuration:ANIMATION_DURATION_SECONDS 108 | animations:^{ self.center = displacedFrom; } 109 | completion:^(BOOL finished){ } ]; 110 | 111 | } 112 | [ self.internalTextView resignFirstResponder ]; 113 | self.internalTextView.userInteractionEnabled = NO; 114 | ntb.text = self.text; 115 | [ self drop ]; 116 | [ deleteBtn removeFromSuperview ]; 117 | [[self layer] setShadowColor:[UIColor clearColor].CGColor]; 118 | [[self layer] setShadowRadius:0.0f]; 119 | [[self layer] setShadowOffset:CGSizeMake(0, 0)]; 120 | } 121 | } 122 | 123 | -(void)moveTo:(CGPoint)point{ 124 | self.center = point; 125 | } 126 | 127 | 128 | -(void)moveToAndDrop:(CGPoint)point { 129 | [UIView beginAnimations:nil context:NULL]; 130 | [UIView setAnimationDuration: ANIMATION_DURATION_SECONDS]; 131 | self.center = point; 132 | [UIView commitAnimations]; 133 | 134 | [ self drop ]; 135 | 136 | [self setAlpha:1]; 137 | [[self layer] setMasksToBounds:NO]; 138 | [[self layer] setShadowColor:[UIColor clearColor].CGColor]; 139 | [[self layer] setShadowOpacity:1.0f]; 140 | [[self layer] setShadowRadius:0.0f]; 141 | [[self layer] setShadowOffset:CGSizeMake(0, 0)]; 142 | } 143 | 144 | 145 | 146 | - (void)dealloc { 147 | [ ntb release ]; 148 | [ deleteBtn removeFromSuperview ]; 149 | [ deleteBtn release ]; 150 | [placardImage release]; 151 | [currentDisplayString release]; 152 | [displayStrings release]; 153 | [super dealloc]; 154 | } 155 | 156 | 157 | 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /Classes/AlarmMapView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MapView.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/23/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AlarmMapView.h" 10 | #import "AlarmPopUpController.h" 11 | #import "LocationAlarmManager.h" 12 | #import "ToggleButton.h" 13 | #import 14 | 15 | @interface AlarmMapView() 16 | @property (nonatomic,retain) MKCircle* circle; 17 | @end 18 | 19 | @implementation AlarmMapView 20 | 21 | @synthesize map, circle; 22 | 23 | -(id)initWithAlarmView:(AlarmPopUpController*)view frame:(CGRect)frame { 24 | self = [ super init ]; 25 | if ( ! self ){ 26 | return nil; 27 | } 28 | 29 | map = [[MKMapView alloc] initWithFrame: frame ]; 30 | map.mapType = MKMapTypeStandard; 31 | map.showsUserLocation = YES; 32 | map.delegate=self; 33 | map.layer.cornerRadius = 20.0f; 34 | pin = [[ AlarmAnnotationPin alloc ] initWithMap:self ]; 35 | [ map addAnnotation: pin.annotation ]; 36 | 37 | self.circle = [MKCircle circleWithCenterCoordinate: map.userLocation.coordinate radius:ALARM_METER_RADIUS]; 38 | [map addOverlay:circle]; 39 | 40 | [ self.map.userLocation addObserver:self forKeyPath:@"location" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) 41 | context:NULL]; 42 | 43 | return self; 44 | 45 | } 46 | 47 | 48 | -(void)moveTo:(CLLocationCoordinate2D)coord { 49 | 50 | // pin.onEnter = NO; 51 | pin.annotation.coordinate = coord; 52 | MKCoordinateRegion region; 53 | region.center = coord; 54 | region.span.longitudeDelta = 0.08; 55 | region.span.latitudeDelta = 0.08; 56 | map.region = region; 57 | if ( ! map.selectedAnnotations.count ){ 58 | [ map selectAnnotation:pin.annotation animated:YES ]; 59 | } 60 | [ map removeOverlays:[map overlays ]]; 61 | 62 | self.circle = [MKCircle circleWithCenterCoordinate: pin.annotation.coordinate radius:ALARM_METER_RADIUS]; 63 | [map addOverlay:self.circle]; 64 | } 65 | 66 | 67 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 68 | if (! dirty && self.map.userLocation.location ){ 69 | [ self moveTo: self.map.userLocation.location.coordinate ]; 70 | dirty = YES; 71 | } 72 | } 73 | 74 | 75 | -(void) reset { 76 | dirty = NO; 77 | if ( map.userLocation.location ){ 78 | [ self moveTo: map.userLocation.location.coordinate ]; 79 | } 80 | pin.onEnter = NO; 81 | [ map deselectAnnotation: pin.annotation animated: NO ]; 82 | [ map selectAnnotation: pin.annotation animated:NO ]; 83 | } 84 | 85 | 86 | -(UIView*)view { 87 | return map; 88 | } 89 | 90 | 91 | -(void)setFromNote:(Note*)note{ 92 | if ( [ note hasCoordinate ] ){ 93 | dirty = YES; 94 | [ self moveTo: note.coordinate ]; 95 | pin.onEnter = note.onEnterRegion; 96 | } 97 | } 98 | 99 | 100 | -(void)saveToNote:(Note*)note{ 101 | note.alarmTag = 2; 102 | note.alarmType = @"Geographical Region"; 103 | [ note setCoordinate: pin.annotation.coordinate onEnterRegion: pin.onEnter ]; 104 | } 105 | 106 | 107 | - (void)dealloc { 108 | [ circle release ]; 109 | [ map release ]; 110 | [super dealloc]; 111 | } 112 | 113 | 114 | #pragma mark - 115 | #pragma mark CLLocationManagerDelegate 116 | 117 | 118 | -(void)onLocationUpdate:(NSNotification*)n { 119 | if (! dirty ){ 120 | [ self moveTo: ((CLLocation*)n.object).coordinate ]; 121 | } 122 | } 123 | 124 | 125 | #pragma mark - 126 | #pragma mark MKMapViewDelegate 127 | 128 | -(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay{ 129 | MKCircleView* circleView = [[MKCircleView alloc] initWithOverlay:overlay]; 130 | circleView.strokeColor = [UIColor darkGrayColor]; 131 | circleView.lineWidth = 1.0; 132 | circleView.fillColor = [UIColor lightGrayColor]; 133 | circleView.alpha= 0.6f; 134 | return [ circleView autorelease ]; 135 | } 136 | 137 | - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id )a { 138 | if ([ a isKindOfClass:[MKUserLocation class]]){ 139 | return nil; 140 | } else { 141 | return pin; 142 | } 143 | } 144 | 145 | -(void) didChangeDragState:(MKAnnotationViewDragState)newDragState fromOldState:(MKAnnotationViewDragState)dragState{ 146 | dirty = YES; 147 | if ( MKAnnotationViewDragStateStarting == newDragState ){ 148 | [ map removeOverlays:[map overlays ]]; 149 | } else if ( MKAnnotationViewDragStateEnding == newDragState || MKAnnotationViewDragStateCanceling == newDragState ){ 150 | self.circle = [MKCircle circleWithCenterCoordinate: pin.annotation.coordinate radius: ALARM_METER_RADIUS ]; 151 | 152 | pin.onEnter = ! ( ALARM_METER_RADIUS > MKMetersBetweenMapPoints(MKMapPointForCoordinate( pin.annotation.coordinate ), 153 | MKMapPointForCoordinate( map.userLocation.location.coordinate ) ) ); 154 | 155 | [ map addOverlay:self.circle ]; 156 | [ map selectAnnotation: pin.annotation animated:YES ]; 157 | } 158 | } 159 | 160 | -(void)setHidden:(BOOL)v{ 161 | map.hidden = v; 162 | } 163 | 164 | -(BOOL)hidden { 165 | return map.hidden; 166 | } 167 | 168 | 169 | @end 170 | -------------------------------------------------------------------------------- /Classes/AlarmSounds.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmSoundsView.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/20/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "AlarmSounds.h" 10 | #import "AlarmPopUpController.h" 11 | #import 12 | #import "ToggleButton.h" 13 | @implementation AlarmSounds 14 | 15 | -(id)initWithAlarmView:(AlarmPopUpController*)view 16 | { 17 | self = [super initWithStyle: UITableViewStyleGrouped ]; 18 | if (self) { 19 | snd = [ [NSUserDefaults standardUserDefaults] integerForKey:@"lastSoundSelected" ]; 20 | } 21 | return self; 22 | } 23 | 24 | -(void)viewDidLoad { 25 | [ super viewDidLoad ]; 26 | self.view.backgroundColor = [ UIColor blackColor ]; 27 | self.tableView.alwaysBounceVertical = NO; 28 | } 29 | 30 | -(void) setFromNote:(Note*)n { 31 | snd = n.soundTag; 32 | } 33 | 34 | -(void) saveToNote: (Note*)note{ 35 | note.soundTag = snd; 36 | } 37 | 38 | - (void)dealloc 39 | { 40 | [ player release ]; 41 | [super dealloc]; 42 | } 43 | 44 | 45 | 46 | 47 | 48 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 49 | return 1; 50 | } 51 | 52 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 53 | return 0.0; 54 | } 55 | 56 | // Customize the number of rows in the table view. 57 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 58 | return SOUND_TYPE_MAX; 59 | } 60 | 61 | 62 | 63 | - (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath { 64 | return 36.0; 65 | } 66 | 67 | 68 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 69 | snd = indexPath.row; 70 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 71 | [ prefs setValue: [NSNumber numberWithInt: snd ] forKey:@"lastSoundSelected" ]; 72 | [ prefs synchronize ]; 73 | [ tableView reloadData ]; 74 | } 75 | 76 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag{ 77 | playingBtn.selectedIndex=0; 78 | playingBtn = nil; 79 | [ player release ]; 80 | player = nil; 81 | } 82 | 83 | -(void)playSound:(ToggleButton*)btn { 84 | UITableViewCell *cell = ( (UITableViewCell*) btn.superview.superview ); 85 | NSIndexPath *indexPath = [ self.tableView indexPathForCell:cell ]; 86 | 87 | // if ( indexPath.row > 0 ){ 88 | NSURL *url = [NSURL fileURLWithPath: [[NSBundle mainBundle] pathForResource: 89 | [ NSString stringWithFormat:@"%d", indexPath.row ] ofType:@"caf"] ]; 90 | if ( player ){ 91 | [ player stop ]; 92 | [ player release ]; 93 | player = nil; 94 | playingBtn.selectedIndex = 0; 95 | } 96 | if ( playingBtn == btn ) { 97 | playingBtn = nil; 98 | } else { 99 | player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL]; 100 | player.delegate = self; 101 | [ player play ]; 102 | playingBtn = btn; 103 | } 104 | 105 | // } 106 | 107 | 108 | } 109 | 110 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 111 | UITableViewCell *cell = [ tableView dequeueReusableCellWithIdentifier:@"SoundsCell" ]; 112 | UILabel *label; 113 | if (cell == nil) { 114 | cell = [[[ UITableViewCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: @"SoundsCell" ] autorelease]; 115 | ToggleButton *btn = [ [ ToggleButton alloc ] initWithImages:[ NSArray arrayWithObjects: 116 | [UIImage imageNamed:@"play.png"], 117 | [UIImage imageNamed:@"stop.png"], 118 | nil ] 119 | Frame:CGRectMake( 8, 3, 30, 30) ]; 120 | 121 | [ btn addTarget:self action:@selector(playSound:) forControlEvents: UIControlEventTouchUpInside ]; 122 | [ cell.contentView addSubview: btn ]; 123 | [ btn release ]; 124 | label = [[[ UILabel alloc ] initWithFrame:CGRectMake(45, 0, 200, 30) ] autorelease]; 125 | [ label setBackgroundColor:[UIColor clearColor] ]; 126 | [ cell.contentView addSubview:label ]; 127 | } else { 128 | label = [cell.contentView.subviews objectAtIndex:1 ]; 129 | } 130 | cell.accessoryType = snd == indexPath.row ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; 131 | cell.tag = indexPath.row; 132 | switch ( indexPath.row ) { 133 | case SOUND_VOICE_TYPE: 134 | label.text = @"Spoken"; 135 | break; 136 | case SOUND_SYSTEM_DEF_TYPE: 137 | label.text = @"System Default"; 138 | break; 139 | case SOUND_BELL_TYPE: 140 | label.text = @"Bell"; 141 | break; 142 | case SOUND_MELODY_TYPE: 143 | label.text = @"Melody"; 144 | break; 145 | case SOUND_CHIRP_TYPE: 146 | label.text = @"Chirp Chrip"; 147 | break; 148 | case SOUND_ROBOT_TYPE: 149 | label.text = @"Computer Bloop"; 150 | break; 151 | case SOUND_TIMER_TYPE: 152 | label.text = @"Electronic Timer"; 153 | break; 154 | case SOUND_KLAXOM_TYPE: 155 | label.text = @"Klaxon"; 156 | break; 157 | default: 158 | break; 159 | } 160 | 161 | return cell; 162 | } 163 | 164 | @end 165 | -------------------------------------------------------------------------------- /Classes/MainViewController.m: -------------------------------------------------------------------------------- 1 | /* This file is part of Remindly. 2 | 3 | Remindly is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, version 3. 6 | 7 | Remindly is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with Remindly. If not, see . 14 | */ 15 | 16 | #import "MainViewController.h" 17 | #import "AlarmPopUpController.h" 18 | #import "ColorButton.h" 19 | #import "DrawingViewController.h" 20 | #import "NotesManager.h" 21 | #import "StoreView.h" 22 | #import "NoteSelectorController.h" 23 | #import "DrawingPaletteController.h" 24 | 25 | 26 | @implementation MainViewController 27 | 28 | @synthesize drawing,selector,alarm,drawTools; 29 | 30 | - (id)init { 31 | self = [super init ]; 32 | 33 | selector = [[ NoteSelectorController alloc ] initWithMainView:self ]; 34 | 35 | drawing = [[ DrawingViewController alloc ] initWithMainView:self ]; 36 | drawing.view.frame = CGRectMake(0, 0, 320, 420 ); 37 | //drawing.note = [ NotesManager noteAtIndex: 0 ]; 38 | 39 | drawTools = [[DrawingPaletteController alloc] init ]; 40 | 41 | toolbar = [[MainToolBar alloc] initWithController:self]; 42 | [ drawing.alarmTitle addTarget:toolbar action:@selector(setAlarmPressed:) forControlEvents:UIControlEventTouchUpInside ]; 43 | 44 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onDisplayNote:) name:@"DisplayNote" object:nil]; 45 | 46 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onIdle:) name:@"onIdle" object:nil]; 47 | 48 | self.view.backgroundColor = [ UIColor grayColor ]; 49 | 50 | return self; 51 | } 52 | 53 | 54 | -(void)loadView { 55 | self.view = [ [ UIView alloc ] initWithFrame:CGRectMake(0, 0, 320, 480) ]; 56 | [ self.view addSubview: drawing.view ]; 57 | [ self.view addSubview: toolbar ]; 58 | } 59 | 60 | -(BOOL)isAlarmShowing { 61 | return ( alarm && [ alarm isShowing ] ); 62 | } 63 | 64 | -(void)setIsAlarmShowing:(BOOL)v{ 65 | if ( v && ! alarm ){ 66 | alarm = [[ AlarmPopUpController alloc ] init ]; 67 | [ self.view addSubview: alarm.view ]; 68 | } 69 | if ( ! v && alarm.isShowing ){ 70 | alarm.isShowing = NO; 71 | } else if ( v ) { 72 | [ alarm showWithNote: drawing.unSavedNote ]; 73 | } 74 | } 75 | 76 | 77 | -(void)setIsDrawToolsShowing:(BOOL)v{ 78 | if ( ! drawTools.isViewLoaded ){ 79 | [ self.view insertSubview: drawTools.view belowSubview: toolbar ]; 80 | } 81 | drawTools.isShowing = v; 82 | } 83 | 84 | -(BOOL)isDrawToolsShowing { 85 | return [ drawTools isShowing ]; 86 | } 87 | 88 | -(void) setDrawingMode:(BOOL)v { 89 | if ( v ){ 90 | drawing.note = [ NotesManager noteAtIndex: [ selector currentIndex ] ]; 91 | 92 | if ( [ selector isViewLoaded ] ){ 93 | [ selector.view removeFromSuperview ]; 94 | } 95 | drawing.view.hidden = NO; 96 | } else { 97 | Note *note = drawing.note; 98 | [ self.view insertSubview:selector.view belowSubview: drawing.view ]; 99 | drawing.view.hidden = YES; 100 | [ selector reload ]; 101 | [ selector selectNoteIndex: note.index ]; 102 | } 103 | [ toolbar setDrawingMode:v ]; 104 | } 105 | 106 | 107 | -(BOOL) drawingMode { 108 | return ! drawing.view.hidden; 109 | } 110 | 111 | 112 | -(void) toggleDrawingMode { 113 | self.drawingMode = ! self.drawingMode; 114 | } 115 | 116 | 117 | -(void) selectNote:(Note*)note{ 118 | drawing.note = note; 119 | if ( ! [ self drawingMode ] ){ 120 | [ self setDrawingMode: YES ]; 121 | } 122 | } 123 | 124 | -(void)onIdle:(NSNotification*)notif{ 125 | if ( ! alarm ){ 126 | alarm = [[ AlarmPopUpController alloc ] init ]; 127 | alarm.view.frame = CGRectMake(0, 480, 320, 400); 128 | [ self.view addSubview: alarm.view ]; 129 | } 130 | } 131 | 132 | -(void)onDisplayNote:(NSNotification*)notif{ 133 | [ self selectNote:(Note*)notif.object ]; 134 | } 135 | 136 | 137 | -(void)viewWillAppear:(BOOL)animated{ 138 | [ super viewWillAppear:animated ]; 139 | 140 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 141 | NSNumber *index =[ prefs objectForKey:@"lastIndexEdited" ]; 142 | if ( [index intValue] >= [ NotesManager count ] ){ 143 | index = [ NSNumber numberWithInt: [ NotesManager count ] - 1 ]; 144 | } 145 | [ drawing viewWillAppear:animated ]; 146 | drawing.view.hidden = NO; 147 | drawing.note = [ NotesManager noteAtIndex: [ index intValue ] ]; 148 | 149 | NSNotification *note = [NSNotification notificationWithName: @"onIdle" object: self]; 150 | [[NSNotificationQueue defaultQueue] enqueueNotification: note 151 | postingStyle: NSPostWhenIdle 152 | coalesceMask: NSNotificationCoalescingOnName | NSNotificationCoalescingOnSender 153 | forModes: nil ]; 154 | } 155 | 156 | 157 | -(void)viewWillDisappear:(BOOL)animated{ 158 | [ super viewWillDisappear:animated ]; 159 | Note *note = drawing.note; 160 | [note save]; 161 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 162 | [ prefs setObject:[ NSNumber numberWithInt: note.index ] forKey:@"lastIndexEdited" ]; 163 | [ prefs synchronize ]; 164 | } 165 | 166 | 167 | - (void)dealloc { 168 | [ toolbar release ]; 169 | [ selector release ]; 170 | [ drawing release ]; 171 | [super dealloc]; 172 | } 173 | 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /Classes/DrawingPaletteController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DrawingToolsPanel.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 3/1/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "DrawingPaletteController.h" 10 | #import 11 | #import "ColorButton.h" 12 | #import "UIColor+Expanded.h" 13 | #import "DrawingPaletteTool.h" 14 | #import "DrawingPaletteView.h" 15 | 16 | @implementation DrawingPaletteController 17 | 18 | @synthesize color,tool; 19 | 20 | -(void)makeButton:(NSString*)c{ 21 | UIColor *cl = [UIColor colorWithName:c]; 22 | ColorButton *b = [[ ColorButton alloc ] initWithButtonColor: cl ]; 23 | b.frame = buttonFrame; 24 | [ b addTarget:self action:@selector(colorSelected:) forControlEvents:UIControlEventTouchUpInside ]; 25 | [ self.view addSubview: b ]; 26 | [ colorButtons addObject:b ]; 27 | [ b release ]; 28 | } 29 | 30 | -(void)makeTopButton:(NSString*)c{ 31 | [ self makeButton:c ]; 32 | buttonFrame.origin.x += buttonFrame.size.width+10; 33 | } 34 | 35 | -(id)init { 36 | self = [ super init ]; 37 | if ( ! self ){ 38 | return nil; 39 | } 40 | self.color = [ UIColor colorWithHexString:[ [NSUserDefaults standardUserDefaults] stringForKey:@"lastColorUsed" ] ]; 41 | tools = [ NSArray arrayWithObjects: 42 | [ DrawingPaletteTool withImage: [ UIImage imageNamed:@"brush_small_picker" ] frame: CGRectMake(230, 50, 45,70) ], 43 | [ DrawingPaletteTool withImage: [ UIImage imageNamed:@"brush_medium_picker" ] frame: CGRectMake(170, 50, 45,70) ], 44 | [ DrawingPaletteTool withImage: [ UIImage imageNamed:@"brush_large_picker" ] frame: CGRectMake(110, 50, 45,70) ], 45 | [ DrawingPaletteTool withImage: [ UIImage imageNamed:@"brush_xlarge_picker" ] frame: CGRectMake(50, 50, 45,70) ], 46 | NULL 47 | ]; 48 | [tools retain]; 49 | 50 | NSInteger w=0; 51 | for (DrawingPaletteTool *b in tools ){ 52 | b.drawingWidth = ( w * 4 ) + 1; 53 | b.tag = w; 54 | w+=1; 55 | } 56 | 57 | NSInteger tindex = [ [NSUserDefaults standardUserDefaults] integerForKey: @"lastToolSelected" ]; 58 | if ( tindex < [ tools count ] ){ 59 | tool = [tools objectAtIndex:tindex ]; 60 | } 61 | 62 | return self; 63 | } 64 | 65 | -(void)loadView { 66 | DrawingPaletteView *dpt = [[DrawingPaletteView alloc ] initWithFrame:CGRectMake(0, 480, 320, 320)]; 67 | self.view = dpt; 68 | 69 | buttonFrame = CGRectMake( 26, 20, 25, 25); 70 | 71 | colorButtons = [[ NSMutableArray alloc ] init ]; 72 | 73 | [ self makeTopButton: @"black" ]; 74 | [ self makeTopButton: @"beige" ]; 75 | [ self makeTopButton: @"aqua" ]; 76 | [ self makeTopButton: @"blue"]; 77 | [ self makeTopButton: @"blueviolet" ]; 78 | [ self makeTopButton: @"brown" ]; 79 | [ self makeTopButton: @"burlywood" ]; 80 | [ self makeTopButton: @"cadetblue" ]; 81 | 82 | buttonFrame = CGRectMake( 7, 50, 25, 25); 83 | [ self makeButton: @"chartreuse" ]; 84 | 85 | buttonFrame = CGRectMake( 7, 85, 25, 25); 86 | [ self makeButton: @"chocolate" ]; 87 | 88 | buttonFrame = CGRectMake( 7, 128, 25, 25); 89 | [ self makeButton: @"coral" ]; 90 | 91 | [ self makeTopButton: @"cornflowerblue" ]; 92 | [ self makeTopButton: @"crimson" ]; 93 | [ self makeTopButton: @"darkblue" ]; 94 | [ self makeTopButton: @"darkgray" ]; 95 | [ self makeTopButton: @"darkgreen" ]; 96 | [ self makeTopButton: @"navy" ]; 97 | [ self makeTopButton: @"mediumpurple" ]; 98 | [ self makeTopButton: @"olive" ]; 99 | [ self makeTopButton: @"yellow" ]; 100 | 101 | buttonFrame = CGRectMake( 285, 50, 25, 25); 102 | [ self makeTopButton: @"tomato" ]; 103 | 104 | buttonFrame = CGRectMake( 285, 85, 25, 25); 105 | [ self makeTopButton: @"powderblue" ]; 106 | 107 | 108 | for ( ColorButton *cb in colorButtons ){ 109 | if ( [self.color isEqual: cb.color ] ){ 110 | cb.marked = YES; 111 | } else { 112 | cb.marked = NO; 113 | } 114 | } 115 | 116 | for (DrawingPaletteTool *b in tools ){ 117 | [ self.view addSubview: b ]; 118 | b.selected = NO; 119 | [ b addTarget:self action:@selector(toolSelected:) forControlEvents:UIControlEventTouchUpInside ]; 120 | } 121 | 122 | tool.selected = YES; 123 | } 124 | 125 | -(void)toolSelected:(DrawingPaletteTool*)t{ 126 | if ( t == tool ){ 127 | return; 128 | } 129 | for (DrawingPaletteTool *b in tools ){ 130 | b.selected = NO; 131 | } 132 | self.tool = t; 133 | tool.selected = YES; 134 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 135 | [ prefs setValue: [NSNumber numberWithInt: tool.tag ] forKey:@"lastToolSelected" ]; 136 | [ prefs synchronize ]; 137 | } 138 | 139 | -(void)colorSelected:(ColorButton*)cv{ 140 | self.color = cv.color; 141 | NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; 142 | [ prefs setValue:[ self.color hexStringFromColor] forKey:@"lastColorUsed" ]; 143 | [ prefs synchronize ]; 144 | for ( ColorButton *cb in colorButtons ){ 145 | cb.marked = NO; 146 | } 147 | cv.marked = YES; 148 | } 149 | 150 | 151 | -(void)setIsShowing:(BOOL)v { 152 | CGRect frame = self.view.frame; 153 | 154 | if ( v ){ 155 | frame.origin.y = 250; 156 | } else { 157 | frame.origin.y = 480; 158 | } 159 | [UIView animateWithDuration:0.4f animations:^{ self.view.frame = frame; } 160 | completion:^ (BOOL finished) { } ]; 161 | 162 | } 163 | 164 | 165 | -(BOOL)isShowing{ 166 | return ( self.isViewLoaded && self.view.frame.origin.y < 420 ); 167 | } 168 | 169 | 170 | - (void)dealloc 171 | { 172 | [ colorButtons release ]; 173 | [super dealloc]; 174 | } 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /Classes/AlarmQuickTimes.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmQuickTImes.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | 19 | #import "AlarmQuickTImes.h" 20 | #import "AlarmPopUpController.h" 21 | #import "Note.h" 22 | 23 | @implementation AlarmQuickTimes 24 | 25 | @synthesize view=picker; 26 | 27 | -(id)initWithAlarmView:(AlarmPopUpController*)view frame:(CGRect)frame { 28 | self = [ super init ]; 29 | if ( ! self ){ 30 | return nil; 31 | } 32 | 33 | alarmView = view; 34 | picker = [[UIPickerView alloc] initWithFrame: frame ]; 35 | picker.delegate = self; 36 | picker.showsSelectionIndicator = YES; 37 | picker.dataSource = self; 38 | 39 | NSString *plist = [ [[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"alarm_times.plist"]; 40 | choicesTimes = [ [ NSMutableDictionary alloc] initWithContentsOfFile: plist ]; 41 | [ choicesTimes retain ]; 42 | quickChoices = [ choicesTimes keysSortedByValueUsingSelector:@selector(compare:)]; 43 | [ quickChoices retain ]; 44 | 45 | picker.showsSelectionIndicator = NO; 46 | 47 | // Resize the picker, rotate it so that it is horizontal and set its position 48 | // I saw this technique explained somewhere, stackoverflow?, can't find it now :( 49 | // sorry for not crediting you, unknown smart person! 50 | CGAffineTransform rotate = CGAffineTransformMakeRotation(-3.14/2); //horizontal angle -pi/2 51 | rotate = CGAffineTransformScale(rotate, 1, 1.50); 52 | CGAffineTransform t0 = CGAffineTransformMakeTranslation(1, -40.5);// (x,y) position 53 | picker.transform = CGAffineTransformConcat(rotate,t0); 54 | 55 | 56 | return self; 57 | } 58 | 59 | -(void)selectBlank { 60 | [ picker selectRow:0 inComponent:0 animated:YES ]; 61 | } 62 | 63 | - (BOOL) isSet { 64 | return ( [ picker selectedRowInComponent:0 ] > 0 ); 65 | } 66 | 67 | -(void)reset { 68 | [ picker selectRow:4 inComponent:0 animated:YES ]; 69 | } 70 | 71 | -(void)saveToNote:(Note*)note{ 72 | note.alarmType = [ quickChoices objectAtIndex:[ picker selectedRowInComponent:0 ] ]; 73 | note.alarmTag = 0; 74 | note.fireDate = [ self date ]; 75 | } 76 | 77 | 78 | -(void)setFromNote:(Note*)note{ 79 | if ( note.alarmType ){ 80 | [ picker selectRow:[ quickChoices indexOfObject: note.alarmType ] inComponent:0 animated:NO ]; 81 | } 82 | } 83 | 84 | 85 | -(BOOL)hasDateType:(NSString*)name{ 86 | NSInteger indx = [ quickChoices indexOfObject: name ]; 87 | return ( NSNotFound != indx ); 88 | } 89 | 90 | 91 | -(NSDate*)date{ 92 | NSInteger selIndex = [ picker selectedRowInComponent:0 ]; 93 | if ( ! selIndex ){ 94 | selIndex = 1; 95 | } 96 | NSNumber *minutes = [ choicesTimes valueForKey: [ quickChoices objectAtIndex: selIndex] ]; 97 | if ( 51 == [ minutes intValue] ){ 98 | NSDate *now = [ NSDate date ]; 99 | NSDateComponents *components = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:now]; 100 | return [ now dateByAddingTimeInterval: (( 60 - [components minute] )*60) ]; 101 | } else if ( ! [ minutes boolValue ] ){ 102 | return NULL; 103 | } else { 104 | return [ NSDate dateWithTimeIntervalSinceNow: [ minutes intValue ] * 60 ]; 105 | } 106 | } 107 | 108 | 109 | 110 | - (void)dealloc { 111 | [ picker release ]; 112 | [ super dealloc ]; 113 | } 114 | 115 | #pragma mark PickerViewController delegate methods 116 | 117 | -(UIView *) pickerView:(UIPickerView *)pickerView 118 | viewForRow:(NSInteger) row 119 | forComponent:(NSInteger)component 120 | reusingView:(UIView *)view { 121 | 122 | if ( view ){ 123 | ((UILabel*)view).text = [ self pickerView:pickerView titleForRow:row forComponent:component]; 124 | return view; 125 | } 126 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; 127 | label.text = [ self pickerView:pickerView titleForRow:row forComponent:component]; 128 | 129 | label.numberOfLines = 0; 130 | label.lineBreakMode = UILineBreakModeWordWrap; 131 | label.textAlignment = UITextAlignmentCenter; 132 | label.textColor = [UIColor blackColor]; 133 | label.textAlignment = UITextAlignmentCenter; 134 | label.font = [UIFont fontWithName:@"Verdana" size:16.0]; 135 | 136 | label.frame = CGRectMake(0, 0, 45, 60 ); 137 | label.backgroundColor = [UIColor clearColor]; 138 | label.opaque = YES; 139 | // rotate the label to match the picker 140 | label.transform = CGAffineTransformRotate(label.transform, M_PI/2 ); 141 | return [ label autorelease ]; 142 | } 143 | 144 | 145 | - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component{ 146 | return 80; 147 | } 148 | 149 | - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { 150 | if ( 0 == row ){ 151 | [ pickerView selectRow:1 inComponent:0 animated:YES ]; 152 | } 153 | [ alarmView quickSelectionMade ]; 154 | 155 | } 156 | 157 | - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)thePickerView { 158 | return 1; 159 | } 160 | 161 | 162 | - (NSInteger)pickerView:(UIPickerView *)thePickerView numberOfRowsInComponent:(NSInteger)component { 163 | return [ quickChoices count]; 164 | } 165 | 166 | - (NSString *)pickerView:(UIPickerView *)thePickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { 167 | id val = [ quickChoices objectAtIndex:row ]; 168 | return val; 169 | } 170 | 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /Classes/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "AppDelegate.h" 19 | #import "MainViewController.h" 20 | #import "NotesManager.h" 21 | #import "PurchaseManager.h" 22 | #import "LocationAlarmManager.h" 23 | #import 24 | #import "Appirater.h" 25 | 26 | @implementation AppDelegate 27 | 28 | 29 | #pragma mark - 30 | #pragma mark Application lifecycle 31 | 32 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 33 | [ NotesManager startup ]; 34 | [ LocationAlarmManager startup ]; 35 | [ PurchaseManager startup ]; 36 | 37 | NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 38 | if ( ! [ defs integerForKey:@"numberNotesAllowed" ] ){ 39 | [ defs setInteger:2 forKey:@"numberNotesAllowed" ]; 40 | [ defs synchronize ]; 41 | } 42 | 43 | application.applicationIconBadgeNumber = 0; 44 | 45 | UILocalNotification *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]; 46 | if ( notification ) { 47 | NSLog(@"Recieved Notification %@",notification); 48 | Note *note = [[ NotesManager instance ] noteWithDirectory: 49 | [ notification.userInfo objectForKey:@"directory" ] ]; 50 | if ( note ){ 51 | [ mvc selectNote: note ]; 52 | } 53 | } 54 | 55 | CGRect windowRect = CGRectMake(0, 0, 320, 480 ); 56 | window = [[UIWindow alloc] initWithFrame:windowRect]; 57 | 58 | mvc = [[MainViewController alloc ] init ]; 59 | mvc.view.frame = CGRectMake(0, 20, 320, 460 ); 60 | 61 | [ window addSubview:mvc.view ]; 62 | 63 | [ window makeKeyAndVisible]; 64 | 65 | [Appirater appLaunched:YES]; 66 | 67 | return YES; 68 | } 69 | 70 | 71 | - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { 72 | if ( buttonIndex ){ 73 | [ mvc selectNote:pendingNote ]; 74 | } else { 75 | [ player stop ]; 76 | } 77 | } 78 | 79 | - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)p successfully:(BOOL)flag{ 80 | [ p release ]; 81 | if ( p == player ){ 82 | player = nil; 83 | } 84 | } 85 | 86 | - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { 87 | 88 | application.applicationIconBadgeNumber = 0; 89 | UIApplicationState state = [application applicationState]; 90 | if (state == UIApplicationStateInactive) { 91 | return; 92 | } 93 | Note *note = [[ NotesManager instance ] noteWithDirectory: 94 | [ notification.userInfo objectForKey:@"directory"] ]; 95 | if ( note ){ 96 | NSLog( @"Firing Alarm Sound: %@", notification.soundName ); 97 | if ( notification.soundName && UILocalNotificationDefaultSoundName != notification.soundName ){ 98 | NSURL *sndURL = [[NSBundle mainBundle ] URLForResource:notification.soundName withExtension:NULL ]; 99 | if ( player ){ 100 | [player release]; 101 | } 102 | player = [[AVAudioPlayer alloc] initWithContentsOfURL:sndURL error:NULL]; 103 | player.delegate = self; 104 | [ player play ]; 105 | AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); 106 | } 107 | pendingNote = note; 108 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alarm expired" 109 | message:notification.alertBody 110 | delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"View",NULL]; 111 | [ alert show ]; 112 | [ alert release ]; 113 | } 114 | 115 | } 116 | 117 | 118 | - (void)applicationWillResignActive:(UIApplication *)application { 119 | /* 120 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 121 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 122 | */ 123 | } 124 | 125 | 126 | - (void)applicationDidEnterBackground:(UIApplication *)application { 127 | /* 128 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 129 | If your application supports background execution, called instead of applicationWillTerminate: when the user quits. 130 | */ 131 | [ mvc viewWillDisappear:NO ]; 132 | } 133 | 134 | 135 | - (void)applicationWillEnterForeground:(UIApplication *)application { 136 | /* 137 | Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. 138 | */ 139 | [Appirater appEnteredForeground:YES]; 140 | } 141 | 142 | 143 | - (void)applicationDidBecomeActive:(UIApplication *)application { 144 | /* 145 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 146 | */ 147 | application.applicationIconBadgeNumber = 0; 148 | 149 | } 150 | 151 | 152 | - (void)applicationWillTerminate:(UIApplication *)application { 153 | /* 154 | Called when the application is about to terminate. 155 | See also applicationDidEnterBackground:. 156 | */ 157 | 158 | } 159 | 160 | 161 | #pragma mark - 162 | #pragma mark Memory management 163 | 164 | - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 165 | /* 166 | Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. 167 | */ 168 | } 169 | 170 | 171 | - (void)dealloc { 172 | [window release]; 173 | [super dealloc]; 174 | } 175 | 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /Classes/NotesScrollView.m: -------------------------------------------------------------------------------- 1 | /* This file is part of Remindly. 2 | 3 | Remindly is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, version 3. 6 | 7 | Remindly is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with Remindly. If not, see . 14 | */ 15 | 16 | 17 | #import "NotesScrollView.h" 18 | #import "NotesManager.h" 19 | #import "NoteThumbnailView.h" 20 | #import "NoteSelectorController.h" 21 | 22 | 23 | @implementation NotesScrollView 24 | 25 | #define PAGE_WIDTH 213 26 | #define PAGE_HEIGHT 280 27 | 28 | @synthesize currentPage; 29 | 30 | - (id)initWithController:(NoteSelectorController*)cntr 31 | frame:(CGRect)frame { 32 | 33 | if ( self != [self initWithFrame:frame]) { 34 | return nil; 35 | } 36 | controller = cntr; 37 | previews = [[ NSMutableDictionary alloc ] init ]; 38 | firstLayout = YES; 39 | currentPage = NSNotFound; 40 | 41 | // Position and size the scrollview. It will be centered in the view. 42 | CGRect scrollViewRect = CGRectMake(0, 0, PAGE_WIDTH, PAGE_HEIGHT ); 43 | scrollViewRect.origin.x = ((self.frame.size.width - PAGE_WIDTH ) / 2); 44 | scrollViewRect.origin.y = ((self.frame.size.height - PAGE_HEIGHT ) / 2); 45 | 46 | scrollView = [[UIScrollView alloc] initWithFrame:scrollViewRect]; 47 | scrollView.clipsToBounds = NO; 48 | scrollView.contentInset = UIEdgeInsetsMake(0, 20, 0, 20 ); 49 | scrollView.contentOffset = CGPointMake(20, 0); 50 | scrollView.pagingEnabled = YES; 51 | scrollView.showsHorizontalScrollIndicator = NO; 52 | scrollView.showsVerticalScrollIndicator = NO; 53 | scrollView.delegate = self; 54 | 55 | [ self addSubview:scrollView ]; 56 | 57 | return self; 58 | } 59 | 60 | 61 | -(NoteThumbnailView*)viewAtIndex:(NSUInteger)index { 62 | NoteThumbnailView *v = [ previews objectForKey:[ NSNumber numberWithInt:index ] ]; 63 | if ( ! v ){ 64 | v = [ [ NoteThumbnailView alloc ] initWithNote: [ NotesManager noteAtIndex: index ] 65 | frame:CGRectMake(0, 0, PAGE_WIDTH, PAGE_HEIGHT ) 66 | scroller:self ]; 67 | [ previews setObject: v forKey: [ NSNumber numberWithInt:index ] ]; 68 | [ v release ]; 69 | } 70 | return v; 71 | } 72 | 73 | 74 | -(NoteThumbnailView*)loadPage:(NSUInteger)page { 75 | // Sanity checks 76 | if ( page > [ NotesManager count ]-1 ){ 77 | return nil; 78 | } 79 | 80 | // Check if the page is already loaded 81 | NoteThumbnailView *view = [ self viewAtIndex:page ]; 82 | 83 | // add the controller's view to the scroll view if it's not already added 84 | if (view.superview == nil) { 85 | // Position the view in our scrollview 86 | CGRect viewFrame = view.frame; 87 | viewFrame.origin.x = viewFrame.size.width * page; 88 | viewFrame.origin.y = 0; 89 | 90 | view.frame = viewFrame; 91 | 92 | [ scrollView addSubview:view]; 93 | } 94 | return view; 95 | } 96 | 97 | 98 | -(void)clear { 99 | for (UIView *view in [ scrollView subviews]) { 100 | [ view removeFromSuperview ]; 101 | } 102 | [ previews removeAllObjects ]; 103 | firstLayout = YES; 104 | } 105 | 106 | 107 | - (void)deleteThumbnail:(NoteThumbnailView*)tn { 108 | [ previews removeObjectForKey:[ NSNumber numberWithInt: tn.note.index ] ]; 109 | 110 | Note *new = [[ NotesManager instance ] deleteNote: tn.note ]; 111 | [ tn removeFromSuperview ]; 112 | [ self clear ]; 113 | 114 | scrollView.contentSize = CGSizeMake([NotesManager count] * scrollView.frame.size.width, scrollView.frame.size.height); 115 | if ( new.index ){ 116 | [ self loadPage: new.index-1 ]; 117 | } 118 | [ self loadPage: new.index ]; 119 | [ self selectNoteIndex: new.index ]; 120 | } 121 | 122 | - (void)reload { 123 | scrollView.contentSize = CGSizeMake([NotesManager count] * scrollView.frame.size.width, scrollView.frame.size.height); 124 | [ self clear ]; 125 | } 126 | 127 | 128 | - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { 129 | 130 | // If the point is not inside the scrollview, ie, in the preview areas we need to return 131 | // the scrollview here for interaction to work 132 | if (!CGRectContainsPoint(scrollView.frame, point)) { 133 | return scrollView; 134 | } 135 | 136 | // If the point is inside the scrollview there's no reason to mess with the event. 137 | // This allows interaction to be handled by the active subview just like any scrollview 138 | return [super hitTest:point withEvent:event]; 139 | } 140 | 141 | 142 | -(NSUInteger)calcPage { 143 | CGFloat pageWidth = scrollView.frame.size.width; 144 | return MIN( [ NotesManager count ]-1, 145 | MAX( 0, floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1 ) ); 146 | } 147 | 148 | - (void)selectNoteIndex:(NSInteger)index{ 149 | if(firstLayout) { 150 | scrollView.contentSize = CGSizeMake([NotesManager count] * scrollView.frame.size.width, scrollView.frame.size.height); 151 | if ( index >= 1 ){ 152 | [ [ self loadPage: index - 1 ] setFocused:NO ]; 153 | } 154 | [ [ self loadPage: index ] setFocused: YES ]; 155 | [ [ self loadPage: index+1 ] setFocused: NO ]; 156 | firstLayout = NO; 157 | } else { 158 | [ scrollView setContentOffset:CGPointMake(scrollView.frame.size.width*index,0 ) ]; 159 | } 160 | } 161 | 162 | -(void) noteWasSelected:(Note*)note{ 163 | [ controller noteWasSelected:note ]; 164 | } 165 | 166 | 167 | #pragma mark - 168 | #pragma mark UIScrollViewDelegate methods 169 | 170 | -(void)scrollViewDidScroll:(UIScrollView *)sv { 171 | int page = [self calcPage]; 172 | if ( page == currentPage ) 173 | return; 174 | 175 | [ controller pageChanged: page ]; 176 | 177 | // Load the visible and neighbouring pages 178 | NoteThumbnailView *tn; 179 | if ( page > 0 ){ 180 | tn = [self loadPage:page-1]; 181 | tn.focused = NO; 182 | } 183 | 184 | tn = [self loadPage:page]; 185 | tn.focused = YES; 186 | 187 | if ( page < [ NotesManager count ] ){ 188 | tn =[self loadPage:page+1]; 189 | tn.focused = NO; 190 | } 191 | 192 | currentPage = page; 193 | } 194 | 195 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{ 196 | [ controller startScrolling ]; 197 | } 198 | 199 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{ 200 | [ controller endScrolling ]; 201 | } 202 | #pragma mark - 203 | #pragma mark Memory management 204 | 205 | 206 | - (void)dealloc { 207 | [ previews release ]; 208 | [ scrollView release ]; 209 | [ super dealloc ]; 210 | } 211 | 212 | 213 | @end 214 | -------------------------------------------------------------------------------- /Classes/Appirater.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of Appirater. 3 | 4 | Copyright (c) 2010, Arash Payan 5 | All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person 8 | obtaining a copy of this software and associated documentation 9 | files (the "Software"), to deal in the Software without 10 | restriction, including without limitation the rights to use, 11 | copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the 13 | Software is furnished to do so, subject to the following 14 | conditions: 15 | 16 | The above copyright notice and this permission notice shall be 17 | included in all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 | OTHER DEALINGS IN THE SOFTWARE. 27 | */ 28 | /* 29 | * Appirater.h 30 | * appirater 31 | * 32 | * Created by Arash Payan on 9/5/09. 33 | * http://arashpayan.com 34 | * Copyright 2010 Arash Payan. All rights reserved. 35 | */ 36 | 37 | #import 38 | 39 | extern NSString *const kAppiraterFirstUseDate; 40 | extern NSString *const kAppiraterUseCount; 41 | extern NSString *const kAppiraterSignificantEventCount; 42 | extern NSString *const kAppiraterCurrentVersion; 43 | extern NSString *const kAppiraterRatedCurrentVersion; 44 | extern NSString *const kAppiraterDeclinedToRate; 45 | 46 | /* 47 | Place your Apple generated software id here. 48 | */ 49 | #define APPIRATER_APP_ID 411254165 50 | 51 | /* 52 | Your app's name. 53 | */ 54 | #define APPIRATER_APP_NAME [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey] 55 | 56 | /* 57 | This is the message your users will see once they've passed the day+launches 58 | threshold. 59 | */ 60 | #define APPIRATER_MESSAGE @"Hello, I'm Nathan.\nI created Remindly. If you find it useful, would you be kind enough to take a few seconds to rate it?\nThanks very much for your support!" 61 | 62 | /* 63 | This is the title of the message alert that users will see. 64 | */ 65 | #define APPIRATER_MESSAGE_TITLE @"Rate Remindly?" 66 | 67 | /* 68 | The text of the button that rejects reviewing the app. 69 | */ 70 | #define APPIRATER_CANCEL_BUTTON @"No, Thanks" 71 | 72 | /* 73 | Text of button that will send user to app review page. 74 | */ 75 | #define APPIRATER_RATE_BUTTON @"Rate Remindly" 76 | 77 | /* 78 | Text for button to remind the user to review later. 79 | */ 80 | #define APPIRATER_RATE_LATER @"Remind me later" 81 | 82 | /* 83 | Users will need to have the same version of your app installed for this many 84 | days before they will be prompted to rate it. 85 | */ 86 | #define APPIRATER_DAYS_UNTIL_PROMPT 10 // double 87 | 88 | /* 89 | An example of a 'use' would be if the user launched the app. Bringing the app 90 | into the foreground (on devices that support it) would also be considered 91 | a 'use'. You tell Appirater about these events using the two methods: 92 | [Appirater appLaunched:] 93 | [Appirater appEnteredForeground:] 94 | 95 | Users need to 'use' the same version of the app this many times before 96 | before they will be prompted to rate it. 97 | */ 98 | #define APPIRATER_USES_UNTIL_PROMPT 10 // integer 99 | 100 | /* 101 | A significant event can be anything you want to be in your app. In a 102 | telephone app, a significant event might be placing or receiving a call. 103 | In a game, it might be beating a level or a boss. This is just another 104 | layer of filtering that can be used to make sure that only the most 105 | loyal of your users are being prompted to rate you on the app store. 106 | If you leave this at a value of -1, then this won't be a criteria 107 | used for rating. To tell Appirater that the user has performed 108 | a significant event, call the method: 109 | [Appirater userDidSignificantEvent:]; 110 | */ 111 | #define APPIRATER_SIG_EVENTS_UNTIL_PROMPT 4 // integer 112 | 113 | /* 114 | Once the rating alert is presented to the user, they might select 115 | 'Remind me later'. This value specifies how long (in days) Appirater 116 | will wait before reminding them. 117 | */ 118 | #define APPIRATER_TIME_BEFORE_REMINDING 2 // double 119 | 120 | /* 121 | 'YES' will show the Appirater alert everytime. Useful for testing how your message 122 | looks and making sure the link to your app's review page works. 123 | */ 124 | #define APPIRATER_DEBUG NO 125 | 126 | @interface Appirater : NSObject { 127 | 128 | UIAlertView *ratingAlert; 129 | } 130 | 131 | @property(nonatomic, retain) UIAlertView *ratingAlert; 132 | 133 | /* 134 | DEPRECATED: While still functional, it's better to use 135 | appLaunched:(BOOL)canPromptForRating instead. 136 | 137 | Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality. 138 | */ 139 | + (void)appLaunched; 140 | 141 | /* 142 | Tells Appirater that the app has launched, and on devices that do NOT 143 | support multitasking, the 'uses' count will be incremented. You should 144 | call this method at the end of your application delegate's 145 | application:didFinishLaunchingWithOptions: method. 146 | 147 | If the app has been used enough to be rated (and enough significant events), 148 | you can suppress the rating alert 149 | by passing NO for canPromptForRating. The rating alert will simply be postponed 150 | until it is called again with YES for canPromptForRating. The rating alert 151 | can also be triggered by appEnteredForeground: and userDidSignificantEvent: 152 | (as long as you pass YES for canPromptForRating in those methods). 153 | */ 154 | + (void)appLaunched:(BOOL)canPromptForRating; 155 | 156 | /* 157 | Tells Appirater that the app was brought to the foreground on multitasking 158 | devices. You should call this method from the application delegate's 159 | applicationWillEnterForeground: method. 160 | 161 | If the app has been used enough to be rated (and enough significant events), 162 | you can suppress the rating alert 163 | by passing NO for canPromptForRating. The rating alert will simply be postponed 164 | until it is called again with YES for canPromptForRating. The rating alert 165 | can also be triggered by appLaunched: and userDidSignificantEvent: 166 | (as long as you pass YES for canPromptForRating in those methods). 167 | */ 168 | + (void)appEnteredForeground:(BOOL)canPromptForRating; 169 | 170 | /* 171 | Tells Appirater that the user performed a significant event. A significant 172 | event is whatever you want it to be. If you're app is used to make VoIP 173 | calls, then you might want to call this method whenever the user places 174 | a call. If it's a game, you might want to call this whenever the user 175 | beats a level boss. 176 | 177 | If the user has performed enough significant events and used the app enough, 178 | you can suppress the rating alert by passing NO for canPromptForRating. The 179 | rating alert will simply be postponed until it is called again with YES for 180 | canPromptForRating. The rating alert can also be triggered by appLaunched: 181 | and appEnteredForeground: (as long as you pass YES for canPromptForRating 182 | in those methods). 183 | */ 184 | + (void)userDidSignificantEvent:(BOOL)canPromptForRating; 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /Classes/AlarmPopUpController.m: -------------------------------------------------------------------------------- 1 | // 2 | // AlarmView.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | 19 | #import "AlarmPopUpController.h" 20 | #import "AlarmQuickTimes.h" 21 | #import "GradientButton.h" 22 | #import "PickerSelectionIndicator.h" 23 | #import 24 | 25 | 26 | @implementation AlarmPopUpController 27 | 28 | @synthesize wasSet; 29 | 30 | 31 | -(void)loadView { 32 | self.view = [ [ UIView alloc ] initWithFrame:CGRectMake( 0, 480, 320, 480 ) ]; 33 | 34 | self.view.backgroundColor = [ UIColor blackColor ]; 35 | 36 | panels = [ NSMutableArray arrayWithObjects: 37 | [[[ UIView alloc ] initWithFrame: CGRectMake(0, 33, 320, 390 ) ] autorelease ], 38 | NULL 39 | ]; 40 | 41 | [ panels retain ]; 42 | absTimes = [[AlarmAbsoluteTimes alloc ] initWithAlarmView:self frame:CGRectMake( 0.0, 0.0, 320.0, 90.0 ) ]; 43 | quickTimes = [[ AlarmQuickTimes alloc ] initWithAlarmView:self frame:CGRectMake( -4.0, 178.0, 320.0, 320.0 ) ]; 44 | 45 | [ [ panels objectAtIndex:0 ] addSubview: quickTimes.view ]; 46 | [ [ panels objectAtIndex:0 ] addSubview: absTimes.view ]; 47 | 48 | UIView *lvbar = [ [UIView alloc ] initWithFrame: CGRectMake( 0, 120, 10, 200 ) ]; 49 | lvbar.backgroundColor = [ UIColor blackColor ]; 50 | [ [ panels objectAtIndex:0 ] addSubview: lvbar ]; 51 | [ lvbar release ]; 52 | 53 | UIView *rvbar = [ [UIView alloc ] initWithFrame: CGRectMake( 310, 120, 10, 200 ) ]; 54 | rvbar.backgroundColor = [ UIColor blackColor ]; 55 | [ [ panels objectAtIndex:0 ] addSubview: rvbar ]; 56 | [ rvbar release ]; 57 | 58 | UIView *hbar = [ [UIView alloc ] initWithFrame: CGRectMake( 0, 280, 320, 80) ]; 59 | hbar.backgroundColor = [ UIColor blackColor ]; 60 | [ [ panels objectAtIndex:0 ] addSubview: hbar ]; 61 | [ hbar release ]; 62 | 63 | NSArray *titles; 64 | if ([CLLocationManager significantLocationChangeMonitoringAvailable] ){ 65 | mapView = [[ AlarmMapView alloc ] initWithAlarmView:self frame:CGRectMake(0, 0, 320, 330 )]; 66 | [ panels addObject: mapView.view ]; 67 | titles = [ NSArray arrayWithObjects: @"Time/Date", @"Map", @"Alarm Sound", nil ]; 68 | } else { 69 | titles = [ NSArray arrayWithObjects: @"Time/Date", @"Alarm Sound", nil ]; 70 | } 71 | 72 | sounds = [[ AlarmSounds alloc ] initWithAlarmView:self ]; 73 | [ panels addObject: sounds.view ]; 74 | 75 | for ( UIView *v in panels ){ 76 | [ self.view addSubview: v ]; 77 | } 78 | sounds.tableView.frame = CGRectMake(0, 30, 320, 380 ); 79 | typeCtrl = [[ UISegmentedControl alloc ] initWithItems:titles]; 80 | typeCtrl.selectedSegmentIndex = 0; 81 | typeCtrl.frame = CGRectMake( 0, -3, 320, 40 ); 82 | typeCtrl.segmentedControlStyle = UISegmentedControlStyleBezeled; 83 | typeCtrl.tintColor = [ UIColor darkGrayColor ]; 84 | [ typeCtrl addTarget:self action:@selector(typeCtrlChanged:) forControlEvents:UIControlEventValueChanged ]; 85 | [ self.view addSubview: typeCtrl ]; 86 | [ typeCtrl release ]; 87 | 88 | PickerSelectionIndicator *psi = [[ PickerSelectionIndicator alloc ] initWithFrame: 89 | CGRectMake( 120, 215, 72, 67) ]; 90 | psi.backgroundColor = [ UIColor clearColor ]; 91 | [ [ panels objectAtIndex:0 ] addSubview: psi ]; 92 | [ psi release ]; 93 | 94 | GradientButton *b = [ [ GradientButton alloc ] initWithFrame: CGRectMake(20, 335, 120, 35 ) ]; 95 | [ b addTarget:self action:@selector(cancelTouched:) forControlEvents:UIControlEventTouchUpInside ]; 96 | [ b setTitle:@"Cancel" forState:UIControlStateNormal ]; 97 | [ b useBlackStyle ]; 98 | [ self.view addSubview: b ]; 99 | [ b release ]; 100 | 101 | saveBtn = [ [ GradientButton alloc ] initWithFrame: CGRectMake(170, 335, 120, 35 ) ]; 102 | [ saveBtn addTarget:self action:@selector(saveTouched:) forControlEvents:UIControlEventTouchUpInside ]; 103 | [ saveBtn setTitle:@"Save" forState:UIControlStateNormal ]; 104 | [ saveBtn useBlueStyle ]; 105 | [ self.view addSubview: saveBtn ]; 106 | 107 | } 108 | 109 | -(void) viewDidUnload { 110 | [ saveBtn release ]; 111 | [ quickTimes release ]; 112 | [ absTimes release ]; 113 | [ mapView release ]; 114 | [ typeCtrl release ]; 115 | [ currentNote release ]; 116 | [ panels release ]; 117 | } 118 | 119 | 120 | - (void)dealloc { 121 | [ super viewDidUnload ]; 122 | [ super dealloc ]; 123 | } 124 | 125 | 126 | -(void)cancelTouched:(id)btn { 127 | self.isShowing = NO; 128 | } 129 | 130 | 131 | -(void)saveTouched:(id)btn { 132 | switch ( typeCtrl.selectedSegmentIndex ) { 133 | case 0: 134 | if ( [ quickTimes isSet ] ){ 135 | [ quickTimes saveToNote: currentNote ]; 136 | } else { 137 | [ absTimes saveToNote: currentNote ]; 138 | } 139 | break; 140 | case 1: 141 | [ mapView saveToNote: currentNote ]; 142 | break; 143 | default: 144 | break; 145 | } 146 | [ sounds saveToNote: currentNote ]; 147 | [ currentNote save ]; 148 | [ currentNote scedule ]; 149 | self.isShowing = NO; 150 | } 151 | 152 | 153 | 154 | -(void)hideAll{ 155 | for ( UIView *v in panels ){ 156 | v.hidden = YES; 157 | } 158 | } 159 | 160 | 161 | -(void)typeCtrlChanged:(id)tbc { 162 | [ self hideAll ]; 163 | NSInteger indx = typeCtrl.selectedSegmentIndex; 164 | saveBtn.hidden = ( 2 == indx ); 165 | ((UIView*)[ panels objectAtIndex: indx ]).hidden = NO; 166 | } 167 | 168 | 169 | -(void)showWithNote:(Note*)note { 170 | currentNote = note; 171 | [ quickTimes reset ]; 172 | [ mapView reset ]; 173 | [ absTimes reset ]; 174 | [ self hideAll ]; 175 | self.isShowing = YES; 176 | 177 | switch ( note.alarmTag ) { 178 | case 0: 179 | [ quickTimes setFromNote:note ]; 180 | typeCtrl.selectedSegmentIndex = 0; 181 | break; 182 | case 1: 183 | typeCtrl.selectedSegmentIndex = 0; 184 | absTimes.date = note.fireDate; 185 | break; 186 | case 2: 187 | typeCtrl.selectedSegmentIndex = 1; 188 | [ mapView setFromNote:note ]; 189 | break; 190 | } 191 | [ self typeCtrlChanged:nil ]; 192 | } 193 | 194 | 195 | -(void)quickSelectionMade { 196 | NSDate *d = [ quickTimes.date retain ]; 197 | if ( d ){ 198 | absTimes.date = d; 199 | } 200 | [ d release ]; 201 | } 202 | 203 | 204 | -(void)absSelectionMade{ 205 | [ quickTimes selectBlank ]; 206 | } 207 | 208 | -(void)setIsShowing:(BOOL)v { 209 | CGRect frame = self.view.frame; 210 | if ( v ){ 211 | frame.origin.y = 480; 212 | self.view.frame = frame; 213 | typeCtrl.selectedSegmentIndex = 0; 214 | frame.origin.y = 90; 215 | [ self hideAll ]; 216 | } else { 217 | frame.origin.y = 480; 218 | } 219 | [UIView animateWithDuration:0.3f animations:^{ 220 | self.view.frame = frame; 221 | } completion:^ (BOOL finished) { 222 | 223 | }]; 224 | 225 | } 226 | 227 | 228 | -(BOOL)isShowing{ 229 | return ( self.view.frame.origin.y < 420 ); 230 | } 231 | 232 | 233 | @end 234 | -------------------------------------------------------------------------------- /Classes/LocationAlarmManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // LocationManager.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/25/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "LocationAlarmManager.h" 10 | #import "NotesManager.h" 11 | #import 12 | 13 | LocationAlarmManager *instance; 14 | 15 | @interface LocationAlarmManager() 16 | -(void)startOrStopMonitor; 17 | @property (nonatomic,retain) CLLocationManager *manager; 18 | @property (nonatomic,readonly) NSMutableDictionary *notes; 19 | @property (nonatomic,retain ) CLLocation *lastLocation; 20 | @end 21 | 22 | @implementation LocationAlarmManager 23 | 24 | @synthesize manager, notes, lastLocation; 25 | 26 | + (void)startup { 27 | if ( ! instance ){ 28 | instance = [[ LocationAlarmManager alloc ] init ]; 29 | } else { 30 | [ instance startOrStopMonitor ]; 31 | } 32 | } 33 | 34 | 35 | -(id) init { 36 | self = [ super init ]; 37 | if ( ! self ){ 38 | return nil; 39 | } 40 | notes = [[ NSMutableDictionary alloc ] init ]; 41 | for ( Note *note in [ NotesManager notesWithLocationAlarms ] ){ 42 | [ notes setObject: note forKey: note.directory ]; 43 | } 44 | 45 | self.manager = [[CLLocationManager alloc] init]; 46 | manager.purpose = @"In order to use geographical alarms that alert you when leaving or entering an area"; 47 | manager.delegate = self; 48 | [ manager release ]; 49 | [ self startOrStopMonitor ]; 50 | 51 | return self; 52 | } 53 | 54 | 55 | -(void)startOrStopMonitor { 56 | NSLog(@"startOrStopMonitor"); 57 | manager.delegate = self; 58 | manager.distanceFilter = ALARM_METER_RADIUS / 0.1; 59 | if ( [notes count] ){ 60 | NSLog(@"startOrStopMonitor -> started monitor"); 61 | [ manager startMonitoringSignificantLocationChanges]; 62 | } else { 63 | NSLog(@"startOrStopMonitor -> stopped monitor"); 64 | [ manager stopMonitoringSignificantLocationChanges ]; 65 | } 66 | } 67 | 68 | 69 | -(void)fireNoteAlarm:(Note*)note { 70 | UILocalNotification *notification = [[UILocalNotification alloc] init]; 71 | 72 | notification.fireDate = [ NSDate date ]; 73 | notification.timeZone = [ NSTimeZone defaultTimeZone]; 74 | notification.alertBody = [ NSString stringWithFormat:@"Location %@\n%@", 75 | note.onEnterRegion ? @"Reached" : @"Left", 76 | note.alarmText ]; 77 | 78 | notification.alertAction = @"View Note"; 79 | NSString *snd = [ note soundPath ]; 80 | notification.soundName = snd ? snd : UILocalNotificationDefaultSoundName; 81 | notification.applicationIconBadgeNumber = 1; 82 | 83 | NSDictionary *infoDict = [NSDictionary dictionaryWithObject: note.directory forKey:@"directory"]; 84 | notification.userInfo = infoDict; 85 | 86 | [ note unScedule ]; 87 | 88 | [ [UIApplication sharedApplication] presentLocalNotificationNow:notification ]; 89 | [ notification release ]; 90 | } 91 | 92 | 93 | 94 | -(void)dealloc { 95 | [ [ NSNotificationCenter defaultCenter] removeObserver:self]; 96 | [ notes release ]; 97 | [ manager release ]; 98 | [ super dealloc ]; 99 | } 100 | 101 | 102 | +(void)unregisterNote:(Note*)note{ 103 | [ instance.notes removeObjectForKey: note.directory ]; 104 | [ instance startOrStopMonitor ]; 105 | } 106 | 107 | 108 | +(CLLocation*)lastCoord { 109 | return instance.manager.location; 110 | } 111 | 112 | 113 | + (void)registerNote:(Note*)note { 114 | [ instance.notes setObject:note forKey:note.directory ]; 115 | [ instance startOrStopMonitor ]; 116 | } 117 | 118 | 119 | // returns a string if the number with one decimal place of precision 120 | // sets the style (commas or periods) based on the locale 121 | NSString * formatDecimal_1(NSNumber *num) { 122 | static NSNumberFormatter *numFormatter; 123 | if (!numFormatter) { 124 | numFormatter = [[[NSNumberFormatter alloc] init] retain]; 125 | [numFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; 126 | [numFormatter setLocale:[NSLocale currentLocale]]; 127 | [numFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; 128 | [numFormatter setMaximumFractionDigits:1]; 129 | [numFormatter setMinimumFractionDigits:1]; 130 | } 131 | return [numFormatter stringFromNumber: num ]; 132 | } 133 | 134 | + (NSString*)distanceStringFrom:(CLLocationCoordinate2D)coord isEnter:(BOOL)isEnter { 135 | double distance = MKMetersBetweenMapPoints( MKMapPointForCoordinate( coord ), 136 | MKMapPointForCoordinate( [ LocationAlarmManager lastCoord ].coordinate ) ); 137 | 138 | if ( isEnter ){ 139 | distance = MAX( distance - ALARM_METER_RADIUS , 0 ); 140 | } else { 141 | distance = (ALARM_METER_RADIUS*1.5) - distance; 142 | } 143 | 144 | NSString * unitName; 145 | NSString *locale = [ [ NSLocale currentLocale ] localeIdentifier ]; 146 | 147 | if ( [ locale isEqual:@"en_US" ]) { 148 | unitName = @"mi"; 149 | distance = distance / 1609.344; 150 | } else { 151 | unitName = @"km"; 152 | distance = distance / 1000; 153 | } 154 | 155 | return [NSString stringWithFormat:@"%@ %@", formatDecimal_1( [NSNumber numberWithDouble: distance] ), unitName ]; 156 | } 157 | 158 | #pragma mark - 159 | #pragma mark CLLocationManager delegate methods 160 | 161 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { 162 | NSLog(@"Location Manager error: %@", [error description] ); 163 | 164 | } 165 | 166 | 167 | - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation 168 | { 169 | if ( ! [ notes count ]) return; 170 | 171 | // test that the horizontal accuracy does not indicate an invalid measurement 172 | if (newLocation.horizontalAccuracy < 0) return; 173 | 174 | 175 | for ( Note *note in [ notes allValues ] ){ 176 | double distance = MKMetersBetweenMapPoints( MKMapPointForCoordinate( newLocation.coordinate ), 177 | MKMapPointForCoordinate( note.coordinate ) ); 178 | 179 | if ( ( ( distance + newLocation.horizontalAccuracy ) < ALARM_METER_RADIUS && note.onEnterRegion ) 180 | || 181 | ( ( distance - newLocation.horizontalAccuracy ) > ( ALARM_METER_RADIUS * 1.5 ) && ! note.onEnterRegion ) ) 182 | { 183 | NSLog(@"Firing %@ Alarm: %f %f distance: %f accuracy %f", 184 | note.onEnterRegion ? @"Enter" : @"Exit", 185 | note.coordinate.latitude, 186 | note.coordinate.longitude, 187 | distance, distance ); 188 | [ self fireNoteAlarm:note ]; 189 | } 190 | } 191 | 192 | 193 | } 194 | 195 | // this sucks balls, terribly inaccurate, alarms only fire about 1/3 of the time 196 | 197 | //- (void)locationManager:(CLLocationManager *)m didEnterRegion:(CLRegion *)region{ 198 | // NSLog(@"-----------------------> Location Manager Entered: %@", region.identifier ); 199 | // Note *note = [ [NotesManager instance] noteWithDirectory: region.identifier ]; 200 | // if ( note ){ //&& note.onEnterRegion ){ 201 | // [ self displayNoteAlarm:note ]; 202 | // } 203 | //// [ m stopMonitoringForRegion:region ]; 204 | //} 205 | // 206 | //- (void)locationManager:(CLLocationManager *)m didExitRegion:(CLRegion *)region{ 207 | // NSLog(@"-----------------------> Location Manager Exited: %@", region.identifier ); 208 | // 209 | // Note *note = [ [NotesManager instance] noteWithDirectory: region.identifier ]; 210 | // if ( note ){// && ! note.onEnterRegion ){ 211 | // [ self displayNoteAlarm:note ]; 212 | // } 213 | //// [ m stopMonitoringForRegion:region ]; 214 | //} 215 | 216 | 217 | @end 218 | -------------------------------------------------------------------------------- /Classes/MainToolBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainToolBar.m 3 | // Remindly 4 | // 5 | // Created by Nathan Stitt on 1/29/11. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "MainToolBar.h" 10 | #import "MainViewController.h" 11 | #import "NotesManager.h" 12 | #import "DrawingViewController.h" 13 | #import "NoteSelectorController.h" 14 | #import "StoreView.h" 15 | #import "UIColor+Expanded.h" 16 | #import "DrawingPaletteController.h" 17 | #import "DrawingPaletteTool.h" 18 | 19 | @implementation MainToolBar 20 | 21 | -(id)initWithController:(MainViewController*)m { 22 | self = [ super init ]; 23 | if ( ! self ){ 24 | return nil; 25 | } 26 | mvc = m; 27 | self.barStyle = UIBarStyleBlack; 28 | self.frame = CGRectMake( 0, 420, 320, 50 ); 29 | [ self sizeToFit ]; 30 | 31 | countBtn = [[ CountingButton alloc ] initWithCount: [ NotesManager count] ]; 32 | [ countBtn.button addTarget:self action: @selector(toggleDrawingMode:) forControlEvents:UIControlEventTouchUpInside ]; 33 | 34 | UIBarButtonItem *text = [[UIBarButtonItem alloc ] initWithImage:[UIImage imageNamed:@"text_icon" ] style:UIBarButtonItemStylePlain target:self action:@selector(addTextPressed:) ]; 35 | UIBarButtonItem *alarm = [[UIBarButtonItem alloc ] initWithImage:[UIImage imageNamed:@"alarm_icon" ] style:UIBarButtonItemStylePlain target:self action:@selector(setAlarmPressed:) ]; 36 | 37 | 38 | UIImage *drawImg = [UIImage imageNamed:@"draw_icon"]; 39 | eraseBtn = [[ToggleButton alloc ] initWithImages: [ NSArray arrayWithObjects: 40 | drawImg, 41 | [UIImage imageNamed:@"erase_icon"], 42 | nil ] 43 | Frame: CGRectMake(0, 0, drawImg.size.width, drawImg.size.height) ]; 44 | 45 | [ eraseBtn addTarget:self action: @selector(toggleErase:) forControlEvents:UIControlEventTouchUpInside ]; 46 | 47 | UIBarButtonItem *deBtn = [[ UIBarButtonItem alloc ] initWithCustomView:eraseBtn ]; 48 | 49 | UIBarButtonItem *space = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:NULL action:NULL ]; 50 | 51 | mvc.drawing.color = mvc.drawTools.color; 52 | ColorButton *b = [[ ColorButton alloc ] initWithButtonColor: mvc.drawTools.color ]; 53 | [ b setBrushImage: [ mvc.drawTools.tool imageView ].image ]; 54 | [ b addTarget:self action:@selector(showPalette:) forControlEvents:UIControlEventTouchUpInside ]; 55 | pickerBtn = [[UIBarButtonItem alloc ] initWithCustomView: b ]; 56 | [ b release ]; 57 | 58 | UIBarButtonItem *add = [[ UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addNote:) ]; 59 | 60 | drawButtons=[ NSArray arrayWithObjects: add, space, pickerBtn, space, deBtn, space, 61 | text, space, alarm, space, countBtn, NULL ]; 62 | [ deBtn release ]; 63 | [ drawButtons retain ]; 64 | [add release ]; 65 | 66 | self.items = drawButtons; 67 | 68 | add = [[ UIBarButtonItem alloc ] initWithTitle:@"Add" style:UIBarButtonItemStyleBordered target:self action:@selector(addNote:) ]; 69 | UIBarButtonItem *done = [[ UIBarButtonItem alloc ] initWithTitle:@"Done" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleDrawingMode:) ]; 70 | 71 | UIBarButtonItem *backward = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:self action:@selector(noteBackward:) ]; 72 | 73 | UIBarButtonItem *forward = [[UIBarButtonItem alloc ] initWithBarButtonSystemItem:UIBarButtonSystemItemFastForward target:self action:@selector(noteForward:) ]; 74 | 75 | selButtons = [ NSArray arrayWithObjects: add, space, backward, space, forward, space, done, NULL ]; 76 | [ selButtons retain ]; 77 | 78 | [ backward release ]; 79 | [ forward release ]; 80 | [ add release ]; 81 | [ alarm release ]; 82 | [ text release ]; 83 | [ space release ]; 84 | [ done release ]; 85 | 86 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(countChanged:) name:NOTES_COUNT_CHANGED_NOTICE object:nil]; 87 | 88 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(drawingBegan:) name:DRAWING_BEGAN_NOTIFICATION object:nil]; 89 | 90 | [ mvc.drawTools addObserver:self forKeyPath:@"color" options:(NSKeyValueObservingOptionNew ) context:NULL]; 91 | 92 | [ mvc.drawTools addObserver:self forKeyPath:@"tool" options:(NSKeyValueObservingOptionNew ) context:NULL]; 93 | mvc.drawing.lineWidth = mvc.drawTools.tool.drawingWidth; 94 | 95 | return self; 96 | } 97 | 98 | 99 | -(void) showPalette:(id)sel{ 100 | mvc.isDrawToolsShowing = ! mvc.isDrawToolsShowing; 101 | if ( mvc.isDrawToolsShowing ){ 102 | eraseBtn.boolValue = mvc.drawing.isErasing = NO; 103 | } 104 | } 105 | 106 | 107 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 108 | if ( [ keyPath isEqual:@"color" ] ) { 109 | ((ColorButton*)pickerBtn.customView).color = mvc.drawing.color = mvc.drawTools.color; 110 | } else if ( [ keyPath isEqual:@"tool" ] ){ 111 | mvc.drawing.lineWidth = ( ( mvc.drawTools.tool.tag * 3.0 ) + 1 ); 112 | [ ((ColorButton*)pickerBtn.customView) setBrushImage: [ mvc.drawTools.tool imageView ].image ]; 113 | } 114 | } 115 | 116 | -(void)noteBackward:(id)btn { 117 | [ mvc.selector selectNoteIndex: [ mvc.selector currentIndex ] - 1 ]; 118 | } 119 | 120 | -(void)noteForward:(id)btn { 121 | [ mvc.selector selectNoteIndex: [ mvc.selector currentIndex ] + 1 ]; 122 | } 123 | 124 | -(void)drawingBegan:(NSNotification*)note { 125 | if ( mvc.alarm.isShowing ){ 126 | mvc.alarm.isShowing=NO; 127 | } 128 | } 129 | 130 | 131 | -(void) setDrawingMode:(BOOL)draw{ 132 | if ( draw ){ 133 | [ self setItems: drawButtons animated:YES]; 134 | } else { 135 | [ self setItems: selButtons animated:YES]; 136 | } 137 | } 138 | 139 | 140 | -(void)toggleErase:(id)sel{ 141 | mvc.drawing.isErasing = ! mvc.drawing.isErasing; 142 | eraseBtn.boolValue = mvc.drawing.isErasing; 143 | mvc.isDrawToolsShowing = NO; 144 | } 145 | 146 | 147 | -(void)countChanged:(NSNotification*)notif { 148 | [ countBtn setCount:[ NotesManager count ] ]; 149 | } 150 | 151 | 152 | -(void)addNote:(id)sel{ 153 | NotesManager *manager = [ NotesManager instance ]; 154 | if ( [ manager isAllowedMoreNotes ] ){ 155 | [ mvc.drawing.note save ]; 156 | mvc.drawing.note = [ manager addNote ]; 157 | mvc.drawingMode = YES; 158 | [ mvc.selector addNote: mvc.drawing.note ]; 159 | } else { 160 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No more reminders" 161 | message:@"You've reached the maximum number of reminders.\n\nWould you like to view options for purchasing additional reminders?" 162 | delegate:self cancelButtonTitle:@"No" otherButtonTitles: @"Yes", nil]; 163 | [alert show]; 164 | [alert release]; 165 | } 166 | mvc.isDrawToolsShowing = NO; 167 | } 168 | 169 | 170 | -(void)addTextPressed:(id)sel{ 171 | [ mvc.drawing addText ]; 172 | mvc.isDrawToolsShowing = NO; 173 | } 174 | 175 | 176 | -(void)showAlarm { 177 | mvc.isDrawToolsShowing = NO; 178 | mvc.isAlarmShowing = ! mvc.isAlarmShowing; 179 | } 180 | 181 | 182 | -(void)setAlarmPressed:(id)sel { 183 | [ self showAlarm ]; 184 | } 185 | 186 | 187 | -(void)toggleDrawingMode:(id)btn { 188 | [ mvc toggleDrawingMode ]; 189 | mvc.isDrawToolsShowing = NO; 190 | } 191 | 192 | #pragma mark UIAlertViewDelegate delegate methods 193 | 194 | - (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex { 195 | if ( 1 == buttonIndex ){ 196 | StoreView *store = [[ StoreView alloc ] initAndShowInto: mvc.view ]; 197 | [ store release ]; 198 | } 199 | } 200 | 201 | 202 | - (void)dealloc { 203 | [[NSNotificationCenter defaultCenter] removeObserver:self ]; 204 | [ drawButtons release ]; 205 | [ selButtons release ]; 206 | [ eraseBtn release ]; 207 | [super dealloc]; 208 | } 209 | 210 | 211 | @end 212 | -------------------------------------------------------------------------------- /Classes/NotesManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // NotesManager.m 3 | /* This file is part of Remindly. 4 | 5 | Remindly is free software: you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation, version 3. 8 | 9 | Remindly is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with Remindly. If not, see . 16 | */ 17 | 18 | #import "NotesManager.h" 19 | #import "Note.h" 20 | #include 21 | 22 | static NotesManager *_instance; 23 | 24 | @interface NotesManager() 25 | @property (nonatomic,retain) NSMutableDictionary *alerts; 26 | @property (nonatomic,retain) NSMutableArray *dirs; 27 | -(void)sortDirs; 28 | @end 29 | 30 | // this is pure evil. Really wish objective-c allowed 'friend' class declarations like C++ 31 | @interface Note(set) 32 | @property (nonatomic) NSUInteger index; 33 | @end 34 | 35 | @implementation Note(set) 36 | -(void)setIndex:(NSUInteger)i{ 37 | index = i; 38 | } 39 | -(NSUInteger)index{ 40 | return index; 41 | } 42 | 43 | @end 44 | 45 | @implementation NotesManager 46 | 47 | @synthesize path, dirs, alerts; 48 | 49 | +(void)startup { 50 | if ( ! _instance ){ 51 | [ Note primeCache ]; 52 | _instance = [[ NotesManager alloc ] init ]; 53 | } 54 | if ( ! [ NotesManager count ] ){ 55 | [ _instance addNote ]; 56 | } 57 | } 58 | 59 | 60 | +(NotesManager*)instance{ 61 | return _instance; 62 | } 63 | 64 | +(NSInteger)count { 65 | return [ _instance.dirs count ]; 66 | } 67 | 68 | +(NSArray*)notesWithLocationAlarms { 69 | NSMutableArray *notes = [[ NSMutableArray alloc ] init ]; 70 | for ( NSUInteger i = 0; i < _instance.dirs.count; i++ ){ 71 | Note *note = [ NotesManager noteAtIndex:i ]; 72 | if ( [note hasCoordinate] ){ 73 | [ notes addObject: note ]; 74 | } 75 | } 76 | return [notes autorelease]; 77 | } 78 | 79 | +(Note*)noteAtIndex:(NSUInteger)index { 80 | Note *note = [ Note noteWithDirectory:[ _instance.dirs objectAtIndex:index] ]; 81 | note.index = index; 82 | if ( ! [note hasNotification] ){ 83 | UILocalNotification *notif = [ _instance.alerts valueForKey: note.directory ]; 84 | if ( notif ){ 85 | note.notification = notif; 86 | } 87 | } 88 | return note; 89 | } 90 | 91 | -(id)init{ 92 | self = [super init ]; 93 | 94 | alerts = [[ NSMutableDictionary alloc ] init ]; 95 | dirs = [[ NSMutableArray alloc ] init ]; 96 | 97 | NSError *error; 98 | 99 | NSFileManager *fm = [ NSFileManager defaultManager ]; 100 | 101 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 102 | 103 | path = [ [paths objectAtIndex:0] stringByAppendingPathComponent: @"notes" ]; 104 | [ path retain ]; 105 | 106 | if ( ! [ fm fileExistsAtPath:path ] ){ 107 | [ fm createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error ]; 108 | } 109 | 110 | NSDirectoryEnumerator *dirEnum = [ fm enumeratorAtPath:path ]; 111 | NSString *note_file; 112 | while ( (note_file = [dirEnum nextObject]) ) { 113 | [ dirEnum skipDescendents ]; 114 | NSString *dir = [ path stringByAppendingPathComponent:note_file ]; 115 | if ( [ [ [ fm attributesOfItemAtPath:dir error:NULL ] valueForKey:@"NSFileType"] isEqualToString:@"NSFileTypeDirectory" ] ){ 116 | [ dirs addObject: note_file ]; 117 | } 118 | } 119 | 120 | for ( UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications ){ 121 | NSString *dir = [ notification.userInfo objectForKey:@"directory"]; 122 | if ( dir ){ 123 | [ alerts setObject: notification forKey: dir ]; 124 | } 125 | } 126 | [ self sortDirs ]; 127 | return self; 128 | } 129 | 130 | 131 | 132 | NSComparisonResult 133 | compare(NSString *dir1, NSString *dir2, void *context) { 134 | NSFileManager *fm = [ NSFileManager defaultManager ]; 135 | 136 | return [ [ [ fm attributesOfItemAtPath:dir1 error:NULL ] valueForKey:@"NSFileCreationDate"] compare: 137 | [ [ fm attributesOfItemAtPath:dir2 error:NULL ] valueForKey:@"NSFileCreationDate"] 138 | ]; 139 | } 140 | 141 | -(void)sortDirs { 142 | [ dirs setArray: [ dirs sortedArrayUsingSelector: @selector(compare:) ] ]; 143 | } 144 | 145 | -(BOOL)hasNoteWithDirectory:(NSString*)dir { 146 | return ( NSNotFound != [ dirs indexOfObject: dir ] ); 147 | } 148 | 149 | -(Note*)noteWithDirectory:(NSString*)dir { 150 | NSUInteger indx = [ dirs indexOfObject: dir ]; 151 | if ( NSNotFound != indx ){ 152 | Note *note = [ Note noteWithDirectory:dir ]; 153 | note.index = indx; 154 | UILocalNotification *notification = [ alerts objectForKey: dir ]; 155 | if ( notification ){ 156 | note.notification = notification; 157 | } 158 | return note; 159 | } else { 160 | return nil; 161 | } 162 | } 163 | 164 | 165 | -(Note*)deleteNote:(Note*)note{ 166 | [ dirs removeObject: note.directory ]; 167 | [ alerts removeObjectForKey: note.directory ]; 168 | Note *ret; 169 | if ( ! [ dirs count ] ){ 170 | ret = [ self addNote ]; 171 | } else if ( note.index < [ NotesManager count ] ){ 172 | ret = [ NotesManager noteAtIndex: note.index ]; 173 | } else { 174 | ret = [ NotesManager noteAtIndex: 0 ]; 175 | } 176 | [ note removeSelf ]; 177 | [[ NSNotificationCenter defaultCenter ] postNotificationName:NOTES_COUNT_CHANGED_NOTICE object: self ]; 178 | return ret; 179 | } 180 | 181 | 182 | -(NSString*)createNoteDirectory { 183 | NSFileManager *fm = [ NSFileManager defaultManager ]; 184 | 185 | NSString *nm = [ NSString stringWithFormat:@"%d",(arc4random() % 10000) ]; 186 | while ( [ fm fileExistsAtPath: [ self.path stringByAppendingPathComponent: nm ] ] ){ 187 | nm = [ NSString stringWithFormat:@"%d",(arc4random() % 10000) ]; 188 | } 189 | NSString *fullPath = [ self.path stringByAppendingPathComponent: nm ]; 190 | 191 | [ fm createDirectoryAtPath: fullPath withIntermediateDirectories:YES attributes:nil error:NULL]; 192 | 193 | [ UIImagePNGRepresentation( [ UIImage imageNamed:@"blank.png" ] ) 194 | writeToFile:[ fullPath stringByAppendingPathComponent:@"image.png"] atomically:YES]; 195 | 196 | [ UIImagePNGRepresentation( [ UIImage imageNamed:@"blank.png" ] ) 197 | writeToFile:[ fullPath stringByAppendingPathComponent:@"thumbnail.png"] atomically:YES]; 198 | 199 | 200 | [ fm copyItemAtPath:[[[NSBundle mainBundle] resourcePath] 201 | stringByAppendingPathComponent:@"empty.plist"] 202 | toPath:[ fullPath stringByAppendingPathComponent:@"info.plist"] 203 | error:NULL]; 204 | 205 | return nm; 206 | } 207 | 208 | 209 | -(Note*)addNote { 210 | Note *note = [ Note noteWithDirectory: [ self createNoteDirectory ] ]; 211 | [ note save ]; 212 | [ dirs insertObject: note.directory atIndex:0 ]; 213 | [[ NSNotificationCenter defaultCenter ] postNotificationName:NOTES_COUNT_CHANGED_NOTICE object: self ]; 214 | return note; 215 | } 216 | 217 | -(NSInteger)maxNumberOfNotes{ 218 | return [[NSUserDefaults standardUserDefaults] integerForKey:@"numberNotesAllowed"]; 219 | } 220 | 221 | -(void)setMaxNumberOfNotes:(NSInteger)n{ 222 | NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; 223 | [ defs setInteger:n forKey:@"numberNotesAllowed"]; 224 | [ defs synchronize ]; 225 | } 226 | 227 | -(BOOL)hasBeenUpgraded { 228 | return ( [ self maxNumberOfNotes ] > 2 ); 229 | } 230 | 231 | -(void)upgradeAllowedNoteCount:(BOOL)unlimited{ 232 | if ( unlimited ){ 233 | [ self setMaxNumberOfNotes:99999]; 234 | } else if ( [ self maxNumberOfNotes ] < 5 ){ 235 | [ self setMaxNumberOfNotes: 5 ]; 236 | } 237 | } 238 | 239 | -(BOOL)isAllowedMoreNotes { 240 | // return YES; 241 | return ( [ dirs count ] < self.maxNumberOfNotes ); 242 | } 243 | 244 | -(Note*)defaultEditingNote { 245 | return [ [ _instance dirs ] count ] ? [ NotesManager noteAtIndex: 0 ] : [ self addNote ]; 246 | } 247 | 248 | - (void)dealloc { 249 | [ path release ]; 250 | [ dirs release ]; 251 | [ alerts release ]; 252 | [ super dealloc ]; 253 | } 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /Classes/DrawingViewController.m: -------------------------------------------------------------------------------- 1 | /* This file is part of Remindly. 2 | 3 | Remindly is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, version 3. 6 | 7 | Remindly is distributed in the hope that it will be useful, 8 | but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | GNU General Public License for more details. 11 | 12 | You should have received a copy of the GNU General Public License 13 | along with Remindly. If not, see . 14 | */ 15 | 16 | #import 17 | #import "MainViewController.h" 18 | #import "AlarmTitleButton.h" 19 | #import "NotesManager.h" 20 | #import "DrawingViewController.h" 21 | #import "DrawingTextBox.h" 22 | 23 | @implementation DrawingViewController 24 | 25 | @synthesize note,color,isErasing,alarmTitle,lineWidth; 26 | 27 | - (id)initWithMainView:(MainViewController*)mv { 28 | self = [super init ]; 29 | mainView = mv; 30 | self.view.backgroundColor = [ UIColor whiteColor ]; 31 | 32 | drawImage = [[UIImageView alloc] initWithImage:nil]; 33 | drawImage.frame = CGRectMake(0, 0, self.view.frame.size.width, 420); 34 | 35 | lineWidth = 5.0; 36 | 37 | [ self.view addSubview:drawImage]; 38 | color = [ UIColor darkGrayColor ]; 39 | 40 | alarmTitle = [[AlarmTitleButton alloc ] initWithFrame:CGRectMake( 0, 0, 320, 27 ) ]; 41 | [ self.view addSubview:alarmTitle ]; 42 | 43 | [ NSTimer scheduledTimerWithTimeInterval:1 44 | target:self 45 | selector:@selector(updateTitle:) 46 | userInfo:nil 47 | repeats:YES ]; 48 | 49 | return self; 50 | } 51 | 52 | 53 | - (void)clearPoints { 54 | for ( NSInteger i=0; i<4; i++){ 55 | points[i] = CGPointZero; 56 | } 57 | } 58 | 59 | 60 | -(void)addText{ 61 | DrawingTextBox *pv = [[ DrawingTextBox alloc ] initWithTextBlob: [ note addTextBlob ] Controller:self ]; 62 | [self.view addSubview: pv ]; 63 | [ pv liftUp ]; 64 | wasMoved = NO; 65 | currentTextEditBox = pv; 66 | pv.isEditing = YES; 67 | [ pv release]; 68 | 69 | } 70 | 71 | 72 | -(void) removeText:(DrawingTextBox*)dtb{ 73 | if ( currentTextEditBox == dtb ){ 74 | currentTextEditBox = nil; 75 | } 76 | [ dtb removeFromSuperview ]; 77 | } 78 | 79 | -(void)updateTitle:(id)sel { 80 | alarmTitle.text = [ note alarmTitle ]; 81 | } 82 | 83 | 84 | -(void)setNote:(Note *)n{ 85 | if ( note != n ){ 86 | note.image = drawImage.image; 87 | [ note save ]; 88 | [ note release ]; 89 | [ n retain ]; 90 | note = n; 91 | } 92 | for ( UIView *view in self.view.subviews ){ 93 | if ([ view isKindOfClass:[DrawingTextBox class] ]){ 94 | [ view removeFromSuperview]; 95 | } 96 | } 97 | for ( NoteTextBlob *text in note.textBlobs ){ 98 | DrawingTextBox *pv = [[ DrawingTextBox alloc ] initWithTextBlob: text Controller:self ]; 99 | [self.view addSubview: pv ]; 100 | [ pv release]; 101 | } 102 | drawImage.image = note.image; 103 | [ self updateTitle:NULL ]; 104 | } 105 | 106 | -(Note*)unSavedNote{ 107 | return note; 108 | } 109 | 110 | -(Note*)note{ 111 | note.image = drawImage.image; 112 | alarmTitle.hidden = YES; 113 | UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, [[UIScreen mainScreen] scale]); 114 | CGContextRef context = UIGraphicsGetCurrentContext(); 115 | [ self.view.layer renderInContext:context ]; 116 | note.thumbnail = UIGraphicsGetImageFromCurrentImageContext(); 117 | UIGraphicsEndImageContext(); 118 | [ note save ]; 119 | alarmTitle.hidden = NO; 120 | return note; 121 | } 122 | 123 | 124 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 125 | UITouch *touch = [touches anyObject]; 126 | CGPoint currentPoint = [touch locationInView:self.view]; 127 | wasMoved = NO; 128 | 129 | // Only move the placard view if the touch was in the placard view 130 | if ([[touch view] isKindOfClass:[DrawingTextBox class] ]){ 131 | [ (DrawingTextBox*)[touch view] liftUp ]; 132 | return; 133 | } 134 | 135 | [[ NSNotificationCenter defaultCenter ] postNotificationName:DRAWING_BEGAN_NOTIFICATION object: self ]; 136 | 137 | [ self clearPoints ]; 138 | points[0] = lastPoint = currentPoint; 139 | } 140 | 141 | 142 | - (CGFloat)distanceBetweenPoint:(CGPoint)a andPoint:(CGPoint)b { 143 | CGFloat a2 = powf(a.x-b.x, 2.f); 144 | CGFloat b2 = powf(a.y-b.y, 2.f); 145 | return sqrtf(a2 + b2); 146 | } 147 | 148 | 149 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 150 | 151 | UITouch *touch = [touches anyObject]; 152 | wasMoved = YES; 153 | CGPoint currentPoint = [touch locationInView:self.view]; 154 | 155 | // Only move the placard view if the touch was in the placard view 156 | if ([[touch view] isKindOfClass:[DrawingTextBox class] ]){ 157 | [ (DrawingTextBox*)[touch view] moveTo: currentPoint ]; 158 | return; 159 | } 160 | 161 | if ( [ self distanceBetweenPoint:points[0] andPoint: currentPoint ] < 10 ){ 162 | return; 163 | } 164 | 165 | for ( NSInteger i=3; i>0; i--){ 166 | points[i] = points[i-1]; 167 | } 168 | 169 | points[0] = currentPoint; 170 | 171 | if ( CGPointEqualToPoint( CGPointZero , points[3] ) ){ 172 | return; 173 | } 174 | 175 | UIGraphicsBeginImageContext(self.view.frame.size); 176 | [ drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; 177 | 178 | CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); 179 | CGContextSetLineWidth(UIGraphicsGetCurrentContext(), self.isErasing ? 20.0 : lineWidth ); 180 | 181 | CGContextSetStrokeColorWithColor( UIGraphicsGetCurrentContext(), 182 | self.isErasing ? [ UIColor whiteColor].CGColor : color.CGColor ); 183 | 184 | CGContextBeginPath(UIGraphicsGetCurrentContext()); 185 | 186 | CGContextMoveToPoint(UIGraphicsGetCurrentContext(), points[3].x, points[3].y); 187 | 188 | CGPoint first = points[0]; 189 | 190 | points[0].y = (points[0].y + points[1].y) / 2; 191 | points[0].x = (points[0].x + points[1].x) / 2; 192 | 193 | CGPoint end = points[0]; 194 | 195 | CGContextAddCurveToPoint(UIGraphicsGetCurrentContext(), 196 | points[2].x, 197 | points[2].y, 198 | points[1].x, 199 | points[1].y, 200 | points[0].x, 201 | points[0].y ); 202 | 203 | [ self clearPoints ]; 204 | points[0] = first; 205 | points[1] = end; 206 | 207 | CGContextStrokePath(UIGraphicsGetCurrentContext()); 208 | 209 | drawImage.image = UIGraphicsGetImageFromCurrentImageContext(); 210 | UIGraphicsEndImageContext(); 211 | 212 | lastPoint = end; 213 | 214 | } 215 | 216 | 217 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 218 | UITouch *touch = [touches anyObject]; 219 | CGPoint currentPoint = [touch locationInView:self.view]; 220 | 221 | if ([[touch view] isKindOfClass:[DrawingTextBox class] ]){ 222 | if ( wasMoved ){ 223 | [ (DrawingTextBox*)[touch view] moveToAndDrop:currentPoint ]; 224 | } else { 225 | currentTextEditBox = (DrawingTextBox*)[touch view] ; 226 | [ currentTextEditBox setIsEditing:YES ]; 227 | } 228 | 229 | return; 230 | } 231 | if ( currentTextEditBox && ! wasMoved ){ 232 | currentTextEditBox.isEditing = NO; 233 | currentTextEditBox = nil; 234 | return; 235 | } 236 | 237 | UIGraphicsBeginImageContext(self.view.frame.size); 238 | [drawImage.image drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; 239 | CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound); 240 | 241 | CGContextSetLineWidth(UIGraphicsGetCurrentContext(), self.isErasing ? 20.0 : lineWidth ); 242 | CGContextSetStrokeColorWithColor( UIGraphicsGetCurrentContext(), 243 | self.isErasing ? [ UIColor whiteColor].CGColor : color.CGColor ); 244 | CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y); 245 | if( wasMoved ){ 246 | CGContextAddQuadCurveToPoint( UIGraphicsGetCurrentContext(), 247 | points[0].x, 248 | points[0].y, 249 | currentPoint.x, 250 | currentPoint.y ); 251 | } else { 252 | CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y); 253 | } 254 | CGContextStrokePath(UIGraphicsGetCurrentContext()); 255 | CGContextFlush(UIGraphicsGetCurrentContext()); 256 | drawImage.image = UIGraphicsGetImageFromCurrentImageContext(); 257 | UIGraphicsEndImageContext(); 258 | } 259 | 260 | 261 | -(BOOL)hidden { 262 | return self.view.hidden; 263 | } 264 | 265 | 266 | -(void)setHidden:(BOOL)h { 267 | self.view.hidden = h; 268 | } 269 | 270 | 271 | - (void)clear { 272 | drawImage.image = nil; 273 | } 274 | 275 | 276 | - (void)didReceiveMemoryWarning { 277 | [super didReceiveMemoryWarning]; 278 | } 279 | 280 | 281 | @end 282 | -------------------------------------------------------------------------------- /Assets/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | image/svg+xml 55 | 56 | Media Playback Start 57 | 58 | 59 | Lapo Calamandrei 60 | 61 | 62 | 63 | 64 | 65 | play 66 | media 67 | music 68 | video 69 | player 70 | 71 | 72 | 73 | 74 | Jakub Steiner 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | --------------------------------------------------------------------------------