How do I edit title and messages in irate for ios? - ios

I have added the .h .m and .bundle files for irate. I set the preview mode to YES so the Alert View pops up right when my app launches on my phone (I'm testing). It doesn't show the Alert View at all if I don't set the preview mode to YES.
So now it pops up the rating Alert View. In the .m file I tried editing the title, message and button text in the string and it still shows the original title, message and button text even though it does not exist in the .m because I have completely changed it. Does anyone know how to edit this text so that it will edit the text that appears on the Alert View. The code is below as it came from my download of irate. If I change the text in the strings it doesn't change when I test it still shows what is there right now. Going around in circles here and I'm guessing I'm missing something simple, any help would be awesome!
- (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 *)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"];
}

As suggested in the iRate documentation on GitHub, there are two ways you can override those strings:
1) you can override the default strings in your app delegate initialize class method:
+ (void)initialize
{
//overriding the default iRate strings
[iRate sharedInstance].messageTitle = NSLocalizedString(#"Rate MyApp", #"iRate message title");
[iRate sharedInstance].message = NSLocalizedString(#"If you like MyApp, please take the time, etc", #"iRate message");
[iRate sharedInstance].cancelButtonLabel = NSLocalizedString(#"No, Thanks", #"iRate decline button");
[iRate sharedInstance].remindButtonLabel = NSLocalizedString(#"Remind Me Later", #"iRate remind button");
[iRate sharedInstance].rateButtonLabel = NSLocalizedString(#"Rate It Now", #"iRate accept button");
}
2) The recommended way is that you can also create your own Localizable.strings file and add those strings found in iRate.h:
//localisation string keys
static NSString *const iRateMessageTitleKey = #"iRateMessageTitle";
static NSString *const iRateAppMessageKey = #"iRateAppMessage";
static NSString *const iRateGameMessageKey = #"iRateGameMessage";
static NSString *const iRateCancelButtonKey = #"iRateCancelButton";
static NSString *const iRateRemindButtonKey = #"iRateRemindButton";
static NSString *const iRateRateButtonKey = #"iRateRateButton";
For example, inside the Localizable.strings file:
"iRateMessageTitle" = "My own rating title";
"iRateAppMessage" = "My own rating message";

Related

App Not Sending PNGs

Trying to learn by digging through some code.
Have an accessory button, when its pressed it loads up a menu so the user can pick either a picture from photo library or video (works perfect) have also a sticker menu that pops up similarly to the photo library. The sticker pops up accordingly, only have one if that matters. However when I select it nothing happens. The view is dismissed and it should be sent however it is not.v THE NSLog prints my check statement, I have even added the JSQ sound to play and it does it as well. Working with Firebase/Parse.
It seems to call everything just doesn't attach the PNG from the grid view to the message.
StickerView.m
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
NSString *file = stickers2[indexPath.item];
NSString *sticker = [file stringByReplacingOccurrencesOfString:#"#2x.png" withString:#""];
if (delegate != nil) [delegate didSelectSticker:sticker];
NSLog(#"Sticker Sent");
[self dismissViewControllerAnimated:YES completion:nil];
}
Chat.m
- (void)didSelectSticker:(NSString *)sticker
{
[self messageSend:sticker Video:nil Picture:nil Audio:nil];
}
messageSend
- (void)messageSend:(NSString *)text Video:(NSURL *)video Picture:(UIImage *)picture Audio:(NSString *)audio
{
Outgoing *outgoing = [[Outgoing alloc] initWith:groupId View:self.navigationController.view];
[outgoing send:text Video:video Picture:picture Audio:audio Sticker:sticker];
[JSQSystemSoundPlayer jsq_playMessageSentSound];
[self finishSendingMessage];
}
LOG
NSString *file = stickers2[indexPath.item];
NSLog (#"%d",indexPath.item);
NSLog (#"%#",file);
NSString *sticker = [file stringByReplacingOccurrencesOfString:#"#2x.png" withString:#"#2x.png"];
NSLog (#"%#",sticker);
if (delegate != nil) [delegate didSelectSticker:sticker];
NSLog(#"Sticker Sent");
[self dismissViewControllerAnimated:YES completion:nil];
indexPath returns a numerical value based on which sticker is selected. These are loaded into the mutableArray based on file name. If the file name contains a string of #"foo" it is loaded into the array. it could be one or one million value based on how many are loaded in. However it does correspond correctly to the selections. One is properly returned when object one is selected and 2 is properly selected and so on.
File name is returned as the correct file name.
Sticker was returned incorrectly based on your suspicious line of code, I have replaced it to not removed the extensions but did not delete it as of yet. Now returning the same value as File.
Outgoing
- (void)send:(NSString *)text Video:(NSURL *)video Picture:(UIImage *)picture Audio:(NSString *)audio Sticker:(NSString *)sticker
{
NSMutableDictionary *item = [[NSMutableDictionary alloc] init];
item[#"userId"] = [PFUser currentId];
item[#"name"] = [PFUser currentName];
item[#"date"] = Date2String([NSDate date]);
item[#"status"] = TEXT_DELIVERED;
item[#"video"] = item[#"thumbnail"] = item[#"picture"] = item[#"audio"] = item[#"latitude"] = item[#"longitude"] = #"";
item[#"video_duration"] = item[#"audio_duration"] = #0;
item[#"picture_width"] = item[#"picture_height"] = #0;
if (text != nil) [self sendTextMessage:item Text:text];
else if (video != nil) [self sendVideoMessage:item Video:video];
else if (picture != nil) [self sendPictureMessage:item Picture:picture];
else if (audio != nil) [self sendAudioMessage:item Audio:audio];
else if (sticker !=nil) [self sendSticker:item Sticker:sticker];
else [self sendLoactionMessage:item];
}
sendSticker
- (void)sendSticker:(NSMutableDictionary *)item Sticker:(NSString *)sticker
{
item[#"sticker"] = sticker;
NSLog(#"%#",sticker);
[self sendMessage:sticker]
}
NSLog never gets called so I know that this is not getting called. I must be missing something, after the user selects the sticker.
Sticker.h
#protocol StickersDelegate
- (void)didSelectSticker:(NSString *)sticker;
#end
#interface StickersView : UIViewController <UICollectionViewDataSource, UICollectionViewDelegate>
#property (nonatomic, assign) IBOutlet id<StickersDelegate>delegate;
#end
I see a couple of potential problem areas, but nothing definitive. I'd check the following either using a debugger or by adding additional logging:
What's the actual numerical value of indexPath.item? Does it represent a "valid" index into your array stickers2?
What is the value of file after you look it up? Is it a valid string, and does it correctly represent the name of an actual file on your file system?
What does the Outgoing class expect for the value of text in its -send:Video:Picture:Audio: method, a fully-qualified path name, or just a simple file name with no path? If the former, you'll either need to look up the system directory and construct the full file path before passing it in, or it would have needed to be constructed that way originally and inserted as such into stickers2, and if the latter, I'm assuming you will have needed to provided a "base" directory to Firebase/Parse somewhere.
This line is suspicious:
NSString *sticker = [file stringByReplacingOccurrencesOfString:#"#2x.png" withString:#""];
Do you mean to strip off the extension entirely? In other words, if you have a base filename of "foo#2x.png", then this will change "foo#2x.png" to "foo", is that what you really want. I'm guessing you might want this to be "foo.png" instead:
NSString *sticker = [file stringByReplacingOccurrencesOfString:#"#2x.png" withString:#".png"];
?
Hope this helps you track it down.

Xcode IOS Create 3 buttons to replace keyboard and text box

I am using an app to lock, unlock, and open the trunk of my car. The only problem is that I can't figure out how to modify the Xcode project so there are 3 buttons. Basically right now if I type "U" then enter- the car unlocks, "L" then enter- the car locks, and "T" then enter- the trunk opens. I want to add three buttons that simulate these three things and eliminate the typing all together. If you want to see my adruino or xcode project code I can upload those. I have put some code about the text box below.
BOOL)textFieldShouldReturn:(UITextField *)textField
{
NSString *text = textField.text;
NSNumber *form = [NSNumber numberWithBool:NO];
NSString *s;
NSData *d;
if (text.length > 16)
s = [text substringToIndex:16];
else
s = text;
d = [s dataUsingEncoding:NSUTF8StringEncoding];
if (bleShield.activePeripheral.state == CBPeripheralStateConnected) {
[bleShield write:d];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:text, TEXT_STR, form, FORM, nil];
[tableData addObject:dict];
[_tableView setContentOffset:CGPointMake(0, CGFLOAT_MAX)];
NSLog(#"%f", _tableView.contentOffset.y);
[self.tableView reloadData];
}
textField.text = #"";
return YES;
Thanks for the help!
Your view controller probably has a textFieldShouldReturn method which is taking the string value from the text field and building a parameter to a call that initiates sending the command. If not this method then perhaps its action method linked to the text field.
You'll need to duplicate parts of that code into a method that receives a string parameter instead of taking it from the text field, say named sendLockCommand:(NSString *)commandString (assuming you're coding in Objective-C, also like that repo).
Make action methods for your buttons, something like lockDoors, unlockDoors, openTrunk, in each call [self sendLockCommand:#"L"], each with the appropriate string. Wire up the buttons to those actions and you're good to go.

How do I find out the current keyboard used on iOS8?

You can get a list of the keyboards installed on the iOS device using:
NSUserDefaults *userDeafaults = [NSUserDefaults standardUserDefaults];
NSDictionary * userDefaultsDict = [userDeafaults dictionaryRepresentation];
NSLog(#"%#", userDefaultsDict);
This yields something in the console like:
{
...
AppleKeyboards = (
"en_US#hw=US;sw=QWERTY",
"es_ES#hw=Spanish - ISO;sw=QWERTY-Spanish",
"emoji#sw=Emoji",
"com.swiftkey.SwiftKeyApp.Keyboard"
);
AppleKeyboardsExpanded = 1;
...
}
This tells me that the device has the Spanish, Emoji and SwiftKey keyboards installed, but it tells me nothing about which will be used when the keyboard comes up.
Is there a way to tell?
There is no public API for this, but I found a solution for you, which requires very little "gray area API" (I define API as "gray area" if an API is not normally exposed, but can be hidden with little to no work).
iOS has the following class: UITextInputMode
This class gives you all the input methods the user can use. Using the following query will give you the currently used, only when the keyboard is open:
UITextInputMode* inputMode = [[[UITextInputMode activeInputModes] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"isDisplayed = YES"]] lastObject];
To get the display name of the extension (or regular Apple keyboard), use:
[inputMode valueForKey:#"displayName"]
or
[inputMode valueForKey:#"extendedDisplayName"]
This only works when the keyboard is visible. So you will have to monitor input mode change yourself using
[[NSNotificationCenter defaultCenter] addObserverForName:UITextInputCurrentInputModeDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", [[[[UITextInputMode activeInputModes] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"isDisplayed = YES"]] lastObject] valueForKey:#"extendedDisplayName"]);
});
}];
We actually need to delay obtaining the current input mode, as the notification is sent before the keyboard internal implementation has updated the system with new value. Obtaining it on the next runloop works well.
Leo Natan's answer is great, but I would like to add something to it. You can actually get the current input mode at any time, not just when the keyboard is open, like this:
UITextView *textView = [[UITextView alloc] init];
UITextInputMode *inputMode = textView.textInputMode;
Please note that textView.textInputMode is nil for the Emoji keyboard for some reason.
Also, in addition to displayName and extendedDisplayName, there are other keys you can retrieve, such as identifier, normalizedIdentifier (iOS 8+), hardwareLayout, ... See the full API here:
https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/UIKit.framework/UIKeyboardInputMode.h
Now I'm not sure if using any of those is more risky than displayName for App Store approval...
it works for me Swift 5.0
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardChanged(_:)), name:UITextInputMode.currentInputModeDidChangeNotification, object: nil)
#objc func keyBoardChanged(_ notification: NSNotification){
if let identifier = textField.textInputMode?.perform(NSSelectorFromString("identifier"))?.takeUnretainedValue() as? String{
if identifier == "YOUR APP IDENTIFIER"{
//Do Whatever you required :)
}
}
}
#Leo Natan's answers is cool but it's may return nil when the keyboard have not display.
So here I use the string to find the UIKeyboardInputMode's property.
I can tell you that this can find out the current keyboard because it's comes from Apple's Private API.
Code here:
+ (BOOL)isTheCustomKeyboard
{
UITextInputMode* inputMode = [UITextInputMode currentInputMode];
if ([inputMode respondsToSelector:NSSelectorFromString(#"identifier")])
{
NSString* indentifier = [inputMode performSelector:NSSelectorFromString(#"identifier")];
if ([indentifier isEqualToString: YOUR_APP_ID])
{
return YES;
}
}
return NO;
}
And more:
+ (BOOL)isContaintCustomKeyboard
{
NSArray * inputModes = [UITextInputMode activeInputModes];
for (id inputModel in inputModes)
{
if ([inputModel respondsToSelector:NSSelectorFromString(#"identifier")])
{
NSString* indentifier = [inputModel performSelector:NSSelectorFromString(#"identifier")];
if ([indentifier isEqualToString: YOUR_APP_ID])
{
return YES;
}
}
}
return NO;
}
Actually we can also use the displayName or the identifier and more.
Swift 5
let inputMode = UIApplication.shared.delegate?.window??.textInputMode
if inputMode?.responds(to: NSSelectorFromString("identifier")) ?? false {
let identifier = inputMode?.perform(NSSelectorFromString("identifier")).takeRetainedValue() as? String
print("\(identifier) // Current keyboard identifier.
}

Is there anyway I can compare a String (which is a word) and a letter which is input by the user and receive an output as a BOOL

I'm new to IOS dev and am making simple programs this one is a hangman game.
I wanted to pick a random string from a plist file (completed).
I now want to compare the user input text (from a text field) and compare it to the string we have randomly picked from our plist.
Here is my code for MainViewController.m as it is a utility. Only the MainView is being used currently.
#import "MainViewController.h"
#import "WordListLoad.h"
#interface MainViewController ()
#end
#implementation MainViewController
#synthesize textField=_textField;
#synthesize button=_button;
#synthesize correct=_correct;
#synthesize UsedLetters=_UsedLetters;
#synthesize newgame=_newgame;
- (IBAction)newg:(id)sender
{
[self start];
}
- (void)start
{
NSMutableArray *swords = [[NSMutableArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"swords" ofType:#"plist"]];
NSLog(#"%#", swords);
NSInteger randomIndex = arc4random() % [swords count];
NSString *randomString = [swords objectAtIndex:randomIndex];
NSLog(#"%#", randomString);
}
This is where i would like to implement the checking
I have tried characterAtIndex and I can't seem to get it to work for hard coded placed in the string let along using a for statement to systematic check the string.
- (void)check: (NSString *) randomString;
{
//NSLogs to check if the values are being sent
NSLog(#"2 %#", self.textField.text);
}
- (IBAction)go:(id)sender
{
[self.textField resignFirstResponder];
NSLog(#"1 %#", self.textField.text);
[self check:(NSString *) self.textField];
_textField.text = nil;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self start];
}
To compare 2 strings: [string1 equalsToString:string2]. This will return true if string1 is equal to string2. To get the string contained in a UITextfield: textfield.text.
Given that it's a hangman game, I assume you are trying to see if a single letter is contained by a given string - so equalsToString: wouldn't be what you want.
Instead, probably better to use rangeOfString:options:
if ([randomString rangeOfString:self.textfield.text options:NSCaseInsensitiveSearch].location != NSNotFound){
// Do stuff for when the letter was found
}
else {
// Do stuff for when the letter wasn't found
}
Also, as was pointed out by Patrick Goley, you need to make sure you're using the textfield.text value to get the string from it. Same with storing the initial word you'll be using as the hidden word.
There are also a couple of other minor code issues (semicolon in the function header, for example) that you'll need to clean up to have a functioning app.
Edit: Made the range of string call actually use the textfield's text, and do so case-insensitive (to prevent false returns when a user puts a capital letter when the word is lower case, or vice-versa). Also included link to documentation of NSString's rangeOfString:options:
For your check method you are sending the UITextfield itself, instead of its text string. Instead try:
[self check: self.textfield.text];
You'll also need to create an NSString property to save your random string from the plist, so you can later access to compare to the textfield string like so:
declare in the interface of the class:
#property (nonatomic,strong) NSString* randomString;
in the start method:
self.randomString = [swords objectAtIndex:randomIndex];
in the check method:
return [self.randomString isEqualToString:randomString];

Programmatic language localisation without restart

I want to create an iPhone application with English and Arabic language. I checked the Internationalization document for language switcher, however to take that into effect I have to manually go and change the iPhone setting. I don't want to do that. So what I am planning is on home screen I will have two button as English and Arabic. If user click Arabic, I will have arabic text and if user select English, app will be in english.
Any idea/ suggestion how to get this done?
Note: I don't want to manually go and change the language.
Edit 1
As per #Jano, I have done below.
Created new project. Added Arabic in Localization. Now I have two storyboard and two InfoPlist.strings file.
Added Localization.h and .m file as shown in answer.
Directory structure is MyProject-ar.lproj & MyProject-en.lproj
Content of Plist are "myButton01" = "Back"; & "myButton01" = "ظهر";
First View Controller have two button as English and Arabic. Called action on those button.
- (IBAction)pressedEnglish:(id)sender {
[Localization sharedInstance].fallbackLanguage = #"ar";
[Localization sharedInstance].preferredLanguage = #"en";
NSLog(#"pressed english");
}
- (IBAction)pressedArabic:(id)sender {
[Localization sharedInstance].fallbackLanguage = #"en";
[Localization sharedInstance].preferredLanguage = #"ar";
NSLog(#"pressed arabic");
}
In second view controller, I added one button and gave name as myButton. Now in viewDidLoad, I have
[self.myButton setTitle:localize(#"myButton01") forState:UIControlStateNormal];
I hope this should be working, however when I run the project, I see button as myButton01
Any reason why this is happening?
Edit 2
I got Edit 1 problem. I renamed InfoPlist.strings to Localizable.strings and it worked. But but but, I am still getting Arabic text irrespective of whatever button I press.
When finding reason, I found that it was because of below statement that we have in Localization.m
static Localization *shared = nil;
dispatch_once(&pred, ^{
shared = [[Localization alloc] init];
shared.fallbackLanguage = #"en";
shared.preferredLanguage = #"ar";
The problem is at last two lines. As we have set Arabic as preferredLanguage, I am always seeing the arabic text.
What changes will I need to do so that I can have it as changeable as per button pressed.
You want to set the language of the app from the app UI ignoring the user preference on the device. This is unusual, but here you go...
First write all your language strings on a directory structure like this:
i18n/en.lproj/Localizable.strings
i18n/ar.lproj/Localizable.strings
Create an additional directory with the corresponding two letter code for each additional language supported.
If the files are recognized as i18n resources, they will be presented like this:
Files will have a key=value with the following format:
"button.back" = "ظهر";
In your code, replace any localizable string with the key. Example:
[self.stateBtn setTitle:localize(#"button.back") forState:UIControlStateNormal];
Usually you would use NSLocalizedString(#"key",#"fallback") but since you want to ignore iPhone settings, I wrote a localize(#"key") macro above that will have the following implementation:
Localization.h
#ifndef localize
#define localize(key) [[Localization sharedInstance] localizedStringForKey:key]
#endif
#interface Localization : NSObject
#property (nonatomic, retain) NSBundle* fallbackBundle;
#property (nonatomic, retain) NSBundle* preferredBundle;
#property (nonatomic, copy) NSString* fallbackLanguage;
#property (nonatomic, copy) NSString* preferredLanguage;
-(NSString*) localizedStringForKey:(NSString*)key;
-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type;
+(Localization*)sharedInstance;
#end
Localization.m
#import "Localization.h"
#implementation Localization
+(Localization *)sharedInstance
{
static dispatch_once_t pred;
static Localization *shared = nil;
dispatch_once(&pred, ^{
shared = [[Localization alloc] init];
[shared setPreferred:#"en" fallback:#"ar"];
});
return shared;
}
-(void) setPreferred:(NSString*)preferred fallback:(NSString*)fallback
{
self.fallbackLanguage = fallback;
self.preferredLanguage = preferred;
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:#"Localizable" ofType:#"strings" inDirectory:nil forLocalization:self.fallbackLanguage];
self.fallbackBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
bundlePath = [[NSBundle mainBundle] pathForResource:#"Localizable" ofType:#"strings" inDirectory:nil forLocalization:self.preferredLanguage];
self.preferredBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
}
-(NSString*) pathForFilename:(NSString*)filename type:(NSString*)type
{
NSString *path = [self.preferredBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.preferredLanguage];
if (!path) path = [self.fallbackBundle pathForResource:filename ofType:type inDirectory:nil forLocalization:self.fallbackLanguage];
if (!path) NSLog(#"Missing file: %#.%#", filename, type);
return path;
}
-(NSString*) localizedStringForKey:(NSString*)key
{
NSString* result = nil;
if (_preferredBundle!=nil) {
result = [_preferredBundle localizedStringForKey:key value:nil table:nil];
}
if (result == nil) {
result = [_fallbackBundle localizedStringForKey:key value:nil table:nil];
}
if (result == nil) {
result = key;
}
return result;
}
#end
This will use lookup the key strings in the arabic file, and if the key is missing, it will look in the arabic file. If you want it the other way, do the following from your button handlers:
[[Localization sharedInstance] setPreferred:#"ar" fallback:#"en"];
Sample project at Github.
If localisation doesn't work
If localisation doesn't work, use the plutil command line tool to verify the format of the file. It should output: Localizable.strings: OK. Example:
$ plutil -lint Localizable.strings
Localizable.strings: OK
This format is described in Internationalization Programming Topics > Localizing String Resources. You can optionally add // single-line or /* multi-line */ comments. For non latin languages it’s recommended to encode Localized.strings in UTF-16. You can convert between encodings in the inspector pane of XCode.
If it still doesn't work, check that you are copying the Localizable.strings file in the Copy files phase of your target. Note that when you add Localizable.strings files there, sometimes they appear in red, keep doing it until a file appears in black, then delete the red ones (hacky I know, blame Xcode).

Resources