diff --git a/Clocker.xcodeproj/project.pbxproj b/Clocker.xcodeproj/project.pbxproj index cf12b96..b369e48 100755 --- a/Clocker.xcodeproj/project.pbxproj +++ b/Clocker.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 9A2000D11BFBD472002BFDE8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9A2000CF1BFBD472002BFDE8 /* Localizable.strings */; settings = {ASSET_TAGS = (); }; }; + 9A25F7451C1A5E17007D369B /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9A25F7421C1A5E17007D369B /* Info.plist */; settings = {ASSET_TAGS = (); }; }; + 9A25F7461C1A5E17007D369B /* iRate.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 9A25F7431C1A5E17007D369B /* iRate.bundle */; settings = {ASSET_TAGS = (); }; }; + 9A25F7471C1A5E17007D369B /* iRate.m in Sources */ = {isa = PBXBuildFile; fileRef = 9A25F7441C1A5E17007D369B /* iRate.m */; settings = {ASSET_TAGS = (); }; }; 9A4379251BEC223900F4E27F /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379211BEC223900F4E27F /* Security.framework */; settings = {ASSET_TAGS = (); }; }; 9A4379261BEC223900F4E27F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379221BEC223900F4E27F /* SystemConfiguration.framework */; settings = {ASSET_TAGS = (); }; }; 9A4379271BEC223900F4E27F /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4379231BEC223900F4E27F /* Fabric.framework */; settings = {ASSET_TAGS = (); }; }; @@ -41,6 +44,18 @@ 9A2000CE1BFBD3D7002BFDE8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/PreferencesWindow.xib; sourceTree = ""; }; 9A2000D01BFBD472002BFDE8 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Clocker/en.lproj/Localizable.strings; sourceTree = ""; }; 9A2000D21BFBD47C002BFDE8 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Clocker/fr.lproj/Localizable.strings; sourceTree = ""; }; + 9A25F7411C1A5E17007D369B /* iRate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iRate.h; path = "Clocker/Rate App/iRate.h"; sourceTree = ""; }; + 9A25F7421C1A5E17007D369B /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = "Clocker/Rate App/Info.plist"; sourceTree = ""; }; + 9A25F7431C1A5E17007D369B /* iRate.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = iRate.bundle; path = "Clocker/Rate App/iRate.bundle"; sourceTree = ""; }; + 9A25F7441C1A5E17007D369B /* iRate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = iRate.m; path = "Clocker/Rate App/iRate.m"; sourceTree = ""; }; + 9A25F7491C1A672A007D369B /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = Clocker/ja.lproj/Localizable.strings; sourceTree = ""; }; + 9A25F74A1C1A672A007D369B /* ja */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ja; path = Clocker/ja.lproj/MainMenu.xib; sourceTree = ""; }; + 9A25F74B1C1A672A007D369B /* ja */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ja; path = ja.lproj/Panel.xib; sourceTree = ""; }; + 9A25F74C1C1A672A007D369B /* ja */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = ja; path = ja.lproj/PreferencesWindow.xib; sourceTree = ""; }; + 9A25F74D1C1A6C08007D369B /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Clocker/de.lproj/Localizable.strings; sourceTree = ""; }; + 9A25F74E1C1A6C08007D369B /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = Clocker/de.lproj/MainMenu.xib; sourceTree = ""; }; + 9A25F74F1C1A6C08007D369B /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/Panel.xib; sourceTree = ""; }; + 9A25F7501C1A6C08007D369B /* de */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = de; path = de.lproj/PreferencesWindow.xib; sourceTree = ""; }; 9A4379211BEC223900F4E27F /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Security.framework; sourceTree = ""; }; 9A4379221BEC223900F4E27F /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SystemConfiguration.framework; sourceTree = ""; }; 9A4379231BEC223900F4E27F /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = ""; }; @@ -112,6 +127,17 @@ name = "Localization Strings"; sourceTree = ""; }; + 9A25F7481C1A5E21007D369B /* Rate */ = { + isa = PBXGroup; + children = ( + 9A25F7411C1A5E17007D369B /* iRate.h */, + 9A25F7421C1A5E17007D369B /* Info.plist */, + 9A25F7431C1A5E17007D369B /* iRate.bundle */, + 9A25F7441C1A5E17007D369B /* iRate.m */, + ); + name = Rate; + sourceTree = ""; + }; 9A8605E01BEC15F400A810A4 /* XIB */ = { isa = PBXGroup; children = ( @@ -184,6 +210,7 @@ DD4F7BF913C30F9F00825C6E = { isa = PBXGroup; children = ( + 9A25F7481C1A5E21007D369B /* Rate */, 9A5B1A8D1BECDFB700A77C68 /* Clocker.entitlements */, 9A43792D1BEC256200F4E27F /* Media.xcassets */, 9A2000C61BFBCEF6002BFDE8 /* Localization Strings */, @@ -270,6 +297,8 @@ en, fr, Base, + ja, + de, ); mainGroup = DD4F7BF913C30F9F00825C6E; productRefGroup = DD4F7C0513C30F9F00825C6E /* Products */; @@ -291,9 +320,11 @@ 9A8605D91BEC155B00A810A4 /* Status.png in Resources */, 9ABA38AC1BFAD7F80073EA4D /* Panel.xib in Resources */, 9A43792E1BEC256200F4E27F /* Media.xcassets in Resources */, + 9A25F7461C1A5E17007D369B /* iRate.bundle in Resources */, 9A2000D11BFBD472002BFDE8 /* Localizable.strings in Resources */, 9A8605DC1BEC155B00A810A4 /* StatusHighlighted@2x.png in Resources */, 9A8605DA1BEC155B00A810A4 /* Status@2x.png in Resources */, + 9A25F7451C1A5E17007D369B /* Info.plist in Resources */, 9A8605DB1BEC155B00A810A4 /* StatusHighlighted.png in Resources */, 9A8605D81BEC155B00A810A4 /* PowerIcon.png in Resources */, ); @@ -323,6 +354,7 @@ buildActionMask = 2147483647; files = ( 9A8605BF1BEC14F600A810A4 /* BackgroundView.m in Sources */, + 9A25F7471C1A5E17007D369B /* iRate.m in Sources */, 9A8605C01BEC14F600A810A4 /* Panel.m in Sources */, 9A8605C11BEC14F600A810A4 /* PreferencesWindowController.m in Sources */, 9A8605BA1BEC14DC00A810A4 /* StatusItemView.m in Sources */, @@ -342,6 +374,8 @@ children = ( 9A2000D01BFBD472002BFDE8 /* en */, 9A2000D21BFBD47C002BFDE8 /* fr */, + 9A25F7491C1A672A007D369B /* ja */, + 9A25F74D1C1A6C08007D369B /* de */, ); name = Localizable.strings; sourceTree = ""; @@ -352,6 +386,8 @@ 9A2000CC1BFBD3D7002BFDE8 /* Base */, 9A825E3B1C064F6C0037CA3B /* en */, 9A825E3C1C064F700037CA3B /* fr */, + 9A25F74A1C1A672A007D369B /* ja */, + 9A25F74E1C1A6C08007D369B /* de */, ); name = MainMenu.xib; sourceTree = ""; @@ -362,6 +398,8 @@ 9ABA38B31BFAD8520073EA4D /* fr */, 9A2000CD1BFBD3D7002BFDE8 /* Base */, 9A825E3F1C06538B0037CA3B /* en */, + 9A25F74B1C1A672A007D369B /* ja */, + 9A25F74F1C1A6C08007D369B /* de */, ); name = Panel.xib; path = Clocker; @@ -373,6 +411,8 @@ 9ABA38B41BFAD8520073EA4D /* fr */, 9A2000CE1BFBD3D7002BFDE8 /* Base */, 9A825E3D1C06534E0037CA3B /* en */, + 9A25F74C1C1A672A007D369B /* ja */, + 9A25F7501C1A6C08007D369B /* de */, ); name = PreferencesWindow.xib; path = Clocker; @@ -392,7 +432,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -408,7 +448,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; SDKROOT = macosx; }; name = Distribution; @@ -419,7 +459,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -431,7 +471,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker; PRODUCT_NAME = Clocker; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Distribution; @@ -447,7 +487,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -471,7 +511,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; SDKROOT = macosx; }; name = Debug; @@ -487,7 +527,7 @@ CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -503,7 +543,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; SDKROOT = macosx; }; name = Release; @@ -514,7 +554,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COMBINE_HIDPI_IMAGES = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( @@ -527,7 +567,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker; PRODUCT_NAME = Clocker; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Debug; @@ -538,7 +578,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = Clocker/Clocker.entitlements; - CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application: Abhishek Banthia (AJS5SNW8EY)"; + CODE_SIGN_IDENTITY = "Mac Developer: Abhishek Banthia (75WFZYE9LW)"; COMBINE_HIDPI_IMAGES = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -550,7 +590,7 @@ MACOSX_DEPLOYMENT_TARGET = 10.10; PRODUCT_BUNDLE_IDENTIFIER = com.abhishek.Clocker; PRODUCT_NAME = Clocker; - PROVISIONING_PROFILE = "1885f3d2-2a35-4a0b-b465-4c0119f4bbaf"; + PROVISIONING_PROFILE = ""; WRAPPER_EXTENSION = app; }; name = Release; diff --git a/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate b/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate index 2d21c73..d9ca436 100644 Binary files a/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate and b/Clocker.xcodeproj/project.xcworkspace/xcuserdata/abhishekbanthia.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index fe2b454..734d44f 100644 --- a/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -2,4 +2,54 @@ + + + + + + + + + + + + + + diff --git a/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcschemes/Clocker.xcscheme b/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcschemes/Clocker.xcscheme index ba89cbf..36ace82 100644 --- a/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcschemes/Clocker.xcscheme +++ b/Clocker.xcodeproj/xcuserdata/abhishekbanthia.xcuserdatad/xcschemes/Clocker.xcscheme @@ -52,7 +52,7 @@ debugServiceExtension = "internal" allowLocationSimulation = "YES" showNonLocalizedStrings = "YES" - language = "en" + language = "fr" region = "AU"> diff --git a/Clocker/ApplicationDelegate.m b/Clocker/ApplicationDelegate.m index ff70c3f..f82965f 100755 --- a/Clocker/ApplicationDelegate.m +++ b/Clocker/ApplicationDelegate.m @@ -28,6 +28,7 @@ #import "ApplicationDelegate.h" #import #import +#import "iRate.h" @implementation ApplicationDelegate @@ -55,38 +56,19 @@ void *kContextActivePanel = &kContextActivePanel; } } ++ (void)initialize +{ + //Configure iRate + [iRate sharedInstance].daysUntilPrompt = 0; + [iRate sharedInstance].usesUntilPrompt = 5; + [iRate sharedInstance].appStoreID = 1056643111; + [iRate sharedInstance].useAllAvailableLanguages = NO; +} + #pragma mark - NSApplicationDelegate - (void)applicationDidFinishLaunching:(NSNotification *)notification { - - if ([[NSUserDefaults standardUserDefaults] objectForKey:@"noOfLaunches"] == nil) - { - NSNumber *numberOfLaunches = @1; - [[NSUserDefaults standardUserDefaults] setObject:numberOfLaunches forKey:@"noOfLaunches"]; - } - else - { - //Check the number of times app has been launched. - - NSNumber *numberOfLaunches = [[NSUserDefaults standardUserDefaults] objectForKey:@"noOfLaunches"]; - NSInteger launches = numberOfLaunches.integerValue; - launches++; - numberOfLaunches = [NSNumber numberWithInteger:launches]; - [[NSUserDefaults standardUserDefaults] setObject:numberOfLaunches forKey:@"noOfLaunches"]; - - if (numberOfLaunches.integerValue == 151) - { - NSAlert *reviewAlert = [[NSAlert alloc] init]; - reviewAlert.alertStyle = NSInformationalAlertStyle; - reviewAlert.messageText = NSLocalizedString(@"SpreadTheWordTitle", nil); - reviewAlert.informativeText = NSLocalizedString(@"SpreadTheWordMessage", nil); - [reviewAlert addButtonWithTitle:NSLocalizedString(@"Cancel", nil)]; - [reviewAlert runModal]; - - } - } - NSArray *defaultPreference = [[NSUserDefaults standardUserDefaults] objectForKey:@"defaultPreferences"]; if (defaultPreference.count == 0) @@ -106,6 +88,11 @@ void *kContextActivePanel = &kContextActivePanel; [Fabric with:@[[Crashlytics class]]]; } +- (void) initialize +{ + //App ID: 1056643111 +} + - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { // Explicitly remove the icon from the menu bar diff --git a/Clocker/PanelController.h b/Clocker/PanelController.h index a00a18a..dbff934 100755 --- a/Clocker/PanelController.h +++ b/Clocker/PanelController.h @@ -56,6 +56,8 @@ @property (nonatomic, strong) NSMutableArray *defaultPreferences; @property (nonatomic) BOOL hasActivePanel; +@property (nonatomic) NSInteger previousSelectedRow; //for color changes on row selection + @property (nonatomic, unsafe_unretained, readonly) id delegate; @property (weak) IBOutlet NSTableView *mainTableview; diff --git a/Clocker/PanelController.m b/Clocker/PanelController.m index e44f573..a2caebc 100755 --- a/Clocker/PanelController.m +++ b/Clocker/PanelController.m @@ -266,7 +266,7 @@ timeCell.stringValue = [self getTimeForTimeZone:self.defaultPreferences[row]]; NSNumber *shouldShowOnlyCity = [[NSUserDefaults standardUserDefaults] objectForKey:@"showOnlyCity"]; - + cellText.stringValue = [self formatStringShouldContainCity:shouldShowOnlyCity.boolValue withTimezoneName:self.defaultPreferences[row]]; return cell; @@ -365,6 +365,38 @@ return [self compareSystemDate:[self getLocalCurrentDate] toTimezoneDate:[dateFormatter stringFromDate:currentDate]];; } +#pragma mark - +#pragma mark NSTableview Minor Customization when selecting rows +#pragma mark - + +-(void)tableViewSelectionDidChange:(NSNotification *)notification +{ + if (self.mainTableview.selectedRow != -1) { + [self updateCellForOldSelection:self.mainTableview.selectedRow andColor:[NSColor whiteColor]]; + } + if (self.previousSelectedRow != -1) { + [self updateCellForOldSelection:self.previousSelectedRow andColor:[NSColor blackColor]]; + } + + self.previousSelectedRow = self.mainTableview.selectedRow; +} + +- (void)updateCellForOldSelection:(NSInteger)rowNumber andColor:(NSColor *)colorName +{ + NSTableCellView *cellView = [self.mainTableview viewAtColumn:self.mainTableview.selectedColumn + row:rowNumber + makeIfNecessary:NO]; + + NSTextField *cellText = [cellView viewWithTag:100]; + NSTextField *timeCell = [cellView viewWithTag:101]; + NSTextField *dateCell = [cellView viewWithTag:102]; + + cellText.textColor = colorName; + timeCell.textColor = colorName; + dateCell.textColor = colorName; +} + + #pragma mark - #pragma mark NSTableview Drag and Drop #pragma mark - @@ -377,6 +409,9 @@ [pboard setData:data forType:@"public.text"]; + [self updateCellForOldSelection:rowIndexes.firstIndex andColor:[NSColor blackColor]]; + NSLog(@"Write row with indexes"); + return YES; } diff --git a/Clocker/Rate App/Info.plist b/Clocker/Rate App/Info.plist new file mode 100755 index 0000000..d3de8ee --- /dev/null +++ b/Clocker/Rate App/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Clocker/Rate App/iRate.bundle/ar.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ar.lproj/Localizable.strings new file mode 100755 index 0000000..38c59cb Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/ar.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/bn.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/bn.lproj/Localizable.strings new file mode 100755 index 0000000..a9f5977 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/bn.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/cs.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/cs.lproj/Localizable.strings new file mode 100755 index 0000000..e31014f --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/cs.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Ohodnotit %@"; +"iRateAppMessage" = "Pokud se vám líbí %@, našli byste si chvilku na ohodnocení aplikace? Nebude to trvat víc než minutu.\nDěkujeme za vaši podporu!"; +"iRateGameMessage" = "Pokud se vám %@ líbí, našli byste si chvilku na ohodnocení hry? Nebude to trvat víc než minutu. Děkujeme za vaši podporu!"; +"iRateCancelButton" = "Ne, děkuji"; +"iRateRateButton" = "Ohodnotit nyní"; +"iRateRemindButton" = "Připomenout později"; diff --git a/Clocker/Rate App/iRate.bundle/da.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/da.lproj/Localizable.strings new file mode 100755 index 0000000..c4fbf79 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/da.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Vurdér %@"; +"iRateAppMessage" = "Hvis du kan lide at bruge %@, vil du så ikke bruge et øjeblik på at give en vurdering? Det tager ikke mere end et minut. Mange tak for hjælpen!"; +"iRateGameMessage" = "Hvis du kan lide at spille %@, vil du så ikke bruge et øjeblik på at vurdere det? Det tager ikke mere end et minut. Mange tak for hjælpen!"; +"iRateCancelButton" = "Nej tak"; +"iRateRateButton" = "Vurdér nu"; +"iRateRemindButton" = "Påmind mig senere"; diff --git a/Clocker/Rate App/iRate.bundle/de-AT.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/de-AT.lproj/Localizable.strings new file mode 100755 index 0000000..fc060f7 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/de-AT.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Bewerte %@"; +"iRateAppMessage" = "Wenn dir %@ gefällt, würdest Du es bitte bewerten? Dies wird nicht länger als eine Minute dauern.\nDanke für die Unterstützung!"; +"iRateGameMessage" = "Wenn dir %@ gefällt, würdest Du es bitte bewerten? Dies wird nicht länger als eine Minute dauern. Danke für die Unterstützung!"; +"iRateCancelButton" = "Nein, danke"; +"iRateRateButton" = "Jetzt bewerten"; +"iRateRemindButton" = "Später erinnern"; \ No newline at end of file diff --git a/Clocker/Rate App/iRate.bundle/de.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/de.lproj/Localizable.strings new file mode 100755 index 0000000..399e881 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/de.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/el.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/el.lproj/Localizable.strings new file mode 100755 index 0000000..502c94a Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/el.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/en.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/en.lproj/Localizable.strings new file mode 100755 index 0000000..ddaf461 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/en.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/es.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/es.lproj/Localizable.strings new file mode 100755 index 0000000..dc96e46 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/es.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/fa.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/fa.lproj/Localizable.strings new file mode 100755 index 0000000..8f4c50c --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/fa.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "امتیاز دهی به %@"; +"iRateAppMessage" = "اگر شما از برنامه‌ی %@ لذت بردین، عالی میشه اگه با این برنامه در اپ‌استور امتیاز دهید! این کار بیشتر از ۱ دقیقه طول نمی‌کشد. با تشکر از حمایت شما!"; +"iRateGameMessage" ="اگر شما از بازی %@ لذت بردین، عالی میشه اگه با این برنامه در اپ‌استور امتیاز دهید! این کار بیشتر از ۱ دقیقه طول نمی‌کشد. با تشکر از حمایت شما!"; +"iRateCancelButton" = "نه، با تشکر"; +"iRateRateButton" = "می‌خوام امتیاز بدم"; +"iRateRemindButton" = "بعدا یادم بنداز"; diff --git a/Clocker/Rate App/iRate.bundle/fr.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/fr.lproj/Localizable.strings new file mode 100755 index 0000000..22f78aa --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/fr.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Notez %@"; +"iRateAppMessage" = "Si vous aimez utiliser %@, n'oubliez pas de donner votre avis sur l'App Store. Cela ne prend qu'une minute. Merci d'avance pour votre soutien !"; +"iRateGameMessage" = "Si vous aimez jouer à %@, n'oubliez pas de donner votre avis sur l'App Store. Cela ne prend qu'une minute. Merci d'avance pour votre soutien !"; +"iRateCancelButton" = "Non, merci"; +"iRateRateButton" = "Noter maintenant"; +"iRateRemindButton" = "Me le rappeler ultérieurement"; diff --git a/Clocker/Rate App/iRate.bundle/he.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/he.lproj/Localizable.strings new file mode 100755 index 0000000..ab9d492 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/he.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/hi.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/hi.lproj/Localizable.strings new file mode 100755 index 0000000..67a532e Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/hi.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/id.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/id.lproj/Localizable.strings new file mode 100755 index 0000000..3758921 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/id.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/it.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/it.lproj/Localizable.strings new file mode 100755 index 0000000..fc674ce Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/it.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/ja.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ja.lproj/Localizable.strings new file mode 100755 index 0000000..60c0710 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/ja.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/ko.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ko.lproj/Localizable.strings new file mode 100755 index 0000000..93599c3 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/ko.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/mk.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/mk.lproj/Localizable.strings new file mode 100755 index 0000000..6c99ce5 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/mk.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/nl.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/nl.lproj/Localizable.strings new file mode 100755 index 0000000..e4dedf9 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/nl.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Beoordeel %@"; +"iRateAppMessage" = "Als het gebruik van %@ je bevalt, wil je dan een moment nemen om het te beoordelen? Het duurt nog geen minuut. Bedankt voor je steun!"; +"iRateGameMessage" = "Als het spelen van %@ je bevalt, wil je dan een moment nemen om het te beoordelen? Het duurt nog geen minuut. Bedankt voor je steun!"; +"iRateCancelButton" = "Nee, bedankt"; +"iRateRateButton" = "Beoordeel nu"; +"iRateRemindButton" = "Herinner me er later aan"; \ No newline at end of file diff --git a/Clocker/Rate App/iRate.bundle/no.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/no.lproj/Localizable.strings new file mode 100755 index 0000000..212909b Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/no.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/pa.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/pa.lproj/Localizable.strings new file mode 100755 index 0000000..3647d91 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/pa.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/pl.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/pl.lproj/Localizable.strings new file mode 100755 index 0000000..9d4f94d Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/pl.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/pt.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/pt.lproj/Localizable.strings new file mode 100755 index 0000000..6ff1900 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/pt.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/ru.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ru.lproj/Localizable.strings new file mode 100755 index 0000000..fdd3af9 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/ru.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/sk.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/sk.lproj/Localizable.strings new file mode 100755 index 0000000..84c739b --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/sk.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Ohodnotiť %@"; +"iRateAppMessage" = "Ak sa vám páči %@, našli by ste si chvíľku na ohodnotenie aplikácie? Nebude to trvať viac ako minútu.\nĎakujeme za vašu podporu!"; +"iRateGameMessage" = "Ak sa vám hra %@ páči, našli by ste si chvíľku na ohodnotenie aplikácie? Nebude to trvať viac ako minútu. Ďakujeme za vašu podporu!"; +"iRateCancelButton" = "Nie, Ďakujem"; +"iRateRateButton" = "Ohodnotiť teraz"; +"iRateRemindButton" = "Pripomenúť neskôr"; \ No newline at end of file diff --git a/Clocker/Rate App/iRate.bundle/sl.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/sl.lproj/Localizable.strings new file mode 100755 index 0000000..25112d2 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/sl.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/sv.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/sv.lproj/Localizable.strings new file mode 100755 index 0000000..22c1fa1 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/sv.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Betygsätt %@"; +"iRateAppMessage" = "Gillar du %@ och kan tänka dig att betygsätta den? Det tar inte mer än en minut. Tack för ditt stöd!"; +"iRateGameMessage" = "Gillar du att spela %@ och kan tänka dig att betygsätta det? Det tar inte mer än en minut. Tack för ditt stöd!"; +"iRateCancelButton" = "Nej tack"; +"iRateRateButton" = "Betygsätt nu!"; +"iRateRemindButton" = "Påminn mig senare"; \ No newline at end of file diff --git a/Clocker/Rate App/iRate.bundle/th.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/th.lproj/Localizable.strings new file mode 100755 index 0000000..7486e24 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/th.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/tr.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/tr.lproj/Localizable.strings new file mode 100755 index 0000000..807f929 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/tr.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/uk.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/uk.lproj/Localizable.strings new file mode 100755 index 0000000..055fe50 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/uk.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/ur-IN.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ur-IN.lproj/Localizable.strings new file mode 100755 index 0000000..b174a90 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/ur-IN.lproj/Localizable.strings @@ -0,0 +1,7 @@ +"iRateMessageTitle" = "کو ریٹ کیجیے %@"; +"iRateAppMessage" = "اگر آپ نے %@ کو مفید پایا ہے تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateGameMessage" = "اگر آپ %@ کھیل کر محظوظ ہوئے ہیں تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateCancelButton" = "نہیں، شکریہ"; +"iRateRateButton" = "ابھی ریٹ کیجیے"; +"iRateRemindButton" = "مجھے بعد میں یاد دلائیں"; +"iRateOkay" = "ٹھیک ہے"; diff --git a/Clocker/Rate App/iRate.bundle/ur-PK.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ur-PK.lproj/Localizable.strings new file mode 100755 index 0000000..b174a90 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/ur-PK.lproj/Localizable.strings @@ -0,0 +1,7 @@ +"iRateMessageTitle" = "کو ریٹ کیجیے %@"; +"iRateAppMessage" = "اگر آپ نے %@ کو مفید پایا ہے تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateGameMessage" = "اگر آپ %@ کھیل کر محظوظ ہوئے ہیں تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateCancelButton" = "نہیں، شکریہ"; +"iRateRateButton" = "ابھی ریٹ کیجیے"; +"iRateRemindButton" = "مجھے بعد میں یاد دلائیں"; +"iRateOkay" = "ٹھیک ہے"; diff --git a/Clocker/Rate App/iRate.bundle/ur.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/ur.lproj/Localizable.strings new file mode 100755 index 0000000..b174a90 --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/ur.lproj/Localizable.strings @@ -0,0 +1,7 @@ +"iRateMessageTitle" = "کو ریٹ کیجیے %@"; +"iRateAppMessage" = "اگر آپ نے %@ کو مفید پایا ہے تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateGameMessage" = "اگر آپ %@ کھیل کر محظوظ ہوئے ہیں تو کیا آپ اپنے قیمتی وقت میں سے چند لمحے نکال کر اس کو ریٹ کریں گے؟ اس میں ایک منٹ سے زیادہ نہیں لگے گا، آپ کے تعاون کا شکریہ!"; +"iRateCancelButton" = "نہیں، شکریہ"; +"iRateRateButton" = "ابھی ریٹ کیجیے"; +"iRateRemindButton" = "مجھے بعد میں یاد دلائیں"; +"iRateOkay" = "ٹھیک ہے"; diff --git a/Clocker/Rate App/iRate.bundle/vi.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/vi.lproj/Localizable.strings new file mode 100755 index 0000000..05b75cc --- /dev/null +++ b/Clocker/Rate App/iRate.bundle/vi.lproj/Localizable.strings @@ -0,0 +1,6 @@ +"iRateMessageTitle" = "Đánh giá %@"; +"iRateAppMessage" = "Nếu thích sử dụng %@, bạn có muốn giành một chút thời gian để đánh giá nó? Sẽ không lâu hơn một phút. Cảm ơn sự hỗ trợ của bạn!"; +"iRateGameMessage" = "Nếu thích chơi %@, bạn có muốn giành một chút thời gian để đánh giá nó? Sẽ không lâu hơn một phút. Cảm ơn sự hỗ trợ của bạn!"; +"iRateCancelButton" = "Không, Cảm ơn"; +"iRateRateButton" = "Đánh Giá Ngay"; +"iRateRemindButton" = "Nhắc Tôi Sau"; diff --git a/Clocker/Rate App/iRate.bundle/zh-Hans.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/zh-Hans.lproj/Localizable.strings new file mode 100755 index 0000000..0db893b Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/zh-Hans.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.bundle/zh-Hant.lproj/Localizable.strings b/Clocker/Rate App/iRate.bundle/zh-Hant.lproj/Localizable.strings new file mode 100755 index 0000000..923de48 Binary files /dev/null and b/Clocker/Rate App/iRate.bundle/zh-Hant.lproj/Localizable.strings differ diff --git a/Clocker/Rate App/iRate.h b/Clocker/Rate App/iRate.h new file mode 100755 index 0000000..12f981c --- /dev/null +++ b/Clocker/Rate App/iRate.h @@ -0,0 +1,174 @@ +// +// iRate.h +// +// Version 1.11.4 +// +// Created by Nick Lockwood on 26/01/2011. +// Copyright 2011 Charcoal Design +// +// Distributed under the permissive zlib license +// Get the latest version from here: +// +// https://github.com/nicklockwood/iRate +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis" + + +#import +#undef weak_delegate +#if __has_feature(objc_arc_weak) && \ +(TARGET_OS_IPHONE || __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8) +#define weak_delegate weak +#else +#define weak_delegate unsafe_unretained +#endif + + +#import +#if TARGET_OS_IPHONE +#import +#define IRATE_EXTERN UIKIT_EXTERN +#else +#import +#define IRATE_EXTERN APPKIT_EXTERN +#endif + +//! Project version number for iRate. +FOUNDATION_EXPORT double iRateVersionNumber; + +//! Project version string for iRate. +FOUNDATION_EXPORT const unsigned char iRateVersionString[]; + +IRATE_EXTERN NSUInteger const iRateAppStoreGameGenreID; +IRATE_EXTERN NSString *const iRateErrorDomain; + +//localisation string keys +IRATE_EXTERN NSString *const iRateMessageTitleKey; //iRateMessageTitle +IRATE_EXTERN NSString *const iRateAppMessageKey; //iRateAppMessage +IRATE_EXTERN NSString *const iRateGameMessageKey; //iRateGameMessage +IRATE_EXTERN NSString *const iRateUpdateMessageKey; //iRateUpdateMessage +IRATE_EXTERN NSString *const iRateCancelButtonKey; //iRateCancelButton +IRATE_EXTERN NSString *const iRateRemindButtonKey; //iRateRemindButton +IRATE_EXTERN NSString *const iRateRateButtonKey; //iRateRateButton + +//notification keys +IRATE_EXTERN NSString *const iRateCouldNotConnectToAppStore; +IRATE_EXTERN NSString *const iRateDidDetectAppUpdate; +IRATE_EXTERN NSString *const iRateDidPromptForRating; +IRATE_EXTERN NSString *const iRateUserDidAttemptToRateApp; +IRATE_EXTERN NSString *const iRateUserDidDeclineToRateApp; +IRATE_EXTERN NSString *const iRateUserDidRequestReminderToRateApp; +IRATE_EXTERN NSString *const iRateDidOpenAppStore; + + +typedef NS_ENUM(NSUInteger, iRateErrorCode) +{ + iRateErrorBundleIdDoesNotMatchAppStore = 1, + iRateErrorApplicationNotFoundOnAppStore, + iRateErrorApplicationIsNotLatestVersion, + iRateErrorCouldNotOpenRatingPageURL +}; + + +@protocol iRateDelegate +@optional + +- (void)iRateCouldNotConnectToAppStore:(NSError *)error; +- (void)iRateDidDetectAppUpdate; +- (BOOL)iRateShouldPromptForRating; +- (void)iRateDidPromptForRating; +- (void)iRateUserDidAttemptToRateApp; +- (void)iRateUserDidDeclineToRateApp; +- (void)iRateUserDidRequestReminderToRateApp; +- (BOOL)iRateShouldOpenAppStore; +- (void)iRateDidOpenAppStore; + +@end + + +@interface iRate : NSObject + ++ (instancetype)sharedInstance; + +//app store ID - this is only needed if your +//bundle ID is not unique between iOS and Mac app stores +@property (nonatomic, assign) NSUInteger appStoreID; + +//application details - these are set automatically +@property (nonatomic, assign) NSUInteger appStoreGenreID; +@property (nonatomic, copy) NSString *appStoreCountry; +@property (nonatomic, copy) NSString *applicationName; +@property (nonatomic, copy) NSString *applicationVersion; +@property (nonatomic, copy) NSString *applicationBundleID; + +//usage settings - these have sensible defaults +@property (nonatomic, assign) NSUInteger usesUntilPrompt; +@property (nonatomic, assign) NSUInteger eventsUntilPrompt; +@property (nonatomic, assign) float daysUntilPrompt; +@property (nonatomic, assign) float usesPerWeekForPrompt; +@property (nonatomic, assign) float remindPeriod; + +//message text, you may wish to customise these +@property (nonatomic, copy) NSString *messageTitle; +@property (nonatomic, copy) NSString *message; +@property (nonatomic, copy) NSString *updateMessage; +@property (nonatomic, copy) NSString *cancelButtonLabel; +@property (nonatomic, copy) NSString *remindButtonLabel; +@property (nonatomic, copy) NSString *rateButtonLabel; + +//debugging and prompt overrides +@property (nonatomic, assign) BOOL useUIAlertControllerIfAvailable; +@property (nonatomic, assign) BOOL useAllAvailableLanguages; +@property (nonatomic, assign) BOOL promptForNewVersionIfUserRated; +@property (nonatomic, assign) BOOL onlyPromptIfLatestVersion; +@property (nonatomic, assign) BOOL onlyPromptIfMainWindowIsAvailable; +@property (nonatomic, assign) BOOL promptAtLaunch; +@property (nonatomic, assign) BOOL verboseLogging; +@property (nonatomic, assign) BOOL previewMode; + +//advanced properties for implementing custom behaviour +@property (nonatomic, strong) NSURL *ratingsURL; +@property (nonatomic, strong) NSDate *firstUsed; +@property (nonatomic, strong) NSDate *lastReminded; +@property (nonatomic, assign) NSUInteger usesCount; +@property (nonatomic, assign) NSUInteger eventCount; +@property (nonatomic, readonly) float usesPerWeek; +@property (nonatomic, assign) BOOL declinedThisVersion; +@property (nonatomic, readonly) BOOL declinedAnyVersion; +@property (nonatomic, assign) BOOL ratedThisVersion; +@property (nonatomic, readonly) BOOL ratedAnyVersion; +@property (nonatomic, weak_delegate) id delegate; + +//manually control behaviour +- (BOOL)shouldPromptForRating; +- (void)promptForRating; +- (void)promptIfNetworkAvailable; +- (void)promptIfAllCriteriaMet; +- (void)openRatingsPageInAppStore; +- (void)logEvent:(BOOL)deferPrompt; + +@end + + +#pragma clang diagnostic pop diff --git a/Clocker/Rate App/iRate.m b/Clocker/Rate App/iRate.m new file mode 100755 index 0000000..e7fc9f7 --- /dev/null +++ b/Clocker/Rate App/iRate.m @@ -0,0 +1,1195 @@ +// +// iRate.m +// +// Version 1.11.4 +// +// Created by Nick Lockwood on 26/01/2011. +// Copyright 2011 Charcoal Design +// +// Distributed under the permissive zlib license +// Get the latest version from here: +// +// https://github.com/nicklockwood/iRate +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. +// + + +#import "iRate.h" + + +#import +#if !__has_feature(objc_arc) +#error This class requires automatic reference counting +#endif + + +#pragma clang diagnostic ignored "-Wreceiver-is-weak" +#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak" +#pragma clang diagnostic ignored "-Wobjc-missing-property-synthesis" +#pragma clang diagnostic ignored "-Wdirect-ivar-access" +#pragma clang diagnostic ignored "-Wunused-macros" +#pragma clang diagnostic ignored "-Wconversion" +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wselector" +#pragma clang diagnostic ignored "-Wgnu" + + +NSUInteger const iRateAppStoreGameGenreID = 6014; +NSString *const iRateErrorDomain = @"iRateErrorDomain"; + + +NSString *const iRateMessageTitleKey = @"iRateMessageTitle"; +NSString *const iRateAppMessageKey = @"iRateAppMessage"; +NSString *const iRateGameMessageKey = @"iRateGameMessage"; +NSString *const iRateUpdateMessageKey = @"iRateUpdateMessage"; +NSString *const iRateCancelButtonKey = @"iRateCancelButton"; +NSString *const iRateRemindButtonKey = @"iRateRemindButton"; +NSString *const iRateRateButtonKey = @"iRateRateButton"; + +NSString *const iRateCouldNotConnectToAppStore = @"iRateCouldNotConnectToAppStore"; +NSString *const iRateDidDetectAppUpdate = @"iRateDidDetectAppUpdate"; +NSString *const iRateDidPromptForRating = @"iRateDidPromptForRating"; +NSString *const iRateUserDidAttemptToRateApp = @"iRateUserDidAttemptToRateApp"; +NSString *const iRateUserDidDeclineToRateApp = @"iRateUserDidDeclineToRateApp"; +NSString *const iRateUserDidRequestReminderToRateApp = @"iRateUserDidRequestReminderToRateApp"; +NSString *const iRateDidOpenAppStore = @"iRateDidOpenAppStore"; + +static NSString *const iRateAppStoreIDKey = @"iRateAppStoreID"; +static NSString *const iRateRatedVersionKey = @"iRateRatedVersionChecked"; +static NSString *const iRateDeclinedVersionKey = @"iRateDeclinedVersion"; +static NSString *const iRateLastRemindedKey = @"iRateLastReminded"; +static NSString *const iRateLastVersionUsedKey = @"iRateLastVersionUsed"; +static NSString *const iRateFirstUsedKey = @"iRateFirstUsed"; +static NSString *const iRateUseCountKey = @"iRateUseCount"; +static NSString *const iRateEventCountKey = @"iRateEventCount"; + +static NSString *const iRateMacAppStoreBundleID = @"com.apple.appstore"; +static NSString *const iRateAppLookupURLFormat = @"https://itunes.apple.com/%@/lookup"; + +static NSString *const iRateiOSAppStoreURLScheme = @"itms-apps"; +static NSString *const iRateiOSAppStoreURLFormat = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%@&pageNumber=0&sortOrdering=2&mt=8"; +static NSString *const iRateiOS7AppStoreURLFormat = @"itms-apps://itunes.apple.com/app/id%@"; +static NSString *const iRateMacAppStoreURLFormat = @"macappstore://itunes.apple.com/app/id%@"; + + +#define SECONDS_IN_A_DAY 86400.0 +#define SECONDS_IN_A_WEEK 604800.0 +#define MAC_APP_STORE_REFRESH_DELAY 5.0 +#define REQUEST_TIMEOUT 60.0 + + +@implementation NSObject (iRate) + +- (void)iRateCouldNotConnectToAppStore:(__unused NSError *)error {} +- (void)iRateDidDetectAppUpdate {} +- (BOOL)iRateShouldPromptForRating { return YES; } +- (void)iRateDidPromptForRating {} +- (void)iRateUserDidAttemptToRateApp {} +- (void)iRateUserDidDeclineToRateApp {} +- (void)iRateUserDidRequestReminderToRateApp {} +- (BOOL)iRateShouldOpenAppStore { return YES; } +- (void)iRateDidOpenAppStore {} + +@end + + +@interface iRate() + +@property (nonatomic, strong) id visibleAlert; +@property (nonatomic, assign) BOOL checkingForPrompt; +@property (nonatomic, assign) BOOL checkingForAppStoreID; + +@end + + +@implementation iRate + ++ (void)load +{ + [self performSelectorOnMainThread:@selector(sharedInstance) withObject:nil waitUntilDone:NO]; +} + ++ (instancetype)sharedInstance +{ + static iRate *sharedInstance = nil; + if (sharedInstance == nil) + { + sharedInstance = [(iRate *)[self alloc] init]; + } + return sharedInstance; +} + +- (NSString *)localizedStringForKey:(NSString *)key withDefault:(NSString *)defaultString +{ + static NSBundle *bundle = nil; + if (bundle == nil) + { + NSString *bundlePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"iRate" ofType:@"bundle"]; + if (self.useAllAvailableLanguages) + { + bundle = [NSBundle bundleWithPath:bundlePath]; + NSString *language = [[NSLocale preferredLanguages] count]? [NSLocale preferredLanguages][0]: @"en"; + if (![[bundle localizations] containsObject:language]) + { + language = [language componentsSeparatedByString:@"-"][0]; + } + if ([[bundle localizations] containsObject:language]) + { + bundlePath = [bundle pathForResource:language ofType:@"lproj"]; + } + } + bundle = [NSBundle bundleWithPath:bundlePath] ?: [NSBundle mainBundle]; + } + defaultString = [bundle localizedStringForKey:key value:defaultString table:nil]; + return [[NSBundle mainBundle] localizedStringForKey:key value:defaultString table:nil]; +} + +- (iRate *)init +{ + if ((self = [super init])) + { + +#if TARGET_OS_IPHONE + + //register for iphone application events + if (&UIApplicationWillEnterForegroundNotification) + { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationWillEnterForeground) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + } + +#endif + + //get country + self.appStoreCountry = [(NSLocale *)[NSLocale currentLocale] objectForKey:NSLocaleCountryCode]; + if ([self.appStoreCountry isEqualToString:@"150"]) + { + self.appStoreCountry = @"eu"; + } + else if (!self.appStoreCountry || [[self.appStoreCountry stringByReplacingOccurrencesOfString:@"[A-Za-z]{2}" withString:@"" options:NSRegularExpressionSearch range:NSMakeRange(0, 2)] length]) + { + self.appStoreCountry = @"us"; + } + + //application version (use short version preferentially) + self.applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; + if ([self.applicationVersion length] == 0) + { + self.applicationVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + } + + //localised application name + self.applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if ([self.applicationName length] == 0) + { + self.applicationName = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey]; + } + + //bundle id + self.applicationBundleID = [[NSBundle mainBundle] bundleIdentifier]; + + //default settings + self.useAllAvailableLanguages = YES; + self.promptForNewVersionIfUserRated = NO; + self.onlyPromptIfLatestVersion = YES; + self.onlyPromptIfMainWindowIsAvailable = YES; + self.promptAtLaunch = YES; + self.usesUntilPrompt = 10; + self.eventsUntilPrompt = 10; + self.daysUntilPrompt = 10.0f; + self.usesPerWeekForPrompt = 0.0f; + self.remindPeriod = 1.0f; + self.verboseLogging = NO; + self.previewMode = NO; + +#if DEBUG + + //enable verbose logging in debug mode + self.verboseLogging = YES; + NSLog(@"iRate verbose logging enabled."); + +#endif + + //app launched + [self performSelectorOnMainThread:@selector(applicationLaunched) withObject:nil waitUntilDone:NO]; + } + return self; +} + +- (id)delegate +{ + if (_delegate == nil) + { + +#if TARGET_OS_IPHONE +#define APP_CLASS UIApplication +#else +#define APP_CLASS NSApplication +#endif + + _delegate = (id)[[APP_CLASS sharedApplication] delegate]; + } + return _delegate; +} + +- (NSString *)messageTitle +{ + return [_messageTitle ?: [self localizedStringForKey:iRateMessageTitleKey withDefault:@"Rate %@"] stringByReplacingOccurrencesOfString:@"%@" withString:self.applicationName]; +} + +- (NSString *)message +{ + NSString *message = _message; + if (!message) + { + message = (self.appStoreGenreID == iRateAppStoreGameGenreID)? [self localizedStringForKey:iRateGameMessageKey withDefault:@"If you enjoy playing %@, would you mind taking a moment to rate it? It won’t take more than a minute. Thanks for your support!"]: [self localizedStringForKey:iRateAppMessageKey withDefault:@"If you enjoy using %@, would you mind taking a moment to rate it? It won’t take more than a minute. Thanks for your support!"]; + } + return [message stringByReplacingOccurrencesOfString:@"%@" withString:self.applicationName]; +} + +- (NSString *)updateMessage +{ + NSString *updateMessage = _updateMessage; + if (!updateMessage) + { + updateMessage = [self localizedStringForKey:iRateUpdateMessageKey withDefault:self.message]; + } + return [updateMessage stringByReplacingOccurrencesOfString:@"%@" withString:self.applicationName]; +} + +- (NSString *)cancelButtonLabel +{ + return _cancelButtonLabel ?: [self localizedStringForKey:iRateCancelButtonKey withDefault:@"No, Thanks"]; +} + +- (NSString *)rateButtonLabel +{ + return _rateButtonLabel ?: [self localizedStringForKey:iRateRateButtonKey withDefault:@"Rate It Now"]; +} + +- (NSString *)remindButtonLabel +{ + return _remindButtonLabel ?: [self localizedStringForKey:iRateRemindButtonKey withDefault:@"Remind Me Later"]; +} + +- (NSURL *)ratingsURL +{ + if (_ratingsURL) + { + return _ratingsURL; + } + + if (!self.appStoreID && self.verboseLogging) + { + NSLog(@"iRate could not find the App Store ID for this application. If the application is not intended for App Store release then you must specify a custom ratingsURL."); + } + + NSString *URLString; + +#if TARGET_OS_IPHONE + + float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue]; + if (iOSVersion >= 7.0f && iOSVersion < 7.1f) + { + URLString = iRateiOS7AppStoreURLFormat; + } + else + { + URLString = iRateiOSAppStoreURLFormat; + } + +#else + + URLString = iRateMacAppStoreURLFormat; + +#endif + + return [NSURL URLWithString:[NSString stringWithFormat:URLString, @(self.appStoreID)]]; + +} + +- (NSUInteger)appStoreID +{ + return _appStoreID ?: [[[NSUserDefaults standardUserDefaults] objectForKey:iRateAppStoreIDKey] unsignedIntegerValue]; +} + +- (NSDate *)firstUsed +{ + return [[NSUserDefaults standardUserDefaults] objectForKey:iRateFirstUsedKey]; +} + +- (void)setFirstUsed:(NSDate *)date +{ + [[NSUserDefaults standardUserDefaults] setObject:date forKey:iRateFirstUsedKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSDate *)lastReminded +{ + return [[NSUserDefaults standardUserDefaults] objectForKey:iRateLastRemindedKey]; +} + +- (void)setLastReminded:(NSDate *)date +{ + [[NSUserDefaults standardUserDefaults] setObject:date forKey:iRateLastRemindedKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSUInteger)usesCount +{ + return [[NSUserDefaults standardUserDefaults] integerForKey:iRateUseCountKey]; +} + +- (void)setUsesCount:(NSUInteger)count +{ + [[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)count forKey:iRateUseCountKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (NSUInteger)eventCount +{ + return [[NSUserDefaults standardUserDefaults] integerForKey:iRateEventCountKey]; +} + +- (void)setEventCount:(NSUInteger)count +{ + [[NSUserDefaults standardUserDefaults] setInteger:(NSInteger)count forKey:iRateEventCountKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (float)usesPerWeek +{ + return (float)self.usesCount / ([[NSDate date] timeIntervalSinceDate:self.firstUsed] / SECONDS_IN_A_WEEK); +} + +- (BOOL)declinedThisVersion +{ + return [[[NSUserDefaults standardUserDefaults] objectForKey:iRateDeclinedVersionKey] isEqualToString:self.applicationVersion]; +} + +- (void)setDeclinedThisVersion:(BOOL)declined +{ + [[NSUserDefaults standardUserDefaults] setObject:(declined? self.applicationVersion: nil) forKey:iRateDeclinedVersionKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (BOOL)declinedAnyVersion +{ + return [(NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:iRateDeclinedVersionKey] length] != 0; +} + +- (BOOL)ratedVersion:(NSString *)version +{ + return [[[NSUserDefaults standardUserDefaults] objectForKey:iRateRatedVersionKey] isEqualToString:version]; +} + +- (BOOL)ratedThisVersion +{ + return [self ratedVersion:self.applicationVersion]; +} + +- (void)setRatedThisVersion:(BOOL)rated +{ + [[NSUserDefaults standardUserDefaults] setObject:(rated? self.applicationVersion: nil) forKey:iRateRatedVersionKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (BOOL)ratedAnyVersion +{ + return [(NSString *)[[NSUserDefaults standardUserDefaults] objectForKey:iRateRatedVersionKey] length] != 0; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)incrementUseCount +{ + self.usesCount ++; +} + +- (void)incrementEventCount +{ + self.eventCount ++; +} + +- (BOOL)shouldPromptForRating +{ + //preview mode? + if (self.previewMode) + { + NSLog(@"iRate preview mode is enabled - make sure you disable this for release"); + return YES; + } + + //check if we've rated this version + else if (self.ratedThisVersion) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the user has already rated this version"); + } + return NO; + } + + //check if we've rated any version + else if (self.ratedAnyVersion && !self.promptForNewVersionIfUserRated) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the user has already rated this app, and promptForNewVersionIfUserRated is disabled"); + } + return NO; + } + + //check if we've declined to rate the app + else if (self.declinedAnyVersion) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the user has declined to rate the app"); + } + return NO; + } + + //check how long we've been using this version + else if ([[NSDate date] timeIntervalSinceDate:self.firstUsed] < self.daysUntilPrompt * SECONDS_IN_A_DAY) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the app was first used less than %g days ago", self.daysUntilPrompt); + } + return NO; + } + + //check how many times we've used it and the number of significant events + else if (self.usesCount < self.usesUntilPrompt && self.eventCount < self.eventsUntilPrompt) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the app has only been used %@ times and only %@ events have been logged", @(self.usesCount), @(self.eventCount)); + } + return NO; + } + + //check if usage frequency is high enough + else if (self.usesPerWeek < self.usesPerWeekForPrompt) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the app has only been used %g times per week on average since it was installed", self.usesPerWeek); + } + return NO; + } + + //check if within the reminder period + else if (self.lastReminded != nil && [[NSDate date] timeIntervalSinceDate:self.lastReminded] < self.remindPeriod * SECONDS_IN_A_DAY) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not prompt for rating because the user last asked to be reminded less than %g days ago", self.remindPeriod); + } + return NO; + } + + //lets prompt! + return YES; +} + +- (NSString *)valueForKey:(NSString *)key inJSON:(id)json +{ + if ([json isKindOfClass:[NSString class]]) + { + //use legacy parser + NSRange keyRange = [json rangeOfString:[NSString stringWithFormat:@"\"%@\"", key]]; + if (keyRange.location != NSNotFound) + { + NSInteger start = keyRange.location + keyRange.length; + NSRange valueStart = [json rangeOfString:@":" options:(NSStringCompareOptions)0 range:NSMakeRange(start, [(NSString *)json length] - start)]; + if (valueStart.location != NSNotFound) + { + start = valueStart.location + 1; + NSRange valueEnd = [json rangeOfString:@"," options:(NSStringCompareOptions)0 range:NSMakeRange(start, [(NSString *)json length] - start)]; + if (valueEnd.location != NSNotFound) + { + NSString *value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)]; + value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + while ([value hasPrefix:@"\""] && ![value hasSuffix:@"\""]) + { + if (valueEnd.location == NSNotFound) + { + break; + } + NSInteger newStart = valueEnd.location + 1; + valueEnd = [json rangeOfString:@"," options:(NSStringCompareOptions)0 range:NSMakeRange(newStart, [(NSString *)json length] - newStart)]; + value = [json substringWithRange:NSMakeRange(start, valueEnd.location - start)]; + value = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + + value = [value stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\""]]; + value = [value stringByReplacingOccurrencesOfString:@"\\\\" withString:@"\\"]; + value = [value stringByReplacingOccurrencesOfString:@"\\/" withString:@"/"]; + value = [value stringByReplacingOccurrencesOfString:@"\\\"" withString:@"\""]; + value = [value stringByReplacingOccurrencesOfString:@"\\n" withString:@"\n"]; + value = [value stringByReplacingOccurrencesOfString:@"\\r" withString:@"\r"]; + value = [value stringByReplacingOccurrencesOfString:@"\\t" withString:@"\t"]; + value = [value stringByReplacingOccurrencesOfString:@"\\f" withString:@"\f"]; + value = [value stringByReplacingOccurrencesOfString:@"\\b" withString:@"\f"]; + + while (YES) + { + NSRange unicode = [value rangeOfString:@"\\u"]; + if (unicode.location == NSNotFound || unicode.location + unicode.length == 0) + { + break; + } + + uint32_t c = 0; + NSString *hex = [value substringWithRange:NSMakeRange(unicode.location + 2, 4)]; + NSScanner *scanner = [NSScanner scannerWithString:hex]; + [scanner scanHexInt:&c]; + + if (c <= 0xffff) + { + value = [value stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6) withString:[NSString stringWithFormat:@"%C", (unichar)c]]; + } + else + { + //convert character to surrogate pair + uint16_t x = (uint16_t)c; + uint16_t u = (c >> 16) & ((1 << 5) - 1); + uint16_t w = (uint16_t)u - 1; + unichar high = 0xd800 | (w << 6) | x >> 10; + unichar low = (uint16_t)(0xdc00 | (x & ((1 << 10) - 1))); + + value = [value stringByReplacingCharactersInRange:NSMakeRange(unicode.location, 6) withString:[NSString stringWithFormat:@"%C%C", high, low]]; + } + } + return value; + } + } + } + } + else + { + return json[key]; + } + return nil; +} + +- (void)setAppStoreIDOnMainThread:(NSString *)appStoreIDString +{ + _appStoreID = [appStoreIDString integerValue]; + [[NSUserDefaults standardUserDefaults] setInteger:_appStoreID forKey:iRateAppStoreIDKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)connectionSucceeded +{ + if (self.checkingForAppStoreID) + { + //no longer checking + self.checkingForPrompt = NO; + self.checkingForAppStoreID = NO; + + //open app store + [self openRatingsPageInAppStore]; + } + else if (self.checkingForPrompt) + { + //no longer checking + self.checkingForPrompt = NO; + + //confirm with delegate + if (![self.delegate iRateShouldPromptForRating]) + { + if (self.verboseLogging) + { + NSLog(@"iRate did not display the rating prompt because the iRateShouldPromptForRating delegate method returned NO"); + } + return; + } + + //prompt user + [self promptForRating]; + } +} + +- (void)connectionError:(NSError *)error +{ + if (self.checkingForPrompt || self.checkingForAppStoreID) + { + //no longer checking + self.checkingForPrompt = NO; + self.checkingForAppStoreID = NO; + + //log the error + if (error) + { + NSLog(@"iRate rating process failed because: %@", [error localizedDescription]); + } + else + { + NSLog(@"iRate rating process failed because an unknown error occured"); + } + + //could not connect + [self.delegate iRateCouldNotConnectToAppStore:error]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateCouldNotConnectToAppStore + object:error]; + } +} + +- (void)checkForConnectivityInBackground +{ + if ([NSThread isMainThread]) + { + [self performSelectorInBackground:@selector(checkForConnectivityInBackground) withObject:nil]; + return; + } + + @autoreleasepool + { + //prevent concurrent checks + static BOOL checking = NO; + if (checking) return; + checking = YES; + + //first check iTunes + NSString *iTunesServiceURL = [NSString stringWithFormat:iRateAppLookupURLFormat, self.appStoreCountry]; + if (_appStoreID) //important that we check ivar and not getter in case it has changed + { + iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?id=%@", @(_appStoreID)]; + } + else + { + iTunesServiceURL = [iTunesServiceURL stringByAppendingFormat:@"?bundleId=%@", self.applicationBundleID]; + } + + if (self.verboseLogging) + { + NSLog(@"iRate is checking %@ to retrieve the App Store details...", iTunesServiceURL); + } + + NSError *error = nil; + NSURLResponse *response = nil; + NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:iTunesServiceURL] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:REQUEST_TIMEOUT]; + NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; + NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; + if (data && statusCode == 200) + { + //in case error is garbage... + error = nil; + + id json = nil; + if ([NSJSONSerialization class]) + { + json = [[NSJSONSerialization JSONObjectWithData:data options:(NSJSONReadingOptions)0 error:&error][@"results"] lastObject]; + } + else + { + //convert to string + json = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + + if (!error) + { + //check bundle ID matches + NSString *bundleID = [self valueForKey:@"bundleId" inJSON:json]; + if (bundleID) + { + if ([bundleID isEqualToString:self.applicationBundleID]) + { + //get genre + if (self.appStoreGenreID == 0) + { + self.appStoreGenreID = [[self valueForKey:@"primaryGenreId" inJSON:json] integerValue]; + } + + //get app id + if (!_appStoreID) + { + NSString *appStoreIDString = [self valueForKey:@"trackId" inJSON:json]; + [self performSelectorOnMainThread:@selector(setAppStoreIDOnMainThread:) withObject:appStoreIDString waitUntilDone:YES]; + + if (self.verboseLogging) + { + NSLog(@"iRate found the app on iTunes. The App Store ID is %@", appStoreIDString); + } + } + + //check version + if (self.onlyPromptIfLatestVersion && !self.previewMode) + { + NSString *latestVersion = [self valueForKey:@"version" inJSON:json]; + if ([latestVersion compare:self.applicationVersion options:NSNumericSearch] == NSOrderedDescending) + { + if (self.verboseLogging) + { + NSLog(@"iRate found that the installed application version (%@) is not the latest version on the App Store, which is %@", self.applicationVersion, latestVersion); + } + + error = [NSError errorWithDomain:iRateErrorDomain code:iRateErrorApplicationIsNotLatestVersion userInfo:@{NSLocalizedDescriptionKey: @"Installed app is not the latest version available"}]; + } + } + } + else + { + if (self.verboseLogging) + { + NSLog(@"iRate found that the application bundle ID (%@) does not match the bundle ID of the app found on iTunes (%@) with the specified App Store ID (%@)", self.applicationBundleID, bundleID, @(self.appStoreID)); + } + + error = [NSError errorWithDomain:iRateErrorDomain code:iRateErrorBundleIdDoesNotMatchAppStore userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Application bundle ID does not match expected value of %@", bundleID]}]; + } + } + else if (_appStoreID || !self.ratingsURL) + { + if (self.verboseLogging) + { + NSLog(@"iRate could not find this application on iTunes. If your app is not intended for App Store release then you must specify a custom ratingsURL. If this is the first release of your application then it's not a problem that it cannot be found on the store yet"); + } + if (!self.previewMode) + { + error = [NSError errorWithDomain:iRateErrorDomain + code:iRateErrorApplicationNotFoundOnAppStore + userInfo:@{NSLocalizedDescriptionKey: @"The application could not be found on the App Store."}]; + } + } + else if (!_appStoreID && self.verboseLogging) + { + NSLog(@"iRate could not find your app on iTunes. If your app is not yet on the store or is not intended for App Store release then don't worry about this"); + } + } + } + else if (statusCode >= 400) + { + //http error + NSString *message = [NSString stringWithFormat:@"The server returned a %@ error", @(statusCode)]; + error = [NSError errorWithDomain:@"HTTPResponseErrorDomain" code:statusCode userInfo:@{NSLocalizedDescriptionKey: message}]; + } + + //handle errors (ignoring sandbox issues) + if (error && !(error.code == EPERM && [error.domain isEqualToString:NSPOSIXErrorDomain] && _appStoreID)) + { + [self performSelectorOnMainThread:@selector(connectionError:) withObject:error waitUntilDone:YES]; + } + else if (self.appStoreID || self.previewMode) + { + //show prompt + [self performSelectorOnMainThread:@selector(connectionSucceeded) withObject:nil waitUntilDone:YES]; + } + + //finished + checking = NO; + } +} + +- (void)promptIfNetworkAvailable +{ + if (!self.checkingForPrompt && !self.checkingForAppStoreID) + { + self.checkingForPrompt = YES; + [self checkForConnectivityInBackground]; + } +} + +- (void)promptIfAllCriteriaMet +{ + if ([self shouldPromptForRating]) + { + [self promptIfNetworkAvailable]; + } +} + +- (BOOL)showRemindButton +{ + return [self.remindButtonLabel length]; +} + +- (BOOL)showCancelButton +{ + return [self.cancelButtonLabel length]; +} + +- (void)promptForRating +{ + if (!self.visibleAlert) + { + NSString *message = self.ratedAnyVersion? self.updateMessage: self.message; + +#if TARGET_OS_IPHONE + + UIViewController *topController = [UIApplication sharedApplication].delegate.window.rootViewController; + while (topController.presentedViewController) + { + topController = topController.presentedViewController; + } + + if ([UIAlertController class] && topController && self.useUIAlertControllerIfAvailable) + { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:self.messageTitle message:message preferredStyle:UIAlertControllerStyleAlert]; + + //rate action + [alert addAction:[UIAlertAction actionWithTitle:self.rateButtonLabel style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [self didDismissAlert:alert withButtonAtIndex:0]; + }]]; + + //cancel action + if ([self showCancelButton]) + { + [alert addAction:[UIAlertAction actionWithTitle:self.cancelButtonLabel style:UIAlertActionStyleCancel handler:^(__unused UIAlertAction *action) { + [self didDismissAlert:alert withButtonAtIndex:1]; + }]]; + } + + //remind action + if ([self showRemindButton]) + { + [alert addAction:[UIAlertAction actionWithTitle:self.remindButtonLabel style:UIAlertActionStyleDefault handler:^(__unused UIAlertAction *action) { + [self didDismissAlert:alert withButtonAtIndex:[self showCancelButton]? 2: 1]; + }]]; + } + + self.visibleAlert = alert; + + //get current view controller and present alert + [topController presentViewController:alert animated:YES completion:NULL]; + } + else + { + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:self.messageTitle + message:message + delegate:(id)self + cancelButtonTitle:nil + otherButtonTitles:self.rateButtonLabel, nil]; + if ([self showCancelButton]) + { + [alert addButtonWithTitle:self.cancelButtonLabel]; + alert.cancelButtonIndex = 1; + } + + if ([self showRemindButton]) + { + [alert addButtonWithTitle:self.remindButtonLabel]; + } + + self.visibleAlert = alert; + [self.visibleAlert show]; + } + +#else + + //only show when main window is available + if (self.onlyPromptIfMainWindowIsAvailable && ![[NSApplication sharedApplication] mainWindow]) + { + [self performSelector:@selector(promptForRating) withObject:nil afterDelay:0.5]; + return; + } + + NSAlert *alert = [[NSAlert alloc] init]; + alert.messageText = self.messageTitle; + alert.informativeText = message; + [alert addButtonWithTitle:self.rateButtonLabel]; + if ([self showCancelButton]) + { + [alert addButtonWithTitle:self.cancelButtonLabel]; + } + if ([self showRemindButton]) + { + [alert addButtonWithTitle:self.remindButtonLabel]; + } + + self.visibleAlert = alert; + +#if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 + + if (![alert respondsToSelector:@selector(beginSheetModalForWindow:completionHandler:)]) + { + [alert beginSheetModalForWindow:[NSApplication sharedApplication].mainWindow + modalDelegate:self + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + } + else + +#endif + + { +// [alert beginSheetModalForWindow:[NSApplication sharedApplication].mainWindow completionHandler:^(NSModalResponse returnCode) { +// [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn]; +// }]; + + NSModalResponse modalResponse = [alert runModal]; + NSLog(@"Modal response code:%zd", modalResponse); + if (modalResponse == NSModalResponseStop) { + [self rate]; + } + else + { + [self remindLater]; + } + } + +#endif + + //inform about prompt + [self.delegate iRateDidPromptForRating]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidPromptForRating + object:nil]; + } +} + +- (void)applicationLaunched +{ + //check if this is a new version + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSString *lastUsedVersion = [defaults objectForKey:iRateLastVersionUsedKey]; + if (!self.firstUsed || ![lastUsedVersion isEqualToString:self.applicationVersion]) + { + [defaults setObject:self.applicationVersion forKey:iRateLastVersionUsedKey]; + if (!self.firstUsed || [self ratedAnyVersion]) + { + //reset defaults + [defaults setObject:[NSDate date] forKey:iRateFirstUsedKey]; + [defaults setInteger:0 forKey:iRateUseCountKey]; + [defaults setInteger:0 forKey:iRateEventCountKey]; + [defaults setObject:nil forKey:iRateLastRemindedKey]; + [defaults synchronize]; + } + else if ([[NSDate date] timeIntervalSinceDate:self.firstUsed] > (self.daysUntilPrompt - 1) * SECONDS_IN_A_DAY) + { + //if was previously installed, but we haven't yet prompted for a rating + //don't reset, but make sure it won't rate for a day at least + self.firstUsed = [[NSDate date] dateByAddingTimeInterval:(self.daysUntilPrompt - 1) * -SECONDS_IN_A_DAY]; + } + + //inform about app update + [self.delegate iRateDidDetectAppUpdate]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidDetectAppUpdate + object:nil]; + } + + [self incrementUseCount]; + [self checkForConnectivityInBackground]; + if (self.promptAtLaunch) + { + [self promptIfAllCriteriaMet]; + } +} + +- (void)didDismissAlert:(__unused id)alertView withButtonAtIndex:(NSInteger)buttonIndex +{ + //get button indices + NSInteger rateButtonIndex = 0; + NSInteger cancelButtonIndex = [self showCancelButton]? 1: 0; + NSInteger remindButtonIndex = [self showRemindButton]? cancelButtonIndex + 1: 0; + + if (buttonIndex == rateButtonIndex) + { + [self rate]; + } + else if (buttonIndex == cancelButtonIndex) + { + [self declineThisVersion]; + } + else if (buttonIndex == remindButtonIndex) + { + [self remindLater]; + } + + //release alert + self.visibleAlert = nil; +} + +#if TARGET_OS_IPHONE + +- (void)applicationWillEnterForeground +{ + if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) + { + [self incrementUseCount]; + [self checkForConnectivityInBackground]; + if (self.promptAtLaunch) + { + [self promptIfAllCriteriaMet]; + } + } +} + +- (void)openRatingsPageInAppStore +{ + if (!_ratingsURL && !self.appStoreID) + { + self.checkingForAppStoreID = YES; + if (!self.checkingForPrompt) + { + [self checkForConnectivityInBackground]; + } + return; + } + + NSString *cantOpenMessage = nil; + +#if TARGET_IPHONE_SIMULATOR + + if ([[self.ratingsURL scheme] isEqualToString:iRateiOSAppStoreURLScheme]) + { + cantOpenMessage = @"iRate could not open the ratings page because the App Store is not available on the iOS simulator"; + } + +#elif DEBUG + + if (![[UIApplication sharedApplication] canOpenURL:self.ratingsURL]) + { + cantOpenMessage = [NSString stringWithFormat:@"iRate was unable to open the specified ratings URL: %@", self.ratingsURL]; + } + +#endif + + if (cantOpenMessage) + { + NSLog(@"%@", cantOpenMessage); + NSError *error = [NSError errorWithDomain:iRateErrorDomain code:iRateErrorCouldNotOpenRatingPageURL userInfo:@{NSLocalizedDescriptionKey: cantOpenMessage}]; + [self.delegate iRateCouldNotConnectToAppStore:error]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateCouldNotConnectToAppStore + object:error]; + } + else + { + if (self.verboseLogging) + { + NSLog(@"iRate will open the App Store ratings page using the following URL: %@", self.ratingsURL); + } + + [[UIApplication sharedApplication] openURL:self.ratingsURL]; + [self.delegate iRateDidOpenAppStore]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateDidOpenAppStore + object:nil]; + } +} + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex +{ + [self didDismissAlert:alertView withButtonAtIndex:buttonIndex]; +} + +#else + +- (void)openAppPageWhenAppStoreLaunched +{ + //check if app store is running + for (NSRunningApplication *app in [[NSWorkspace sharedWorkspace] runningApplications]) + { + if ([app.bundleIdentifier isEqualToString:iRateMacAppStoreBundleID]) + { + //open app page + [[NSWorkspace sharedWorkspace] performSelector:@selector(openURL:) withObject:self.ratingsURL afterDelay:MAC_APP_STORE_REFRESH_DELAY]; + return; + } + } + + //try again + [self performSelector:@selector(openAppPageWhenAppStoreLaunched) withObject:nil afterDelay:0.0]; +} + +- (void)openRatingsPageInAppStore +{ + if (!_ratingsURL && !self.appStoreID) + { + self.checkingForAppStoreID = YES; + if (!self.checkingForPrompt) + { + [self checkForConnectivityInBackground]; + } + return; + } + + if (self.verboseLogging) + { + NSLog(@"iRate will open the App Store ratings page using the following URL: %@", self.ratingsURL); + } + + [[NSWorkspace sharedWorkspace] openURL:self.ratingsURL]; + [self openAppPageWhenAppStoreLaunched]; + [self.delegate iRateDidOpenAppStore]; +} + +- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(__unused void *)contextInfo +{ + [self didDismissAlert:alert withButtonAtIndex:returnCode - NSAlertFirstButtonReturn]; +} + +#endif + +- (void)logEvent:(BOOL)deferPrompt +{ + [self incrementEventCount]; + if (!deferPrompt) + { + [self promptIfAllCriteriaMet]; + } +} + +#pragma mark - User's actions + +- (void)declineThisVersion +{ + //ignore this version + self.declinedThisVersion = YES; + + //log event + [self.delegate iRateUserDidDeclineToRateApp]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidDeclineToRateApp + object:nil]; +} + +- (void)remindLater +{ + //remind later + self.lastReminded = [NSDate date]; + + //log event + [self.delegate iRateUserDidRequestReminderToRateApp]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidRequestReminderToRateApp + object:nil]; +} + +- (void)rate +{ + //mark as rated + self.ratedThisVersion = YES; + + //log event + [self.delegate iRateUserDidAttemptToRateApp]; + [[NSNotificationCenter defaultCenter] postNotificationName:iRateUserDidAttemptToRateApp + object:nil]; + + if ([self.delegate iRateShouldOpenAppStore]) + { + //launch mac app store + [self openRatingsPageInAppStore]; + } +} + +@end diff --git a/Clocker/de.lproj/Localizable.strings b/Clocker/de.lproj/Localizable.strings new file mode 100644 index 0000000..fd9be7a --- /dev/null +++ b/Clocker/de.lproj/Localizable.strings @@ -0,0 +1,19 @@ +/* + Localizable.strings + Clocker + + Created by Abhishek Banthia on 11/17/15. + +*/ + +"Yesterday" = "Gestern"; +"Today" = "Heute"; +"Tomorrow" = "Morgen"; +"MaximumTimezoneMessage" = "Maximal 10 Zeitzonen erlaubt!"; +"DuplicateTimezoneMessage" = "Zeitzone bereits angewählt!"; +"iRateMessageTitle" = "Bewerte %@"; +"iRateAppMessage" = "Wenn dir %@ gefällt, würdest Du es bitte bewerten? Dies wird nicht länger als eine Minute dauern. Danke für die Unterstützung!"; +"iRateGameMessage" = "Wenn dir %@ gefällt, würdest Du es bitte bewerten? Dies wird nicht länger als eine Minute dauern. Danke für die Unterstützung!"; +"iRateCancelButton" = "Nein, danke"; +"iRateRateButton" = "Jetzt bewerten"; +"iRateRemindButton" = "Später erinnern"; \ No newline at end of file diff --git a/Clocker/de.lproj/MainMenu.xib b/Clocker/de.lproj/MainMenu.xib new file mode 100755 index 0000000..926bcde --- /dev/null +++ b/Clocker/de.lproj/MainMenu.xib @@ -0,0 +1,652 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clocker/de.lproj/Panel.xib b/Clocker/de.lproj/Panel.xib new file mode 100755 index 0000000..5ad46fb --- /dev/null +++ b/Clocker/de.lproj/Panel.xib @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clocker/de.lproj/PreferencesWindow.xib b/Clocker/de.lproj/PreferencesWindow.xib new file mode 100644 index 0000000..08d4b63 --- /dev/null +++ b/Clocker/de.lproj/PreferencesWindow.xib @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + addToFavorites: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clocker/en.lproj/Localizable.strings b/Clocker/en.lproj/Localizable.strings index e85e253..82cbfec 100644 --- a/Clocker/en.lproj/Localizable.strings +++ b/Clocker/en.lproj/Localizable.strings @@ -9,8 +9,11 @@ "Yesterday" = "Yesterday"; "Today" = "Today"; "Tomorrow" = "Tomorrow"; -"SpreadTheWordTitle" = "Spread the word, maybe"; -"SpreadTheWordMessage" = "Clocker is completely open source. If it helped you in any way, please leave a kind of opinion on the App Store!"; -"Cancel" = "Cancel"; "MaximumTimezoneMessage" = "Maximum 10 timezones allowed!"; -"DuplicateTimezoneMessage" = "Timezone has already been selected!"; \ No newline at end of file +"DuplicateTimezoneMessage" = "Timezone has already been selected!"; +"iRateMessageTitle" = "Rate %@"; +"iRateAppMessage" = "If you enjoy using %@, would you mind taking a moment to rate it? It won’t take more than a minute. Thanks for your support!"; +"iRateGameMessage" = "If you enjoy playing %@, would you mind taking a moment to rate it? It won’t take more than a minute. Thanks for your support!"; +"iRateCancelButton" = "No, Thanks"; +"iRateRateButton" = "Rate It Now"; +"iRateRemindButton" = "Remind Me Later"; \ No newline at end of file diff --git a/Clocker/fr.lproj/Localizable.strings b/Clocker/fr.lproj/Localizable.strings index 71962c3..4a87af9 100644 --- a/Clocker/fr.lproj/Localizable.strings +++ b/Clocker/fr.lproj/Localizable.strings @@ -10,8 +10,12 @@ "Yesterday" = "Hier"; "Today" = "Aujourd'hui"; "Tomorrow" = "Demain"; -"SpreadTheWordTitle" = "Passez le mot"; -"SpreadTheWordMessage" = "Clocker est complètement open source . Si cela vous a aidé de quelque façon , s'il vous plaît laisser un avis de genre sur l'App Store !"; -"Cancel" = "Annuler"; "MaximumTimezoneMessage" = "Maximum 10 fuseaux horaires autorisés!"; -"DuplicateTimezoneMessage" = "Fuseau horaire a déjà été sélectionnée!"; \ No newline at end of file +"DuplicateTimezoneMessage" = "Fuseau horaire a déjà été sélectionnée!"; + +"iRateMessageTitle" = "Notez %@"; +"iRateAppMessage" = "Si vous aimez utiliser %@, n'oubliez pas de donner votre avis sur l'App Store. Cela ne prend qu'une minute. Merci d'avance pour votre soutien !"; +"iRateGameMessage" = "Si vous aimez jouer à %@, n'oubliez pas de donner votre avis sur l'App Store. Cela ne prend qu'une minute. Merci d'avance pour votre soutien !"; +"iRateCancelButton" = "Non, merci"; +"iRateRateButton" = "Noter maintenant"; +"iRateRemindButton" = "Me le rappeler ultérieurement"; diff --git a/Clocker/ja.lproj/Localizable.strings b/Clocker/ja.lproj/Localizable.strings new file mode 100644 index 0000000..e54dda7 --- /dev/null +++ b/Clocker/ja.lproj/Localizable.strings @@ -0,0 +1,19 @@ +/* + Localizable.strings + Clocker + + Created by Abhishek Banthia on 11/17/15. + +*/ + +"Yesterday" = "昨日"; +"Today" = "今日"; +"Tomorrow" = "明日"; +"MaximumTimezoneMessage" = "最大10タイムゾーンを許可します"; +"DuplicateTimezoneMessage" = "タイムゾーンが既に選択されています"; +"iRateMessageTitle" = "%@の評価"; +"iRateAppMessage" = "%@をお使いいただき大変ありがとうございます。もしよろしければ1分程で済みますので、このアプリの評価をお願いします。ご協力感謝いたします!"; +"iRateGameMessage" = "%@をプレイしていただき大変ありがとうございます。もしよろしければ1分程で済みますので、このアプリの評価をお願いします。ご協力感謝いたします!"; +"iRateCancelButton" = "いえ、結構です"; +"iRateRateButton" = "今すぐ評価する"; +"iRateRemindButton" = "後でする"; \ No newline at end of file diff --git a/Clocker/ja.lproj/MainMenu.xib b/Clocker/ja.lproj/MainMenu.xib new file mode 100755 index 0000000..926bcde --- /dev/null +++ b/Clocker/ja.lproj/MainMenu.xib @@ -0,0 +1,652 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clocker/ja.lproj/Panel.xib b/Clocker/ja.lproj/Panel.xib new file mode 100755 index 0000000..5ad46fb --- /dev/null +++ b/Clocker/ja.lproj/Panel.xib @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clocker/ja.lproj/PreferencesWindow.xib b/Clocker/ja.lproj/PreferencesWindow.xib new file mode 100644 index 0000000..57dd157 --- /dev/null +++ b/Clocker/ja.lproj/PreferencesWindow.xib @@ -0,0 +1,374 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + addToFavorites: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +