I have my app filling out the tweet sheet for the user and sometimes it may go over 140 characters including the url. I am trying to develop a method which can split the tweet into two parts and post part 2 first, and then part 1 so it will look like:
(1/2) blah blah blah
(2/2) blah blah blah
Here is the method I have so far:
(void)sendTweet:(NSString *)msg setURL:(NSString*)url setImg:(UIImage*)img {
// Set up the built-in twitter composition view controller.
TWTweetComposeViewController *tweetViewController = [[TWTweetComposeViewController alloc] init];
// Set the initial tweet text. See the framework for additional properties that can be set.
if (![tweetViewController addURL:[NSURL URLWithString:url]])
NSLog(#"Unable to add the URL!");
if (![tweetViewController addImage:img])
NSLog(#"Unable to add the image!");
if (![tweetViewController setInitialText:msg])
NSLog(#"Unable to add the message!");
// Create the completion handler block.
[tweetViewController setCompletionHandler:^(TWTweetComposeViewControllerResult result) {
NSString *output;
switch (result) {
case TWTweetComposeViewControllerResultCancelled:
// The cancel button was tapped.
output = #"Tweet cancelled.";
break;
case TWTweetComposeViewControllerResultDone:
// The tweet was sent.
output = #"Tweet sent.";
break;
default:
break;
}
// Show alert to see how things went...
UIAlertView* alertView = [[UIAlertView alloc]
initWithTitle:#"The Predictor"
message:output
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
// Dismiss the tweet composition view controller.
[self dismissModalViewControllerAnimated:YES];
}];
// Present the tweet composition view controller modally.
[self presentModalViewController:tweetViewController animated:YES];
}
Here is how i'm calling it, although the two part stuff isn't working...and I would like this functionality built-in to the method above.
if ([alertView tag] == 1) {
if (buttonIndex != [alertView cancelButtonIndex]) {
NSString *theURL = #"PredictorApps.com";
NSString *theTweet = [NSString stringWithFormat:#"%# - %#\n%#", [[Singleton sharedSingleton].spreadDate substringToIndex:5], theTitle, theMessage];
if (([theURL length] + [theTweet length]) <= 120)
[self sendTweet:theTweet setURL:theURL setImg:nil];
else if (([theURL length] + [theTweet length]) > 120) {
NSString *partTwo = [theTweet substringFromIndex:(([theURL length] + [theTweet length]) / 2)];
NSLog(#"Part Two: %#", partTwo);
[self sendTweet:partTwo setURL:theURL setImg:nil];
NSString *partOne = [theTweet substringToIndex:(([theURL length] + [theTweet length]) / 2)];
NSLog(#"Part One: %#", partOne);
[self sendTweet:partOne setURL:theURL setImg:nil];
}
}
}
any assistance is appreciated.
You have to use URL shorteners for reduce the URL size to post in twitter of facebook...For that you can refer to this link..This is a simple coding to shortening any type of URL u have..So u can reduce 2 part of post into single..I hope this will help you....
http://www.icodeblog.com/2010/02/04/iphone-coding-recipe-shortening-urls/
All the best....
Related
I have a UITableView that get its data from an array and the array contains the filenames of a directory.
I am trying to make user edit filename on row selection.
My code is:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self editChattWithName:[self.listArray objectAtIndex:indexPath.row] atIndex:indexPath];
[self.tabView deselectRowAtIndexPath:indexPath animated:YES];
}
- (void)editChattWithName:(NSString*)name atIndex:(NSIndexPath *)indexPath {
UIAlertView* editAlert = [[UIAlertView alloc]
initWithTitle:nil
message:#"Edit FileName"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Update", nil];
[editAlert setAlertViewStyle:UIAlertViewStylePlainTextInput];
UITextField* nameField = [editAlert textFieldAtIndex:0];
[nameField setPlaceholder:#"New FileName"];
[nameField setText:name];
[editAlert show];
[editAlert release];
NSString *newFileName = nameField.text;
[editAlert showWithCompletion:^(UIAlertView *alertView, NSInteger buttonIndex) {
if (buttonIndex == 0) { }
else if (buttonIndex == 1) {
NSError *error;
// Edit filename inside directory
[fm moveItemAtPath:[NSString stringWithFormat:#"%#%#",directory,name] toPath:[NSString stringWithFormat:#"%#%#",directory,newFileName] error:&error];
// Update value inside array
[self.listArray replaceObjectAtIndex:indexPath.row withObject:newChatName];
// reload table data to show new filename
[self.tabView reloadData];
NSLog(#"Old Filename: %#%#",directory,name);
NSLog(#"New Filename: %#%#",directory,newFileName);
NSLog(#"Error: %#",error);
}
}];
}
The issue is that name and newFileName are having the same value name and that is resulting an error with NSFileManager saying that the file already exists.
I have tried removing [nameField setText:name] but the problem was still there.
I am out of luck and not able to find the issue, your help is much appreciated.
Well, if you already know that the method moveItemAtPath:toPath: is causing the error only in case that the old and the new file name are identical then it should be quite easy to catch this error:
if (![newFileName isEqualToString:name]) {
[fm moveItemAtPath:[NSString stringWithFormat:#"%#%#",directory,name] toPath:[NSString stringWithFormat:#"%#%#",directory,newFileName] error:&error];
}
Now your file will only me moved (i.e. renamed) when the new file name differs from the old name.
Edit:
Furthermore, if you want to get the new file name that the user just entered in the alert view you should put this line:
NSString *newFileName = nameField.text;
in your completion block. Otherwise it will be set when the alert view is first displayed and hence have its initial value. To put it all together:
[editAlert showWithCompletion:^(UIAlertView *alertView, NSInteger buttonIndex) {
if (buttonIndex == 1) {
NSString *newFileName = nameField.text;
NSError *error;
// Edit filename inside directory
if (![newFileName isEqualToString:name]) {
[fm moveItemAtPath:[NSString stringWithFormat:#"%#%#",directory,name] toPath:[NSString stringWithFormat:#"%#%#",directory,newFileName] error:&error];
}
// Update value inside array
[self.listArray replaceObjectAtIndex:indexPath.row withObject:newChatName];
// reload table data to show new filename
[self.tabView reloadData];
}
}];
Supplement:
In order to not confuse other users it should be noted that showWithCompletion: is not a native UIAlertView method. An Objective-C category has been created to extend UIAlertView with this method. An example can be found here.
Twitter has deprecated its API 1.0 and implemented new API 1.1
As per the new API we need to authentication before fetching the public time line.
I read the new API documentation here: https://dev.twitter.com/docs/api/1.1
but I have not clear idea, how to implement it in iOS.
Can anyone tell me the best way to fetch public time-line form Twitter using the API 1.1
Thanks in advance.
First, you need to Authenticate your request (Get permission).
second, see follow these steps:
1.Download FHSTwitterEngine Twitter Library.
2.Add the folder FHSTwitterEngine" to your project and #import "FHSTwitterEngine.h".
3.add SystemConfiguration.framework to your project.
Usage : 1.in the [ViewDidLoad] add the following code.
UIButton *logIn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
logIn.frame = CGRectMake(100, 100, 100, 100);
[logIn setTitle:#"Login" forState:UIControlStateNormal];
[logIn addTarget:self action:#selector(showLoginWindow:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:logIn];
[[FHSTwitterEngine sharedEngine]permanentlySetConsumerKey:#"<consumer_key>" andSecret:#"<consumer_secret>"];
[[FHSTwitterEngine sharedEngine]setDelegate:self];
and don't forget to import the delegate FHSTwitterEngineAccessTokenDelegate.
you need to get the permission for your request, with the following method which will present Login window:
- (void)showLoginWindow:(id)sender {
[[FHSTwitterEngine sharedEngine]showOAuthLoginControllerFromViewController:self withCompletion:^(BOOL success) {
NSLog(success?#"L0L success":#"O noes!!! Loggen faylur!!!");
}];
}
when the Login window is presented, enter your Twitter Username and Password to authenticate your request.
add the following methods to your code:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[FHSTwitterEngine sharedEngine]loadAccessToken];
NSString *username = [[FHSTwitterEngine sharedEngine]loggedInUsername];// self.engine.loggedInUsername;
if (username.length > 0) {
lbl.text = [NSString stringWithFormat:#"Logged in as %#",username];
[self listResults];
} else {
lbl.text = #"You are not logged in.";
}
}
- (void)storeAccessToken:(NSString *)accessToken {
[[NSUserDefaults standardUserDefaults]setObject:accessToken forKey:#"SavedAccessHTTPBody"];
}
- (NSString *)loadAccessToken {
return [[NSUserDefaults standardUserDefaults]objectForKey:#"SavedAccessHTTPBody"];
}
4.Now you are ready to get your request, with the following method(in this method I created a `Twitter` search for some `Hashtag`, to get the screen_name for example):
- (void)listResults {
dispatch_async(GCDBackgroundThread, ^{
#autoreleasepool {
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
// the following line contains a FHSTwitterEngine method wich do the search.
dict = [[FHSTwitterEngine sharedEngine]searchTweetsWithQuery:#"#iOS" count:100 resultType:FHSTwitterEngineResultTypeRecent unil:nil sinceID:nil maxID:nil];
// NSLog(#"%#",dict);
NSArray *results = [dict objectForKey:#"statuses"];
// NSLog(#"array text = %#",results);
for (NSDictionary *item in results) {
NSLog(#"text == %#",[item objectForKey:#"text"]);
NSLog(#"name == %#",[[item objectForKey:#"user"]objectForKey:#"name"]);
NSLog(#"screen name == %#",[[item objectForKey:#"user"]objectForKey:#"screen_name"]);
NSLog(#"pic == %#",[[item objectForKey:#"user"]objectForKey:#"profile_image_url_https"]);
}
dispatch_sync(GCDMainThread, ^{
#autoreleasepool {
UIAlertView *av = [[UIAlertView alloc]initWithTitle:#"Complete!" message:#"Your list of followers has been fetched" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[av show];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
});
}
});
}
That's all. I just got the screen_name from a search Query, you can get a timeline for a user using the following methods:
// statuses/user_timeline
- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count;
- (id)getTimelineForUser:(NSString *)user isID:(BOOL)isID count:(int)count sinceID:(NSString *)sinceID maxID:(NSString *)maxID;
instead of the search method above.
Note: see the FHSTwitterEngine.h to know what method you need to use.
Note: to get the <consumer_key> and the <consumer_secret> you need to
to visit this link to register your app in Twitter.
You might be interested in the following library.
https://github.com/nst/STTwitter
It is a lightweight Objective-C wrapper for Twitter REST API 1.1.
Look at the ReadMe and Demo project for examples
This is just one of the many methods the library has:
- (void)getUserTimelineWithScreenName:(NSString *)screenName
successBlock:(void(^)(NSArray *statuses))successBlock
errorBlock:(void(^)(NSError *error))errorBlock;
I am getting stream on iPad from an IP camera named Foscam. If I open IP in iPad browser then it is working good but when I fetch stream in my application then it gets on frist screen shot and stuck on it. App is not getting continuous streaming from cam. I am using this way
- (IBAction)powerChanged:(id)sender {
UISwitch * s = (UISwitch *)sender;
if( s.on == TRUE){
[self initializeData];
if(![deviceClient connect]){
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"Can not connect to T-Rex device!"
message:[[NSString alloc] initWithFormat:#"Could not connec to %# and %d port",deviceClient.host,deviceClient.port]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[message show];
[s setOn:FALSE animated:TRUE];
} else {
[self adjustLayout:TRUE];
[self startFrequencyTimer];
}
}else {
[self stopFrequencyTimer];
[self adjustLayout:FALSE];
}
}
-(void)initializeData {
[cameraViewFront loadRequest:[NSURLRequest requestWithURL:[frontCameraClient getVideoStreamURL]]];
}
-(BOOL)connect {
if (udpSocket == nil){
udpSocket = [[GCDAsyncUdpSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];
}
NSLog(#"host %# and port %i", self.host, self.port);
return [udpSocket connectToHost:self.host onPort:self.port error:nil];
}
- (NSURL *) getURL:(NSString *)forPage {
NSLog(#"front cam IP %#" ,self.host);
return [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"http://%#/%#user=%#&pwd=%#",self.host,forPage,self.username, self.password]];
}
-(NSURL *)getVideoStreamURL{
return [self getURL:#"videostream.cgi?"];
}
I figured it out. I am using foscam and foscam provides a list of URLs on this link so I searched my cam model and then tried all the given URLs for MPEG connection type and http://IPADDRESS/videostream.cgi?user=[USERNAME]&pwd=[PASSWORD]&resolution=32&rate=0 URL worked for my case. But still there is a problem that it is working awesome on iOS5 and on iOS6 it still stuck on first frame.
To fix this problem this link helped me a lot. This method works for iOS5 and 6 both.
So I have a compiled and running Siphon app but it just won't make the calls.
I get:
registration error - default error message.
Full error is this:
15:04:02.032 pjsua_call.c Making call with acc #0 to sip:6476805821#voip5-2.acanac.com
15:04:02.032 pjsua_call.c .Unable to make call because account is not valid: Invalid operation (PJ_EINVALIDOP) [status=70013]
15:04:05.580 call.m Error making call: Invalid operation (PJ_EINVALIDOP) [status=70013]
But when I use the same account on a different SIP app, it works perfectly fine.
When pjsip calls sip_dial_with_uri(_sip_acc_id, [url UTF8String], &call_id);
_sip_acc_id is 0 since I believe it's the 0th account that's in the settings for siphon.
url is the correct phone number I'm trying to dial but shows something like:
sip:62304892#url.com
and call id is just a reference so I dunno if it's important.
When I look at other voip apps, they have a registration process. Where you enter you username, password, and sip server domain or ip.
For Siphon, this is done in the settings file. However, if "register or login" is done in Siphon's code or not, I'm not sure.
Could that be the problem?
This is the code that tries to make an actual call:
/** FIXME plutôt à mettre dans l'objet qui gère les appels **/
-(void) dialup:(NSString *)phoneNumber number:(BOOL)isNumber
{
pjsua_call_id call_id;
pj_status_t status;
NSString *number;
UInt32 hasMicro, size;
// Verify if microphone is available (perhaps we should verify in another place ?)
size = sizeof(hasMicro);
AudioSessionGetProperty(kAudioSessionProperty_AudioInputAvailable,
&size, &hasMicro);
/*if (!hasMicro)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Microphone Available", #"SiphonApp")
message:NSLocalizedString(#"Connect a microphone to phone", #"SiphonApp")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK", #"SiphonApp")
otherButtonTitles:nil];
[alert show];
[alert release];
return;
}*/
if (isNumber)
number = [self normalizePhoneNumber:phoneNumber];
else
number = phoneNumber;
if ([[NSUserDefaults standardUserDefaults] boolForKey:#"removeIntlPrefix"])
{
number = [number stringByReplacingOccurrencesOfString:#"+"
withString:#""
options:0
range:NSMakeRange(0,1)];
}
else
{
NSString *prefix = [[NSUserDefaults standardUserDefaults] stringForKey:
#"intlPrefix"];
if ([prefix length] > 0)
{
number = [number stringByReplacingOccurrencesOfString:#"+"
withString:prefix
options:0
range:NSMakeRange(0,1)];
}
}
// Manage pause symbol
NSArray * array = [number componentsSeparatedByString:#","];
[callViewController setDtmfCmd:#""];
if ([array count] > 1)
{
number = [array objectAtIndex:0];
[callViewController setDtmfCmd:[array objectAtIndex:1]];
}
if (!isConnected && [self wakeUpNetwork] == NO)
{
_phoneNumber = [[NSString stringWithString: number] retain];
if (isIpod)
{
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:nil
message:NSLocalizedString(#"You must enable Wi-Fi or SIP account to place a call.",#"SiphonApp")
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",#"SiphonApp")
otherButtonTitles:nil] autorelease];
[alertView show];
}
else
{
UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle:NSLocalizedString(#"The SIP server is unreachable!",#"SiphonApp")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Cancel",#"SiphonApp")
destructiveButtonTitle:nil
otherButtonTitles:NSLocalizedString(#"Cellular call",#"SiphonApp"),
nil] autorelease];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView: self.window];
}
return;
}
if ([self sipConnect])
{
NSRange range = [number rangeOfString:#"#"];
NSLog(#"%i", _sip_acc_id);
if (range.location != NSNotFound)
{
status = sip_dial_with_uri(_sip_acc_id, [[NSString stringWithFormat:#"sip:%#", number] UTF8String], &call_id);
}
else
status = sip_dial(_sip_acc_id, [number UTF8String], &call_id);
if (status != PJ_SUCCESS)
{
// FIXME
//[self displayStatus:status withTitle:nil];
const pj_str_t *str = pjsip_get_status_text(status);
NSString *msg = [[NSString alloc]
initWithBytes:str->ptr
length:str->slen
encoding:[NSString defaultCStringEncoding]];
[self displayError:msg withTitle:#"registration error"];
}
}
}
Also if anyone has a link to the Siphon app's code that's newer and maybe works better, I'd appreciate that as well.
More info:
in call.m file essentially this gets called:
status = pjsua_call_make_call(acc_id, &pj_uri, 0, NULL, NULL, call_id);
and here
acc_id = 0
pj_uri = char *-> "sip:6476805821#voip5-2.acanac.com"
pj_ssize_t -> 33
call_id = 803203976
I figured this out. Turns out, the siphon app wasn't registering the account.
The code below is important:
pj_status_t sip_connect(pj_pool_t *pool, pjsua_acc_id *acc_id)
{
// ID
acc_cfg.id.ptr = (char*) pj_pool_alloc(/*app_config.*/pool, PJSIP_MAX_URL_SIZE);
if (contactname && strlen(contactname))
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"\"%s\"<sip:%s#%s>", contactname, uname, server);
else
acc_cfg.id.slen = pj_ansi_snprintf(acc_cfg.id.ptr, PJSIP_MAX_URL_SIZE,
"sip:%s#%s", uname, server);
if ((status = pjsua_verify_sip_url(acc_cfg.id.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in local id argument",
acc_cfg.id));
[app displayParameterError: #"Invalid value for username or server."];
return status;
}
// Registrar
acc_cfg.reg_uri.ptr = (char*) pj_pool_alloc(/*app_config.*/pool,
PJSIP_MAX_URL_SIZE);
acc_cfg.reg_uri.slen = pj_ansi_snprintf(acc_cfg.reg_uri.ptr,
PJSIP_MAX_URL_SIZE, "sip:%s", server);
if ((status = pjsua_verify_sip_url(acc_cfg.reg_uri.ptr)) != 0)
{
PJ_LOG(1,(THIS_FILE, "Error: invalid SIP URL '%s' in registrar argument",
acc_cfg.reg_uri));
[app displayParameterError: #"Invalid value for server parameter."];
return status;
}
...
more code here
...
}
This is where your account gets registered to a SIP server.
Make sure the sip_connect function gets called from the main application itself shown below:
/* */
- (BOOL)sipConnect
{
pj_status_t status;
if (![self sipStartup])
return FALSE;
//if ([self wakeUpNetwork] == NO)
// return NO;
NSLog(#"%i", _sip_acc_id);
//if (_sip_acc_id == PJSUA_INVALID_ID)
//{
self.networkActivityIndicatorVisible = YES;
if ((status = sip_connect(_app_config.pool, &_sip_acc_id)) != PJ_SUCCESS)
{
self.networkActivityIndicatorVisible = NO;
return FALSE;
}
//}
return TRUE;
}
in my case _sip_acc_id wasn't equal to PJSUA_INVALID_ID therefore sip_connect was never getting called.
Thanks for all of those who tried to solve it in their head? :)
You are unlikely to get any useful help unless you post a code snippet as well as error output (at minimum). More context, such as configuration info and relevant aspects of your network, will further improve your chances.
(I would have added this as a comment on the question, but don't yet have the required reputation.)
The issue I have is that after users tap on the "Share" button of the FBDialog, they do not get any visual feedback until the request completes or fail... and over 3G that can takes a while. During this time users do not know if they tapped "Share" correctly or not, and there's risk of posting content twice.
Is there a way I can get a callback so I can display a loading indicator during this time? Where should I put this piece in?
Thank you!
Below code you write to fbAgent.m and also obser code here u get one "PID" at that time u write to alert msg ....... user can understand to that msg was success posted Facebook.
I hope this helps.
- (void)request:(FBRequest*)request didLoad:(id)result {
if ([request.method isEqualToString:#"facebook.fql.query"]) {
NSArray* users = result;
NSDictionary* user = [users objectAtIndex:0];
NSString* name = [user objectForKey:#"name"];
// Calling the delegate callback
[delegate facebookAgent:self didLoadName:name];
} else if ([request.method isEqualToString:#"facebook.users.setStatus"]) {
newStatus = nil;
NSString* success = result;
if ([success isEqualToString:#"1"]) {
// Calling the delegate callback
[delegate facebookAgent:self statusChanged:YES];
} else {
[delegate facebookAgent:self statusChanged:NO];
}
} else if ([request.method isEqualToString:#"facebook.photos.upload"]) {
NSDictionary* photoInfo = result;
NSString* pid = [photoInfo objectForKey:#"pid"];
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:nil message:[NSString stringWithFormat:#"success Uploaded Your image please check your FaceBook", pid] delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alertView show];
[alertView release];
fbbut.enabled=YES;
[fbact stopAnimating];
self.uploadImageData = nil;
self.uploadImageCaption = nil;
self.uploadImageAlbum = nil;
//[delegate facebookAgent:self photoUploaded:pid];
if(newStatus){
[self setStatus:newStatus];
}
}
}
Start your indicator when you click on button and stop on Delegate of Facebook function
- (void)dialogDidComplete:(FBDialog *)dialog
Hope it helps....