diff --git a/.gitignore b/.gitignore index 27f53cc..365d4a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .repl_history build +examples/FacebookGraph/build +examples/FacebookGraph/vendor \ No newline at end of file diff --git a/examples/FacebookGraph/README.md b/examples/FacebookGraph/README.md new file mode 100644 index 0000000..9008f2a --- /dev/null +++ b/examples/FacebookGraph/README.md @@ -0,0 +1,32 @@ +# Facebook Graph Example + +The Facebook Graph API is a great example of how powerful RemoteModel is. Facebook auth code adapted from [facebook-auth-ruby-motion-example](https://github.com/aaronfeng/facebook-auth-ruby-motion-example) + +## Running + +You need [motion-cocoapods](https://github.com/HipByte/motion-cocoapods) installed to load the Facebook iOS SDK. + +It also appears that (as of May 9 2011), motion-cocoapods doesn't play nice with the FB SDK and you need to use `rake --trace` to get it to load correctly. + +You need to specify an FB app ID, which you can create [in FB's Developer app](https://www.facebook.com/developers): + +###### app_delegate.rby + +```ruby +def application(application, didFinishLaunchingWithOptions:launchOptions) + ... + @facebook = Facebook.alloc.initWithAppId("YOUR-APP-ID", andDelegate:self) + ... +end +``` + +###### Rakefile + +```ruby +Motion::Project::App.setup do |app| + ... + fb_app_id = "YOUR-APP-ID" + app.info_plist['CFBundleURLTypes'] = [{'CFBundleURLSchemes' => ["fb#{fb_app_id}"]}] + ... +end +``` \ No newline at end of file diff --git a/examples/FacebookGraph/Rakefile b/examples/FacebookGraph/Rakefile index ae3235b..e446ef8 100644 --- a/examples/FacebookGraph/Rakefile +++ b/examples/FacebookGraph/Rakefile @@ -1,5 +1,6 @@ $:.unshift("/Library/RubyMotion/lib") require 'motion/project' +require 'motion-cocoapods' Motion::Project::App.setup do |app| # Use `rake config' to see complete project settings. @@ -7,4 +8,14 @@ Motion::Project::App.setup do |app| app.files = Dir.glob(File.join(app.project_dir, '../../vendor/BubbleWrap/lib/**/*.rb')) + Dir.glob(File.join(app.project_dir, '../../lib/**/*.rb')) + app.files -end + app.files_dependencies 'app/controllers/facebook_login_controller.rb' => 'app/initializers/remote_model.rb' + fb_app_id = "YOUR-APP-ID" + if fb_app_id == "YOUR-APP-ID" + raise "You need to specify a Facebook App ID in ./Rakefile" + end + app.info_plist['CFBundleURLTypes'] = [{'CFBundleURLSchemes' => ["fb#{fb_app_id}"]}] + + app.pods do + dependency 'Facebook-iOS-SDK' + end +end \ No newline at end of file diff --git a/examples/FacebookGraph/app/app_delegate.rb b/examples/FacebookGraph/app/app_delegate.rb index 43b2aa9..d34562b 100644 --- a/examples/FacebookGraph/app/app_delegate.rb +++ b/examples/FacebookGraph/app/app_delegate.rb @@ -1,5 +1,49 @@ class AppDelegate + attr_accessor :facebook + attr_accessor :navigationController + def application(application, didFinishLaunchingWithOptions:launchOptions) + @window = UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds) + @navigationController = UINavigationController.alloc.init + @window.rootViewController = @navigationController + + fb_app_id = "YOUR-APP-ID" + if fb_app_id == "YOUR-APP-ID" + raise "You need to specify a Facebook App ID in ./app/app_delegate.rb" + end + @facebook = Facebook.alloc.initWithAppId(fb_app_id, andDelegate:self) + + defaults = NSUserDefaults.standardUserDefaults + + if defaults["FBAccessTokenKey"] && defaults["FBExpirationDateKey"] + @facebook.accessToken = defaults["FBAccessTokenKey"] + @facebook.expirationDate = defaults["FBExpirationDateKey"] + openFriendsContorller + else + @navigationController.pushViewController(FacebookLoginController.alloc.init, animated: false) + end + + @window.rootViewController.wantsFullScreenLayout = true + @window.makeKeyAndVisible true end + + def openFriendsContorller + @navigationController.setViewControllers([FriendsController.alloc.initWithUserId], animated: false) + end + + def fbDidLogin + defaults = NSUserDefaults.standardUserDefaults + defaults["FBAccessTokenKey"] = @facebook.accessToken + defaults["FBExpirationDateKey"] = @facebook.expirationDate + defaults.synchronize + openFriendsContorller + end + + def application(application, + openURL:url, + sourceApplication:sourceApplication, + annotation:annotation) + @facebook.handleOpenURL(url) + end end diff --git a/examples/FacebookGraph/app/controllers/facebook_login_controller.rb b/examples/FacebookGraph/app/controllers/facebook_login_controller.rb new file mode 100644 index 0000000..05bbbda --- /dev/null +++ b/examples/FacebookGraph/app/controllers/facebook_login_controller.rb @@ -0,0 +1,21 @@ +class FacebookLoginController < UIViewController + def viewDidLoad + self.title = "Login" + self.view.backgroundColor = UIColor.whiteColor + + button = UIButton.buttonWithType UIButtonTypeRoundedRect + button.when(UIControlEventTouchUpInside) do + UIApplication.sharedApplication.delegate.facebook.authorize nil + end + button.setTitle("FB Login", forState: UIControlStateNormal) + button.sizeToFit + + # ugly, dont really do this. + width, height = button.frame.size.width, button.frame.size.height + button.frame = CGRectMake(((self.view.frame.size.width - width) / 2).round, + ((self.view.frame.size.height - height) / 2).round, + width, + height) + self.view.addSubview button + end +end \ No newline at end of file diff --git a/examples/FacebookGraph/app/controllers/friends_controller.rb b/examples/FacebookGraph/app/controllers/friends_controller.rb new file mode 100644 index 0000000..b8bd5ce --- /dev/null +++ b/examples/FacebookGraph/app/controllers/friends_controller.rb @@ -0,0 +1,60 @@ +class FriendsController < UITableViewController + attr_reader :user + + def initWithUserId(id = "me") + @user = User.new(id: id) + self + end + + def initWithUser(user) + raise "User cannot be nil" if user.nil? + @user = user + self + end + + def viewDidLoad + super + self.title = @user.name ? "Friends of #{@user.name}" : "Friends of #{@user.id}" + + defaults = NSUserDefaults.standardUserDefaults + RemoteModule::RemoteModel.set_access_token(defaults["FBAccessTokenKey"]) + + @activity = UIActivityIndicatorView.alloc.initWithActivityIndicatorStyle(UIActivityIndicatorViewStyleGray) + self.view.addSubview @activity + @activity.center = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2) + @activity.startAnimating + + @user.find_friends do |user| + @activity.stopAnimating + @activity.removeFromSuperview + self.tableView.reloadData + end + end + + def tableView(tableView, numberOfRowsInSection:section) + return @user.friends.count + end + + def tableView(tableView, cellForRowAtIndexPath:indexPath) + reuseIdentifier = "FriendCell" + + cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) || begin + cell = UITableViewCell.alloc.initWithStyle(UITableViewCellStyleSubtitle, reuseIdentifier:reuseIdentifier) + cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton + cell + end + + friend = @user.friends[indexPath.row] + cell.textLabel.text = friend.name + cell.detailTextLabel.text = friend.id + + cell + end + + def tableView(tableView, didSelectRowAtIndexPath:indexPath) + tableView.deselectRowAtIndexPath(indexPath, animated:true) + friend = @user.friends[indexPath.row] + + UIApplication.sharedApplication.delegate.navigationController.pushViewController(FriendsController.alloc.initWithUser(friend), animated: true) + end +end \ No newline at end of file diff --git a/examples/FacebookGraph/app/initializers/remote_model.rb b/examples/FacebookGraph/app/initializers/remote_model.rb index b9e05d1..8778238 100644 --- a/examples/FacebookGraph/app/initializers/remote_model.rb +++ b/examples/FacebookGraph/app/initializers/remote_model.rb @@ -3,10 +3,12 @@ class RemoteModel self.root_url = "https://graph.facebook.com/" self.extension = "" - self.default_url_options = { + def self.set_access_token(token) + self.default_url_options = { :query => { - "access_token" => "AAAAAAITEghMBAOKs0vDSPuxPZAZBZBUcP1ruJaZC2ZARYKU0j5goBI3ZCZB9K5qgzvIzwwGM1zvDxJlnbOk8Bv6PZAlButKV5cp7NRTbviyWU4cwlCIwjZCdB", + "access_token" => token } } + end end end \ No newline at end of file diff --git a/examples/FacebookGraph/app/models/User.rb b/examples/FacebookGraph/app/models/User.rb index 449a30f..50951af 100644 --- a/examples/FacebookGraph/app/models/User.rb +++ b/examples/FacebookGraph/app/models/User.rb @@ -16,7 +16,14 @@ class User < RemoteModule::RemoteModel # end def find_friends(&block) get(self.friends_url) do |response, json| - self.friends = json[:data] + self.friends = (json && json[:data]) || [] + if json.nil? + alert = UIAlertView.new + alert.title = "Friends not given" + alert.message = "Denied privacy permissions." + alert.addButtonWithTitle "OK" + alert.show + end if block block.call self end diff --git a/examples/FacebookGraph/app/models/WallPost.rb b/examples/FacebookGraph/app/models/WallPost.rb index 1c52f9d..358d5be 100644 --- a/examples/FacebookGraph/app/models/WallPost.rb +++ b/examples/FacebookGraph/app/models/WallPost.rb @@ -1,6 +1,8 @@ class WallPost < RemoteModule::RemoteModel attr_accessor :id, :message + # if we encounter "from" in the JSON return, + # use the User class. has_one :from => :user collection_url "" diff --git a/vendor/BubbleWrap b/vendor/BubbleWrap index d2f1002..ef429db 160000 --- a/vendor/BubbleWrap +++ b/vendor/BubbleWrap @@ -1 +1 @@ -Subproject commit d2f1002340304cfcc3b287116c7b69eeefc5fbdc +Subproject commit ef429db21e5b90e8fedef75e3453717ef254d402