This repository was archived by the owner on May 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathTWViewController.m
More file actions
218 lines (187 loc) · 8.27 KB
/
TWViewController.m
File metadata and controls
218 lines (187 loc) · 8.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
//
// TWViewController.m
// TWiOSReverseAuthExample
//
// Copyright (c) 2013 Sean Cook
//
// 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 <Accounts/Accounts.h>
#import <Twitter/Twitter.h>
#import "OAuth+Additions.h"
#import "TWAPIManager.h"
#import "TWSignedRequest.h"
#import "TWViewController.h"
#define ERROR_TITLE_MSG @"Whoa, there cowboy"
#define ERROR_PERM_ACCESS @"We weren't granted access to the user's accounts"
#define ERROR_NO_KEYS @"You need to add your Twitter app keys to Info.plist to use this demo.\nPlease see README.md for more info."
#define ERROR_OK @"OK"
@interface TWViewController()
@property (nonatomic, strong) ACAccountStore *accountStore;
@property (nonatomic, strong) TWAPIManager *apiManager;
@property (nonatomic, strong) NSArray *accounts;
@property (nonatomic, strong) UIButton *reverseAuthBtn;
@end
@implementation TWViewController
#pragma mark - UIViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
_accountStore = [[ACAccountStore alloc] init];
_apiManager = [[TWAPIManager alloc] init];
}
return self;
}
- (void)loadView
{
CGRect appFrame = [UIScreen mainScreen].applicationFrame;
CGRect buttonFrame = appFrame;
buttonFrame.origin.y = floorf(0.75f * appFrame.size.height);
buttonFrame.size.height = 44.0f;
buttonFrame = CGRectInset(buttonFrame, 20, 0);
UIView *view = [[UIView alloc] initWithFrame:appFrame];
[view setBackgroundColor:[UIColor colorWithWhite:0.502 alpha:1.000]];
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"twitter.png"]];
[view addSubview:imageView];
[imageView sizeToFit];
imageView.center = view.center;
CGRect imageFrame = imageView.frame;
imageFrame.origin.y = floorf(0.25f * appFrame.size.height);
imageView.frame = imageFrame;
_reverseAuthBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_reverseAuthBtn setTitle:@"Perform Token Exchange" forState:UIControlStateNormal];
[_reverseAuthBtn addTarget:self action:@selector(performReverseAuth:) forControlEvents:UIControlEventTouchUpInside];
_reverseAuthBtn.frame = buttonFrame;
_reverseAuthBtn.enabled = NO;
[_reverseAuthBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[view addSubview:_reverseAuthBtn];
self.view = view;
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self refreshTwitterAccounts];
}
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshTwitterAccounts) name:ACAccountStoreDidChangeNotification object:nil];
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - UIActionSheetDelegate
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex != actionSheet.cancelButtonIndex) {
[_apiManager performReverseAuthForAccount:_accounts[buttonIndex] withHandler:^(NSData *responseData, NSError *error) {
if (responseData) {
NSString *responseStr = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
TWDLog(@"Reverse Auth process returned: %@", responseStr);
NSArray *parts = [responseStr componentsSeparatedByString:@"&"];
NSString *lined = [parts componentsJoinedByString:@"\n"];
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Success!" message:lined delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
});
}
else {
TWALog(@"Reverse Auth process failed. Error returned was: %@\n", [error localizedDescription]);
}
}];
}
}
#pragma mark - Private
/**
* Checks for the current Twitter configuration on the device / simulator.
*
* First, we check to make sure that we've got keys to work with inside Info.plist (see README)
*
* Then we check to see if the device has accounts available via +[TWAPIManager isLocalTwitterAccountAvailable].
*
* Next, we ask the user for permission to access his/her accounts.
*
* Upon completion, the button to continue will be displayed, or the user will be presented with a status message.
*/
- (void)refreshTwitterAccounts
{
TWDLog(@"Refreshing Twitter Accounts \n");
if (![TWAPIManager hasAppKeys]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ERROR_TITLE_MSG message:ERROR_NO_KEYS delegate:nil cancelButtonTitle:ERROR_OK otherButtonTitles:nil];
[alert show];
}
else if (![TWAPIManager isLocalTwitterAccountAvailable]) {
TWTweetComposeViewController *tweetView = [[TWTweetComposeViewController alloc] init];
tweetView.view.hidden = YES;
tweetView.completionHandler = ^(TWTweetComposeViewControllerResult result) {
[self dismissModalViewControllerAnimated:NO];
};
[self presentModalViewController:tweetView animated:NO];
[tweetView.view endEditing:YES];
}
else {
[self obtainAccessToAccountsWithBlock:^(BOOL granted) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
_reverseAuthBtn.enabled = YES;
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ERROR_TITLE_MSG message:ERROR_PERM_ACCESS delegate:nil cancelButtonTitle:ERROR_OK otherButtonTitles:nil];
[alert show];
TWALog(@"You were not granted access to the Twitter accounts.");
}
});
}];
}
}
- (void)obtainAccessToAccountsWithBlock:(void (^)(BOOL))block
{
ACAccountType *twitterType = [_accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
ACAccountStoreRequestAccessCompletionHandler handler = ^(BOOL granted, NSError *error) {
if (granted) {
self.accounts = [_accountStore accountsWithAccountType:twitterType];
}
block(granted);
};
// This method changed in iOS6. If the new version isn't available, fall back to the original (which means that we're running on iOS5+).
if ([_accountStore respondsToSelector:@selector(requestAccessToAccountsWithType:options:completion:)]) {
[_accountStore requestAccessToAccountsWithType:twitterType options:nil completion:handler];
}
else {
[_accountStore requestAccessToAccountsWithType:twitterType withCompletionHandler:handler];
}
}
/**
* Handles the button press that initiates the token exchange.
*
* We check the current configuration inside -[UIViewController viewDidAppear].
*/
- (void)performReverseAuth:(id)sender
{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Choose an Account" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
for (ACAccount *acct in _accounts) {
[sheet addButtonWithTitle:acct.username];
}
sheet.cancelButtonIndex = [sheet addButtonWithTitle:@"Cancel"];
[sheet showInView:self.view];
}
@end