Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

import the project

  • Loading branch information...
commit ae387a46cdf1f5d46089e3238452f9df36d555e6 1 parent f2125aa
@ntaku authored
Showing with 5,594 additions and 1 deletion.
  1. +416 −0 ASFBPost.xcodeproj/project.pbxproj
  2. +49 −0 ASFBPost/ASFBPost-Info.plist
  3. +30 −0 ASFBPost/ASFBPost-Prefix.pch
  4. +13 −0 ASFBPost/ASFBPostController.h
  5. +430 −0 ASFBPost/ASFBPostController.m
  6. +14 −0 ASFBPost/AppDelegate.h
  7. +60 −0 ASFBPost/AppDelegate.m
  8. +10 −0 ASFBPost/MainController.h
  9. +42 −0 ASFBPost/MainController.m
  10. +14 −0 ASFBPost/main.m
  11. +25 −1 README.md
  12. +9 −0 Resources/en.lproj/Localizable.strings
  13. +9 −0 Resources/ja.lproj/Localizable.strings
  14. BIN  Resources/sample.jpg
  15. BIN  Resources/sample_thumb.jpg
  16. +12 −0 Vendor/AppStair/ASColor+Hex.h
  17. +21 −0 Vendor/AppStair/ASColor+Hex.m
  18. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginNormal.png
  19. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginNormal@2x.png
  20. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginPressed.png
  21. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginPressed@2x.png
  22. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookNormal.png
  23. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookNormal@2x.png
  24. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookPressed.png
  25. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookPressed@2x.png
  26. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutNormal.png
  27. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutNormal@2x.png
  28. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutPressed.png
  29. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutPressed@2x.png
  30. BIN  Vendor/FacebookSDK/FBConnect.bundle/images/runaround_image.jpg
  31. +22 −0 Vendor/FacebookSDK/FBConnect.h
  32. BIN  Vendor/FacebookSDK/FBDialog.bundle/images/close.png
  33. BIN  Vendor/FacebookSDK/FBDialog.bundle/images/close@2x.png
  34. BIN  Vendor/FacebookSDK/FBDialog.bundle/images/fbicon.png
  35. +165 −0 Vendor/FacebookSDK/FBDialog.h
  36. +688 −0 Vendor/FacebookSDK/FBDialog.m
  37. +74 −0 Vendor/FacebookSDK/FBFrictionlessRequestSettings.h
  38. +162 −0 Vendor/FacebookSDK/FBFrictionlessRequestSettings.m
  39. +48 −0 Vendor/FacebookSDK/FBLoginDialog.h
  40. +94 −0 Vendor/FacebookSDK/FBLoginDialog.m
  41. +142 −0 Vendor/FacebookSDK/FBRequest.h
  42. +381 −0 Vendor/FacebookSDK/FBRequest.m
  43. +153 −0 Vendor/FacebookSDK/Facebook.h
  44. +848 −0 Vendor/FacebookSDK/Facebook.m
  45. +50 −0 Vendor/FacebookSDK/JSON/JSON.h
  46. +68 −0 Vendor/FacebookSDK/JSON/NSObject+SBJSON.h
  47. +53 −0 Vendor/FacebookSDK/JSON/NSObject+SBJSON.m
  48. +58 −0 Vendor/FacebookSDK/JSON/NSString+SBJSON.h
  49. +55 −0 Vendor/FacebookSDK/JSON/NSString+SBJSON.m
  50. +75 −0 Vendor/FacebookSDK/JSON/SBJSON.h
  51. +212 −0 Vendor/FacebookSDK/JSON/SBJSON.m
  52. +86 −0 Vendor/FacebookSDK/JSON/SBJsonBase.h
  53. +78 −0 Vendor/FacebookSDK/JSON/SBJsonBase.m
  54. +87 −0 Vendor/FacebookSDK/JSON/SBJsonParser.h
  55. +475 −0 Vendor/FacebookSDK/JSON/SBJsonParser.m
  56. +129 −0 Vendor/FacebookSDK/JSON/SBJsonWriter.h
  57. +237 −0 Vendor/FacebookSDK/JSON/SBJsonWriter.m
View
416 ASFBPost.xcodeproj/project.pbxproj
@@ -0,0 +1,416 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 2B91CEEE15A1E220007993FD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B91CEED15A1E220007993FD /* UIKit.framework */; };
+ 2B91CEF015A1E220007993FD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B91CEEF15A1E220007993FD /* Foundation.framework */; };
+ 2B91CEF215A1E220007993FD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2B91CEF115A1E220007993FD /* CoreGraphics.framework */; };
+ 2B91CEFA15A1E220007993FD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91CEF915A1E220007993FD /* main.m */; };
+ 2B91CEFE15A1E220007993FD /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91CEFD15A1E220007993FD /* AppDelegate.m */; };
+ 2B91CF2515A1E2EB007993FD /* MainController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91CF2415A1E2EB007993FD /* MainController.m */; };
+ 2B91CF6115A1F064007993FD /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 2B91CF6315A1F064007993FD /* Localizable.strings */; };
+ 2B91CFDA15A1F291007993FD /* ASColor+Hex.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91CFAD15A1F291007993FD /* ASColor+Hex.m */; };
+ 2B91CFF215A29127007993FD /* sample_thumb.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2B91CFF015A29127007993FD /* sample_thumb.jpg */; };
+ 2B91CFF315A29127007993FD /* sample.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 2B91CFF115A29127007993FD /* sample.jpg */; };
+ 2B91CFFA15A29562007993FD /* ASFBPostController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91CFF915A29561007993FD /* ASFBPostController.m */; };
+ 2B91D01D15A29924007993FD /* Facebook.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D00315A29924007993FD /* Facebook.m */; };
+ 2B91D01E15A29924007993FD /* FBConnect.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2B91D00415A29924007993FD /* FBConnect.bundle */; };
+ 2B91D01F15A29924007993FD /* FBDialog.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 2B91D00615A29924007993FD /* FBDialog.bundle */; };
+ 2B91D02015A29924007993FD /* FBDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D00815A29924007993FD /* FBDialog.m */; };
+ 2B91D02115A29924007993FD /* FBFrictionlessRequestSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D00A15A29924007993FD /* FBFrictionlessRequestSettings.m */; };
+ 2B91D02215A29924007993FD /* FBLoginDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D00C15A29924007993FD /* FBLoginDialog.m */; };
+ 2B91D02315A29924007993FD /* FBRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D00E15A29924007993FD /* FBRequest.m */; };
+ 2B91D02415A29924007993FD /* NSObject+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01215A29924007993FD /* NSObject+SBJSON.m */; };
+ 2B91D02515A29924007993FD /* NSString+SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01415A29924007993FD /* NSString+SBJSON.m */; };
+ 2B91D02615A29924007993FD /* SBJSON.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01615A29924007993FD /* SBJSON.m */; };
+ 2B91D02715A29924007993FD /* SBJsonBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01815A29924007993FD /* SBJsonBase.m */; };
+ 2B91D02815A29924007993FD /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01A15A29924007993FD /* SBJsonParser.m */; };
+ 2B91D02915A29924007993FD /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 2B91D01C15A29924007993FD /* SBJsonWriter.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 2B91CEE915A1E220007993FD /* ASFBPost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ASFBPost.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 2B91CEED15A1E220007993FD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ 2B91CEEF15A1E220007993FD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ 2B91CEF115A1E220007993FD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
+ 2B91CEF515A1E220007993FD /* ASFBPost-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "ASFBPost-Info.plist"; path = "ASFBPost/ASFBPost-Info.plist"; sourceTree = "<group>"; };
+ 2B91CEF915A1E220007993FD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 2B91CEFB15A1E220007993FD /* ASFBPost-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASFBPost-Prefix.pch"; sourceTree = "<group>"; };
+ 2B91CEFC15A1E220007993FD /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+ 2B91CEFD15A1E220007993FD /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+ 2B91CF2315A1E2EB007993FD /* MainController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainController.h; sourceTree = "<group>"; };
+ 2B91CF2415A1E2EB007993FD /* MainController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainController.m; sourceTree = "<group>"; };
+ 2B91CF6215A1F064007993FD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 2B91CF6415A1F070007993FD /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
+ 2B91CFAC15A1F291007993FD /* ASColor+Hex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASColor+Hex.h"; sourceTree = "<group>"; };
+ 2B91CFAD15A1F291007993FD /* ASColor+Hex.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ASColor+Hex.m"; sourceTree = "<group>"; };
+ 2B91CFF015A29127007993FD /* sample_thumb.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = sample_thumb.jpg; path = Resources/sample_thumb.jpg; sourceTree = "<group>"; };
+ 2B91CFF115A29127007993FD /* sample.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = sample.jpg; path = Resources/sample.jpg; sourceTree = "<group>"; };
+ 2B91CFF815A29561007993FD /* ASFBPostController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASFBPostController.h; sourceTree = "<group>"; };
+ 2B91CFF915A29561007993FD /* ASFBPostController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASFBPostController.m; sourceTree = "<group>"; };
+ 2B91D00215A29924007993FD /* Facebook.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Facebook.h; sourceTree = "<group>"; };
+ 2B91D00315A29924007993FD /* Facebook.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Facebook.m; sourceTree = "<group>"; };
+ 2B91D00415A29924007993FD /* FBConnect.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBConnect.bundle; sourceTree = "<group>"; };
+ 2B91D00515A29924007993FD /* FBConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBConnect.h; sourceTree = "<group>"; };
+ 2B91D00615A29924007993FD /* FBDialog.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = FBDialog.bundle; sourceTree = "<group>"; };
+ 2B91D00715A29924007993FD /* FBDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBDialog.h; sourceTree = "<group>"; };
+ 2B91D00815A29924007993FD /* FBDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBDialog.m; sourceTree = "<group>"; };
+ 2B91D00915A29924007993FD /* FBFrictionlessRequestSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBFrictionlessRequestSettings.h; sourceTree = "<group>"; };
+ 2B91D00A15A29924007993FD /* FBFrictionlessRequestSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBFrictionlessRequestSettings.m; sourceTree = "<group>"; };
+ 2B91D00B15A29924007993FD /* FBLoginDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBLoginDialog.h; sourceTree = "<group>"; };
+ 2B91D00C15A29924007993FD /* FBLoginDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBLoginDialog.m; sourceTree = "<group>"; };
+ 2B91D00D15A29924007993FD /* FBRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBRequest.h; sourceTree = "<group>"; };
+ 2B91D00E15A29924007993FD /* FBRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBRequest.m; sourceTree = "<group>"; };
+ 2B91D01015A29924007993FD /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = "<group>"; };
+ 2B91D01115A29924007993FD /* NSObject+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+SBJSON.h"; sourceTree = "<group>"; };
+ 2B91D01215A29924007993FD /* NSObject+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+SBJSON.m"; sourceTree = "<group>"; };
+ 2B91D01315A29924007993FD /* NSString+SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSString+SBJSON.h"; sourceTree = "<group>"; };
+ 2B91D01415A29924007993FD /* NSString+SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSString+SBJSON.m"; sourceTree = "<group>"; };
+ 2B91D01515A29924007993FD /* SBJSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJSON.h; sourceTree = "<group>"; };
+ 2B91D01615A29924007993FD /* SBJSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJSON.m; sourceTree = "<group>"; };
+ 2B91D01715A29924007993FD /* SBJsonBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonBase.h; sourceTree = "<group>"; };
+ 2B91D01815A29924007993FD /* SBJsonBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonBase.m; sourceTree = "<group>"; };
+ 2B91D01915A29924007993FD /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = "<group>"; };
+ 2B91D01A15A29924007993FD /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = "<group>"; };
+ 2B91D01B15A29924007993FD /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = "<group>"; };
+ 2B91D01C15A29924007993FD /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 2B91CEE615A1E220007993FD /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2B91CEEE15A1E220007993FD /* UIKit.framework in Frameworks */,
+ 2B91CEF015A1E220007993FD /* Foundation.framework in Frameworks */,
+ 2B91CEF215A1E220007993FD /* CoreGraphics.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 2B91CEDE15A1E220007993FD = {
+ isa = PBXGroup;
+ children = (
+ 2B91CEF315A1E220007993FD /* App */,
+ 2B91CFAA15A1F291007993FD /* Vendor */,
+ 2B91CF0D15A1E27D007993FD /* Resources */,
+ 2B91CEEC15A1E220007993FD /* Frameworks */,
+ 2B91CEEA15A1E220007993FD /* Products */,
+ );
+ sourceTree = "<group>";
+ };
+ 2B91CEEA15A1E220007993FD /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CEE915A1E220007993FD /* ASFBPost.app */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 2B91CEEC15A1E220007993FD /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CEED15A1E220007993FD /* UIKit.framework */,
+ 2B91CEEF15A1E220007993FD /* Foundation.framework */,
+ 2B91CEF115A1E220007993FD /* CoreGraphics.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 2B91CEF315A1E220007993FD /* App */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CFFB15A2956A007993FD /* supporting files */,
+ 2B91CFF815A29561007993FD /* ASFBPostController.h */,
+ 2B91CFF915A29561007993FD /* ASFBPostController.m */,
+ );
+ name = App;
+ path = ASFBPost;
+ sourceTree = "<group>";
+ };
+ 2B91CF0D15A1E27D007993FD /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CFF015A29127007993FD /* sample_thumb.jpg */,
+ 2B91CFF115A29127007993FD /* sample.jpg */,
+ 2B91CF6315A1F064007993FD /* Localizable.strings */,
+ 2B91CEF515A1E220007993FD /* ASFBPost-Info.plist */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 2B91CFAA15A1F291007993FD /* Vendor */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91D00115A29924007993FD /* FacebookSDK */,
+ 2B91CFAB15A1F291007993FD /* AppStair */,
+ );
+ path = Vendor;
+ sourceTree = "<group>";
+ };
+ 2B91CFAB15A1F291007993FD /* AppStair */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CFAC15A1F291007993FD /* ASColor+Hex.h */,
+ 2B91CFAD15A1F291007993FD /* ASColor+Hex.m */,
+ );
+ path = AppStair;
+ sourceTree = "<group>";
+ };
+ 2B91CFFB15A2956A007993FD /* supporting files */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91CEFB15A1E220007993FD /* ASFBPost-Prefix.pch */,
+ 2B91CEF915A1E220007993FD /* main.m */,
+ 2B91CEFC15A1E220007993FD /* AppDelegate.h */,
+ 2B91CEFD15A1E220007993FD /* AppDelegate.m */,
+ 2B91CF2315A1E2EB007993FD /* MainController.h */,
+ 2B91CF2415A1E2EB007993FD /* MainController.m */,
+ );
+ name = "supporting files";
+ sourceTree = "<group>";
+ };
+ 2B91D00115A29924007993FD /* FacebookSDK */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91D00215A29924007993FD /* Facebook.h */,
+ 2B91D00315A29924007993FD /* Facebook.m */,
+ 2B91D00415A29924007993FD /* FBConnect.bundle */,
+ 2B91D00515A29924007993FD /* FBConnect.h */,
+ 2B91D00615A29924007993FD /* FBDialog.bundle */,
+ 2B91D00715A29924007993FD /* FBDialog.h */,
+ 2B91D00815A29924007993FD /* FBDialog.m */,
+ 2B91D00915A29924007993FD /* FBFrictionlessRequestSettings.h */,
+ 2B91D00A15A29924007993FD /* FBFrictionlessRequestSettings.m */,
+ 2B91D00B15A29924007993FD /* FBLoginDialog.h */,
+ 2B91D00C15A29924007993FD /* FBLoginDialog.m */,
+ 2B91D00D15A29924007993FD /* FBRequest.h */,
+ 2B91D00E15A29924007993FD /* FBRequest.m */,
+ 2B91D00F15A29924007993FD /* JSON */,
+ );
+ path = FacebookSDK;
+ sourceTree = "<group>";
+ };
+ 2B91D00F15A29924007993FD /* JSON */ = {
+ isa = PBXGroup;
+ children = (
+ 2B91D01015A29924007993FD /* JSON.h */,
+ 2B91D01115A29924007993FD /* NSObject+SBJSON.h */,
+ 2B91D01215A29924007993FD /* NSObject+SBJSON.m */,
+ 2B91D01315A29924007993FD /* NSString+SBJSON.h */,
+ 2B91D01415A29924007993FD /* NSString+SBJSON.m */,
+ 2B91D01515A29924007993FD /* SBJSON.h */,
+ 2B91D01615A29924007993FD /* SBJSON.m */,
+ 2B91D01715A29924007993FD /* SBJsonBase.h */,
+ 2B91D01815A29924007993FD /* SBJsonBase.m */,
+ 2B91D01915A29924007993FD /* SBJsonParser.h */,
+ 2B91D01A15A29924007993FD /* SBJsonParser.m */,
+ 2B91D01B15A29924007993FD /* SBJsonWriter.h */,
+ 2B91D01C15A29924007993FD /* SBJsonWriter.m */,
+ );
+ path = JSON;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 2B91CEE815A1E220007993FD /* ASFBPost */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 2B91CF0115A1E220007993FD /* Build configuration list for PBXNativeTarget "ASFBPost" */;
+ buildPhases = (
+ 2B91CEE515A1E220007993FD /* Sources */,
+ 2B91CEE615A1E220007993FD /* Frameworks */,
+ 2B91CEE715A1E220007993FD /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = ASFBPost;
+ productName = ASFBPost;
+ productReference = 2B91CEE915A1E220007993FD /* ASFBPost.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 2B91CEE015A1E220007993FD /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0430;
+ ORGANIZATIONNAME = AppStair;
+ };
+ buildConfigurationList = 2B91CEE315A1E220007993FD /* Build configuration list for PBXProject "ASFBPost" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ ja,
+ );
+ mainGroup = 2B91CEDE15A1E220007993FD;
+ productRefGroup = 2B91CEEA15A1E220007993FD /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 2B91CEE815A1E220007993FD /* ASFBPost */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 2B91CEE715A1E220007993FD /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2B91CF6115A1F064007993FD /* Localizable.strings in Resources */,
+ 2B91CFF215A29127007993FD /* sample_thumb.jpg in Resources */,
+ 2B91CFF315A29127007993FD /* sample.jpg in Resources */,
+ 2B91D01E15A29924007993FD /* FBConnect.bundle in Resources */,
+ 2B91D01F15A29924007993FD /* FBDialog.bundle in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 2B91CEE515A1E220007993FD /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2B91CEFA15A1E220007993FD /* main.m in Sources */,
+ 2B91CEFE15A1E220007993FD /* AppDelegate.m in Sources */,
+ 2B91CF2515A1E2EB007993FD /* MainController.m in Sources */,
+ 2B91CFDA15A1F291007993FD /* ASColor+Hex.m in Sources */,
+ 2B91CFFA15A29562007993FD /* ASFBPostController.m in Sources */,
+ 2B91D01D15A29924007993FD /* Facebook.m in Sources */,
+ 2B91D02015A29924007993FD /* FBDialog.m in Sources */,
+ 2B91D02115A29924007993FD /* FBFrictionlessRequestSettings.m in Sources */,
+ 2B91D02215A29924007993FD /* FBLoginDialog.m in Sources */,
+ 2B91D02315A29924007993FD /* FBRequest.m in Sources */,
+ 2B91D02415A29924007993FD /* NSObject+SBJSON.m in Sources */,
+ 2B91D02515A29924007993FD /* NSString+SBJSON.m in Sources */,
+ 2B91D02615A29924007993FD /* SBJSON.m in Sources */,
+ 2B91D02715A29924007993FD /* SBJsonBase.m in Sources */,
+ 2B91D02815A29924007993FD /* SBJsonParser.m in Sources */,
+ 2B91D02915A29924007993FD /* SBJsonWriter.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+ 2B91CF6315A1F064007993FD /* Localizable.strings */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 2B91CF6215A1F064007993FD /* en */,
+ 2B91CF6415A1F070007993FD /* ja */,
+ );
+ name = Localizable.strings;
+ path = Resources;
+ sourceTree = "<group>";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 2B91CEFF15A1E220007993FD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ SDKROOT = iphoneos;
+ };
+ name = Debug;
+ };
+ 2B91CF0015A1E220007993FD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ARCHS = "$(ARCHS_STANDARD_32_BIT)";
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 2B91CF0215A1E220007993FD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "ASFBPost/ASFBPost-Prefix.pch";
+ INFOPLIST_FILE = "ASFBPost/ASFBPost-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Debug;
+ };
+ 2B91CF0315A1E220007993FD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_PRECOMPILE_PREFIX_HEADER = YES;
+ GCC_PREFIX_HEADER = "ASFBPost/ASFBPost-Prefix.pch";
+ INFOPLIST_FILE = "ASFBPost/ASFBPost-Info.plist";
+ IPHONEOS_DEPLOYMENT_TARGET = 5.1;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TARGETED_DEVICE_FAMILY = "1,2";
+ WRAPPER_EXTENSION = app;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 2B91CEE315A1E220007993FD /* Build configuration list for PBXProject "ASFBPost" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2B91CEFF15A1E220007993FD /* Debug */,
+ 2B91CF0015A1E220007993FD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 2B91CF0115A1E220007993FD /* Build configuration list for PBXNativeTarget "ASFBPost" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 2B91CF0215A1E220007993FD /* Debug */,
+ 2B91CF0315A1E220007993FD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 2B91CEE015A1E220007993FD /* Project object */;
+}
View
49 ASFBPost/ASFBPost-Info.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.appstair.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>fb1234567</string>
+ </array>
+ </dict>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
View
30 ASFBPost/ASFBPost-Prefix.pch
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <UIKit/UIKit.h>
+#import <Foundation/Foundation.h>
+
+
+// Shortcut
+
+#define LOG(...) NSLog(__VA_ARGS__)
+#define UIAppDelegate (AppDelegate *)[[UIApplication sharedApplication] delegate]
+#define IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
+#define LS(name) NSLocalizedString(name, @"")
+#define RELEASE(x) [_ ## x release], _ ## x = nil
+
+
+// Facebook
+
+#define FB_APP_ID @"1234567"
+#define FB_PERMISSIONS @"publish_stream"
+
+
+// UserDefault for Facebook
+
+#define FB_ACCESS_TOKEN @"FBAccessTokenKey"
+#define FB_EXPIRATION_DATE @"FBExpirationDateKey"
+#define FB_LOGINNAME @"FBLoginName"
+
View
13 ASFBPost/ASFBPostController.h
@@ -0,0 +1,13 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <UIKit/UIKit.h>
+
+@interface ASFBPostController : UITableViewController
+
+@property (nonatomic, retain) UIImage *originalImage;
+@property (nonatomic, retain) UIImage *thumbnailImage;
+
+@end
View
430 ASFBPost/ASFBPostController.m
@@ -0,0 +1,430 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import "ASFBPostController.h"
+#import "FBConnect.h"
+#import "AppDelegate.h"
+#import "ASColor+Hex.h"
+
+@interface ASFBPostController () <FBSessionDelegate, FBRequestDelegate>
+
+@property (nonatomic, retain) Facebook *facebook;
+@property (nonatomic, retain) NSString *loginName;
+@property (nonatomic, retain) UITextView *textView;
+@property (nonatomic, retain) UIAlertView *loadingAlert;
+
+- (void)createFbInstance;
+- (void)setViewStyle;
+- (void)loading:(BOOL)isLoading;
+
+@end
+
+
+@implementation ASFBPostController
+
+@synthesize facebook = _facebook;
+@synthesize loginName = _loginName;
+@synthesize textView = _textView;
+@synthesize loadingAlert = _loadingAlert;
+@synthesize originalImage = _originalImage;
+@synthesize thumbnailImage = _thumbnailImage;
+
+
+- (void)viewDidUnload{
+ [super viewDidUnload];
+}
+
+- (void)dealloc{
+ [UIAppDelegate setFacebook:nil];
+
+ RELEASE(facebook);
+ RELEASE(loginName);
+ RELEASE(textView);
+ RELEASE(loadingAlert);
+ RELEASE(thumbnailImage);
+ RELEASE(originalImage);
+ [super dealloc];
+}
+
+- (id)init{
+ if(self = [super initWithStyle:UITableViewStyleGrouped]){
+ self.title = @"Facebook";
+ }
+ return self;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark View LifeCycle
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (void)viewDidLoad{
+ [super viewDidLoad];
+ [self createFbInstance];
+
+ self.tableView.backgroundColor = [UIColor colorWithHex:0xE1E6EF];
+ self.tableView.scrollEnabled = NO;
+
+ // navi buttons
+ UIBarButtonItem *btn;
+ btn = [[UIBarButtonItem alloc]
+ initWithTitle:LS(@"FB_POST")
+ style:UIBarButtonItemStyleBordered
+ target:self
+ action:@selector(actionSave)];
+ self.navigationItem.rightBarButtonItem = btn;
+ [btn release];
+
+ btn = [[UIBarButtonItem alloc]
+ initWithTitle:LS(@"FB_CANCEL")
+ style:UIBarButtonItemStyleBordered
+ target:self
+ action:@selector(actionCancel)];
+ self.navigationItem.leftBarButtonItem = btn;
+ [btn release];
+}
+
+- (void)viewWillAppear:(BOOL)animated{
+ [super viewWillAppear:animated];
+ [self setViewStyle];
+}
+
+- (void)viewDidAppear:(BOOL)animated{
+ [super viewDidAppear:animated];
+ [self setViewStyle];
+ [self.textView becomeFirstResponder];
+}
+
+- (void)setViewStyle{
+ self.navigationController.navigationBar.translucent = NO;
+ self.navigationController.navigationBar.tintColor = [UIColor colorWithHex:0x2C4287];
+}
+
+- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
+ return (interfaceOrientation == UIInterfaceOrientationPortrait);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Delegate (UITableView)
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
+ return 1;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
+ return 2;
+}
+
+- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
+ if(indexPath.row == 0){
+ return 45;
+ }
+ return IPAD ? 120 : 80;
+}
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"indexCell"];
+ if (cell == nil) {
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:@"indexCell"] autorelease];
+ cell.textLabel.font = [UIFont systemFontOfSize:14];
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ }
+
+ // accout
+ if(indexPath.row == 0){
+ UIButton *_btn = [UIButton buttonWithType:UIButtonTypeCustom];
+ UIImage *image;
+
+ if(self.loginName){
+ image = [UIImage imageNamed:@"FBConnect.bundle/images/LogoutNormal.png"];
+ [_btn addTarget:self action:@selector(fbLogout) forControlEvents:UIControlEventTouchUpInside];
+ cell.textLabel.text = self.loginName;
+ }else{
+ image = [UIImage imageNamed:@"FBConnect.bundle/images/LoginNormal.png"];
+ [_btn addTarget:self action:@selector(fbLogin) forControlEvents:UIControlEventTouchUpInside];
+ cell.textLabel.text = LS(@"FB_NEED_LOGIN");
+ }
+
+ [_btn setBackgroundImage:image forState:UIControlStateNormal];
+ [_btn setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
+ cell.accessoryView = _btn;
+
+ // message
+ }else{
+ CGFloat thumbSize = IPAD ? 100 : 60;
+ CGFloat textSzie = IPAD ? 348 : 210;
+
+ UIImageView *_back = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, thumbSize, thumbSize)];
+ _back.image = self.thumbnailImage;
+ [cell.contentView addSubview:_back];
+ [_back release];
+
+ if(!self.textView){
+ UITextView *tv = [[UITextView alloc] initWithFrame:CGRectMake(thumbSize + 20, 10, textSzie, thumbSize)];
+ tv.font = [UIFont systemFontOfSize:16];
+ tv.backgroundColor = [UIColor colorWithHex:0xefefef];
+ self.textView = tv;
+ [tv release];
+ }else{
+ [self.textView removeFromSuperview];
+ }
+ [cell.contentView addSubview:self.textView];
+ }
+ return cell;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Action
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (void)actionSave{
+ NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
+ self.originalImage, @"source",
+ self.textView.text, @"message",
+ nil];
+
+ [self.facebook requestWithGraphPath:@"me/photos"
+ andParams:params
+ andHttpMethod:@"POST"
+ andDelegate:self];
+}
+
+- (void)actionCancel{
+ [self dismissModalViewControllerAnimated:YES];
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Facebook Login/Logout
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (void)createFbInstance{
+ if(self.facebook){
+ return;
+ }
+ Facebook *fb = [[Facebook alloc] initWithAppId:FB_APP_ID andDelegate:self];
+ self.facebook = fb;
+ [fb release];
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ if([defaults objectForKey:FB_ACCESS_TOKEN] && [defaults objectForKey:FB_EXPIRATION_DATE]){
+ self.facebook.accessToken = [defaults objectForKey:FB_ACCESS_TOKEN];
+ self.facebook.expirationDate = [defaults objectForKey:FB_EXPIRATION_DATE];
+ }
+ if([defaults objectForKey:FB_LOGINNAME]){
+ self.loginName = [defaults objectForKey:FB_LOGINNAME];
+ }
+}
+
+- (void)fbLogin{
+ if(!self.facebook){
+ [self createFbInstance];
+ }
+ if([self.facebook isSessionValid]){
+ LOG(@"facebook: valid session");
+ }
+ NSArray *permissions = [[NSArray alloc] initWithObjects:FB_PERMISSIONS, nil];
+ [UIAppDelegate setFacebook:self.facebook];
+ [self.facebook authorize:permissions];
+ [permissions release];
+}
+
+- (void)fbLogout{
+ [self createFbInstance];
+ [self.facebook logout];
+ RELEASE(facebook);
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Delegate (FBSessionDelegate)
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+// get user info and check requried permission
+// API explorer
+// http://developers.facebook.com/tools/explorer/?method=GET&path=me%2Fpermissions
+
+- (void)fbDidLogin {
+ LOG(@"facebook: did login");
+ [self saveFbSession:self.facebook.accessToken expiresAt:self.facebook.expirationDate];
+
+ [self.facebook requestWithGraphPath:@"me" andDelegate:self];
+ [self.facebook requestWithGraphPath:@"me/permissions" andDelegate:self];
+}
+
+- (void)fbDidExtendToken:(NSString*)accessToken expiresAt:(NSDate*)expiresAt{
+ LOG(@"facebook: token extended");
+ [self saveFbSession:accessToken expiresAt:expiresAt];
+}
+
+- (void)fbDidLogout{
+ LOG(@"facebook: did logout");
+ [self clearFbSession];
+ [self.tableView reloadData];
+}
+
+- (void)fbDidNotLogin:(BOOL)cancelled{
+ // nothing todo
+}
+
+- (void)fbSessionInvalidated{
+ [self clearFbSession];
+ [self fbLogout];
+}
+
+- (void)saveFbSession:(NSString*)accessToken expiresAt:(NSDate*)expiresAt{
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ if(accessToken && expiresAt){
+ [defaults setObject:accessToken forKey:FB_ACCESS_TOKEN];
+ [defaults setObject:expiresAt forKey:FB_EXPIRATION_DATE];
+ [defaults synchronize];
+ }
+}
+
+- (void)clearFbSession{
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ if ([defaults objectForKey:FB_ACCESS_TOKEN]) {
+ [defaults removeObjectForKey:FB_ACCESS_TOKEN];
+ [defaults removeObjectForKey:FB_EXPIRATION_DATE];
+ [defaults removeObjectForKey:FB_LOGINNAME];
+ [defaults synchronize];
+ }
+ RELEASE(facebook);
+ self.loginName = nil;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Delegate (FBRequestDelegate)
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (void)requestLoading:(FBRequest *)request{
+ if([request.url isEqual:@"https://graph.facebook.com/me/photos"]){
+ [self loading:YES];
+ }
+}
+
+- (void)request:(FBRequest *)request didFailWithError:(NSError *)error{
+ LOG(@"%@", [error description]);
+ [self loading:NO];
+
+ UIAlertView *alert = [[UIAlertView alloc]
+ initWithTitle:@""
+ message:LS(@"FB_ERROR")
+ delegate:self
+ cancelButtonTitle:nil
+ otherButtonTitles:@"OK", nil];
+ [alert show];
+ [alert release];
+}
+
+- (void)request:(FBRequest *)request didLoad:(id)result{
+ LOG(@"%@ : %@", request.url, [result description]);
+ [self loading:NO];
+
+ if(!result){
+ return;
+ }
+
+ // permission check
+ if([request.url isEqual:@"https://graph.facebook.com/me/permissions"]){
+ NSArray *data = [((NSDictionary *)result) objectForKey:@"data"];
+ if(data.count > 0){
+ int isPermitted = [[(NSDictionary *)[data objectAtIndex:0] objectForKey:@"publish_stream"] intValue];
+ if(!isPermitted){
+ UIAlertView *alert = [[UIAlertView alloc]
+ initWithTitle:@""
+ message:LS(@"FB_NO_PERMISSION")
+ delegate:self
+ cancelButtonTitle:nil
+ otherButtonTitles:@"OK", nil];
+ [alert show];
+ [alert release];
+ [self fbLogout];
+ }
+ }
+
+ // user info
+ }else if([request.url isEqual:@"https://graph.facebook.com/me"]){
+ self.loginName = [((NSDictionary *)result) objectForKey:@"name"];
+
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+ [defaults setObject:self.loginName forKey:FB_LOGINNAME];
+ [defaults synchronize];
+ [self.tableView reloadData];
+
+ // post
+ }else if([request.url isEqual:@"https://graph.facebook.com/me/photos"]){
+ NSString *postId = [((NSDictionary *)result) objectForKey:@"post_id"];
+ if(postId){
+ [self actionCancel];
+ }else{
+ UIAlertView *alert = [[UIAlertView alloc]
+ initWithTitle:@""
+ message:LS(@"FB_NO_PERMISSION2")
+ delegate:self
+ cancelButtonTitle:nil
+ otherButtonTitles:@"OK", nil];
+ [alert show];
+ [alert release];
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+#pragma mark -
+#pragma mark Util
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+- (void)loading:(BOOL)isLoading{
+ // start loading
+ if(isLoading){
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
+ if(self.loadingAlert){
+ return;
+ }
+ UIAlertView *_alert = [[UIAlertView alloc] initWithTitle: @"Loading"
+ message: @""
+ delegate: nil
+ cancelButtonTitle: nil
+ otherButtonTitles: nil];
+ self.loadingAlert = _alert;
+ [_alert release];
+
+ UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+ activityView.frame = CGRectMake(139.0f-18.0f, 51.0f, 37.0f, 37.0f);
+ [self.loadingAlert addSubview:activityView];
+ [activityView startAnimating];
+ [activityView release];
+
+ [self.loadingAlert show];
+
+ // stop loading
+ }else{
+ [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
+ [self.loadingAlert dismissWithClickedButtonIndex:0 animated:NO];
+ RELEASE(loadingAlert);
+ }
+}
+
+@end
View
14 ASFBPost/AppDelegate.h
@@ -0,0 +1,14 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <UIKit/UIKit.h>
+#import "FBConnect.h"
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+@property (nonatomic, assign) Facebook *facebook;
+
+@end
View
60 ASFBPost/AppDelegate.m
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import "AppDelegate.h"
+#import "MainController.h"
+
+@interface AppDelegate()
+
+@property (nonatomic, retain) MainController *mainCtrl;
+
+@end
+
+
+@implementation AppDelegate
+
+@synthesize window = _window;
+@synthesize facebook = _facebook;
+@synthesize mainCtrl = _mainCtrl;
+
+- (void)dealloc{
+ _facebook = nil;
+ RELEASE(mainCtrl);
+ RELEASE(window);
+ [super dealloc];
+}
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
+ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
+ self.window.backgroundColor = [UIColor whiteColor];
+
+ MainController *c = [[MainController alloc] init];
+ self.mainCtrl = c;
+ [c release];
+
+ [self.window addSubview:self.mainCtrl.view];
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+// for after iOS 4.2
+- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
+ if(self.facebook){
+ return [self.facebook handleOpenURL:url];
+ }
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application{}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application{}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application{}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application{}
+
+- (void)applicationWillTerminate:(UIApplication *)application{}
+
+@end
View
10 ASFBPost/MainController.h
@@ -0,0 +1,10 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <UIKit/UIKit.h>
+
+@interface MainController : UIViewController
+
+@end
View
42 ASFBPost/MainController.m
@@ -0,0 +1,42 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import "MainController.h"
+#import "ASFBPostController.h"
+
+
+@implementation MainController
+
+- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{
+ self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+ if (self) {
+
+ }
+ return self;
+}
+
+- (void)viewDidLoad{
+ [super viewDidLoad];
+
+ UIButton *_btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
+ [_btn setTitle:@"Open" forState:UIControlStateNormal];
+ [_btn addTarget:self action:@selector(showFBPost) forControlEvents:UIControlEventTouchUpInside];
+ [_btn setFrame:CGRectMake(10, 10, 140, 40)];
+ [self.view addSubview:_btn];
+}
+
+- (void)showFBPost{
+ ASFBPostController *c = [[ASFBPostController alloc] init];
+ c.thumbnailImage = [UIImage imageNamed:@"sample_thumb.jpg"];
+ c.originalImage = [UIImage imageNamed:@"sample.jpg"];
+
+ UINavigationController *n = [[UINavigationController alloc] initWithRootViewController:c];
+ n.modalPresentationStyle = UIModalPresentationFormSheet;
+ [c release];
+ [self presentModalViewController:n animated:YES];
+ [n release];
+}
+
+@end
View
14 ASFBPost/main.m
@@ -0,0 +1,14 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+ }
+}
View
26 README.md
@@ -1,4 +1,28 @@
ASFBPostController
==================
-ASFBPostController provides photo posting function to Facebook. You can easily integrate Facebook post function to you iOS app.
+ASFBPostController provides photo posting function to Facebook. You can easily integrate Facebook post function to you iOS app.
+
+The ASFBPostController is licensed under the Apache License, Version 2.0 as same as the Facebook SDK.
+
+http://www.apache.org/licenses/LICENSE-2.0.html
+https://github.com/facebook/facebook-ios-sdk/
+
+
+Setup
+==================
+
+1. Create your iOS facebook App.
+2. Replace sample ID with your Facebook App ID.
+
+* ASFBPost-Prefix.pch
+#define FB_APP_ID @"1234567"
+
+* ASFBPost-Infor.plist
+URL types > Item 0 > URL Schemes > Item 0 > fb1234567
+
+
+Screens
+==================
+![Screenshot1](https://dl.dropbox.com/u/339699/github/ASFBPostController_iphone.png)
+![Screenshot1](https://dl.dropbox.com/u/339699/github/ASFBPostController_ipad.png)
View
9 Resources/en.lproj/Localizable.strings
@@ -0,0 +1,9 @@
+
+/* Facebook */
+"FACEBOOK" = "Facebook";
+"FB_POST" = "Post";
+"FB_CANCEL" = "Cancel";
+"FB_NEED_LOGIN" = "Not logged in";
+"FB_ERROR" = "Error has occured. Please login again.";
+"FB_NO_PERMISSION" = "You have to permit to post your timeline. Please login again to fix it.";
+"FB_NO_PERMISSION2" = "Post failed. Please check whether post to timeline is permitted. You can add that by re-login.";
View
9 Resources/ja.lproj/Localizable.strings
@@ -0,0 +1,9 @@
+
+/* Facebook */
+"FACEBOOK" = "Facebook";
+"FB_POST" = "投稿する";
+"FB_CANCEL" = "キャンセル";
+"FB_NEED_LOGIN" = "ログインしていません";
+"FB_ERROR" = "エラーが発生しました。再度ログインしてください。";
+"FB_NO_PERMISSION" = "タイムラインへの投稿が許可されていません。再度ログインし、投稿を許可してください。";
+"FB_NO_PERMISSION2" = "投稿できませんでした。タイムラインへの投稿が許可されているか確認してください。再度ログインで権限を追加できます。";
View
BIN  Resources/sample.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Resources/sample_thumb.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
12 Vendor/AppStair/ASColor+Hex.h
@@ -0,0 +1,12 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import <Foundation/Foundation.h>
+
+@interface UIColor (Hex)
+
++ (UIColor *)colorWithHex:(UInt32)hex;
+
+@end
View
21 Vendor/AppStair/ASColor+Hex.m
@@ -0,0 +1,21 @@
+//
+// Copyright (c) 2012 AppStair LLC. All rights reserved.
+// http://appstair.com
+//
+
+#import "ASColor+Hex.h"
+
+@implementation UIColor (Hex)
+
++ (UIColor *)colorWithHex:(UInt32)hex {
+ int r = (hex >> 16) & 0xFF;
+ int g = (hex >> 8) & 0xFF;
+ int b = (hex) & 0xFF;
+
+ return [UIColor colorWithRed:r / 255.0f
+ green:g / 255.0f
+ blue:b / 255.0f
+ alpha:1.0f];
+}
+
+@end
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginNormal.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginNormal@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginPressed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginPressed@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookNormal.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookNormal@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookPressed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LoginWithFacebookPressed@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutNormal.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutNormal@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutPressed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/LogoutPressed@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBConnect.bundle/images/runaround_image.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
22 Vendor/FacebookSDK/FBConnect.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "Facebook.h"
+#include "FBDialog.h"
+#include "FBLoginDialog.h"
+#include "FBRequest.h"
+#include "SBJSON.h"
View
BIN  Vendor/FacebookSDK/FBDialog.bundle/images/close.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBDialog.bundle/images/close@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  Vendor/FacebookSDK/FBDialog.bundle/images/fbicon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
165 Vendor/FacebookSDK/FBDialog.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2010 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+@protocol FBDialogDelegate;
+@class FBFrictionlessRequestSettings;
+
+/**
+ * Do not use this interface directly, instead, use dialog in Facebook.h
+ *
+ * Facebook dialog interface for start the facebook webView UIServer Dialog.
+ */
+
+@interface FBDialog : UIView <UIWebViewDelegate> {
+ id<FBDialogDelegate> _delegate;
+ NSMutableDictionary *_params;
+ NSString * _serverURL;
+ NSURL* _loadingURL;
+ UIWebView* _webView;
+ UIActivityIndicatorView* _spinner;
+ UIButton* _closeButton;
+ UIInterfaceOrientation _orientation;
+ BOOL _showingKeyboard;
+ BOOL _isViewInvisible;
+ FBFrictionlessRequestSettings* _frictionlessSettings;
+
+ // Ensures that UI elements behind the dialog are disabled.
+ UIView* _modalBackgroundView;
+}
+
+/**
+ * The delegate.
+ */
+@property(nonatomic,assign) id<FBDialogDelegate> delegate;
+
+/**
+ * The parameters.
+ */
+@property(nonatomic, retain) NSMutableDictionary* params;
+
+- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle;
+
+- (id)initWithURL: (NSString *) loadingURL
+ params: (NSMutableDictionary *) params
+ isViewInvisible: (BOOL) isViewInvisible
+ frictionlessSettings: (FBFrictionlessRequestSettings *) frictionlessSettings
+ delegate: (id <FBDialogDelegate>) delegate;
+
+/**
+ * Displays the view with an animation.
+ *
+ * The view will be added to the top of the current key window.
+ */
+- (void)show;
+
+/**
+ * Displays the first page of the dialog.
+ *
+ * Do not ever call this directly. It is intended to be overriden by subclasses.
+ */
+- (void)load;
+
+/**
+ * Displays a URL in the dialog.
+ */
+- (void)loadURL:(NSString*)url
+ get:(NSDictionary*)getParams;
+
+/**
+ * Hides the view and notifies delegates of success or cancellation.
+ */
+- (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated;
+
+/**
+ * Hides the view and notifies delegates of an error.
+ */
+- (void)dismissWithError:(NSError*)error animated:(BOOL)animated;
+
+/**
+ * Subclasses may override to perform actions just prior to showing the dialog.
+ */
+- (void)dialogWillAppear;
+
+/**
+ * Subclasses may override to perform actions just after the dialog is hidden.
+ */
+- (void)dialogWillDisappear;
+
+/**
+ * Subclasses should override to process data returned from the server in a 'fbconnect' url.
+ *
+ * Implementations must call dismissWithSuccess:YES at some point to hide the dialog.
+ */
+- (void)dialogDidSucceed:(NSURL *)url;
+
+/**
+ * Subclasses should override to process data returned from the server in a 'fbconnect' url.
+ *
+ * Implementations must call dismissWithSuccess:YES at some point to hide the dialog.
+ */
+- (void)dialogDidCancel:(NSURL *)url;
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+/*
+ *Your application should implement this delegate
+ */
+@protocol FBDialogDelegate <NSObject>
+
+@optional
+
+/**
+ * Called when the dialog succeeds and is about to be dismissed.
+ */
+- (void)dialogDidComplete:(FBDialog *)dialog;
+
+/**
+ * Called when the dialog succeeds with a returning url.
+ */
+- (void)dialogCompleteWithUrl:(NSURL *)url;
+
+/**
+ * Called when the dialog get canceled by the user.
+ */
+- (void)dialogDidNotCompleteWithUrl:(NSURL *)url;
+
+/**
+ * Called when the dialog is cancelled and is about to be dismissed.
+ */
+- (void)dialogDidNotComplete:(FBDialog *)dialog;
+
+/**
+ * Called when dialog failed to load due to an error.
+ */
+- (void)dialog:(FBDialog*)dialog didFailWithError:(NSError *)error;
+
+/**
+ * Asks if a link touched by a user should be opened in an external browser.
+ *
+ * If a user touches a link, the default behavior is to open the link in the Safari browser,
+ * which will cause your app to quit. You may want to prevent this from happening, open the link
+ * in your own internal browser, or perhaps warn the user that they are about to leave your app.
+ * If so, implement this method on your delegate and return NO. If you warn the user, you
+ * should hold onto the URL and once you have received their acknowledgement open the URL yourself
+ * using [[UIApplication sharedApplication] openURL:].
+ */
+- (BOOL)dialog:(FBDialog*)dialog shouldOpenURLInExternalBrowser:(NSURL *)url;
+
+@end
View
688 Vendor/FacebookSDK/FBDialog.m
@@ -0,0 +1,688 @@
+/*
+ * Copyright 2010 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#import "FBDialog.h"
+#import "Facebook.h"
+#import "FBFrictionlessRequestSettings.h"
+#import "JSON.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// global
+
+static CGFloat kBorderGray[4] = {0.3, 0.3, 0.3, 0.8};
+static CGFloat kBorderBlack[4] = {0.3, 0.3, 0.3, 1};
+
+static CGFloat kTransitionDuration = 0.3;
+
+static CGFloat kPadding = 0;
+static CGFloat kBorderWidth = 10;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static BOOL FBIsDeviceIPad() {
+#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
+ if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+ return YES;
+ }
+#endif
+ return NO;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation FBDialog
+
+@synthesize delegate = _delegate,
+params = _params;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// private
+
+- (void)addRoundedRectToPath:(CGContextRef)context rect:(CGRect)rect radius:(float)radius {
+ CGContextBeginPath(context);
+ CGContextSaveGState(context);
+
+ if (radius == 0) {
+ CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
+ CGContextAddRect(context, rect);
+ } else {
+ rect = CGRectOffset(CGRectInset(rect, 0.5, 0.5), 0.5, 0.5);
+ CGContextTranslateCTM(context, CGRectGetMinX(rect)-0.5, CGRectGetMinY(rect)-0.5);
+ CGContextScaleCTM(context, radius, radius);
+ float fw = CGRectGetWidth(rect) / radius;
+ float fh = CGRectGetHeight(rect) / radius;
+
+ CGContextMoveToPoint(context, fw, fh/2);
+ CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
+ CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
+ CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
+ CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
+ }
+
+ CGContextClosePath(context);
+ CGContextRestoreGState(context);
+}
+
+- (void)drawRect:(CGRect)rect fill:(const CGFloat*)fillColors radius:(CGFloat)radius {
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+
+ if (fillColors) {
+ CGContextSaveGState(context);
+ CGContextSetFillColor(context, fillColors);
+ if (radius) {
+ [self addRoundedRectToPath:context rect:rect radius:radius];
+ CGContextFillPath(context);
+ } else {
+ CGContextFillRect(context, rect);
+ }
+ CGContextRestoreGState(context);
+ }
+
+ CGColorSpaceRelease(space);
+}
+
+- (void)strokeLines:(CGRect)rect stroke:(const CGFloat*)strokeColor {
+ CGContextRef context = UIGraphicsGetCurrentContext();
+ CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
+
+ CGContextSaveGState(context);
+ CGContextSetStrokeColorSpace(context, space);
+ CGContextSetStrokeColor(context, strokeColor);
+ CGContextSetLineWidth(context, 1.0);
+
+ {
+ CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y-0.5},
+ {rect.origin.x+rect.size.width, rect.origin.y-0.5}};
+ CGContextStrokeLineSegments(context, points, 2);
+ }
+ {
+ CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y+rect.size.height-0.5},
+ {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height-0.5}};
+ CGContextStrokeLineSegments(context, points, 2);
+ }
+ {
+ CGPoint points[] = {{rect.origin.x+rect.size.width-0.5, rect.origin.y},
+ {rect.origin.x+rect.size.width-0.5, rect.origin.y+rect.size.height}};
+ CGContextStrokeLineSegments(context, points, 2);
+ }
+ {
+ CGPoint points[] = {{rect.origin.x+0.5, rect.origin.y},
+ {rect.origin.x+0.5, rect.origin.y+rect.size.height}};
+ CGContextStrokeLineSegments(context, points, 2);
+ }
+
+ CGContextRestoreGState(context);
+
+ CGColorSpaceRelease(space);
+}
+
+- (BOOL)shouldRotateToOrientation:(UIInterfaceOrientation)orientation {
+ if (orientation == _orientation) {
+ return NO;
+ } else {
+ return orientation == UIInterfaceOrientationPortrait
+ || orientation == UIInterfaceOrientationPortraitUpsideDown
+ || orientation == UIInterfaceOrientationLandscapeLeft
+ || orientation == UIInterfaceOrientationLandscapeRight;
+ }
+}
+
+- (CGAffineTransform)transformForOrientation {
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (orientation == UIInterfaceOrientationLandscapeLeft) {
+ return CGAffineTransformMakeRotation(M_PI*1.5);
+ } else if (orientation == UIInterfaceOrientationLandscapeRight) {
+ return CGAffineTransformMakeRotation(M_PI/2);
+ } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
+ return CGAffineTransformMakeRotation(-M_PI);
+ } else {
+ return CGAffineTransformIdentity;
+ }
+}
+
+- (void)sizeToFitOrientation:(BOOL)transform {
+ if (transform) {
+ self.transform = CGAffineTransformIdentity;
+ }
+
+ CGRect frame = [UIScreen mainScreen].applicationFrame;
+ CGPoint center = CGPointMake(
+ frame.origin.x + ceil(frame.size.width/2),
+ frame.origin.y + ceil(frame.size.height/2));
+
+ CGFloat scale_factor = 1.0f;
+ if (FBIsDeviceIPad()) {
+ // On the iPad the dialog's dimensions should only be 60% of the screen's
+ scale_factor = 0.6f;
+ }
+
+ CGFloat width = floor(scale_factor * frame.size.width) - kPadding * 2;
+ CGFloat height = floor(scale_factor * frame.size.height) - kPadding * 2;
+
+ _orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (UIInterfaceOrientationIsLandscape(_orientation)) {
+ self.frame = CGRectMake(kPadding, kPadding, height, width);
+ } else {
+ self.frame = CGRectMake(kPadding, kPadding, width, height);
+ }
+ self.center = center;
+
+ if (transform) {
+ self.transform = [self transformForOrientation];
+ }
+}
+
+- (void)updateWebOrientation {
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (UIInterfaceOrientationIsLandscape(orientation)) {
+ [_webView stringByEvaluatingJavaScriptFromString:
+ @"document.body.setAttribute('orientation', 90);"];
+ } else {
+ [_webView stringByEvaluatingJavaScriptFromString:
+ @"document.body.removeAttribute('orientation');"];
+ }
+}
+
+- (void)bounce1AnimationStopped {
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:kTransitionDuration/2];
+ [UIView setAnimationDelegate:self];
+ [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)];
+ self.transform = CGAffineTransformScale([self transformForOrientation], 0.9, 0.9);
+ [UIView commitAnimations];
+}
+
+- (void)bounce2AnimationStopped {
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:kTransitionDuration/2];
+ self.transform = [self transformForOrientation];
+ [UIView commitAnimations];
+}
+
+- (NSURL*)generateURL:(NSString*)baseURL params:(NSDictionary*)params {
+ if (params) {
+ NSMutableArray* pairs = [NSMutableArray array];
+ for (NSString* key in params.keyEnumerator) {
+ NSString* value = [params objectForKey:key];
+ NSString* escaped_value = (NSString *)CFURLCreateStringByAddingPercentEscapes(
+ NULL, /* allocator */
+ (CFStringRef)value,
+ NULL, /* charactersToLeaveUnescaped */
+ (CFStringRef)@"!*'();:@&=+$,/?%#[]",
+ kCFStringEncodingUTF8);
+
+ [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, escaped_value]];
+ [escaped_value release];
+ }
+
+ NSString* query = [pairs componentsJoinedByString:@"&"];
+ NSString* url = [NSString stringWithFormat:@"%@?%@", baseURL, query];
+ return [NSURL URLWithString:url];
+ } else {
+ return [NSURL URLWithString:baseURL];
+ }
+}
+
+- (void)addObservers {
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(deviceOrientationDidChange:)
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(keyboardWillShow:) name:@"UIKeyboardWillShowNotification" object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(keyboardWillHide:) name:@"UIKeyboardWillHideNotification" object:nil];
+}
+
+- (void)removeObservers {
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:@"UIKeyboardWillShowNotification" object:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self
+ name:@"UIKeyboardWillHideNotification" object:nil];
+}
+
+- (void)postDismissCleanup {
+ [self removeObservers];
+ [self removeFromSuperview];
+ [_modalBackgroundView removeFromSuperview];
+}
+
+- (void)dismiss:(BOOL)animated {
+ [self dialogWillDisappear];
+
+ // If the dialog has been closed, then we need to cancel the order to open it.
+ // This happens in the case of a frictionless request, see webViewDidFinishLoad for details
+ [NSObject cancelPreviousPerformRequestsWithTarget:self
+ selector:@selector(showWebView)
+ object:nil];
+
+ [_loadingURL release];
+ _loadingURL = nil;
+
+ if (animated) {
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:kTransitionDuration];
+ [UIView setAnimationDelegate:self];
+ [UIView setAnimationDidStopSelector:@selector(postDismissCleanup)];
+ self.alpha = 0;
+ [UIView commitAnimations];
+ } else {
+ [self postDismissCleanup];
+ }
+}
+
+- (void)cancel {
+ [self dialogDidCancel:nil];
+}
+
+- (BOOL)testBoolUrlParam:(NSURL *)url param:(NSString *)param {
+ NSString *paramVal = [self getStringFromUrl: [url absoluteString]
+ needle: param];
+ return [paramVal boolValue];
+}
+
+- (void)dialogSuccessHandleFrictionlessResponses:(NSURL *)url {
+ // did we receive a recipient list?
+ NSString *recipientJson = [self getStringFromUrl:[url absoluteString]
+ needle:@"frictionless_recipients="];
+ if (recipientJson) {
+ // if value parses as an array, treat as set of fbids
+ SBJsonParser *parser = [[[SBJsonParser alloc]
+ init]
+ autorelease];
+ id recipients = [parser objectWithString:recipientJson];
+
+ // if we got something usable, copy the ids out and update the cache
+ if ([recipients isKindOfClass:[NSArray class]]) {
+ NSMutableArray *ids = [[[NSMutableArray alloc]
+ initWithCapacity:[recipients count]]
+ autorelease];
+ for (id recipient in recipients) {
+ NSString *fbid = [NSString stringWithFormat:@"%@", recipient];
+ [ids addObject:fbid];
+ }
+ // we may be tempted to terminate outstanding requests before this
+ // point, but that would cause problems if the user cancelled a dialog
+ [_frictionlessSettings updateRecipientCacheWithRecipients:ids];
+ }
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// NSObject
+
+- (id)init {
+ if ((self = [super initWithFrame:CGRectZero])) {
+ _delegate = nil;
+ _loadingURL = nil;
+ _showingKeyboard = NO;
+
+ self.backgroundColor = [UIColor clearColor];
+ self.autoresizesSubviews = YES;
+ self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ self.contentMode = UIViewContentModeRedraw;
+
+ _webView = [[UIWebView alloc] initWithFrame:CGRectMake(kPadding, kPadding, 480, 480)];
+ _webView.delegate = self;
+ _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ [self addSubview:_webView];
+
+ UIImage* closeImage = [UIImage imageNamed:@"FBDialog.bundle/images/close.png"];
+
+ UIColor* color = [UIColor colorWithRed:167.0/255 green:184.0/255 blue:216.0/255 alpha:1];
+ _closeButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
+ [_closeButton setImage:closeImage forState:UIControlStateNormal];
+ [_closeButton setTitleColor:color forState:UIControlStateNormal];
+ [_closeButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
+ [_closeButton addTarget:self action:@selector(cancel)
+ forControlEvents:UIControlEventTouchUpInside];
+
+ // To be compatible with OS 2.x
+#if __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_2_2
+ _closeButton.font = [UIFont boldSystemFontOfSize:12];
+#else
+ _closeButton.titleLabel.font = [UIFont boldSystemFontOfSize:12];
+#endif
+
+ _closeButton.showsTouchWhenHighlighted = YES;
+ _closeButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin
+ | UIViewAutoresizingFlexibleBottomMargin;
+ [self addSubview:_closeButton];
+
+ _spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:
+ UIActivityIndicatorViewStyleWhiteLarge];
+ if ([_spinner respondsToSelector:@selector(setColor:)]) {
+ [_spinner setColor:[UIColor grayColor]];
+ } else {
+ [_spinner setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
+ }
+ _spinner.autoresizingMask =
+ UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
+ | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
+ [self addSubview:_spinner];
+ _modalBackgroundView = [[UIView alloc] init];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ _webView.delegate = nil;
+ [_webView release];
+ [_params release];
+ [_serverURL release];
+ [_spinner release];
+ [_closeButton release];
+ [_loadingURL release];
+ [_modalBackgroundView release];
+ [_frictionlessSettings release];
+ [super dealloc];
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UIView
+
+- (void)drawRect:(CGRect)rect {
+ [self drawRect:rect fill:kBorderGray radius:0];
+
+ CGRect webRect = CGRectMake(
+ ceil(rect.origin.x + kBorderWidth), ceil(rect.origin.y + kBorderWidth)+1,
+ rect.size.width - kBorderWidth*2, _webView.frame.size.height+1);
+
+ [self strokeLines:webRect stroke:kBorderBlack];
+}
+
+// Display the dialog's WebView with a slick pop-up animation
+- (void)showWebView {
+ UIWindow* window = [UIApplication sharedApplication].keyWindow;
+ if (!window) {
+ window = [[UIApplication sharedApplication].windows objectAtIndex:0];
+ }
+ _modalBackgroundView.frame = window.frame;
+ [_modalBackgroundView addSubview:self];
+ [window addSubview:_modalBackgroundView];
+
+ self.transform = CGAffineTransformScale([self transformForOrientation], 0.001, 0.001);
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:kTransitionDuration/1.5];
+ [UIView setAnimationDelegate:self];
+ [UIView setAnimationDidStopSelector:@selector(bounce1AnimationStopped)];
+ self.transform = CGAffineTransformScale([self transformForOrientation], 1.1, 1.1);
+ [UIView commitAnimations];
+
+ [self dialogWillAppear];
+ [self addObservers];
+}
+
+// Show a spinner during the loading time for the dialog. This is designed to show
+// on top of the webview but before the contents have loaded.
+- (void)showSpinner {
+ [_spinner sizeToFit];
+ [_spinner startAnimating];
+ _spinner.center = _webView.center;
+}
+
+- (void)hideSpinner {
+ [_spinner stopAnimating];
+ _spinner.hidden = YES;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UIWebViewDelegate
+
+- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
+ navigationType:(UIWebViewNavigationType)navigationType {
+ NSURL* url = request.URL;
+
+ if ([url.scheme isEqualToString:@"fbconnect"]) {
+ if ([[url.resourceSpecifier substringToIndex:8] isEqualToString:@"//cancel"]) {
+ NSString * errorCode = [self getStringFromUrl:[url absoluteString] needle:@"error_code="];
+ NSString * errorStr = [self getStringFromUrl:[url absoluteString] needle:@"error_msg="];
+ if (errorCode) {
+ NSDictionary * errorData = [NSDictionary dictionaryWithObject:errorStr forKey:@"error_msg"];
+ NSError * error = [NSError errorWithDomain:@"facebookErrDomain"
+ code:[errorCode intValue]
+ userInfo:errorData];
+ [self dismissWithError:error animated:YES];
+ } else {
+ [self dialogDidCancel:url];
+ }
+ } else {
+ if (_frictionlessSettings.enabled) {
+ [self dialogSuccessHandleFrictionlessResponses:url];
+ }
+ [self dialogDidSucceed:url];
+ }
+ return NO;
+ } else if ([_loadingURL isEqual:url]) {
+ return YES;
+ } else if (navigationType == UIWebViewNavigationTypeLinkClicked) {
+ if ([_delegate respondsToSelector:@selector(dialog:shouldOpenURLInExternalBrowser:)]) {
+ if (![_delegate dialog:self shouldOpenURLInExternalBrowser:url]) {
+ return NO;
+ }
+ }
+
+ [[UIApplication sharedApplication] openURL:request.URL];
+ return NO;
+ } else {
+ return YES;
+ }
+}
+
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+ if (_isViewInvisible) {
+ // if our cache asks us to hide the view, then we do, but
+ // in case of a stale cache, we will display the view in a moment
+ // note that showing the view now would cause a visible white
+ // flash in the common case where the cache is up to date
+ [self performSelector:@selector(showWebView) withObject:nil afterDelay:.05];
+ } else {
+ [self hideSpinner];
+ }
+ [self updateWebOrientation];
+}
+
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+ // 102 == WebKitErrorFrameLoadInterruptedByPolicyChange
+ // -999 == "Operation could not be completed", note -999 occurs when the user clicks away before
+ // the page has completely loaded, if we find cases where we want this to result in dialog failure
+ // (usually this just means quick-user), then we should add something more robust here to account
+ // for differences in application needs
+ if (!(([error.domain isEqualToString:@"NSURLErrorDomain"] && error.code == -999) ||
+ ([error.domain isEqualToString:@"WebKitErrorDomain"] && error.code == 102))) {
+ [self dismissWithError:error animated:YES];
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UIDeviceOrientationDidChangeNotification
+
+- (void)deviceOrientationDidChange:(void*)object {
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (!_showingKeyboard && [self shouldRotateToOrientation:orientation]) {
+ [self updateWebOrientation];
+
+ CGFloat duration = [UIApplication sharedApplication].statusBarOrientationAnimationDuration;
+ [UIView beginAnimations:nil context:nil];
+ [UIView setAnimationDuration:duration];
+ [self sizeToFitOrientation:YES];
+ [UIView commitAnimations];
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UIKeyboardNotifications
+
+- (void)keyboardWillShow:(NSNotification*)notification {
+
+ _showingKeyboard = YES;
+
+ if (FBIsDeviceIPad()) {
+ // On the iPad the screen is large enough that we don't need to
+ // resize the dialog to accomodate the keyboard popping up
+ return;
+ }
+
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (UIInterfaceOrientationIsLandscape(orientation)) {
+ _webView.frame = CGRectInset(_webView.frame,
+ -(kPadding + kBorderWidth),
+ -(kPadding + kBorderWidth));
+ }
+}
+
+- (void)keyboardWillHide:(NSNotification*)notification {
+ _showingKeyboard = NO;
+
+ if (FBIsDeviceIPad()) {
+ return;
+ }
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ if (UIInterfaceOrientationIsLandscape(orientation)) {
+ _webView.frame = CGRectInset(_webView.frame,
+ kPadding + kBorderWidth,
+ kPadding + kBorderWidth);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////
+// public
+
+/**
+ * Find a specific parameter from the url
+ */
+- (NSString *) getStringFromUrl: (NSString*) url needle:(NSString *) needle {
+ NSString * str = nil;
+ NSRange start = [url rangeOfString:needle];
+ if (start.location != NSNotFound) {
+ // confirm that the parameter is not a partial name match
+ unichar c = '?';
+ if (start.location != 0) {
+ c = [url characterAtIndex:start.location - 1];
+ }
+ if (c == '?' || c == '&' || c == '#') {
+ NSRange end = [[url substringFromIndex:start.location+start.length] rangeOfString:@"&"];
+ NSUInteger offset = start.location+start.length;
+ str = end.location == NSNotFound ?
+ [url substringFromIndex:offset] :
+ [url substringWithRange:NSMakeRange(offset, end.location)];
+ str = [str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ }
+ }
+ return str;
+}
+
+- (id)initWithURL: (NSString *) serverURL
+ params: (NSMutableDictionary *) params
+ isViewInvisible: (BOOL)isViewInvisible
+ frictionlessSettings: (FBFrictionlessRequestSettings*) frictionlessSettings
+ delegate: (id <FBDialogDelegate>) delegate {
+
+ self = [self init];
+ _serverURL = [serverURL retain];
+ _params = [params retain];
+ _delegate = delegate;
+ _isViewInvisible = isViewInvisible;
+ _frictionlessSettings = [frictionlessSettings retain];
+
+ return self;
+}
+
+- (void)load {
+ [self loadURL:_serverURL get:_params];
+}
+
+- (void)loadURL:(NSString*)url get:(NSDictionary*)getParams {
+
+ [_loadingURL release];
+ _loadingURL = [[self generateURL:url params:getParams] retain];
+ NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:_loadingURL];
+
+ [_webView loadRequest:request];
+}
+
+- (void)show {
+ [self load];
+ [self sizeToFitOrientation:NO];
+
+ CGFloat innerWidth = self.frame.size.width - (kBorderWidth+1)*2;
+ [_closeButton sizeToFit];
+
+ _closeButton.frame = CGRectMake(
+ 2,
+ 2,
+ 29,
+ 29);
+
+ _webView.frame = CGRectMake(
+ kBorderWidth+1,
+ kBorderWidth+1,
+ innerWidth,
+ self.frame.size.height - (1 + kBorderWidth*2));
+
+ if (!_isViewInvisible) {
+ [self showSpinner];
+ [self showWebView];
+ }
+}
+
+- (void)dismissWithSuccess:(BOOL)success animated:(BOOL)animated {
+ if (success) {
+ if ([_delegate respondsToSelector:@selector(dialogDidComplete:)]) {
+ [_delegate dialogDidComplete:self];
+ }
+ } else {
+ if ([_delegate respondsToSelector:@selector(dialogDidNotComplete:)]) {
+ [_delegate dialogDidNotComplete:self];
+ }
+ }
+
+ [self dismiss:animated];
+}
+
+- (void)dismissWithError:(NSError*)error animated:(BOOL)animated {
+ if ([_delegate respondsToSelector:@selector(dialog:didFailWithError:)]) {
+ [_delegate dialog:self didFailWithError:error];
+ }
+
+ [self dismiss:animated];
+}
+
+- (void)dialogWillAppear {
+}
+
+- (void)dialogWillDisappear {
+}
+
+- (void)dialogDidSucceed:(NSURL *)url {
+
+ if ([_delegate respondsToSelector:@selector(dialogCompleteWithUrl:)]) {
+ [_delegate dialogCompleteWithUrl:url];
+ }
+ [self dismissWithSuccess:YES animated:YES];
+}
+
+- (void)dialogDidCancel:(NSURL *)url {
+ if ([_delegate respondsToSelector:@selector(dialogDidNotCompleteWithUrl:)]) {
+ [_delegate dialogDidNotCompleteWithUrl:url];
+ }
+ [self dismissWithSuccess:NO animated:YES];
+}
+
+@end
View
74 Vendor/FacebookSDK/FBFrictionlessRequestSettings.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class Facebook;
+
+/**
+ * Do not use this interface directly, instead, use methods in Facebook.h
+ *
+ * Handles frictionless interaction and recipient-caching by the SDK,
+ * see https://developers.facebook.com/docs/reference/dialogs/requests/
+ */
+@interface FBFrictionlessRequestSettings : NSObject<FBRequestDelegate> {
+@private
+ NSArray* _allowedRecipients;
+ FBRequest* _activeRequest;
+ BOOL _enabled;
+}
+
+/**
+ * BOOL indicating whether frictionless request sending has been enabled
+ */
+@property(nonatomic, readonly) BOOL enabled;
+
+/**
+ * Enable frictionless request sending by the sdk; this means:
+ * 1. query and cache the current set of frictionless recipients
+ * 2. flag other facets of the sdk to behave in a frictionless way
+ */
+- (void)enableWithFacebook:(Facebook*)facebook;
+
+/**
+ * Reload recipient cache; called by the sdk to keep the cache fresh;
+ * method makes graph request: me/apprequestformerrecipients
+ */
+- (void)reloadRecipientCacheWithFacebook:(Facebook*)facebook;
+
+/**
+ * Update the recipient cache; called by the sdk to keep the cache fresh;
+ */
+- (void)updateRecipientCacheWithRecipients:(NSArray*)ids;
+
+/**
+ * Given an fbID for a user, indicates whether user is enabled for
+ * frictionless calls
+ */
+- (BOOL)isFrictionlessEnabledForRecipient:(id)fbid;
+
+/**
+ * Given an array of user fbIDs, indicates whether they are enabled for
+ * frictionless calls
+ */
+- (BOOL)isFrictionlessEnabledForRecipients:(NSArray*)fbids;
+
+/**
+ * init the frictionless cache object
+ */
+- (id)init;
+
+@end
View
162 Vendor/FacebookSDK/FBFrictionlessRequestSettings.m
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2012 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "Facebook.h"
+#import "FBFrictionlessRequestSettings.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// private interface
+//
+@interface FBFrictionlessRequestSettings ()
+
+@property (readwrite, retain) NSArray * allowedRecipients;
+@property (readwrite, retain) FBRequest* activeRequest;
+
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation FBFrictionlessRequestSettings
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// public
+
+@synthesize enabled = _enabled;
+
+- (id)init {
+ if (self = [super init]) {
+ // start life with an empty frictionless cache
+ self.allowedRecipients = [[[NSArray alloc] init] autorelease];
+ }
+ return self;
+}
+
+- (void)enableWithFacebook:(Facebook*)facebook {
+ if (!_enabled) {
+ _enabled = true;
+ [self reloadRecipientCacheWithFacebook:facebook];
+ }
+}
+
+- (void)reloadRecipientCacheWithFacebook:(Facebook *)facebook {
+ // request the list of frictionless recipients from the server
+ id request = [facebook requestWithGraphPath:@"me/apprequestformerrecipients"
+ andDelegate:self];
+ if (request) {
+ self.activeRequest = request;
+ }
+}
+
+- (void)updateRecipientCacheWithRecipients:(NSArray*)ids {
+ // if setting recipients directly, no need to complete pending request
+ self.activeRequest = nil;
+
+ if (ids == nil) {
+ self.allowedRecipients = [[[NSArray alloc] init] autorelease];
+ } else {
+ self.allowedRecipients = [[[NSArray alloc] initWithArray:ids] autorelease];
+ }
+}
+
+- (BOOL)isFrictionlessEnabledForRecipient:(NSString *)fbid {
+ // trim whitespace from edges
+ fbid = [fbid stringByTrimmingCharactersInSet:
+ [NSCharacterSet whitespaceCharacterSet]];
+
+ // linear search through cache for a match
+ for (NSString *entry in self.allowedRecipients) {
+ if ([entry isEqualToString:fbid]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (BOOL)isFrictionlessEnabledForRecipients:(NSArray*)fbids {
+ // we handle arrays of NSString and NSNumber, and throw on anything else
+ for (id fbid in fbids) {
+ NSString* fbidstr;
+ // give us a number, and we convert it to a string
+ if ([fbid isKindOfClass:[NSNumber class]]) {
+ fbidstr = [(NSNumber*)fbid stringValue];
+ } else if ([fbid isKindOfClass:[NSString class]]) {
+ // or give us a string, and we just use it as is
+ fbidstr = (NSString*)fbid;
+ } else {
+ // unexpected type found in the array of fbids
+ @throw [NSException exceptionWithName:NSInvalidArgumentException
+ reason:@"items in fbids must be NSString or NSNumber"
+ userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ [fbid class], @"invalid class",
+ nil]];
+ }
+
+ // if we miss our cache once, we fail the set
+ if (![self isFrictionlessEnabledForRecipient:fbidstr]) {
+ return NO;
+ }
+ }
+ return YES;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// FBRequestDelegate
+
+- (void)request:(FBRequest *)request
+ didLoad:(id)result {
+
+ // a little request bookkeeping
+ self.activeRequest = nil;
+
+ int items = [[result objectForKey: @"data"] count];
+ NSMutableArray* recipients = [[[NSMutableArray alloc] initWithCapacity: items] autorelease];
+
+ for (int i = 0; i < items; i++) {
+ [recipients addObject: [[[result objectForKey: @"data"]
+ objectAtIndex: i]
+ objectForKey: @"recipient_id"]] ;
+ }
+
+ self.allowedRecipients = recipients;
+}
+
+- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
+ // if the request to load the frictionless recipients fails, proceed without updating
+ // the recipients cache; the cache may become invalid due to a failed update or other reasons
+ // (e.g. simultaneous use of the same app from multiple devices), in the case of an invalid
+ // cache, a request dialog may either appear a moment later than it usually would, or appear
+ // briefly when it should not appear at all; in either case the correct request behavior
+ // occurs, and the cache is updated
+ self.activeRequest = nil;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// NSObject
+
+- (void)dealloc {
+ self.activeRequest = nil;
+ self.allowedRecipients = nil;
+ [super dealloc];
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// private helpers
+//
+
+@synthesize allowedRecipients = _allowedRecipients;
+@synthesize activeRequest = _activeRequest;
+
+@end
View
48 Vendor/FacebookSDK/FBLoginDialog.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2010 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#import "FBDialog.h"
+
+@protocol FBLoginDialogDelegate;
+
+/**
+ * Do not use this interface directly, instead, use authorize in Facebook.h
+ *
+ * Facebook Login Dialog interface for start the facebook webView login dialog.
+ * It start pop-ups prompting for credentials and permissions.
+ */
+
+@interface FBLoginDialog : FBDialog {
+ id<FBLoginDialogDelegate> _loginDelegate;
+}
+
+-(id) initWithURL:(NSString *) loginURL
+ loginParams:(NSMutableDictionary *) params
+ delegate:(id <FBLoginDialogDelegate>) delegate;
+@end
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+@protocol FBLoginDialogDelegate <NSObject>
+
+- (void)fbDialogLogin:(NSString*)token expirationDate:(NSDate*)expirationDate;
+
+- (void)fbDialogNotLogin:(BOOL)cancelled;
+
+@end
+
+
View
94 Vendor/FacebookSDK/FBLoginDialog.m
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2010 Facebook
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FBDialog.h"
+#import "FBLoginDialog.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+@implementation FBLoginDialog
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// public
+
+/*
+ * initialize the FBLoginDialog with url and parameters
+ */
+- (id)initWithURL:(NSString*) loginURL
+ loginParams:(NSMutableDictionary*) params
+ delegate:(id <FBLoginDialogDelegate>) delegate{
+
+ self = [super init];
+ _serverURL = [loginURL retain];
+ _params = [params retain];
+ _loginDelegate = delegate;
+ return self;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// FBDialog
+
+/**
+ * Override FBDialog : to call when the webView Dialog did succeed
+ */
+- (void) dialogDidSucceed:(NSURL*)url {
+ NSString *q = [url absoluteString];
+ NSString *token = [self getStringFromUrl:q needle:@"access_token="];
+ NSString *expTime = [self getStringFromUrl:q needle:@"expires_in="];
+ NSDate *expirationDate =nil;
+
+ if (expTime != nil) {
+ int expVal = [expTime intValue];
+ if (expVal == 0) {
+ expirationDate = [NSDate distantFuture];
+ } else {
+ expirationDate = [NSDate dateWithTimeIntervalSinceNow:expVal];
+ }
+ }
+
+ if ((token == (NSString *) [NSNull null]) || (token.length == 0)) {
+ [self dialogDidCancel:url];
+ [self dismissWithSuccess:NO animated:YES];
+ } else {
+ if ([_loginDelegate respondsToSelector:@selector(fbDialogLogin:expirationDate:)]) {
+ [_loginDelegate fbDialogLogin:token expirationDate:expirationDate];
+ }
+ [self dismissWithSuccess:YES animated:YES];
+ }
+
+}
+
+/**
+ * Override FBDialog : to call with the login dialog get canceled
+ */
+- (void)dialogDidCancel:(NSURL *)url {
+ [self dismissWithSuccess:NO animated:YES];
+ if ([_loginDelegate respondsToSelector:@selector(fbDialogNotLogin:)]) {
+ [_loginDelegate fbDialogNotLogin:YES];
+ }
+}
+
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {