# HG changeset patch # User antonc27 # Date 1446765157 -3600 # Node ID 402baa6d4f64823eaf545ef866102801ec55d47d # Parent 92b02309515302d953bb64e24d1231f1d60cd1b7 - Appirater: - - Updated to last version - - Added localization bundle - - StoreKit framework linked diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater.h --- a/project_files/HedgewarsMobile/Classes/Appirater.h Thu Nov 05 21:54:19 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - This file is part of Appirater, http://arashpayan.com - - Copyright (c) 2010, Arash Payan - All rights reserved. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - */ - - -#import - -extern NSString *const kAppiraterLaunchDate; -extern NSString *const kAppiraterLaunchCount; -extern NSString *const kAppiraterCurrentVersion; -extern NSString *const kAppiraterRatedCurrentVersion; -extern NSString *const kAppiraterDeclinedToRate; - -/* - Place your Apple generated software id here. - */ -#define APPIRATER_APP_ID 391234866 - -/* - Your app's name. - */ -#define APPIRATER_APP_NAME [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleNameKey] - -/* - This is the message your users will see once they've passed the day+launches - threshold. - */ -#define APPIRATER_MESSAGE [NSString stringWithFormat:@"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!", APPIRATER_APP_NAME] - -/* - This is the title of the message alert that users will see. - */ -#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME] - -/* - The text of the button that rejects reviewing the app. - */ -#define APPIRATER_CANCEL_BUTTON NSLocalizedString(@"No thanks",@"") - -/* - Text of button that will send user to app review page. - */ -#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:@"Rate %@", APPIRATER_APP_NAME] - -/* - Text for button to remind the user to review later. - */ -#define APPIRATER_RATE_LATER NSLocalizedString(@"Remind me later",@"") - -/* - Users will need to have the same version of your app installed for this many - days before they will be prompted to rate it. - */ -#define DAYS_UNTIL_PROMPT 3 // double - -/* - Users will need to launch the same version of the app this many times before - they will be prompted to rate it. - */ -#define LAUNCHES_UNTIL_PROMPT 5 // integer - -/* - 'YES' will show the Appirater alert everytime. Useful for testing how your message - looks and making sure the link to your app's review page works. - */ -#define APPIRATER_DEBUG NO // bool - -@interface Appirater : NSObject { - -} - -+(void) appLaunched; - -@end diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater.m --- a/project_files/HedgewarsMobile/Classes/Appirater.m Thu Nov 05 21:54:19 2015 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,159 +0,0 @@ -/* - This file is part of Appirater, http://arashpayan.com - - Copyright (c) 2010, Arash Payan - All rights reserved. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - */ - - -#import "Appirater.h" -#import -#import - -NSString *const kAppiraterLaunchDate = @"kAppiraterLaunchDate"; -NSString *const kAppiraterLaunchCount = @"kAppiraterLaunchCount"; -NSString *const kAppiraterCurrentVersion = @"kAppiraterCurrentVersion"; -NSString *const kAppiraterRatedCurrentVersion = @"kAppiraterRatedCurrentVersion"; -NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate"; - -NSString *templateReviewURL = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"; - -@implementation Appirater - -+(void) appLaunched { - Appirater *appirater = [[Appirater alloc] init]; - [NSThread detachNewThreadSelector:@selector(appLaunchedHandler) toTarget:appirater withObject:nil]; -} - --(void) appLaunchedHandler { - @autoreleasepool { - - if (APPIRATER_DEBUG) { - [self performSelectorOnMainThread:@selector(showPrompt) withObject:nil waitUntilDone:NO]; - return; - } - - BOOL willShowPrompt = NO; - - // get the app's version - NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey]; - - // get the version number that we've been tracking - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion]; - if (trackingVersion == nil) { - trackingVersion = version; - [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; - } - - if (APPIRATER_DEBUG) - DLog(@"APPIRATER Tracking version: %@", trackingVersion); - - if ([trackingVersion isEqualToString:version]) { - // get the launch date - NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterLaunchDate]; - if (timeInterval == 0) { - timeInterval = [[NSDate date] timeIntervalSince1970]; - [userDefaults setDouble:timeInterval forKey:kAppiraterLaunchDate]; - } - - NSTimeInterval secondsSinceLaunch = [[NSDate date] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:timeInterval]]; - double secondsUntilPrompt = 60 * 60 * 24 * DAYS_UNTIL_PROMPT; - - // get the launch count - NSInteger launchCount = [userDefaults integerForKey:kAppiraterLaunchCount]; - launchCount++; - [userDefaults setInteger:launchCount forKey:kAppiraterLaunchCount]; - if (APPIRATER_DEBUG) - NSLog(@"APPIRATER Launch count: %ld", (long)launchCount); - - // have they previously declined to rate this version of the app? - BOOL declinedToRate = [userDefaults boolForKey:kAppiraterDeclinedToRate]; - - // have they already rated the app? - BOOL ratedApp = [userDefaults boolForKey:kAppiraterRatedCurrentVersion]; - - if (secondsSinceLaunch > secondsUntilPrompt && - launchCount > LAUNCHES_UNTIL_PROMPT && - !declinedToRate && - !ratedApp) { - if ([HWUtils isNetworkReachable]) { // check if they can reach the app store - willShowPrompt = YES; - [self performSelectorOnMainThread:@selector(showPrompt) withObject:nil waitUntilDone:NO]; - } - } - } else { - // it's a new version of the app, so restart tracking - [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; - [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterLaunchDate]; - [userDefaults setInteger:1 forKey:kAppiraterLaunchCount]; - [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion]; - [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate]; - } - - [userDefaults synchronize]; - if (!willShowPrompt) - [self autorelease]; - - } -} - --(void) showPrompt { - UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:APPIRATER_MESSAGE_TITLE - message:APPIRATER_MESSAGE - delegate:self - cancelButtonTitle:APPIRATER_CANCEL_BUTTON - otherButtonTitles:APPIRATER_RATE_BUTTON, APPIRATER_RATE_LATER, nil]; - [alertView show]; - [alertView release]; -} - --(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger) buttonIndex { - NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; - - switch (buttonIndex) { - case 0: - // they don't want to rate it - [userDefaults setBool:YES forKey:kAppiraterDeclinedToRate]; - break; - case 1: - // they want to rate it - [[UIApplication sharedApplication] openURL: - [NSURL URLWithString:[templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%d", APPIRATER_APP_ID]]]]; - - [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion]; - break; - case 2: - // remind them later - break; - default: - break; - } - - [userDefaults synchronize]; - - [self release]; -} - -@end diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ar.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ar.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "إذا كنت تستمع باستخدام %@، فهل تمانع بأن تأخذ دقيقة من وقتك لتقيمه؟ لن يستغرق الأمر أكثر من دقيقة. شكرا لدعمك!"; +"Rate %@" = "قيم %@"; +"No, Thanks" = "لا شكرا"; +"Remind me later" = "ذكرني لاحقا"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ca.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ca.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Si li agrada utilitzar %@, li importaria prendre’s un moment per a valorar-lo? No trigarà més d’un minut. Gràcies por la seva col·laboració!"; +"Rate %@" = "Valorar %@"; +"No, Thanks" = "No, gràcies"; +"Remind me later" = "Recordar-m’ho més tard"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/cs.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/cs.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Pokud se Vám aplikace %@ líbí, mohli byste ji prosím ohodnotit v App Store? Zabere to jen chvilku. Díky za Vaši podporu!"; +"Rate %@" = "Ohodnotit %@"; +"No, Thanks" = "Ne, díky"; +"Remind me later" = "Možná později"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/da.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/da.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Hvis du synes om at bruge %@, vil du have noget imod at bruge et kort øjeblik på at bedømme det? Det tager kun et minut. Tak for din støtte!"; +"Rate %@" = "Bedøm %@"; +"No, Thanks" = "Nej tak"; +"Remind me later" = "Påmind mig senere"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/de.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/de.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Sie nutzen %@ gerne? Dann nehmen Sie sich bitte für eine Bewertung einen Moment Zeit! Es dauert nicht länger als eine Minute. Vielen Dank!"; +"Rate %@" = "Bewerte %@"; +"No, Thanks" = "Nein, danke"; +"Remind me later" = "Später erinnern"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/el.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/el.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Αν σου αρέσει το %@, θα μπορούσες να αφιερώσεις μια στιγμή για να το βαθμολογήσεις; Η διαδικασία είναι πολύ σύντομη. Ευχαριστούμε για τη στήριξη!"; +"Rate %@" = "Βαθμολόγηση του %@"; +"No, Thanks" = "Όχι, ευχαριστώ"; +"Remind me later" = "Υπενθύμιση αργότερα"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/en.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/en.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "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!"; +"Rate %@" = "Rate %@"; +"No, Thanks" = "No, thanks"; +"Remind me later" = "Remind me later"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/es.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/es.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Si te ha gustado %@, ¿te gustaría calificarnos? No te tomará más de un minuto. ¡Gracias por tu colaboración!"; +"Rate %@" = "Calificar %@"; +"No, Thanks" = "No, gracias"; +"Remind me later" = "Recuérdame más tarde"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/fi.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/fi.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Jos käytät mielelläsi %@, voisitko käyttää hetken ja arvostella sen? Se ei kestä minuuttia kauempaa. Kiitos tuestasi!"; +"Rate %@" = "Arvioi %@"; +"No, Thanks" = "Ei kiitos"; +"Remind me later" = "Muistuta minua myöhemmin"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/fr.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/fr.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Si vous aimez %@, voulez-vous prendre un moment pour l'évaluer ? Cela ne vous prendra pas plus d'une minute. Merci de votre soutien !"; +"Rate %@" = "Évaluer %@"; +"No, Thanks" = "Non, merci"; +"Remind me later" = "Me rappeler plus tard"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/he.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/he.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "אם נהנת להשתמש ב %@, האם תסכים לדרג אותה? זה לא יקח יותר מדקה. תודה על התמיכה!"; +"Rate %@" = "דרג את %@"; +"No, Thanks" = "לא תודה"; +"Remind me later" = "מאוחר יותר"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/hu.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/hu.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Ha tetszik a %@, ne felejtsd el értékelni az App Store-ban! Csak egy perc az egész. Köszönet a támogatásért!"; +"Rate %@" = "%@ értékelése"; +"No, Thanks" = "Most inkább nem"; +"Remind me later" = "Emlékeztess később"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/id.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/id.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Jika anda menyukai %@, maukah anda memberikan rating kepada aplikasi ini? Rating hanya memakan waktu kurang dari 1 menit. Terimakasih untuk dukungan anda!"; +"Rate %@" = "Rating %@"; +"No, Thanks" = "Tidak, terimakasih"; +"Remind me later" = "Silakan ingatkan saya lagi"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/it.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/it.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Se ti piace %@, perché non dedichi qualche istante a darne una valutazione sull'App Store? Non richiederà più di un minuto. Grazie per il supporto!"; +"Rate %@" = "Valuta %@"; +"No, Thanks" = "No, grazie"; +"Remind me later" = "Ricordamelo più tardi"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ja.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ja.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "%@をお使いいただきありがとうございます。もしよろしければ、ほんの少しだけお時間をいただき評価をお願いできませんか?ご協力感謝いたします!"; +"Rate %@" = "%@を評価する"; +"No, Thanks" ="結構です"; +"Remind me later" = "あとで"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ko.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ko.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "%@ 사용이 맘에 드셨나요? 잠시만 시간을 내서 평가를 부탁드리겠습니다. 감사합니다!"; +"Rate %@" = "%@ 평가하기"; +"No, Thanks" = "평가하지 않겠습니다"; +"Remind me later" = "다음에 평가하겠습니다"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ms.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ms.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Jika anda suka %@, bolehkah luangkan sedikit masa untuk beri penarafan? Tak sampai seminit pun. Terima kasih atas sokongan anda!"; +"Rate %@" = "Tarafkan %@"; +"No, Thanks" = "Terima kasih saja"; +"Remind me later" = "Ingatkan saya lain kali"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/nb.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/nb.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Hvis du liker å bruke %@, kan du ta deg et øyeblikk for å vurdere den? Det vil ikke ta mer enn ett minutt. Takk for din støtte!"; +"Rate %@" = "Vurder %@"; +"No, Thanks" = "Nei, takk"; +"Remind me later" = "Påminn meg senere"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/nl.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/nl.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Als het gebruik van %@ je bevalt, zou je dan een momentje de tijd willen nemen om het te beoordelen? Het duurt nog geen minuut. Bedankt voor je steun!"; +"Rate %@" = "%@ beoordelen"; +"No, Thanks" = "Nee, bedankt"; +"Remind me later" = "Herinner me er later aan"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pl.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pl.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Jeżeli podoba Ci się korzystanie z %@, może zechciałbyś poświęcić chwilę czasu, aby ocenić aplikację? Nie zajmie Ci to więcej niż minutę. Dziękujemy za pomoc!"; +"Rate %@" = "Oceń %@"; +"No, Thanks" = "Nie, dziękuję"; +"Remind me later" = "Przypomnij później"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pt-BR.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pt-BR.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Se você gosta de usar o %@, que tal avaliá-lo? Não levará mais de um minuto. Agradecemos o seu apoio!"; +"Rate %@" = "Avaliar o %@"; +"No, Thanks" = "Não, obrigado"; +"Remind me later" = "Mais tarde"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pt.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/pt.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Se você gosta de usar o %@, que tal avaliá-lo? Não levará mais de um minuto. Agradecemos o seu apoio!"; +"Rate %@" = "Avaliar o %@"; +"No, Thanks" = "Não, obrigado"; +"Remind me later" = "Mais tarde"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ro.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ro.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Dacă îți place %@, acordă-i o notă te rog, nu durează mult. Mulțumim pentru susținere!"; +"Rate %@" = "Acordă notă pentru %@"; +"No, Thanks" = "Nu, mulțumesc"; +"Remind me later" = "Adu-mi aminte mai târziu"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ru.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/ru.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Если Вам нравится %@, пожалуйста, поставьте свою оценку. Это займет у Вас не больше одной минуты.\n Спасибо за поддержку!"; +"Rate %@" = "Оценить %@"; +"No, Thanks" = "Нет, спасибо"; +"Remind me later" = "Напомнить позже"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/sk.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/sk.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Pokiaľ sa Vám páči aplikácia %@, mohli by ste ju prosím ohodnotiť v App Store? Zaberie to len chvíľu. Vďaka za Vašu podporu!"; +"Rate %@" = "Ohodnotiť %@"; +"No, Thanks" = "Nie, ďakujem"; +"Remind me later" = "Pripomenúť neskôr"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/sv.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/sv.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Om du gillar att använda %@, kan du tänka dig att betygsätta det åt oss? Det tar bara en minut. Tack för hjälpen!"; +"Rate %@" = "Betygsätt %@"; +"No, Thanks" = "Nej tack"; +"Remind me later" = "Påminn mig senare"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/th.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/th.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "ถ้าคุณกำลังใช้ %@ โปรดสละเวลาสักครู่ในการให้อันดับแก่เรา คุณจะเสียเวลาไม่เกินหนึ่งนาที ขอบคุณสำหรับการสนับสนุน!"; +"Rate %@" = "ให้อันดับ %@"; +"No, Thanks" = "ไม่ ขอบคุณ"; +"Remind me later" = "เตือนฉันภายหลัง"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/tr.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/tr.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Eğer %@ uygulamasını kullanmaktan keyif alıyorsanız, onu değerlendirmek için zaman ayırabilir misiniz? Desteğiniz için teşekkür ederiz!"; +"Rate %@" = "%@ uygulamasını değerlendir"; +"No, Thanks" = "Hayır, teşekkürler"; +"Remind me later" = "Daha sonra hatırlat"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/uk.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/uk.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Якщо вам сподобалося %@, будь ласка, поставте свою оцінку. Це займає не більше однієї хвилини.\n Дякуємо за підтримку!"; +"Rate %@" = "Оцінити %@"; +"No, Thanks" = "Ні, дякую"; +"Remind me later" = "Нагадати пізніше"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/vi.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/vi.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "Cảm ơn bạn đã sử dụng ứng dụng %@ trong thời gian qua, bạn có thể dành chút thời gian để đánh giá ứng dụng trong AppStore không?"; +"Rate %@" = "Đánh giá %@"; +"No, Thanks" = "Không, xin cảm ơn"; +"Remind me later" = "Hãy nhắc nhở tôi sau"; \ No newline at end of file diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/zh-Hans.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/zh-Hans.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "如果你喜欢使用%@,你介意花一点时间给它评分吗?不会超过一分钟。感谢您的支持!"; +"Rate %@" = "给%@评分"; +"No, Thanks" = "不,谢谢"; +"Remind me later" = "稍后提醒我"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/zh-Hant.lproj/AppiraterLocalizable.strings --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.bundle/zh-Hant.lproj/AppiraterLocalizable.strings Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,4 @@ +"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!" = "如果你喜歡使用%@,你介意花一點時間給它評分嗎?不會超過一分鐘。感謝您的支持!"; +"Rate %@" = "給%@評分"; +"No, Thanks" = "不,謝謝"; +"Remind me later" = "稍後提醒我"; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.h Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,331 @@ +/* + This file is part of Appirater. + + Copyright (c) 2012, Arash Payan + All rights reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + */ +/* + * Appirater.h + * appirater + * + * Created by Arash Payan on 9/5/09. + * http://arashpayan.com + * Copyright 2012 Arash Payan. All rights reserved. + */ + +#import +#import "AppiraterDelegate.h" +#import + +extern NSString *const kAppiraterFirstUseDate; +extern NSString *const kAppiraterUseCount; +extern NSString *const kAppiraterSignificantEventCount; +extern NSString *const kAppiraterCurrentVersion; +extern NSString *const kAppiraterRatedCurrentVersion; +extern NSString *const kAppiraterDeclinedToRate; +extern NSString *const kAppiraterReminderRequestDate; + +/*! + Your localized app's name. + */ +#define APPIRATER_LOCALIZED_APP_NAME [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"] + +/*! + Your app's name. + */ +#define APPIRATER_APP_NAME APPIRATER_LOCALIZED_APP_NAME ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleDisplayName"] ?: [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"] + +/*! + This is the message your users will see once they've passed the day+launches + threshold. + */ +#define APPIRATER_LOCALIZED_MESSAGE NSLocalizedStringFromTableInBundle(@"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!", @"AppiraterLocalizable", [Appirater bundle], nil) +#define APPIRATER_MESSAGE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE, APPIRATER_APP_NAME] + +/*! + This is the title of the message alert that users will see. + */ +#define APPIRATER_LOCALIZED_MESSAGE_TITLE NSLocalizedStringFromTableInBundle(@"Rate %@", @"AppiraterLocalizable", [Appirater bundle], nil) +#define APPIRATER_MESSAGE_TITLE [NSString stringWithFormat:APPIRATER_LOCALIZED_MESSAGE_TITLE, APPIRATER_APP_NAME] + +/*! + The text of the button that rejects reviewing the app. + */ +#define APPIRATER_CANCEL_BUTTON NSLocalizedStringFromTableInBundle(@"No, Thanks", @"AppiraterLocalizable", [Appirater bundle], nil) + +/*! + Text of button that will send user to app review page. + */ +#define APPIRATER_LOCALIZED_RATE_BUTTON NSLocalizedStringFromTableInBundle(@"Rate %@", @"AppiraterLocalizable", [Appirater bundle], nil) +#define APPIRATER_RATE_BUTTON [NSString stringWithFormat:APPIRATER_LOCALIZED_RATE_BUTTON, APPIRATER_APP_NAME] + +/*! + Text for button to remind the user to review later. + */ +#define APPIRATER_RATE_LATER NSLocalizedStringFromTableInBundle(@"Remind me later", @"AppiraterLocalizable", [Appirater bundle], nil) + +@interface Appirater : NSObject { + + UIAlertView *ratingAlert; +} + +@property(nonatomic, strong) UIAlertView *ratingAlert; +@property(nonatomic) BOOL openInAppStore; +#if __has_feature(objc_arc_weak) +@property(nonatomic, weak) NSObject *delegate; +#else +@property(nonatomic, unsafe_unretained) NSObject *delegate; +#endif + +/*! + Tells Appirater that the app has launched, and on devices that do NOT + support multitasking, the 'uses' count will be incremented. You should + call this method at the end of your application delegate's + application:didFinishLaunchingWithOptions: method. + + If the app has been used enough to be rated (and enough significant events), + you can suppress the rating alert + by passing NO for canPromptForRating. The rating alert will simply be postponed + until it is called again with YES for canPromptForRating. The rating alert + can also be triggered by appEnteredForeground: and userDidSignificantEvent: + (as long as you pass YES for canPromptForRating in those methods). + */ ++ (void)appLaunched:(BOOL)canPromptForRating; + +/*! + Tells Appirater that the app was brought to the foreground on multitasking + devices. You should call this method from the application delegate's + applicationWillEnterForeground: method. + + If the app has been used enough to be rated (and enough significant events), + you can suppress the rating alert + by passing NO for canPromptForRating. The rating alert will simply be postponed + until it is called again with YES for canPromptForRating. The rating alert + can also be triggered by appLaunched: and userDidSignificantEvent: + (as long as you pass YES for canPromptForRating in those methods). + */ ++ (void)appEnteredForeground:(BOOL)canPromptForRating; + +/*! + Tells Appirater that the user performed a significant event. A significant + event is whatever you want it to be. If you're app is used to make VoIP + calls, then you might want to call this method whenever the user places + a call. If it's a game, you might want to call this whenever the user + beats a level boss. + + If the user has performed enough significant events and used the app enough, + you can suppress the rating alert by passing NO for canPromptForRating. The + rating alert will simply be postponed until it is called again with YES for + canPromptForRating. The rating alert can also be triggered by appLaunched: + and appEnteredForeground: (as long as you pass YES for canPromptForRating + in those methods). + */ ++ (void)userDidSignificantEvent:(BOOL)canPromptForRating; + +/*! + Tells Appirater to try and show the prompt (a rating alert). The prompt will be showed + if there is connection available, the user hasn't declined to rate + or hasn't rated current version. + + You could call to show the prompt regardless Appirater settings, + e.g., in case of some special event in your app. + */ ++ (void)tryToShowPrompt; + +/*! + Tells Appirater to show the prompt (a rating alert). + Similar to tryToShowPrompt, but without checks (the prompt is always displayed). + Passing false will hide the rate later button on the prompt. + + The only case where you should call this is if your app has an + explicit "Rate this app" command somewhere. This is similar to rateApp, + but instead of jumping to the review directly, an intermediary prompt is displayed. + */ ++ (void)forceShowPrompt:(BOOL)displayRateLaterButton; + +/*! + Tells Appirater to open the App Store page where the user can specify a + rating for the app. Also records the fact that this has happened, so the + user won't be prompted again to rate the app. + + The only case where you should call this directly is if your app has an + explicit "Rate this app" command somewhere. In all other cases, don't worry + about calling this -- instead, just call the other functions listed above, + and let Appirater handle the bookkeeping of deciding when to ask the user + whether to rate the app. + */ ++ (void)rateApp; + +/*! + Tells Appirater to immediately close any open rating modals (e.g. StoreKit rating VCs). +*/ ++ (void)closeModal; + +/*! + Asks Appirater if the user has declined to rate; +*/ +- (BOOL)userHasDeclinedToRate; + +/*! + Asks Appirater if the user has rated the current version. + Note that this is not a guarantee that the user has actually rated the app in the + app store, but they've just clicked the rate button on the Appirater dialog. +*/ +- (BOOL)userHasRatedCurrentVersion; + +@end + +@interface Appirater(Configuration) + +/*! + Set your Apple generated software id here. + */ ++ (void) setAppId:(NSString*)appId; + +/*! + Users will need to have the same version of your app installed for this many + days before they will be prompted to rate it. + */ ++ (void) setDaysUntilPrompt:(double)value; + +/*! + An example of a 'use' would be if the user launched the app. Bringing the app + into the foreground (on devices that support it) would also be considered + a 'use'. You tell Appirater about these events using the two methods: + [Appirater appLaunched:] + [Appirater appEnteredForeground:] + + Users need to 'use' the same version of the app this many times before + before they will be prompted to rate it. + */ ++ (void) setUsesUntilPrompt:(NSInteger)value; + +/*! + A significant event can be anything you want to be in your app. In a + telephone app, a significant event might be placing or receiving a call. + In a game, it might be beating a level or a boss. This is just another + layer of filtering that can be used to make sure that only the most + loyal of your users are being prompted to rate you on the app store. + If you leave this at a value of -1, then this won't be a criterion + used for rating. To tell Appirater that the user has performed + a significant event, call the method: + [Appirater userDidSignificantEvent:]; + */ ++ (void) setSignificantEventsUntilPrompt:(NSInteger)value; + + +/*! + Once the rating alert is presented to the user, they might select + 'Remind me later'. This value specifies how long (in days) Appirater + will wait before reminding them. + */ ++ (void) setTimeBeforeReminding:(double)value; + +/*! + Set customized title for alert view. + */ ++ (void) setCustomAlertTitle:(NSString *)title; + +/*! + Set customized message for alert view. + */ ++ (void) setCustomAlertMessage:(NSString *)message; + +/*! + Set customized cancel button title for alert view. + */ ++ (void) setCustomAlertCancelButtonTitle:(NSString *)cancelTitle; + +/*! + Set customized rate button title for alert view. + */ ++ (void) setCustomAlertRateButtonTitle:(NSString *)rateTitle; + +/*! + Set customized rate later button title for alert view. + */ ++ (void) setCustomAlertRateLaterButtonTitle:(NSString *)rateLaterTitle; + +/*! + 'YES' will show the Appirater alert everytime. Useful for testing how your message + looks and making sure the link to your app's review page works. + */ ++ (void) setDebug:(BOOL)debug; + +/*! + Set the delegate if you want to know when Appirater does something + */ ++ (void)setDelegate:(id)delegate; + +/*! + Set whether or not Appirater uses animation (currently respected when pushing modal StoreKit rating VCs). + */ ++ (void)setUsesAnimation:(BOOL)animation; + +/*! + If set to YES, Appirater will open App Store link (instead of SKStoreProductViewController on iOS 6). Default YES. + */ ++ (void)setOpenInAppStore:(BOOL)openInAppStore; + +/*! + If set to YES, the main bundle will always be used to load localized strings. + Set this to YES if you have provided your own custom localizations in AppiraterLocalizable.strings + in your main bundle. Default is NO. + */ ++ (void)setAlwaysUseMainBundle:(BOOL)useMainBundle; + +@end + + +/*! + Methods in this interface are public out of necessity, but may change without notice + */ +@interface Appirater(Unsafe) + +/*! + The bundle localized strings will be loaded from. +*/ ++(NSBundle *)bundle; + +@end + +@interface Appirater(Deprecated) + +/*! + DEPRECATED: While still functional, it's better to use + appLaunched:(BOOL)canPromptForRating instead. + + Calls [Appirater appLaunched:YES]. See appLaunched: for details of functionality. + */ ++ (void)appLaunched __attribute__((deprecated)); + +/*! + DEPRECATED: While still functional, it's better to use + tryToShowPrompt instead. + + Calls [Appirater tryToShowPrompt]. See tryToShowPrompt for details of functionality. + */ ++ (void)showPrompt __attribute__((deprecated)); + +@end diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/Appirater.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/Appirater.m Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,732 @@ +/* + This file is part of Appirater. + + Copyright (c) 2012, Arash Payan + All rights reserved. + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + */ +/* + * Appirater.m + * appirater + * + * Created by Arash Payan on 9/5/09. + * http://arashpayan.com + * Copyright 2012 Arash Payan. All rights reserved. + */ + +#import "Appirater.h" +#import +#include + +#if ! __has_feature(objc_arc) +#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). +#endif + +NSString *const kAppiraterFirstUseDate = @"kAppiraterFirstUseDate"; +NSString *const kAppiraterUseCount = @"kAppiraterUseCount"; +NSString *const kAppiraterSignificantEventCount = @"kAppiraterSignificantEventCount"; +NSString *const kAppiraterCurrentVersion = @"kAppiraterCurrentVersion"; +NSString *const kAppiraterRatedCurrentVersion = @"kAppiraterRatedCurrentVersion"; +NSString *const kAppiraterDeclinedToRate = @"kAppiraterDeclinedToRate"; +NSString *const kAppiraterReminderRequestDate = @"kAppiraterReminderRequestDate"; + +NSString *templateReviewURL = @"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=APP_ID"; +NSString *templateReviewURLiOS7 = @"itms-apps://itunes.apple.com/app/idAPP_ID"; +NSString *templateReviewURLiOS8 = @"itms-apps://itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?id=APP_ID&onlyLatestVersion=true&pageNumber=0&sortOrdering=1&type=Purple+Software"; + +static NSString *_appId; +static double _daysUntilPrompt = 30; +static NSInteger _usesUntilPrompt = 20; +static NSInteger _significantEventsUntilPrompt = -1; +static double _timeBeforeReminding = 1; +static BOOL _debug = NO; +#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 + static id _delegate; +#else + __weak static id _delegate; +#endif +static BOOL _usesAnimation = TRUE; +static UIStatusBarStyle _statusBarStyle; +static BOOL _modalOpen = false; +static BOOL _alwaysUseMainBundle = NO; + +@interface Appirater () +@property (nonatomic, copy) NSString *alertTitle; +@property (nonatomic, copy) NSString *alertMessage; +@property (nonatomic, copy) NSString *alertCancelTitle; +@property (nonatomic, copy) NSString *alertRateTitle; +@property (nonatomic, copy) NSString *alertRateLaterTitle; +- (BOOL)connectedToNetwork; ++ (Appirater*)sharedInstance; +- (void)showPromptWithChecks:(BOOL)withChecks + displayRateLaterButton:(BOOL)displayRateLaterButton; +- (void)showRatingAlert:(BOOL)displayRateLaterButton; +- (void)showRatingAlert; +- (BOOL)ratingAlertIsAppropriate; +- (BOOL)ratingConditionsHaveBeenMet; +- (void)incrementUseCount; +- (void)hideRatingAlert; +@end + +@implementation Appirater + +@synthesize ratingAlert; + ++ (void) setAppId:(NSString *)appId { + _appId = appId; +} + ++ (void) setDaysUntilPrompt:(double)value { + _daysUntilPrompt = value; +} + ++ (void) setUsesUntilPrompt:(NSInteger)value { + _usesUntilPrompt = value; +} + ++ (void) setSignificantEventsUntilPrompt:(NSInteger)value { + _significantEventsUntilPrompt = value; +} + ++ (void) setTimeBeforeReminding:(double)value { + _timeBeforeReminding = value; +} + ++ (void) setCustomAlertTitle:(NSString *)title +{ + [self sharedInstance].alertTitle = title; +} + ++ (void) setCustomAlertMessage:(NSString *)message +{ + [self sharedInstance].alertMessage = message; +} + ++ (void) setCustomAlertCancelButtonTitle:(NSString *)cancelTitle +{ + [self sharedInstance].alertCancelTitle = cancelTitle; +} + ++ (void) setCustomAlertRateButtonTitle:(NSString *)rateTitle +{ + [self sharedInstance].alertRateTitle = rateTitle; +} + ++ (void) setCustomAlertRateLaterButtonTitle:(NSString *)rateLaterTitle +{ + [self sharedInstance].alertRateLaterTitle = rateLaterTitle; +} + ++ (void) setDebug:(BOOL)debug { + _debug = debug; +} ++ (void)setDelegate:(id)delegate{ + _delegate = delegate; +} ++ (void)setUsesAnimation:(BOOL)animation { + _usesAnimation = animation; +} ++ (void)setOpenInAppStore:(BOOL)openInAppStore { + [Appirater sharedInstance].openInAppStore = openInAppStore; +} ++ (void)setStatusBarStyle:(UIStatusBarStyle)style { + _statusBarStyle = style; +} ++ (void)setModalOpen:(BOOL)open { + _modalOpen = open; +} ++ (void)setAlwaysUseMainBundle:(BOOL)alwaysUseMainBundle { + _alwaysUseMainBundle = alwaysUseMainBundle; +} + ++ (NSBundle *)bundle +{ + NSBundle *bundle; + + if (_alwaysUseMainBundle) { + bundle = [NSBundle mainBundle]; + } else { + NSURL *appiraterBundleURL = [[NSBundle mainBundle] URLForResource:@"Appirater" withExtension:@"bundle"]; + + if (appiraterBundleURL) { + // Appirater.bundle will likely only exist when used via CocoaPods + bundle = [NSBundle bundleWithURL:appiraterBundleURL]; + } else { + bundle = [NSBundle mainBundle]; + } + } + + return bundle; +} + +- (NSString *)alertTitle +{ + return _alertTitle ? _alertTitle : APPIRATER_MESSAGE_TITLE; +} + +- (NSString *)alertMessage +{ + return _alertMessage ? _alertMessage : APPIRATER_MESSAGE; +} + +- (NSString *)alertCancelTitle +{ + return _alertCancelTitle ? _alertCancelTitle : APPIRATER_CANCEL_BUTTON; +} + +- (NSString *)alertRateTitle +{ + return _alertRateTitle ? _alertRateTitle : APPIRATER_RATE_BUTTON; +} + +- (NSString *)alertRateLaterTitle +{ + return _alertRateLaterTitle ? _alertRateLaterTitle : APPIRATER_RATE_LATER; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (id)init { + self = [super init]; + if (self) { + if ([[UIDevice currentDevice].systemVersion floatValue] >= 7.0) { + self.openInAppStore = YES; + } else { + self.openInAppStore = NO; + } + } + + return self; +} + +- (BOOL)connectedToNetwork { + // Create zero addy + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + // Recover reachability flags + SCNetworkReachabilityRef defaultRouteReachability = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&zeroAddress); + SCNetworkReachabilityFlags flags; + + Boolean didRetrieveFlags = SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags); + CFRelease(defaultRouteReachability); + + if (!didRetrieveFlags) + { + NSLog(@"Error. Could not recover network reachability flags"); + return NO; + } + + BOOL isReachable = flags & kSCNetworkFlagsReachable; + BOOL needsConnection = flags & kSCNetworkFlagsConnectionRequired; + BOOL nonWiFi = flags & kSCNetworkReachabilityFlagsTransientConnection; + + NSURL *testURL = [NSURL URLWithString:@"http://www.apple.com/"]; + NSURLRequest *testRequest = [NSURLRequest requestWithURL:testURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:20.0]; + NSURLConnection *testConnection = [[NSURLConnection alloc] initWithRequest:testRequest delegate:self]; + + return ((isReachable && !needsConnection) || nonWiFi) ? (testConnection ? YES : NO) : NO; +} + ++ (Appirater*)sharedInstance { + static Appirater *appirater = nil; + if (appirater == nil) + { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + appirater = [[Appirater alloc] init]; + appirater.delegate = _delegate; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive) name: + UIApplicationWillResignActiveNotification object:nil]; + }); + } + + return appirater; +} + +- (void)showRatingAlert:(BOOL)displayRateLaterButton { + UIAlertView *alertView = nil; + id delegate = _delegate; + + if(delegate && [delegate respondsToSelector:@selector(appiraterShouldDisplayAlert:)] && ![delegate appiraterShouldDisplayAlert:self]) { + return; + } + + if (displayRateLaterButton) { + alertView = [[UIAlertView alloc] initWithTitle:self.alertTitle + message:self.alertMessage + delegate:self + cancelButtonTitle:self.alertCancelTitle + otherButtonTitles:self.alertRateTitle, self.alertRateLaterTitle, nil]; + } else { + alertView = [[UIAlertView alloc] initWithTitle:self.alertTitle + message:self.alertMessage + delegate:self + cancelButtonTitle:self.alertCancelTitle + otherButtonTitles:self.alertRateTitle, nil]; + } + + self.ratingAlert = alertView; + [alertView show]; + + if (delegate && [delegate respondsToSelector:@selector(appiraterDidDisplayAlert:)]) { + [delegate appiraterDidDisplayAlert:self]; + } +} + +- (void)showRatingAlert +{ + [self showRatingAlert:true]; +} + +// is this an ok time to show the alert? (regardless of whether the rating conditions have been met) +// +// things checked here: +// * connectivity with network +// * whether user has rated before +// * whether user has declined to rate +// * whether rating alert is currently showing visibly +// things NOT checked here: +// * time since first launch +// * number of uses of app +// * number of significant events +// * time since last reminder +- (BOOL)ratingAlertIsAppropriate { + return ([self connectedToNetwork] + && ![self userHasDeclinedToRate] + && !self.ratingAlert.visible + && ![self userHasRatedCurrentVersion]); +} + +// have the rating conditions been met/earned? (regardless of whether this would be a moment when it's appropriate to show a new rating alert) +// +// things checked here: +// * time since first launch +// * number of uses of app +// * number of significant events +// * time since last reminder +// things NOT checked here: +// * connectivity with network +// * whether user has rated before +// * whether user has declined to rate +// * whether rating alert is currently showing visibly +- (BOOL)ratingConditionsHaveBeenMet { + if (_debug) + return YES; + + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + + NSDate *dateOfFirstLaunch = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterFirstUseDate]]; + NSTimeInterval timeSinceFirstLaunch = [[NSDate date] timeIntervalSinceDate:dateOfFirstLaunch]; + NSTimeInterval timeUntilRate = 60 * 60 * 24 * _daysUntilPrompt; + if (timeSinceFirstLaunch < timeUntilRate) + return NO; + + // check if the app has been used enough + NSInteger useCount = [userDefaults integerForKey:kAppiraterUseCount]; + if (useCount < _usesUntilPrompt) + return NO; + + // check if the user has done enough significant events + NSInteger sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount]; + if (sigEventCount < _significantEventsUntilPrompt) + return NO; + + // if the user wanted to be reminded later, has enough time passed? + NSDate *reminderRequestDate = [NSDate dateWithTimeIntervalSince1970:[userDefaults doubleForKey:kAppiraterReminderRequestDate]]; + NSTimeInterval timeSinceReminderRequest = [[NSDate date] timeIntervalSinceDate:reminderRequestDate]; + NSTimeInterval timeUntilReminder = 60 * 60 * 24 * _timeBeforeReminding; + if (timeSinceReminderRequest < timeUntilReminder) + return NO; + + return YES; +} + +- (void)incrementUseCount { + // get the app's version + NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey]; + + // get the version number that we've been tracking + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion]; + if (trackingVersion == nil) + { + trackingVersion = version; + [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; + } + + if (_debug) + NSLog(@"APPIRATER Tracking version: %@", trackingVersion); + + if ([trackingVersion isEqualToString:version]) + { + // check if the first use date has been set. if not, set it. + NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate]; + if (timeInterval == 0) + { + timeInterval = [[NSDate date] timeIntervalSince1970]; + [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate]; + } + + // increment the use count + NSInteger useCount = [userDefaults integerForKey:kAppiraterUseCount]; + useCount++; + [userDefaults setInteger:useCount forKey:kAppiraterUseCount]; + if (_debug) + NSLog(@"APPIRATER Use count: %@", @(useCount)); + } + else + { + // it's a new version of the app, so restart tracking + [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; + [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterFirstUseDate]; + [userDefaults setInteger:1 forKey:kAppiraterUseCount]; + [userDefaults setInteger:0 forKey:kAppiraterSignificantEventCount]; + [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion]; + [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate]; + [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate]; + } + + [userDefaults synchronize]; +} + +- (void)incrementSignificantEventCount { + // get the app's version + NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString*)kCFBundleVersionKey]; + + // get the version number that we've been tracking + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + NSString *trackingVersion = [userDefaults stringForKey:kAppiraterCurrentVersion]; + if (trackingVersion == nil) + { + trackingVersion = version; + [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; + } + + if (_debug) + NSLog(@"APPIRATER Tracking version: %@", trackingVersion); + + if ([trackingVersion isEqualToString:version]) + { + // check if the first use date has been set. if not, set it. + NSTimeInterval timeInterval = [userDefaults doubleForKey:kAppiraterFirstUseDate]; + if (timeInterval == 0) + { + timeInterval = [[NSDate date] timeIntervalSince1970]; + [userDefaults setDouble:timeInterval forKey:kAppiraterFirstUseDate]; + } + + // increment the significant event count + NSInteger sigEventCount = [userDefaults integerForKey:kAppiraterSignificantEventCount]; + sigEventCount++; + [userDefaults setInteger:sigEventCount forKey:kAppiraterSignificantEventCount]; + if (_debug) + NSLog(@"APPIRATER Significant event count: %@", @(sigEventCount)); + } + else + { + // it's a new version of the app, so restart tracking + [userDefaults setObject:version forKey:kAppiraterCurrentVersion]; + [userDefaults setDouble:0 forKey:kAppiraterFirstUseDate]; + [userDefaults setInteger:0 forKey:kAppiraterUseCount]; + [userDefaults setInteger:1 forKey:kAppiraterSignificantEventCount]; + [userDefaults setBool:NO forKey:kAppiraterRatedCurrentVersion]; + [userDefaults setBool:NO forKey:kAppiraterDeclinedToRate]; + [userDefaults setDouble:0 forKey:kAppiraterReminderRequestDate]; + } + + [userDefaults synchronize]; +} + +- (void)incrementAndRate:(BOOL)canPromptForRating { + [self incrementUseCount]; + + if (canPromptForRating && + [self ratingConditionsHaveBeenMet] && + [self ratingAlertIsAppropriate]) + { + dispatch_async(dispatch_get_main_queue(), + ^{ + [self showRatingAlert]; + }); + } +} + +- (void)incrementSignificantEventAndRate:(BOOL)canPromptForRating { + [self incrementSignificantEventCount]; + + if (canPromptForRating && + [self ratingConditionsHaveBeenMet] && + [self ratingAlertIsAppropriate]) + { + dispatch_async(dispatch_get_main_queue(), + ^{ + [self showRatingAlert]; + }); + } +} + +- (BOOL)userHasDeclinedToRate { + return [[NSUserDefaults standardUserDefaults] boolForKey:kAppiraterDeclinedToRate]; +} + +- (BOOL)userHasRatedCurrentVersion { + return [[NSUserDefaults standardUserDefaults] boolForKey:kAppiraterRatedCurrentVersion]; +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-implementations" ++ (void)appLaunched { + [Appirater appLaunched:YES]; +} +#pragma GCC diagnostic pop + ++ (void)appLaunched:(BOOL)canPromptForRating { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), + ^{ + Appirater *a = [Appirater sharedInstance]; + if (_debug) { + dispatch_async(dispatch_get_main_queue(), + ^{ + [a showRatingAlert]; + }); + } else { + [a incrementAndRate:canPromptForRating]; + } + }); +} + +- (void)hideRatingAlert { + if (self.ratingAlert.visible) { + if (_debug) + NSLog(@"APPIRATER Hiding Alert"); + [self.ratingAlert dismissWithClickedButtonIndex:-1 animated:NO]; + } +} + ++ (void)appWillResignActive { + if (_debug) + NSLog(@"APPIRATER appWillResignActive"); + [[Appirater sharedInstance] hideRatingAlert]; +} + ++ (void)appEnteredForeground:(BOOL)canPromptForRating { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), + ^{ + [[Appirater sharedInstance] incrementAndRate:canPromptForRating]; + }); +} + ++ (void)userDidSignificantEvent:(BOOL)canPromptForRating { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), + ^{ + [[Appirater sharedInstance] incrementSignificantEventAndRate:canPromptForRating]; + }); +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-implementations" ++ (void)showPrompt { + [Appirater tryToShowPrompt]; +} +#pragma GCC diagnostic pop + ++ (void)tryToShowPrompt { + [[Appirater sharedInstance] showPromptWithChecks:true + displayRateLaterButton:true]; +} + ++ (void)forceShowPrompt:(BOOL)displayRateLaterButton { + [[Appirater sharedInstance] showPromptWithChecks:false + displayRateLaterButton:displayRateLaterButton]; +} + +- (void)showPromptWithChecks:(BOOL)withChecks + displayRateLaterButton:(BOOL)displayRateLaterButton { + if (withChecks == NO || [self ratingAlertIsAppropriate]) { + [self showRatingAlert:displayRateLaterButton]; + } +} + ++ (id)getRootViewController { + UIWindow *window = [[UIApplication sharedApplication] keyWindow]; + if (window.windowLevel != UIWindowLevelNormal) { + NSArray *windows = [[UIApplication sharedApplication] windows]; + for(window in windows) { + if (window.windowLevel == UIWindowLevelNormal) { + break; + } + } + } + + return [Appirater iterateSubViewsForViewController:window]; // iOS 8+ deep traverse +} + ++ (id)iterateSubViewsForViewController:(UIView *) parentView { + for (UIView *subView in [parentView subviews]) { + UIResponder *responder = [subView nextResponder]; + if([responder isKindOfClass:[UIViewController class]]) { + return [self topMostViewController: (UIViewController *) responder]; + } + id found = [Appirater iterateSubViewsForViewController:subView]; + if( nil != found) { + return found; + } + } + return nil; +} + ++ (UIViewController *) topMostViewController: (UIViewController *) controller { + BOOL isPresenting = NO; + do { + // this path is called only on iOS 6+, so -presentedViewController is fine here. + UIViewController *presented = [controller presentedViewController]; + isPresenting = presented != nil; + if(presented != nil) { + controller = presented; + } + + } while (isPresenting); + + return controller; +} + ++ (void)rateApp { + + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setBool:YES forKey:kAppiraterRatedCurrentVersion]; + [userDefaults synchronize]; + + //Use the in-app StoreKit view if available (iOS 6) and imported. This works in the simulator. + if (![Appirater sharedInstance].openInAppStore && NSStringFromClass([SKStoreProductViewController class]) != nil) { + + SKStoreProductViewController *storeViewController = [[SKStoreProductViewController alloc] init]; + NSNumber *appId = [NSNumber numberWithInteger:_appId.integerValue]; + [storeViewController loadProductWithParameters:@{SKStoreProductParameterITunesItemIdentifier:appId} completionBlock:nil]; + storeViewController.delegate = self.sharedInstance; + + id delegate = self.sharedInstance.delegate; + if ([delegate respondsToSelector:@selector(appiraterWillPresentModalView:animated:)]) { + [delegate appiraterWillPresentModalView:self.sharedInstance animated:_usesAnimation]; + } + [[self getRootViewController] presentViewController:storeViewController animated:_usesAnimation completion:^{ + [self setModalOpen:YES]; + //Temporarily use a black status bar to match the StoreKit view. + [self setStatusBarStyle:[UIApplication sharedApplication].statusBarStyle]; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 + [[UIApplication sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent animated:_usesAnimation]; +#endif + }]; + + //Use the standard openUrl method if StoreKit is unavailable. + } else { + + #if TARGET_IPHONE_SIMULATOR + NSLog(@"APPIRATER NOTE: iTunes App Store is not supported on the iOS simulator. Unable to open App Store page."); + #else + NSString *reviewURL = [templateReviewURL stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]]; + + // iOS 7 needs a different templateReviewURL @see https://github.com/arashpayan/appirater/issues/131 + // Fixes condition @see https://github.com/arashpayan/appirater/issues/205 + if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0 && [[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) { + reviewURL = [templateReviewURLiOS7 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]]; + } + // iOS 8 needs a different templateReviewURL also @see https://github.com/arashpayan/appirater/issues/182 + else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) + { + reviewURL = [templateReviewURLiOS8 stringByReplacingOccurrencesOfString:@"APP_ID" withString:[NSString stringWithFormat:@"%@", _appId]]; + } + + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:reviewURL]]; + #endif + } +} + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + + id delegate = _delegate; + + switch (buttonIndex) { + case 0: + { + // they don't want to rate it + [userDefaults setBool:YES forKey:kAppiraterDeclinedToRate]; + [userDefaults synchronize]; + if(delegate && [delegate respondsToSelector:@selector(appiraterDidDeclineToRate:)]){ + [delegate appiraterDidDeclineToRate:self]; + } + break; + } + case 1: + { + // they want to rate it + [Appirater rateApp]; + if(delegate&& [delegate respondsToSelector:@selector(appiraterDidOptToRate:)]){ + [delegate appiraterDidOptToRate:self]; + } + break; + } + case 2: + // remind them later + [userDefaults setDouble:[[NSDate date] timeIntervalSince1970] forKey:kAppiraterReminderRequestDate]; + [userDefaults synchronize]; + if(delegate && [delegate respondsToSelector:@selector(appiraterDidOptToRemindLater:)]){ + [delegate appiraterDidOptToRemindLater:self]; + } + break; + default: + break; + } +} + +//Delegate call from the StoreKit view. +- (void)productViewControllerDidFinish:(SKStoreProductViewController *)viewController { + [Appirater closeModal]; +} + +//Close the in-app rating (StoreKit) view and restore the previous status bar style. ++ (void)closeModal { + if (_modalOpen) { + [[UIApplication sharedApplication]setStatusBarStyle:_statusBarStyle animated:_usesAnimation]; + BOOL usedAnimation = _usesAnimation; + [self setModalOpen:NO]; + + // get the top most controller (= the StoreKit Controller) and dismiss it + UIViewController *presentingController = [UIApplication sharedApplication].keyWindow.rootViewController; + presentingController = [self topMostViewController: presentingController]; + [presentingController dismissViewControllerAnimated:_usesAnimation completion:^{ + id delegate = self.sharedInstance.delegate; + if ([delegate respondsToSelector:@selector(appiraterDidDismissModalView:animated:)]) { + [delegate appiraterDidDismissModalView:(Appirater *)self animated:usedAnimation]; + } + }]; + [self.class setStatusBarStyle:(UIStatusBarStyle)nil]; + } +} + +@end diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/Appirater/AppiraterDelegate.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/project_files/HedgewarsMobile/Classes/Appirater/AppiraterDelegate.h Fri Nov 06 00:12:37 2015 +0100 @@ -0,0 +1,23 @@ +// +// AppiraterDelegate.h +// Banana Stand +// +// Created by Robert Haining on 9/25/12. +// Copyright (c) 2012 News.me. All rights reserved. +// + +#import + +@class Appirater; + +@protocol AppiraterDelegate + +@optional +-(BOOL)appiraterShouldDisplayAlert:(Appirater *)appirater; +-(void)appiraterDidDisplayAlert:(Appirater *)appirater; +-(void)appiraterDidDeclineToRate:(Appirater *)appirater; +-(void)appiraterDidOptToRate:(Appirater *)appirater; +-(void)appiraterDidOptToRemindLater:(Appirater *)appirater; +-(void)appiraterWillPresentModalView:(Appirater *)appirater animated:(BOOL)animated; +-(void)appiraterDidDismissModalView:(Appirater *)appirater animated:(BOOL)animated; +@end diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/HedgewarsAppDelegate.m --- a/project_files/HedgewarsMobile/Classes/HedgewarsAppDelegate.m Thu Nov 05 21:54:19 2015 +0100 +++ b/project_files/HedgewarsMobile/Classes/HedgewarsAppDelegate.m Fri Nov 06 00:12:37 2015 +0100 @@ -19,7 +19,7 @@ #import "HedgewarsAppDelegate.h" #import "MainMenuViewController.h" - +#import "Appirater.h" @implementation SDLUIKitDelegate (customDelegate) @@ -50,7 +50,16 @@ } // override the direct execution of SDL_main to allow us to implement our own frontend --(void) postFinishLaunch { +-(void) postFinishLaunch +{ + // Setup Appirater + [Appirater setAppId:@"391234866"]; + [Appirater setDaysUntilPrompt:3]; + [Appirater setUsesUntilPrompt:5]; + [Appirater setSignificantEventsUntilPrompt:-1]; + [Appirater setTimeBeforeReminding:1]; + //[Appirater setDebug:YES]; + [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; [[UIApplication sharedApplication] setStatusBarHidden:YES]; diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Classes/MainMenuViewController.m --- a/project_files/HedgewarsMobile/Classes/MainMenuViewController.m Thu Nov 05 21:54:19 2015 +0100 +++ b/project_files/HedgewarsMobile/Classes/MainMenuViewController.m Fri Nov 06 00:12:37 2015 +0100 @@ -94,7 +94,7 @@ else { // let's not prompt for rating when app crashed >_> - [Appirater appLaunched]; + [Appirater appLaunched:YES]; } /* diff -r 92b023095153 -r 402baa6d4f64 project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj --- a/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj Thu Nov 05 21:54:19 2015 +0100 +++ b/project_files/HedgewarsMobile/Hedgewars.xcodeproj/project.pbxproj Fri Nov 06 00:12:37 2015 +0100 @@ -207,7 +207,6 @@ 61A670C112747DB900B06CE7 /* MainMenuViewController-iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6165924C11CA9CB400D6E256 /* MainMenuViewController-iPhone.xib */; }; 61A670C212747DBD00B06CE7 /* MapConfigViewController-iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6165924E11CA9CB400D6E256 /* MapConfigViewController-iPhone.xib */; }; 61A976B3136F668500DD9878 /* uCursor.pas in Sources */ = {isa = PBXBuildFile; fileRef = 61A976B2136F668500DD9878 /* uCursor.pas */; }; - 61AC067412B2E32D000B52A2 /* Appirater.m in Sources */ = {isa = PBXBuildFile; fileRef = 61AC067312B2E32D000B52A2 /* Appirater.m */; }; 61B37A1F17837C78009F283D /* ArgParsers.pas in Sources */ = {isa = PBXBuildFile; fileRef = 61B37A1D17837C78009F283D /* ArgParsers.pas */; }; 61B37A2017837C78009F283D /* uVisualGearsList.pas in Sources */ = {isa = PBXBuildFile; fileRef = 61B37A1E17837C78009F283D /* uVisualGearsList.pas */; }; 61B37A80178381DB009F283D /* uGearsHandlersMess.pas in Sources */ = {isa = PBXBuildFile; fileRef = 61B37A7F178381DB009F283D /* uGearsHandlersMess.pas */; }; @@ -273,6 +272,9 @@ F65E1DC01B9B95A400A78ADF /* Icon-76.png in Resources */ = {isa = PBXBuildFile; fileRef = F65E1DBD1B9B95A400A78ADF /* Icon-76.png */; }; F65E1DC11B9B95A400A78ADF /* Icon-76@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F65E1DBE1B9B95A400A78ADF /* Icon-76@2x.png */; }; F6756D801BD8550500B6AB6B /* LabelWithIBLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = F6756D7F1BD8550500B6AB6B /* LabelWithIBLocalization.m */; }; + F67FC8121BEC06E700A9DC75 /* Appirater.m in Sources */ = {isa = PBXBuildFile; fileRef = F67FC8101BEC06E700A9DC75 /* Appirater.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + F67FC8141BEC072B00A9DC75 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F67FC8131BEC072B00A9DC75 /* StoreKit.framework */; }; + F67FC8161BEC17AC00A9DC75 /* Appirater.bundle in Resources */ = {isa = PBXBuildFile; fileRef = F67FC8151BEC17AC00A9DC75 /* Appirater.bundle */; }; F6BA38461BA7A834005D16EA /* GameLogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = F6BA38451BA7A834005D16EA /* GameLogViewController.m */; }; F6D7E09F1B76884E004F3BCF /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F6D7E09E1B76884E004F3BCF /* Default-568h@2x.png */; }; F6D7E0C21B768F19004F3BCF /* uLandGenPerlin.pas in Sources */ = {isa = PBXBuildFile; fileRef = F6D7E0BF1B768F19004F3BCF /* uLandGenPerlin.pas */; }; @@ -674,8 +676,6 @@ 61A4A39312A5CCC2004D81E6 /* uVariables.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uVariables.pas; path = ../../hedgewars/uVariables.pas; sourceTree = SOURCE_ROOT; }; 61A4A3A112A5CD56004D81E6 /* uCaptions.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uCaptions.pas; path = ../../hedgewars/uCaptions.pas; sourceTree = SOURCE_ROOT; }; 61A976B2136F668500DD9878 /* uCursor.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uCursor.pas; path = ../../hedgewars/uCursor.pas; sourceTree = SOURCE_ROOT; }; - 61AC067212B2E32D000B52A2 /* Appirater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Appirater.h; path = Classes/Appirater.h; sourceTree = ""; }; - 61AC067312B2E32D000B52A2 /* Appirater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Appirater.m; path = Classes/Appirater.m; sourceTree = ""; }; 61B37A1D17837C78009F283D /* ArgParsers.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = ArgParsers.pas; path = ../../hedgewars/ArgParsers.pas; sourceTree = SOURCE_ROOT; }; 61B37A1E17837C78009F283D /* uVisualGearsList.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uVisualGearsList.pas; path = ../../hedgewars/uVisualGearsList.pas; sourceTree = SOURCE_ROOT; }; 61B37A7F178381DB009F283D /* uGearsHandlersMess.pas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = uGearsHandlersMess.pas; path = ../../hedgewars/uGearsHandlersMess.pas; sourceTree = SOURCE_ROOT; }; @@ -766,6 +766,11 @@ F65E1DBE1B9B95A400A78ADF /* Icon-76@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Icon-76@2x.png"; path = "Resources/Icons/Icon-76@2x.png"; sourceTree = ""; }; F6756D7E1BD8550500B6AB6B /* LabelWithIBLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LabelWithIBLocalization.h; sourceTree = ""; }; F6756D7F1BD8550500B6AB6B /* LabelWithIBLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LabelWithIBLocalization.m; sourceTree = ""; }; + F67FC80F1BEC06E700A9DC75 /* Appirater.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Appirater.h; sourceTree = ""; }; + F67FC8101BEC06E700A9DC75 /* Appirater.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Appirater.m; sourceTree = ""; }; + F67FC8111BEC06E700A9DC75 /* AppiraterDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppiraterDelegate.h; sourceTree = ""; }; + F67FC8131BEC072B00A9DC75 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + F67FC8151BEC17AC00A9DC75 /* Appirater.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Appirater.bundle; sourceTree = ""; }; F6BA38441BA7A834005D16EA /* GameLogViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameLogViewController.h; sourceTree = ""; }; F6BA38451BA7A834005D16EA /* GameLogViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GameLogViewController.m; sourceTree = ""; }; F6D7E09E1B76884E004F3BCF /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; @@ -788,6 +793,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F67FC8141BEC072B00A9DC75 /* StoreKit.framework in Frameworks */, F6FF25A21BB8AEE300124053 /* GameController.framework in Frameworks */, F6D7E0C81B7698BF004F3BCF /* libstdc++.dylib in Frameworks */, F6D7E0C61B769819004F3BCF /* CoreMotion.framework in Frameworks */, @@ -868,8 +874,7 @@ 61F8535314578999002CA294 /* Helpers */, 61641FE21437CD8F006E049C /* Headers */, 61DE91561258B76800B80214 /* Custom UIs */, - 61AC067212B2E32D000B52A2 /* Appirater.h */, - 61AC067312B2E32D000B52A2 /* Appirater.m */, + F67FC80E1BEC06E700A9DC75 /* Appirater */, 61006F93128DE31F00EBA7F7 /* CreationChamber.h */, 61006F94128DE31F00EBA7F7 /* CreationChamber.m */, 6165929C11CA9E2F00D6E256 /* HedgewarsAppDelegate.h */, @@ -904,6 +909,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + F67FC8131BEC072B00A9DC75 /* StoreKit.framework */, F6FF25A11BB8AEE300124053 /* GameController.framework */, 617D78D816D932310091D4D6 /* Physfs.xcodeproj */, 617D794316D933B00091D4D6 /* Physlayer.xcodeproj */, @@ -1398,6 +1404,18 @@ path = "Resources/Frontend/Help Bubbles"; sourceTree = ""; }; + F67FC80E1BEC06E700A9DC75 /* Appirater */ = { + isa = PBXGroup; + children = ( + F67FC80F1BEC06E700A9DC75 /* Appirater.h */, + F67FC8101BEC06E700A9DC75 /* Appirater.m */, + F67FC8111BEC06E700A9DC75 /* AppiraterDelegate.h */, + F67FC8151BEC17AC00A9DC75 /* Appirater.bundle */, + ); + name = Appirater; + path = Classes/Appirater; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1658,6 +1676,7 @@ 61188C0412A6FE880026C5DA /* savesButton@2x.png in Resources */, 61188C0512A6FE8F0026C5DA /* Data in Resources */, 61188C0612A6FE950026C5DA /* smallerBackground@2x~iphone.png in Resources */, + F67FC8161BEC17AC00A9DC75 /* Appirater.bundle in Resources */, F65724FD1B7E784700A86262 /* helpabove.png in Resources */, F6F07BDE1B7E72D40010E48F /* HelpPageLobbyViewController-iPad.xib in Resources */, 61188C0712A6FE960026C5DA /* settingsButton@2x.png in Resources */, @@ -1877,12 +1896,12 @@ 61A4A3A212A5CD56004D81E6 /* uCaptions.pas in Sources */, 61E5D68D12AB006F00566F29 /* uLandPainted.pas in Sources */, 61F544C712AF1748007FD913 /* HoldTableViewCell.m in Sources */, - 61AC067412B2E32D000B52A2 /* Appirater.m in Sources */, 61E2E12E12BAAEE30051B659 /* ServerProtocolNetwork.m in Sources */, 61B7A33812CC21080086B604 /* StatsPageViewController.m in Sources */, F6D7E0C41B768F19004F3BCF /* uLandUtils.pas in Sources */, 61EDB5B0135B3F97009B29A6 /* GameInterfaceBridge.m in Sources */, 61A976B3136F668500DD9878 /* uCursor.pas in Sources */, + F67FC8121BEC06E700A9DC75 /* Appirater.m in Sources */, 6167A6761391514600AA6D07 /* RestoreViewController.m in Sources */, 61C28D3F142D380400DA16C2 /* AudioManagerController.m in Sources */, 611D7A50142FDCD3006E0798 /* uTouch.pas in Sources */,