From 99657e56e0ee9dda88a57b1fd8b8ec045f76b17a Mon Sep 17 00:00:00 2001 From: jamie Date: Thu, 28 Mar 2013 12:47:44 +0800 Subject: [PATCH 001/278] Use file create time --- wammer/WAPhotoStreamViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wammer/WAPhotoStreamViewController.m b/wammer/WAPhotoStreamViewController.m index 1b26fd98..a9c2440d 100644 --- a/wammer/WAPhotoStreamViewController.m +++ b/wammer/WAPhotoStreamViewController.m @@ -80,7 +80,7 @@ - (void)viewControllerInitialAppeareadOnDayView { NSPredicate *allFromToday = [NSPredicate predicateWithFormat:@"created BETWEEN {%@, %@} AND hidden == NO", [onDate dayBegin], [onDate dayEnd]]; NSMutableArray *unsortedPhotos = [[WAFile MR_findAllWithPredicate:allFromToday inContext:[[WADataStore defaultStore] defaultAutoUpdatedMOC]] mutableCopy]; - NSSortDescriptor *sortByTime = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:NO]; + NSSortDescriptor *sortByTime = [[NSSortDescriptor alloc] initWithKey:@"created" ascending:NO]; [unsortedPhotos sortUsingDescriptors:@[sortByTime]]; _photos = unsortedPhotos; From 04af1dcf3a90b85398cd8e67e1a3ab38dc76f952 Mon Sep 17 00:00:00 2001 From: syshen Date: Thu, 28 Mar 2013 15:38:34 +0800 Subject: [PATCH 002/278] bump --- wammer.xcodeproj/project.pbxproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 06324097..114dedfd 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -4658,7 +4658,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 583; + CURRENT_PROJECT_VERSION = 584; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = ( "WF_USES_TESTFLIGHT=$(WF_USES_TESTFLIGHT)", @@ -5137,7 +5137,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 583; + CURRENT_PROJECT_VERSION = 584; GCC_C_LANGUAGE_STANDARD = c99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -5200,7 +5200,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 583; + CURRENT_PROJECT_VERSION = 584; GCC_C_LANGUAGE_STANDARD = c99; GCC_PREPROCESSOR_DEFINITIONS = ( "WF_USES_TESTFLIGHT=$(WF_USES_TESTFLIGHT)", From 38757b4e9b551f611d74356a9eb71c46bdd63999 Mon Sep 17 00:00:00 2001 From: syshen Date: Thu, 4 Apr 2013 18:55:56 +0800 Subject: [PATCH 003/278] change bundle name and product name --- wammer.xcodeproj/project.pbxproj | 12 ++++++------ .../xcshareddata/xcschemes/wammer-iOS.xcscheme | 8 ++++---- wammer/en.lproj/InfoPlist.strings | 4 ++-- wammer/wammer-iOS-Info.plist | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 114dedfd..320d46ff 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -1785,7 +1785,7 @@ FFCCDF4615B41B0000AEBB85 /* WAUserGlyph@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "WAUserGlyph@2x.png"; path = "Resources/WAUserGlyph@2x.png"; sourceTree = ""; }; FFCD325014B9EA4D0035C4F5 /* WAFile+WAAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WAFile+WAAdditions.h"; sourceTree = ""; }; FFCD325114B9EA4D0035C4F5 /* WAFile+WAAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WAFile+WAAdditions.m"; sourceTree = ""; }; - FFCFE0FB142111E100B9E6AF /* aostream.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = aostream.app; sourceTree = BUILT_PRODUCTS_DIR; }; + FFCFE0FB142111E100B9E6AF /* partio.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = partio.app; sourceTree = BUILT_PRODUCTS_DIR; }; FFD14F0514C5E24C0053116F /* Crashlytics.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = Crashlytics.framework; path = external/CrashlyticsSDK/Crashlytics.framework; sourceTree = ""; }; FFD4F92E157E07F90027BF3F /* IRObjectQueue.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = IRObjectQueue.xcodeproj; path = external/IRObjectQueue/IRObjectQueue.xcodeproj; sourceTree = ""; }; FFD5295515B94DCA008DA71B /* WALocalizedTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WALocalizedTextField.h; sourceTree = ""; }; @@ -2771,7 +2771,7 @@ FF73A53F13D6C2CC00D54EC6 /* Products */ = { isa = PBXGroup; children = ( - FFCFE0FB142111E100B9E6AF /* aostream.app */, + FFCFE0FB142111E100B9E6AF /* partio.app */, 4B8CA96814BBE7BA006E06BB /* UnitTests.octest */, 7D0CDD00162E5A080027D35F /* StreamTests.octest */, ); @@ -3530,7 +3530,7 @@ ); name = "wammer-iOS"; productName = "wammer-iOS"; - productReference = FFCFE0FB142111E100B9E6AF /* aostream.app */; + productReference = FFCFE0FB142111E100B9E6AF /* partio.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -4764,7 +4764,7 @@ "-weak_framework", Social, ); - PRODUCT_NAME = aostream; + PRODUCT_NAME = partio; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; STREAM_BUNDLE_ID_SUFFIX = .beta; @@ -5305,7 +5305,7 @@ "-weak_framework", Social, ); - PRODUCT_NAME = aostream; + PRODUCT_NAME = partio; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; STREAM_BUNDLE_ID_SUFFIX = .develop; @@ -5374,7 +5374,7 @@ "-weak_framework", Social, ); - PRODUCT_NAME = aostream; + PRODUCT_NAME = partio; PROVISIONING_PROFILE = ""; SDKROOT = iphoneos; STREAM_BUNDLE_ID_SUFFIX = ""; diff --git a/wammer.xcodeproj/xcshareddata/xcschemes/wammer-iOS.xcscheme b/wammer.xcodeproj/xcshareddata/xcschemes/wammer-iOS.xcscheme index 0a89ca82..42b1dea6 100644 --- a/wammer.xcodeproj/xcshareddata/xcschemes/wammer-iOS.xcscheme +++ b/wammer.xcodeproj/xcshareddata/xcschemes/wammer-iOS.xcscheme @@ -15,7 +15,7 @@ @@ -53,7 +53,7 @@ @@ -72,7 +72,7 @@ @@ -108,7 +108,7 @@ diff --git a/wammer/en.lproj/InfoPlist.strings b/wammer/en.lproj/InfoPlist.strings index db5e5b5c..31105e0c 100644 --- a/wammer/en.lproj/InfoPlist.strings +++ b/wammer/en.lproj/InfoPlist.strings @@ -1,4 +1,4 @@ /* Localized versions of Info.plist keys */ -"CFBundleName" = "aostream"; -"CFBundleDisplayName" = "aostream"; +"CFBundleName" = "partio"; +"CFBundleDisplayName" = "partio"; diff --git a/wammer/wammer-iOS-Info.plist b/wammer/wammer-iOS-Info.plist index 1a747cbc..60dd11a5 100644 --- a/wammer/wammer-iOS-Info.plist +++ b/wammer/wammer-iOS-Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - aostream + partio CFBundleExecutable ${EXECUTABLE_NAME} CFBundleGetInfoString @@ -26,7 +26,7 @@ CFBundleIdentifier - com.waveface.stream-iphone${STREAM_BUNDLE_ID_SUFFIX} + com.waveface.partio-iphone${STREAM_BUNDLE_ID_SUFFIX} CFBundleInfoDictionaryVersion 6.0 CFBundleName From fbf5cfc57fcefdeefc5eb87a9348ce004a2e21b3 Mon Sep 17 00:00:00 2001 From: syshen Date: Mon, 8 Apr 2013 15:29:43 +0800 Subject: [PATCH 004/278] partio initial UI with Photo highlights and photo timeline views --- WAPhotoCollageCell_Stack1.xib | 297 +++++ wammer.xcodeproj/project.pbxproj | 156 ++- wammer/FBRequestConnection+WAAdditions.h | 15 + wammer/FBRequestConnection+WAAdditions.m | 79 ++ wammer/WAAppDelegate_iOS.m | 73 +- wammer/WAAssetsLibraryManager.h | 2 + wammer/WAAssetsLibraryManager.m | 95 +- ...WACheckin+WARemoteInterfaceEntitySyncing.h | 13 + ...WACheckin+WARemoteInterfaceEntitySyncing.m | 75 ++ wammer/WACheckin.h | 22 + wammer/WACheckin.m | 20 + wammer/WAFirstUseIntroView.xib | 32 +- wammer/WAGeoLocation.h | 16 + wammer/WAGeoLocation.m | 158 +++ wammer/WAModel.xcdatamodeld/.xccurrentversion | 2 +- .../WAModel 43.xcdatamodel/contents | 9 +- .../WAModel 44.xcdatamodel/contents | 330 ++++++ wammer/WAPartioFirstUse.storyboard | 117 ++ wammer/WAPartioFirstUseViewController.h | 18 + wammer/WAPartioFirstUseViewController.m | 55 + wammer/WAPartioWelcomeViewController.h | 13 + wammer/WAPartioWelcomeViewController.m | 129 +++ wammer/WAPhotoCollageCell.h | 15 + wammer/WAPhotoCollageCell.m | 40 + wammer/WAPhotoCollageCell_Stack2.xib | 424 +++++++ wammer/WAPhotoCollageCell_Stack3.xib | 551 +++++++++ wammer/WAPhotoCollageCell_Stack4.xib | 678 +++++++++++ wammer/WAPhotoHighlightViewCell.h | 22 + wammer/WAPhotoHighlightViewCell.m | 40 + wammer/WAPhotoHighlightViewCell.xib | 660 +++++++++++ wammer/WAPhotoHighlightsViewController.h | 13 + wammer/WAPhotoHighlightsViewController.m | 300 +++++ wammer/WAPhotoHighlightsViewController.xib | 145 +++ wammer/WAPhotoTimelineCover.h | 20 + wammer/WAPhotoTimelineCover.m | 46 + wammer/WAPhotoTimelineCover.xib | 1032 +++++++++++++++++ wammer/WAPhotoTimelineLayout.h | 13 + wammer/WAPhotoTimelineLayout.m | 46 + wammer/WAPhotoTimelineNavigationBar.h | 15 + wammer/WAPhotoTimelineNavigationBar.m | 74 ++ wammer/WAPhotoTimelineViewController.h | 16 + wammer/WAPhotoTimelineViewController.m | 404 +++++++ wammer/WAPhotoTimelineViewController.xib | 480 ++++++++ wammer/WATimelineIndexView.h | 16 + wammer/WATimelineIndexView.m | 183 +++ 45 files changed, 6869 insertions(+), 90 deletions(-) create mode 100644 WAPhotoCollageCell_Stack1.xib create mode 100644 wammer/FBRequestConnection+WAAdditions.h create mode 100644 wammer/FBRequestConnection+WAAdditions.m create mode 100644 wammer/WACheckin+WARemoteInterfaceEntitySyncing.h create mode 100644 wammer/WACheckin+WARemoteInterfaceEntitySyncing.m create mode 100644 wammer/WACheckin.h create mode 100644 wammer/WACheckin.m create mode 100644 wammer/WAGeoLocation.h create mode 100644 wammer/WAGeoLocation.m create mode 100644 wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents create mode 100644 wammer/WAPartioFirstUse.storyboard create mode 100644 wammer/WAPartioFirstUseViewController.h create mode 100644 wammer/WAPartioFirstUseViewController.m create mode 100644 wammer/WAPartioWelcomeViewController.h create mode 100644 wammer/WAPartioWelcomeViewController.m create mode 100644 wammer/WAPhotoCollageCell.h create mode 100644 wammer/WAPhotoCollageCell.m create mode 100644 wammer/WAPhotoCollageCell_Stack2.xib create mode 100644 wammer/WAPhotoCollageCell_Stack3.xib create mode 100644 wammer/WAPhotoCollageCell_Stack4.xib create mode 100644 wammer/WAPhotoHighlightViewCell.h create mode 100644 wammer/WAPhotoHighlightViewCell.m create mode 100644 wammer/WAPhotoHighlightViewCell.xib create mode 100644 wammer/WAPhotoHighlightsViewController.h create mode 100644 wammer/WAPhotoHighlightsViewController.m create mode 100644 wammer/WAPhotoHighlightsViewController.xib create mode 100644 wammer/WAPhotoTimelineCover.h create mode 100644 wammer/WAPhotoTimelineCover.m create mode 100644 wammer/WAPhotoTimelineCover.xib create mode 100644 wammer/WAPhotoTimelineLayout.h create mode 100644 wammer/WAPhotoTimelineLayout.m create mode 100644 wammer/WAPhotoTimelineNavigationBar.h create mode 100644 wammer/WAPhotoTimelineNavigationBar.m create mode 100644 wammer/WAPhotoTimelineViewController.h create mode 100644 wammer/WAPhotoTimelineViewController.m create mode 100644 wammer/WAPhotoTimelineViewController.xib create mode 100644 wammer/WATimelineIndexView.h create mode 100644 wammer/WATimelineIndexView.m diff --git a/WAPhotoCollageCell_Stack1.xib b/WAPhotoCollageCell_Stack1.xib new file mode 100644 index 00000000..5082faff --- /dev/null +++ b/WAPhotoCollageCell_Stack1.xib @@ -0,0 +1,297 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionViewCell + IBUIImageView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 1292 + + + + 1280 + + + + 1298 + {{10, 5}, {300, 200}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + {320, 210} + + + + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + {320, 210} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + + imageViews + + + NSArray + NO + + 10 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + 9 + 0 + + 9 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + 0 + + 0 + 1 + + 300 + + 1000 + + 3 + 9 + 1 + + + + 8 + 0 + + 0 + 1 + + 200 + + 1000 + + 3 + 9 + 1 + + + + + + 7 + + + + + 8 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoCollageCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 10 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + UICollectionViewCell + UICollectionReusableView + + IBProjectSource + ./Classes/UICollectionViewCell.h + + + + WAPhotoCollageCell + UICollectionViewCell + + imageViews + + imageViews + UIImageView + NSArray + + + + IBProjectSource + ./Classes/WAPhotoCollageCell.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 320d46ff..e1a1f31b 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -219,6 +219,18 @@ 80074F97167F204400A23EED /* WAWebStreamViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80074F96167F204400A23EED /* WAWebStreamViewCell.xib */; }; 800770E016797AE70085E525 /* WATimelineViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = DEBED834166C8801001A2B24 /* WATimelineViewCell.m */; }; 800770E3167982850085E525 /* WAFoursquareConnectSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = 800770E2167982850085E525 /* WAFoursquareConnectSwitch.m */; }; + 80090B47170E8BBF005AF6B8 /* WAGeoLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B46170E8BBF005AF6B8 /* WAGeoLocation.m */; }; + 80090B4F170EC817005AF6B8 /* WAPhotoTimelineViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B4D170EC817005AF6B8 /* WAPhotoTimelineViewController.m */; }; + 80090B50170EC817005AF6B8 /* WAPhotoTimelineViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B4E170EC817005AF6B8 /* WAPhotoTimelineViewController.xib */; }; + 80090B53170EC8A5005AF6B8 /* WAPhotoTimelineLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B52170EC8A5005AF6B8 /* WAPhotoTimelineLayout.m */; }; + 80090B56170EC929005AF6B8 /* WAPhotoTimelineNavigationBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B55170EC929005AF6B8 /* WAPhotoTimelineNavigationBar.m */; }; + 80090B59170EC9D8005AF6B8 /* WAPhotoTimelineCover.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B58170EC9D8005AF6B8 /* WAPhotoTimelineCover.m */; }; + 80090B5B170EC9FE005AF6B8 /* WAPhotoTimelineCover.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B5A170EC9FD005AF6B8 /* WAPhotoTimelineCover.xib */; }; + 80090B5E170ECE28005AF6B8 /* WAPhotoCollageCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80090B5D170ECE28005AF6B8 /* WAPhotoCollageCell.m */; }; + 80090B60170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */; }; + 80090B62170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */; }; + 80090B64170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */; }; + 80090B66170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */; }; 80092D3916AFD5A000020F64 /* WADataPlanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80092D3816AFD5A000020F64 /* WADataPlanViewController.m */; }; 800D9A9216719B5D0034CDF6 /* MKMapView+ZoomLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 800D9A9116719B5D0034CDF6 /* MKMapView+ZoomLevel.m */; }; 800E4FCE1671DD0C00F50E0B /* WATimelineViewCell-Checkin.xib in Resources */ = {isa = PBXBuildFile; fileRef = 800E4FCD1671DD0C00F50E0B /* WATimelineViewCell-Checkin.xib */; }; @@ -228,6 +240,7 @@ 8023BAF116770D2B00E6BED2 /* pindrop.png in Resources */ = {isa = PBXBuildFile; fileRef = 8023BAEF16770D2A00E6BED2 /* pindrop.png */; }; 8023BAF216770D2B00E6BED2 /* pindrop@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8023BAF016770D2A00E6BED2 /* pindrop@2x.png */; }; 802427091689E1AF002454A7 /* WACollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 802427081689E1AF002454A7 /* WACollection.m */; }; + 8027264F1710078800BB1733 /* WATimelineIndexView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8027264E1710078800BB1733 /* WATimelineIndexView.m */; }; 802FFDA816DF642A00237762 /* downloadStation.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA516DF642A00237762 /* downloadStation.png */; }; 802FFDA916DF642A00237762 /* Intro1.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA616DF642A00237762 /* Intro1.png */; }; 802FFDAA16DF642A00237762 /* Intro2.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA716DF642A00237762 /* Intro2.png */; }; @@ -315,6 +328,10 @@ 80B0A38B16D75C3E00E391D2 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80B0A38A16D75C3E00E391D2 /* ImageIO.framework */; }; 80B0A38D16D75C5400E391D2 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80B0A38C16D75C5400E391D2 /* OpenGLES.framework */; }; 80B0A38F16D75F2300E391D2 /* GoogleMaps.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 80B0A38E16D75F2300E391D2 /* GoogleMaps.bundle */; }; + 80B1138E170DD0D90087EBC4 /* WAPhotoHighlightsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80B1138C170DD0D90087EBC4 /* WAPhotoHighlightsViewController.m */; }; + 80B1138F170DD0D90087EBC4 /* WAPhotoHighlightsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80B1138D170DD0D90087EBC4 /* WAPhotoHighlightsViewController.xib */; }; + 80B11391170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80B11390170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib */; }; + 80B11394170DD1450087EBC4 /* WAPhotoHighlightViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80B11393170DD1450087EBC4 /* WAPhotoHighlightViewCell.m */; }; 80B143FD16BA7F6E009A5FA9 /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 80B143FC16BA7F6E009A5FA9 /* Twitter.framework */; }; 80B1440E16BA8157009A5FA9 /* OAuth+Additions.m in Sources */ = {isa = PBXBuildFile; fileRef = 80B1440D16BA8156009A5FA9 /* OAuth+Additions.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 80B1441116BA8479009A5FA9 /* OAuthCore.m in Sources */ = {isa = PBXBuildFile; fileRef = 80B1441016BA8478009A5FA9 /* OAuthCore.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; @@ -360,6 +377,12 @@ 80C6FD9316D766F100D450D3 /* FourSquareLogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 80C6FD9116D766F100D450D3 /* FourSquareLogo.png */; }; 80C6FD9416D766F100D450D3 /* GoogleLogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 80C6FD9216D766F100D450D3 /* GoogleLogo.png */; }; 80C6FD9616D7671900D450D3 /* twitterLogo.png in Resources */ = {isa = PBXBuildFile; fileRef = 80C6FD9516D7671900D450D3 /* twitterLogo.png */; }; + 80C768DE17105789000F10A8 /* WAPartioFirstUse.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 80C768DD17105789000F10A8 /* WAPartioFirstUse.storyboard */; }; + 80C768E117105BEA000F10A8 /* WAPartioFirstUseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768E017105BEA000F10A8 /* WAPartioFirstUseViewController.m */; }; + 80C768E717105CFC000F10A8 /* WAPartioWelcomeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768E617105CFC000F10A8 /* WAPartioWelcomeViewController.m */; }; + 80C768EA1710789D000F10A8 /* FBRequestConnection+WAAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768E91710789D000F10A8 /* FBRequestConnection+WAAdditions.m */; }; + 80C768EE1711B9D5000F10A8 /* WACheckin.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768ED1711B9D5000F10A8 /* WACheckin.m */; }; + 80C768F21711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768F11711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m */; }; 80C979F71649796A004F0CF4 /* EventCardBG.png in Resources */ = {isa = PBXBuildFile; fileRef = 80C979F61649796A004F0CF4 /* EventCardBG.png */; }; 80DA984F16496FED0030CA21 /* WAEventHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DA984216496FED0030CA21 /* WAEventHeaderView.m */; }; 80DA985116496FED0030CA21 /* WAEventLinkViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DA984516496FED0030CA21 /* WAEventLinkViewCell.m */; }; @@ -1168,6 +1191,24 @@ 80074F96167F204400A23EED /* WAWebStreamViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WAWebStreamViewCell.xib; sourceTree = ""; }; 800770E1167982850085E525 /* WAFoursquareConnectSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAFoursquareConnectSwitch.h; path = wammer/WAFoursquareConnectSwitch.h; sourceTree = ""; }; 800770E2167982850085E525 /* WAFoursquareConnectSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAFoursquareConnectSwitch.m; path = wammer/WAFoursquareConnectSwitch.m; sourceTree = ""; }; + 80090B45170E8BBF005AF6B8 /* WAGeoLocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAGeoLocation.h; path = wammer/WAGeoLocation.h; sourceTree = ""; }; + 80090B46170E8BBF005AF6B8 /* WAGeoLocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAGeoLocation.m; path = wammer/WAGeoLocation.m; sourceTree = ""; }; + 80090B4C170EC817005AF6B8 /* WAPhotoTimelineViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoTimelineViewController.h; path = wammer/WAPhotoTimelineViewController.h; sourceTree = ""; }; + 80090B4D170EC817005AF6B8 /* WAPhotoTimelineViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoTimelineViewController.m; path = wammer/WAPhotoTimelineViewController.m; sourceTree = ""; }; + 80090B4E170EC817005AF6B8 /* WAPhotoTimelineViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoTimelineViewController.xib; path = wammer/WAPhotoTimelineViewController.xib; sourceTree = ""; }; + 80090B51170EC8A5005AF6B8 /* WAPhotoTimelineLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoTimelineLayout.h; path = wammer/WAPhotoTimelineLayout.h; sourceTree = ""; }; + 80090B52170EC8A5005AF6B8 /* WAPhotoTimelineLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoTimelineLayout.m; path = wammer/WAPhotoTimelineLayout.m; sourceTree = ""; }; + 80090B54170EC928005AF6B8 /* WAPhotoTimelineNavigationBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoTimelineNavigationBar.h; path = wammer/WAPhotoTimelineNavigationBar.h; sourceTree = ""; }; + 80090B55170EC929005AF6B8 /* WAPhotoTimelineNavigationBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoTimelineNavigationBar.m; path = wammer/WAPhotoTimelineNavigationBar.m; sourceTree = ""; }; + 80090B57170EC9D8005AF6B8 /* WAPhotoTimelineCover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoTimelineCover.h; path = wammer/WAPhotoTimelineCover.h; sourceTree = ""; }; + 80090B58170EC9D8005AF6B8 /* WAPhotoTimelineCover.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoTimelineCover.m; path = wammer/WAPhotoTimelineCover.m; sourceTree = ""; }; + 80090B5A170EC9FD005AF6B8 /* WAPhotoTimelineCover.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoTimelineCover.xib; path = wammer/WAPhotoTimelineCover.xib; sourceTree = ""; }; + 80090B5C170ECE28005AF6B8 /* WAPhotoCollageCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoCollageCell.h; path = wammer/WAPhotoCollageCell.h; sourceTree = ""; }; + 80090B5D170ECE28005AF6B8 /* WAPhotoCollageCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoCollageCell.m; path = wammer/WAPhotoCollageCell.m; sourceTree = ""; }; + 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack4.xib; path = wammer/WAPhotoCollageCell_Stack4.xib; sourceTree = ""; }; + 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack3.xib; path = wammer/WAPhotoCollageCell_Stack3.xib; sourceTree = ""; }; + 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack2.xib; path = wammer/WAPhotoCollageCell_Stack2.xib; sourceTree = ""; }; + 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WAPhotoCollageCell_Stack1.xib; sourceTree = ""; }; 80092D3716AFD5A000020F64 /* WADataPlanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WADataPlanViewController.h; path = wammer/WADataPlanViewController.h; sourceTree = ""; }; 80092D3816AFD5A000020F64 /* WADataPlanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WADataPlanViewController.m; path = wammer/WADataPlanViewController.m; sourceTree = ""; }; 800D9A9016719B5D0034CDF6 /* MKMapView+ZoomLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MKMapView+ZoomLevel.h"; path = "wammer/MKMapView+ZoomLevel.h"; sourceTree = ""; }; @@ -1183,6 +1224,8 @@ 8023BAF016770D2A00E6BED2 /* pindrop@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "pindrop@2x.png"; path = "Resources/pindrop@2x.png"; sourceTree = ""; }; 802427071689E1AF002454A7 /* WACollection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WACollection.h; sourceTree = ""; }; 802427081689E1AF002454A7 /* WACollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACollection.m; sourceTree = ""; }; + 8027264D1710078800BB1733 /* WATimelineIndexView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WATimelineIndexView.h; path = wammer/WATimelineIndexView.h; sourceTree = ""; }; + 8027264E1710078800BB1733 /* WATimelineIndexView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WATimelineIndexView.m; path = wammer/WATimelineIndexView.m; sourceTree = ""; }; 802FFDA516DF642A00237762 /* downloadStation.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = downloadStation.png; path = Resources/downloadStation.png; sourceTree = ""; }; 802FFDA616DF642A00237762 /* Intro1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Intro1.png; path = Resources/Intro1.png; sourceTree = ""; }; 802FFDA716DF642A00237762 /* Intro2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Intro2.png; path = Resources/Intro2.png; sourceTree = ""; }; @@ -1299,6 +1342,12 @@ 80B0A38A16D75C3E00E391D2 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = System/Library/Frameworks/ImageIO.framework; sourceTree = SDKROOT; }; 80B0A38C16D75C5400E391D2 /* OpenGLES.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGLES.framework; path = System/Library/Frameworks/OpenGLES.framework; sourceTree = SDKROOT; }; 80B0A38E16D75F2300E391D2 /* GoogleMaps.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = GoogleMaps.bundle; path = wammer/Libraries/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle; sourceTree = ""; }; + 80B1138B170DD0D90087EBC4 /* WAPhotoHighlightsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoHighlightsViewController.h; path = wammer/WAPhotoHighlightsViewController.h; sourceTree = ""; }; + 80B1138C170DD0D90087EBC4 /* WAPhotoHighlightsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoHighlightsViewController.m; path = wammer/WAPhotoHighlightsViewController.m; sourceTree = ""; }; + 80B1138D170DD0D90087EBC4 /* WAPhotoHighlightsViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoHighlightsViewController.xib; path = wammer/WAPhotoHighlightsViewController.xib; sourceTree = ""; }; + 80B11390170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoHighlightViewCell.xib; path = wammer/WAPhotoHighlightViewCell.xib; sourceTree = ""; }; + 80B11392170DD1450087EBC4 /* WAPhotoHighlightViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPhotoHighlightViewCell.h; path = wammer/WAPhotoHighlightViewCell.h; sourceTree = ""; }; + 80B11393170DD1450087EBC4 /* WAPhotoHighlightViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPhotoHighlightViewCell.m; path = wammer/WAPhotoHighlightViewCell.m; sourceTree = ""; }; 80B143FC16BA7F6E009A5FA9 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; 80B1440C16BA8156009A5FA9 /* OAuth+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "OAuth+Additions.h"; path = "external/TWReverseAuth/Source/Vendor/ABOAuthCore/OAuth+Additions.h"; sourceTree = ""; }; 80B1440D16BA8156009A5FA9 /* OAuth+Additions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "OAuth+Additions.m"; path = "external/TWReverseAuth/Source/Vendor/ABOAuthCore/OAuth+Additions.m"; sourceTree = ""; }; @@ -1354,6 +1403,18 @@ 80C6FD9116D766F100D450D3 /* FourSquareLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = FourSquareLogo.png; path = Resources/FourSquareLogo.png; sourceTree = ""; }; 80C6FD9216D766F100D450D3 /* GoogleLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = GoogleLogo.png; path = Resources/GoogleLogo.png; sourceTree = ""; }; 80C6FD9516D7671900D450D3 /* twitterLogo.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = twitterLogo.png; path = Resources/twitterLogo.png; sourceTree = ""; }; + 80C768DD17105789000F10A8 /* WAPartioFirstUse.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = WAPartioFirstUse.storyboard; path = wammer/WAPartioFirstUse.storyboard; sourceTree = ""; }; + 80C768DF17105BEA000F10A8 /* WAPartioFirstUseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPartioFirstUseViewController.h; path = wammer/WAPartioFirstUseViewController.h; sourceTree = ""; }; + 80C768E017105BEA000F10A8 /* WAPartioFirstUseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPartioFirstUseViewController.m; path = wammer/WAPartioFirstUseViewController.m; sourceTree = ""; }; + 80C768E517105CFC000F10A8 /* WAPartioWelcomeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPartioWelcomeViewController.h; path = wammer/WAPartioWelcomeViewController.h; sourceTree = ""; }; + 80C768E617105CFC000F10A8 /* WAPartioWelcomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPartioWelcomeViewController.m; path = wammer/WAPartioWelcomeViewController.m; sourceTree = ""; }; + 80C768E81710789D000F10A8 /* FBRequestConnection+WAAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "FBRequestConnection+WAAdditions.h"; path = "wammer/FBRequestConnection+WAAdditions.h"; sourceTree = ""; }; + 80C768E91710789D000F10A8 /* FBRequestConnection+WAAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "FBRequestConnection+WAAdditions.m"; path = "wammer/FBRequestConnection+WAAdditions.m"; sourceTree = ""; }; + 80C768EB1711B84B000F10A8 /* WAModel 44.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = file; path = "WAModel 44.xcdatamodel"; sourceTree = ""; }; + 80C768EC1711B9D5000F10A8 /* WACheckin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WACheckin.h; sourceTree = ""; }; + 80C768ED1711B9D5000F10A8 /* WACheckin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACheckin.m; sourceTree = ""; }; + 80C768F01711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WACheckin+WARemoteInterfaceEntitySyncing.h"; sourceTree = ""; }; + 80C768F11711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WACheckin+WARemoteInterfaceEntitySyncing.m"; sourceTree = ""; }; 80C979F61649796A004F0CF4 /* EventCardBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = EventCardBG.png; path = Resources/EventCardBG.png; sourceTree = ""; }; 80DA984116496FED0030CA21 /* WAEventHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAEventHeaderView.h; path = wammer/WAEventHeaderView.h; sourceTree = ""; }; 80DA984216496FED0030CA21 /* WAEventHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAEventHeaderView.m; path = wammer/WAEventHeaderView.m; sourceTree = ""; }; @@ -2321,6 +2382,31 @@ path = wammer; sourceTree = ""; }; + 80090B48170EC74A005AF6B8 /* New Event View */ = { + isa = PBXGroup; + children = ( + 80090B4C170EC817005AF6B8 /* WAPhotoTimelineViewController.h */, + 80090B4D170EC817005AF6B8 /* WAPhotoTimelineViewController.m */, + 80090B4E170EC817005AF6B8 /* WAPhotoTimelineViewController.xib */, + 80090B54170EC928005AF6B8 /* WAPhotoTimelineNavigationBar.h */, + 80090B55170EC929005AF6B8 /* WAPhotoTimelineNavigationBar.m */, + 80090B51170EC8A5005AF6B8 /* WAPhotoTimelineLayout.h */, + 80090B52170EC8A5005AF6B8 /* WAPhotoTimelineLayout.m */, + 80090B57170EC9D8005AF6B8 /* WAPhotoTimelineCover.h */, + 80090B58170EC9D8005AF6B8 /* WAPhotoTimelineCover.m */, + 80090B5A170EC9FD005AF6B8 /* WAPhotoTimelineCover.xib */, + 80090B5C170ECE28005AF6B8 /* WAPhotoCollageCell.h */, + 80090B5D170ECE28005AF6B8 /* WAPhotoCollageCell.m */, + 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */, + 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */, + 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */, + 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */, + 8027264D1710078800BB1733 /* WATimelineIndexView.h */, + 8027264E1710078800BB1733 /* WATimelineIndexView.m */, + ); + name = "New Event View"; + sourceTree = ""; + }; 80092D3316AFD46400020F64 /* Data Plan */ = { isa = PBXGroup; children = ( @@ -2420,6 +2506,44 @@ name = "Event View"; sourceTree = ""; }; + 80B1137D170DD08D0087EBC4 /* Photo Groups */ = { + isa = PBXGroup; + children = ( + 80090B45170E8BBF005AF6B8 /* WAGeoLocation.h */, + 80090B46170E8BBF005AF6B8 /* WAGeoLocation.m */, + 80C768E81710789D000F10A8 /* FBRequestConnection+WAAdditions.h */, + 80C768E91710789D000F10A8 /* FBRequestConnection+WAAdditions.m */, + 80B1138B170DD0D90087EBC4 /* WAPhotoHighlightsViewController.h */, + 80B1138C170DD0D90087EBC4 /* WAPhotoHighlightsViewController.m */, + 80B1138D170DD0D90087EBC4 /* WAPhotoHighlightsViewController.xib */, + 80B11390170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib */, + 80B11392170DD1450087EBC4 /* WAPhotoHighlightViewCell.h */, + 80B11393170DD1450087EBC4 /* WAPhotoHighlightViewCell.m */, + ); + name = "Photo Groups"; + sourceTree = ""; + }; + 80C768DC17105683000F10A8 /* Partio Welcome */ = { + isa = PBXGroup; + children = ( + 80C768DD17105789000F10A8 /* WAPartioFirstUse.storyboard */, + 80C768DF17105BEA000F10A8 /* WAPartioFirstUseViewController.h */, + 80C768E017105BEA000F10A8 /* WAPartioFirstUseViewController.m */, + 80C768E517105CFC000F10A8 /* WAPartioWelcomeViewController.h */, + 80C768E617105CFC000F10A8 /* WAPartioWelcomeViewController.m */, + ); + name = "Partio Welcome"; + sourceTree = ""; + }; + 80C768EF1711B9DF000F10A8 /* Checkin */ = { + isa = PBXGroup; + children = ( + 80C768EC1711B9D5000F10A8 /* WACheckin.h */, + 80C768ED1711B9D5000F10A8 /* WACheckin.m */, + ); + name = Checkin; + sourceTree = ""; + }; 80DAA56A16BA7BD100A4E352 /* TwitterReverseAuth */ = { isa = PBXGroup; children = ( @@ -2729,6 +2853,9 @@ FF73A53313D6C2CC00D54EC6 = { isa = PBXGroup; children = ( + 80C768DC17105683000F10A8 /* Partio Welcome */, + 80090B48170EC74A005AF6B8 /* New Event View */, + 80B1137D170DD08D0087EBC4 /* Photo Groups */, DE7B38A0165CBB9900718262 /* Calendar Picker */, 7D0CDD04162E5A080027D35F /* StreamTests */, 4B8CA96F14BBE7BA006E06BB /* UnitTests */, @@ -2883,6 +3010,7 @@ FF4BDEAB156A535300C105D5 /* Article */, 132D60341622B66F00148829 /* Cache */, 7D7A4431164CF85800E156CF /* Collection */, + 80C768EF1711B9DF000F10A8 /* Checkin */, FF4BDEAC156A539100C105D5 /* Data Store */, FF4BDEAD156A53AD00C105D5 /* File */, 13B6DB9E1615740C00B9CC35 /* FileExif */, @@ -2978,6 +3106,8 @@ 4BB6A9041696BBA300AB5F14 /* WACollection+RemoteOperations.m */, 13C17D6E169C142F00F909E5 /* WAStation+WARemoteInterfaceEntitySyncing.h */, 13C17D6F169C142F00F909E5 /* WAStation+WARemoteInterfaceEntitySyncing.m */, + 80C768F01711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.h */, + 80C768F11711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m */, ); name = "Data Store Additions"; sourceTree = ""; @@ -4058,6 +4188,15 @@ 802FFDBE16DF8DB900237762 /* coachmark-568h.png in Resources */, 802FFDBF16DF8DB900237762 /* coachmark.png in Resources */, 8093C70216F3239700C7D001 /* WACollectionPickerCell.xib in Resources */, + 80B1138F170DD0D90087EBC4 /* WAPhotoHighlightsViewController.xib in Resources */, + 80B11391170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib in Resources */, + 80090B50170EC817005AF6B8 /* WAPhotoTimelineViewController.xib in Resources */, + 80090B5B170EC9FE005AF6B8 /* WAPhotoTimelineCover.xib in Resources */, + 80090B60170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib in Resources */, + 80090B62170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib in Resources */, + 80090B64170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib in Resources */, + 80090B66170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib in Resources */, + 80C768DE17105789000F10A8 /* WAPartioFirstUse.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4541,6 +4680,20 @@ 800F240E16F2D3DC000157C1 /* WAFile.m in Sources */, 8093C6F116F3236F00C7D001 /* WACollectionPickerCell.m in Sources */, 80FA833816F9E79B003BF983 /* WAEventPhotoAddingCell.m in Sources */, + 80B1138E170DD0D90087EBC4 /* WAPhotoHighlightsViewController.m in Sources */, + 80B11394170DD1450087EBC4 /* WAPhotoHighlightViewCell.m in Sources */, + 80090B47170E8BBF005AF6B8 /* WAGeoLocation.m in Sources */, + 80090B4F170EC817005AF6B8 /* WAPhotoTimelineViewController.m in Sources */, + 80090B53170EC8A5005AF6B8 /* WAPhotoTimelineLayout.m in Sources */, + 80090B56170EC929005AF6B8 /* WAPhotoTimelineNavigationBar.m in Sources */, + 80090B59170EC9D8005AF6B8 /* WAPhotoTimelineCover.m in Sources */, + 80090B5E170ECE28005AF6B8 /* WAPhotoCollageCell.m in Sources */, + 8027264F1710078800BB1733 /* WATimelineIndexView.m in Sources */, + 80C768E117105BEA000F10A8 /* WAPartioFirstUseViewController.m in Sources */, + 80C768E717105CFC000F10A8 /* WAPartioWelcomeViewController.m in Sources */, + 80C768EA1710789D000F10A8 /* FBRequestConnection+WAAdditions.m in Sources */, + 80C768EE1711B9D5000F10A8 /* WACheckin.m in Sources */, + 80C768F21711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5436,9 +5589,10 @@ 4B603C4C16C37D6C003692CB /* WAModel.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 80C768EB1711B84B000F10A8 /* WAModel 44.xcdatamodel */, 4B603C4D16C37D6C003692CB /* WAModel 43.xcdatamodel */, ); - currentVersion = 4B603C4D16C37D6C003692CB /* WAModel 43.xcdatamodel */; + currentVersion = 80C768EB1711B84B000F10A8 /* WAModel 44.xcdatamodel */; path = WAModel.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/wammer/FBRequestConnection+WAAdditions.h b/wammer/FBRequestConnection+WAAdditions.h new file mode 100644 index 00000000..83b43eda --- /dev/null +++ b/wammer/FBRequestConnection+WAAdditions.h @@ -0,0 +1,15 @@ +// +// FBRequestConnection+WAAdditions.h +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface FBRequestConnection (WAAdditions) + ++ (FBRequestConnection*)startForUserCheckinsAfterId:(NSNumber*)latestCheckinID completeHandler:(FBRequestHandler)completionBlock; + +@end diff --git a/wammer/FBRequestConnection+WAAdditions.m b/wammer/FBRequestConnection+WAAdditions.m new file mode 100644 index 00000000..49d0b2e6 --- /dev/null +++ b/wammer/FBRequestConnection+WAAdditions.m @@ -0,0 +1,79 @@ +// +// FBRequestConnection+WAAdditions.m +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "FBRequestConnection+WAAdditions.h" + +@implementation FBRequestConnection (WAAdditions) + ++ (FBRequestConnection*)startForUserCheckinsAfterId:(NSNumber*)checkinID completeHandler:(FBRequestHandler)completionBlock { + + NSString *checkinQueryName = @"checkinQuery"; + NSString *placeQueryName = @"placeQuery"; + NSDictionary *queries = @{ + checkinQueryName:@"SELECT checkin_id,coords,tagged_uids,page_id,message,timestamp FROM checkin WHERE author_uid = me()", + placeQueryName:[NSString stringWithFormat:@"SELECT name,page_id from place WHERE page_id IN (SELECT page_id FROM #%@)", checkinQueryName] + }; + + + NSString *queryString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:queries options:0 error:nil] encoding:NSUTF8StringEncoding]; + + NSLog(@"query: %@", queryString); + return [FBRequestConnection startWithGraphPath:@"/fql" + parameters:@{@"q":queryString} + HTTPMethod:@"GET" + completionHandler:^(FBRequestConnection *connection, NSDictionary *response, NSError *error) { + + if (error) { + completionBlock(connection, nil, error); + return; + } + + NSArray *data = response[@"data"]; + if (!data) { + completionBlock(connection, nil, [NSError errorWithDomain:@"FBResponse" code:-1 userInfo:nil]); + return; + } + + + NSMutableArray *returningList = [NSMutableArray array]; + NSArray *checkinList = @[]; + NSArray *placeList = @[]; + + for (NSDictionary *results in data) { + NSArray *resultSet = results[@"fql_result_set"]; + NSString *queryName = results[@"name"]; + + if ([queryName isEqualToString:checkinQueryName]) { + checkinList = [NSMutableArray arrayWithArray:resultSet]; + } else if ([queryName isEqualToString:placeQueryName]) { + placeList = [NSArray arrayWithArray:resultSet]; + } + } + + for (NSDictionary *place in placeList) { + + if (!place[@"page_id"]) + continue; + + for (NSDictionary *checkin in checkinList) { + if ([place[@"page_id"] isEqualToNumber:checkin[@"page_id"]]) { + NSMutableDictionary *returningItem = [NSMutableDictionary dictionaryWithDictionary:checkin]; + returningItem[@"name"] = place[@"name"]; + [returningList addObject:returningItem]; + break; + } + } + + } + + completionBlock(connection, [NSArray arrayWithArray:returningList], nil); + }]; + +} + +@end diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 9cc54c6b..538eb069 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -30,6 +30,9 @@ #import "WAUserInfoViewController.h" #import "WAOverlayBezel.h" +#import "WAPhotoHighlightsViewController.h" +#import "WAPartioFirstUseViewController.h" + #import "Foundation+IRAdditions.h" #import "UIKit+IRAdditions.h" @@ -198,9 +201,9 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: [self recreateViewHierarchy]; - } else if (![self hasAuthenticationData]) { - - [self applicationRootViewControllerDidRequestReauthentication:nil]; +// } else if (![self hasAuthenticationData]) { +// +// [self applicationRootViewControllerDidRequestReauthentication:nil]; } else { @@ -209,8 +212,8 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: if (lastAuthenticatedUserIdentifier) [self bootstrapPersistentStoreWithUserIdentifier:lastAuthenticatedUserIdentifier]; - self.fetchManager = [[WAFetchManager alloc] init]; - self.syncManager = [[WASyncManager alloc] init]; +// self.fetchManager = [[WAFetchManager alloc] init]; +// self.syncManager = [[WASyncManager alloc] init]; [self recreateViewHierarchy]; @@ -342,31 +345,43 @@ - (void) recreateViewHierarchy { [[IRRemoteResourcesManager sharedManager].queue cancelAllOperations]; - self.slidingMenu = [[WASlidingMenuViewController alloc] init]; - self.slidingMenu.delegate = self; - WANavigationController *navSlide = [[WANavigationController alloc] initWithRootViewController:self.slidingMenu]; - navSlide.navigationBarHidden = YES; - - NSParameterAssert(self.syncManager); - - IIViewDeckController *viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:[WASlidingMenuViewController dayViewControllerForViewStyle:WAEventsViewStyle] - leftViewController:navSlide]; - viewDeckController.view.backgroundColor = [UIColor blackColor]; - - if (isPad() && (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))) - viewDeckController.leftLedge = self.window.frame.size.height - [WASlidingMenuViewController ledgeSize]; - else - viewDeckController.leftLedge = self.window.frame.size.width - [WASlidingMenuViewController ledgeSize]; - - viewDeckController.rotationBehavior = IIViewDeckRotationKeepsLedgeSizes; - // viewDeckController.animationBehavior = IIViewDeckAnimationPullIn; - viewDeckController.panningMode = IIViewDeckNoPanning; - [viewDeckController setWantsFullScreenLayout:YES]; - viewDeckController.delegate = self.slidingMenu; - viewDeckController.centerhiddenInteractivity = IIViewDeckCenterHiddenNotUserInteractiveWithTapToClose; - - self.window.rootViewController = viewDeckController; +// self.slidingMenu = [[WASlidingMenuViewController alloc] init]; +// self.slidingMenu.delegate = self; +// WANavigationController *navSlide = [[WANavigationController alloc] initWithRootViewController:self.slidingMenu]; +// navSlide.navigationBarHidden = YES; +// +// NSParameterAssert(self.syncManager); +// +// IIViewDeckController *viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:[WASlidingMenuViewController dayViewControllerForViewStyle:WAEventsViewStyle] +// leftViewController:navSlide]; +// viewDeckController.view.backgroundColor = [UIColor blackColor]; +// +// if (isPad() && (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))) +// viewDeckController.leftLedge = self.window.frame.size.height - [WASlidingMenuViewController ledgeSize]; +// else +// viewDeckController.leftLedge = self.window.frame.size.width - [WASlidingMenuViewController ledgeSize]; +// +// viewDeckController.rotationBehavior = IIViewDeckRotationKeepsLedgeSizes; +// // viewDeckController.animationBehavior = IIViewDeckAnimationPullIn; +// viewDeckController.panningMode = IIViewDeckNoPanning; +// [viewDeckController setWantsFullScreenLayout:YES]; +// viewDeckController.delegate = self.slidingMenu; +// viewDeckController.centerhiddenInteractivity = IIViewDeckCenterHiddenNotUserInteractiveWithTapToClose; + + __weak WAAppDelegate_iOS *wSelf = self; + WAPartioFirstUseViewController *partioFirstUse = [WAPartioFirstUseViewController firstUseViewControllerWithCompletionBlock:^{ + UIViewController *rootVC = self.window.rootViewController; + + [rootVC zapModal]; + + WAPhotoHighlightsViewController *photoGroupsVC = [[WAPhotoHighlightsViewController alloc] initWithStyle:UITableViewStylePlain]; + wSelf.window.rootViewController = photoGroupsVC; + + } failure:^(NSError *error) { + NSLog(@"fail to sign up for error: %@", error); + }]; + self.window.rootViewController = partioFirstUse; UIViewController *vc = self.window.rootViewController; diff --git a/wammer/WAAssetsLibraryManager.h b/wammer/WAAssetsLibraryManager.h index ce0a4c0b..33f8227b 100644 --- a/wammer/WAAssetsLibraryManager.h +++ b/wammer/WAAssetsLibraryManager.h @@ -31,4 +31,6 @@ * @param onFailureBlock The block to invoke when unable to enumerate assets. */ - (void)enumerateSavedPhotosSince:(NSDate *)sinceDate onProgess:(void (^)(NSArray *assets))onProgressBlock onComplete:(void(^)())onCompleteBlock onFailure:(void(^)(NSError *error))onFailureBlock; + +- (void)retrieveTimeSortedPhotosWhenComplete:(void (^)(NSArray *result))onCompleteBlock onFailure:(void (^)(NSError *))onFailureBlock; @end diff --git a/wammer/WAAssetsLibraryManager.m b/wammer/WAAssetsLibraryManager.m index 8eb439b6..184cf0ad 100644 --- a/wammer/WAAssetsLibraryManager.m +++ b/wammer/WAAssetsLibraryManager.m @@ -71,6 +71,39 @@ - (void)writeImageToSavedPhotosAlbum:(CGImageRef)imageRef orientation:(ALAssetOr } +- (void)retrieveTimeSortedPhotosWhenComplete:(void (^)(NSArray *result))onCompleteBlock onFailure:(void (^)(NSError *))onFailureBlock { + NSMutableArray *allAssets = [NSMutableArray array]; + + [self.assetsLibrary enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) { + + if (group) { + + [group setAssetsFilter:[ALAssetsFilter allPhotos]]; + + // sorting all photos in camera roll by photo creation date + [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { + if (result) { + NSUInteger indexToInsert = [allAssets indexOfObject:result inSortedRange:NSMakeRange(0, [allAssets count]) options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult(ALAsset *asset1, ALAsset *asset2) { + return [[asset2 valueForProperty:ALAssetPropertyDate] compare:[asset1 valueForProperty:ALAssetPropertyDate]]; + }]; + [allAssets insertObject:result atIndex:indexToInsert]; + } + }]; + + } else { + + onCompleteBlock([NSArray arrayWithArray:allAssets]); + + } + + } failureBlock:^(NSError *error) { + + onFailureBlock(error); + + }]; + +} + - (void)enumerateSavedPhotosSince:(NSDate *)sinceDate onProgess:(void (^)(NSArray *))onProgressBlock onComplete:(void (^)())onCompleteBlock onFailure:(void (^)(NSError *))onFailureBlock { NSCalendar *calendar = [NSCalendar currentCalendar]; @@ -100,53 +133,53 @@ - (void)enumerateSavedPhotosSince:(NSDate *)sinceDate onProgess:(void (^)(NSArra NSMutableArray *allAssets = [NSMutableArray array]; [group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { if (result) { - if (![importedFileAssetURLs containsObject:[[[result defaultRepresentation] url] absoluteString]]) { - NSUInteger indexToInsert = [allAssets indexOfObject:result inSortedRange:NSMakeRange(0, [allAssets count]) options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult(ALAsset *asset1, ALAsset *asset2) { - return [[asset1 valueForProperty:ALAssetPropertyDate] compare:[asset2 valueForProperty:ALAssetPropertyDate]]; - }]; - [allAssets insertObject:result atIndex:indexToInsert]; - } + if (![importedFileAssetURLs containsObject:[[[result defaultRepresentation] url] absoluteString]]) { + NSUInteger indexToInsert = [allAssets indexOfObject:result inSortedRange:NSMakeRange(0, [allAssets count]) options:NSBinarySearchingInsertionIndex usingComparator:^NSComparisonResult(ALAsset *asset1, ALAsset *asset2) { + return [[asset1 valueForProperty:ALAssetPropertyDate] compare:[asset2 valueForProperty:ALAssetPropertyDate]]; + }]; + [allAssets insertObject:result atIndex:indexToInsert]; + } } }]; [allAssets enumerateObjectsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) { if (result) { + + NSDate *assetDate = [result valueForProperty:ALAssetPropertyDate]; + NSDateComponents *assetDateComponents = [calendar components:comps fromDate:assetDate]; + assetDate = [calendar dateFromComponents:assetDateComponents]; + if (sinceDate && ([assetDate compare:sinceDate] != NSOrderedDescending)) { + return; + } - NSDate *assetDate = [result valueForProperty:ALAssetPropertyDate]; - NSDateComponents *assetDateComponents = [calendar components:comps fromDate:assetDate]; - assetDate = [calendar dateFromComponents:assetDateComponents]; - if (sinceDate && ([assetDate compare:sinceDate] != NSOrderedDescending)) { - return; - } - - if (midnight) { + if (midnight) { - if ([assetDate compare:midnight] != NSOrderedAscending) { - - NSArray *assets = [insertedAssets copy]; - onProgressBlock(assets); - [insertedAssets removeAllObjects]; - midnight = [assetDate laterMidnight]; + if ([assetDate compare:midnight] != NSOrderedAscending) { - } + NSArray *assets = [insertedAssets copy]; + onProgressBlock(assets); + [insertedAssets removeAllObjects]; + midnight = [assetDate laterMidnight]; + + } + + } else { - } else { - - midnight = [assetDate laterMidnight]; - - } + midnight = [assetDate laterMidnight]; + + } - [insertedAssets addObject:result]; + [insertedAssets addObject:result]; } if (index == [allAssets count] - 1) { - NSArray *assets = [insertedAssets copy]; - onProgressBlock(assets); - [insertedAssets removeAllObjects]; - + NSArray *assets = [insertedAssets copy]; + onProgressBlock(assets); + [insertedAssets removeAllObjects]; + } }]; diff --git a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.h b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.h new file mode 100644 index 00000000..b4b6bd22 --- /dev/null +++ b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.h @@ -0,0 +1,13 @@ +// +// WACheckin+WARemoteInterfaceEntitySyncing.h +// wammer +// +// Created by Shen Steven on 4/7/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WACheckin.h" + +@interface WACheckin (WARemoteInterfaceEntitySyncing) + +@end diff --git a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m new file mode 100644 index 00000000..e4db532d --- /dev/null +++ b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m @@ -0,0 +1,75 @@ +// +// WACheckin+WARemoteInterfaceEntitySyncing.m +// wammer +// +// Created by Shen Steven on 4/7/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WACheckin+WARemoteInterfaceEntitySyncing.h" + +@implementation WACheckin (WARemoteInterfaceEntitySyncing) + ++ (NSString *) keyPathHoldingUniqueValue { + + return @"identifier"; + +} + ++ (BOOL) skipsNonexistantRemoteKey { + + // Allows piecemeal data patching, by skipping code path that assigns a placeholder value for any missing value + // that -configureWithRemoteDictionary: gets + return YES; + +} + ++ (NSDictionary *) remoteDictionaryConfigurationMapping { + + static NSDictionary *mapping = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + + mapping = @{ + @"name": @"name", + @"message": @"message", + @"checkin_id": @"identifier", + @"create_time": @"createDate", + @"tagged_uids": @"taggedUsers" + }; + + }); + + return mapping; + +} + ++ (NSDictionary *) transformedRepresentationForRemoteRepresentation:(NSDictionary *)incomingDictionary { + NSMutableDictionary *returnedDictionary = [incomingDictionary mutableCopy]; + + NSNumber *timestampNumber = incomingDictionary[@"timestamp"]; + if (timestampNumber) { + returnedDictionary[@"create_time"] = [NSDate dateWithTimeIntervalSince1970:timestampNumber.intValue]; + } + + return returnedDictionary; +} + ++ (id) transformedValue:(id)aValue + fromRemoteKeyPath:(NSString *)aRemoteKeyPath + toLocalKeyPath:(NSString *)aLocalKeyPath { + + if ( [aLocalKeyPath isEqualToString:@"checkin_id"] ) + return [NSString stringWithFormat:@"%@", aValue]; + if ( [aLocalKeyPath isEqualToString:@"tagged_uids"]) + return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:(NSArray*)aValue options:0 error:nil] encoding:NSUTF8StringEncoding]; + + + return [super transformedValue:aValue + fromRemoteKeyPath:aRemoteKeyPath + toLocalKeyPath:aLocalKeyPath]; + +} + + +@end diff --git a/wammer/WACheckin.h b/wammer/WACheckin.h new file mode 100644 index 00000000..a9301b9f --- /dev/null +++ b/wammer/WACheckin.h @@ -0,0 +1,22 @@ +// +// WACheckin.h +// wammer +// +// Created by Shen Steven on 4/7/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import +#import +#import "CoreData+IRAdditions.h" + + +@interface WACheckin : IRManagedObject + +@property (nonatomic, retain) NSString * name; +@property (nonatomic, retain) NSString * message; +@property (nonatomic, retain) NSString * taggedUsers; +@property (nonatomic, retain) NSString * identifier; +@property (nonatomic, retain) NSDate * createDate; + +@end diff --git a/wammer/WACheckin.m b/wammer/WACheckin.m new file mode 100644 index 00000000..9f7ff9a8 --- /dev/null +++ b/wammer/WACheckin.m @@ -0,0 +1,20 @@ +// +// WACheckin.m +// wammer +// +// Created by Shen Steven on 4/7/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WACheckin.h" + + +@implementation WACheckin + +@dynamic name; +@dynamic message; +@dynamic taggedUsers; +@dynamic identifier; +@dynamic createDate; + +@end diff --git a/wammer/WAFirstUseIntroView.xib b/wammer/WAFirstUseIntroView.xib index ff6ae8d2..c57aa65f 100644 --- a/wammer/WAFirstUseIntroView.xib +++ b/wammer/WAFirstUseIntroView.xib @@ -2,10 +2,10 @@ 1552 - 12C60 + 12D78 3084 - 1187.34 - 625.00 + 1187.37 + 626.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin 2083 @@ -126,7 +126,6 @@ 292 {{20, 423}, {280, 40}} - _NS:9 NO YES @@ -184,7 +183,7 @@ IBCocoaTouchFramework - + 292 @@ -257,7 +256,6 @@ 292 {{20, 442}, {280, 21}} - _NS:9 NO YES @@ -280,7 +278,6 @@ {320, 568} - _NS:9 @@ -1644,26 +1641,7 @@ 457 - - - - NSLayoutConstraint - NSObject - - IBProjectSource - ./Classes/NSLayoutConstraint.h - - - - WALocalizedLabel - UILabel - - IBProjectSource - ./Classes/WALocalizedLabel.h - - - - + 0 IBCocoaTouchFramework YES diff --git a/wammer/WAGeoLocation.h b/wammer/WAGeoLocation.h new file mode 100644 index 00000000..5dab9afb --- /dev/null +++ b/wammer/WAGeoLocation.h @@ -0,0 +1,16 @@ +// +// WAGeoLocation.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import +#import + +@interface WAGeoLocation : NSObject + +- (void) identifyLocation:(CLLocationCoordinate2D)coordinate onComplete:(void(^)(NSArray*))completeBlock onError:(void(^)(NSError*))failureBlock; + +@end diff --git a/wammer/WAGeoLocation.m b/wammer/WAGeoLocation.m new file mode 100644 index 00000000..b4483eec --- /dev/null +++ b/wammer/WAGeoLocation.m @@ -0,0 +1,158 @@ +// +// WAGeoLocation.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAGeoLocation.h" + +@interface WAGeoLocation () + +@property (nonatomic, strong) NSURLConnection *connection; +@property (nonatomic, copy) void (^completionBlock) (NSArray *results); +@property (nonatomic, copy) void (^failureBlock) (NSError *error); +@property (nonatomic, strong) NSMutableData *responseData; +@property (nonatomic, assign) CLLocationCoordinate2D coordinate; + +@end + +@implementation WAGeoLocation + ++ (NSMutableDictionary*)cachedData { + + static NSMutableDictionary *cachedLocation = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + cachedLocation = [NSMutableDictionary dictionary]; + }); + + return cachedLocation; +} + +- (void) identifyLocation:(CLLocationCoordinate2D)coordinate onComplete:(void(^)(NSArray*))completeBlock onError:(void(^)(NSError*))failureBlock { + + NSMutableDictionary *cache = [[self class] cachedData]; + NSString *key = [NSString stringWithFormat:@"%.2f/%.2f", coordinate.latitude, coordinate.longitude]; + + NSDictionary *langMapping = @{@"zh-Hant": @"zh-TW", @"zh-Hans": @"zh-CN"}; + + if (cache[key] != nil) { + if (completeBlock) + completeBlock(cache[key]); + } else { + + self.coordinate = coordinate; + self.completionBlock = completeBlock; + self.failureBlock = failureBlock; + + NSString *preferedLanguage = @"en"; + NSArray *preferedLanguages = [NSLocale preferredLanguages]; + if ([preferedLanguages count] > 0) { + if (langMapping[preferedLanguages[0]]) + preferedLanguage = langMapping[preferedLanguages[0]]; + } + + NSString *urlString = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/geocode/json?latlng=%f,%f&sensor=true&language=%@", coordinate.latitude, coordinate.longitude, preferedLanguage]; + + NSURL *requestURL = [NSURL URLWithString:urlString]; + NSURLRequest *request = [[NSURLRequest alloc] initWithURL:requestURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20]; + self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; + if (self.connection) { + self.responseData = [NSMutableData data]; + } + } +} + +- (void)connection:(NSURLConnection *)conn didReceiveResponse:(NSURLResponse *)response { + + [self.responseData setLength:0]; + +} + +- (void)connection:(NSURLConnection *)conn didReceiveData:(NSData *)data { + + [self.responseData appendData:data]; + +} + +- (void)connection:(NSURLConnection *)conn didFailWithError:(NSError *)error { + + if (self.failureBlock) + self.failureBlock(error); + +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)conn { + + NSError *jsonError = nil; + + NSDictionary *parsedJSON = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingAllowFragments error:&jsonError]; + + if (jsonError) { + if (self.failureBlock) { + self.failureBlock(jsonError); + return; + } + } + + if (!parsedJSON[@"status"] || ![parsedJSON[@"status"] isEqual:@"OK"]) { + NSLog(@"%@", parsedJSON); + if (self.failureBlock) + self.failureBlock([NSError errorWithDomain:@"GoogleResponse" code:-1 userInfo:@{NSLocalizedDescriptionKey: parsedJSON[@"status"]}]); + return; + } + + if (!parsedJSON[@"results"]) { + if (self.failureBlock) + self.failureBlock([NSError errorWithDomain:@"GoogleResponse" code:-2 userInfo:@{NSLocalizedDescriptionKey: @"no results responsed"}]); + return; + } + + NSArray *results = parsedJSON[@"results"]; + if (!results.count) { + if (self.failureBlock) + self.failureBlock([NSError errorWithDomain:@"GoogleResponse" code:-3 userInfo:@{NSLocalizedDescriptionKey: @"empty results"}]); + return; + } + + if (!results[0][@"address_components"]) { + if (self.failureBlock) + self.failureBlock([NSError errorWithDomain:@"GoogleResponse" code:-4 userInfo:@{NSLocalizedDescriptionKey: @"No address components available"}]); + return; + } + + NSArray *validTypes = @[@"locality", @"administrative_area_level_2", @"administrative_area_level_1", @"country"]; + NSArray *addrComponents = results[0][@"address_components"]; + NSMutableArray *regions = [NSMutableArray array]; + + [addrComponents enumerateObjectsUsingBlock:^(NSDictionary *component, NSUInteger idx, BOOL *stop) { + NSArray *types = component[@"types"]; + __block BOOL match = NO; + + [types enumerateObjectsUsingBlock:^(NSString *value, NSUInteger idx, BOOL *stop2) { + + if ([validTypes indexOfObject:value] != NSNotFound) { + *stop2 = YES; + match = YES; + } + + }]; + + if (match) { + *stop = YES; + [regions addObject:component[@"long_name"]]; + } + + }]; + + if (self.completionBlock) { + [[[self class] cachedData] setValue:regions forKey:[NSString stringWithFormat:@"%.2f/%.2f", self.coordinate.latitude, self.coordinate.longitude]]; + + self.completionBlock([NSArray arrayWithArray:regions]); + } +} + + +@end diff --git a/wammer/WAModel.xcdatamodeld/.xccurrentversion b/wammer/WAModel.xcdatamodeld/.xccurrentversion index 5f3f409c..6957f73b 100644 --- a/wammer/WAModel.xcdatamodeld/.xccurrentversion +++ b/wammer/WAModel.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - WAModel 43.xcdatamodel + WAModel 44.xcdatamodel diff --git a/wammer/WAModel.xcdatamodeld/WAModel 43.xcdatamodel/contents b/wammer/WAModel.xcdatamodeld/WAModel 43.xcdatamodel/contents index 9dad1c2b..116d00bf 100644 --- a/wammer/WAModel.xcdatamodeld/WAModel 43.xcdatamodel/contents +++ b/wammer/WAModel.xcdatamodeld/WAModel 43.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -54,6 +54,12 @@ + + + + + + @@ -318,5 +324,6 @@ + \ No newline at end of file diff --git a/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents b/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents new file mode 100644 index 00000000..da4d2289 --- /dev/null +++ b/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wammer/WAPartioFirstUse.storyboard b/wammer/WAPartioFirstUse.storyboard new file mode 100644 index 00000000..bd6e95f9 --- /dev/null +++ b/wammer/WAPartioFirstUse.storyboard @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/wammer/WAPartioFirstUseViewController.h b/wammer/WAPartioFirstUseViewController.h new file mode 100644 index 00000000..392d96c8 --- /dev/null +++ b/wammer/WAPartioFirstUseViewController.h @@ -0,0 +1,18 @@ +// +// WAPartioWelcomViewController.h +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPartioFirstUseViewController : UINavigationController + +@property (nonatomic, copy) void (^completionBlock)(void); +@property (nonatomic, copy) void (^failureBlock)(NSError *); + ++ (WAPartioFirstUseViewController*) firstUseViewControllerWithCompletionBlock:(void(^)(void))completion failure:(void(^)(NSError*))failure; + +@end diff --git a/wammer/WAPartioFirstUseViewController.m b/wammer/WAPartioFirstUseViewController.m new file mode 100644 index 00000000..d563b8af --- /dev/null +++ b/wammer/WAPartioFirstUseViewController.m @@ -0,0 +1,55 @@ +// +// WAPartioWelcomViewController.m +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPartioFirstUseViewController.h" + +@interface WAPartioFirstUseViewController () + +@end + +@implementation WAPartioFirstUseViewController ++ (WAPartioFirstUseViewController*) firstUseViewControllerWithCompletionBlock:(void(^)(void))completion failure:(void(^)(NSError*))failure { + + UIStoryboard *sb = [UIStoryboard storyboardWithName:@"WAPartioFirstUse" bundle:nil]; + WAPartioFirstUseViewController *vc = [sb instantiateInitialViewController]; + vc.completionBlock = completion; + vc.failureBlock = failure; + vc.navigationBar.opaque = NO; + + return vc; +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (BOOL) shouldAutorotate { + return YES; +} + +- (NSUInteger) supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} +@end diff --git a/wammer/WAPartioWelcomeViewController.h b/wammer/WAPartioWelcomeViewController.h new file mode 100644 index 00000000..6955830c --- /dev/null +++ b/wammer/WAPartioWelcomeViewController.h @@ -0,0 +1,13 @@ +// +// WAPartioWelcomeViewController.h +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPartioWelcomeViewController : UITableViewController + +@end diff --git a/wammer/WAPartioWelcomeViewController.m b/wammer/WAPartioWelcomeViewController.m new file mode 100644 index 00000000..4a3c3aa0 --- /dev/null +++ b/wammer/WAPartioWelcomeViewController.m @@ -0,0 +1,129 @@ +// +// WAPartioWelcomeViewController.m +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPartioWelcomeViewController.h" +#import "WAPartioFirstUseViewController.h" +#import "WAOverlayBezel.h" +#import "WARemoteInterface.h" +#import +#import + +@interface WAPartioWelcomeViewController () + +@end + +@implementation WAPartioWelcomeViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; +} + + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + + WAPartioFirstUseViewController *firstUse = (WAPartioFirstUseViewController*)self.navigationController; + + if (indexPath.row == 0) { + if (firstUse.completionBlock) + firstUse.completionBlock(); + } else if (indexPath.row == 1) { + + WAOverlayBezel *busyBezel = [WAOverlayBezel bezelWithStyle:WAActivityIndicatorBezelStyle]; + [busyBezel showWithAnimation:WAOverlayBezelAnimationFade]; + + // http://stackoverflow.com/questions/12601191/facebook-sdk-3-1-error-validating-access-token + // This should and will be fixed from FB SDK + + ACAccountStore *accountStore; + ACAccountType *accountTypeFB; + if ((accountStore = [[ACAccountStore alloc] init]) && + (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){ + + NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB]; + id account; + if (fbAccounts && [fbAccounts count] > 0 && + (account = [fbAccounts objectAtIndex:0])){ + + [accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { + //we don't actually need to inspect renewResult or error. + if (error){ + + } + }]; + } + } + + [FBSession + openActiveSessionWithReadPermissions:@[@"email", @"user_photos", @"user_videos", @"user_notes", @"user_status", @"user_likes", @"read_stream", @"friends_photos", @"friends_videos", @"friends_status", @"friends_notes", @"friends_likes"] + allowLoginUI:YES + completionHandler:^(FBSession *session, FBSessionState status, NSError *error) { + + if (error) { + + NSLog(@"Facebook auth error: %@", error); + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + if (firstUse.failureBlock) + firstUse.failureBlock(error); + + }); + + + return; + } + + [[WARemoteInterface sharedInterface] + signupUserWithFacebookToken:session.accessTokenData.accessToken + withOptions:nil + onSuccess:^(NSString *token, NSDictionary *userRep, NSArray *groupReps) { + + dispatch_async(dispatch_get_main_queue(), ^{ + if (firstUse.completionBlock) + firstUse.completionBlock(); + }); + + + } onFailure:^(NSError *error) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + + if (firstUse.failureBlock) + firstUse.failureBlock(error); + + }); + + }]; + + }]; + + } +} + +@end diff --git a/wammer/WAPhotoCollageCell.h b/wammer/WAPhotoCollageCell.h new file mode 100644 index 00000000..0a1a4285 --- /dev/null +++ b/wammer/WAPhotoCollageCell.h @@ -0,0 +1,15 @@ +// +// WAPhotoCollageCell.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPhotoCollageCell : UICollectionViewCell + +@property (nonatomic, strong) IBOutletCollection(UIImageView) NSArray *imageViews; + +@end diff --git a/wammer/WAPhotoCollageCell.m b/wammer/WAPhotoCollageCell.m new file mode 100644 index 00000000..396029ba --- /dev/null +++ b/wammer/WAPhotoCollageCell.m @@ -0,0 +1,40 @@ +// +// WAPhotoCollageCell.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoCollageCell.h" + +@implementation WAPhotoCollageCell + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void) awakeFromNib { + + [self.imageViews enumerateObjectsUsingBlock:^(UIImageView *imageView, NSUInteger idx, BOOL *stop) { + + imageView.layer.cornerRadius = 5; + }]; + +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/wammer/WAPhotoCollageCell_Stack2.xib b/wammer/WAPhotoCollageCell_Stack2.xib new file mode 100644 index 00000000..e0218c4c --- /dev/null +++ b/wammer/WAPhotoCollageCell_Stack2.xib @@ -0,0 +1,424 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionViewCell + IBUIImageView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 1292 + + + + 1280 + + + + 1298 + {{10, 5}, {145, 120}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{165, 5}, {145, 120}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + {320, 130} + + + + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + {320, 130} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + + imageViews + + + NSArray + NO + + 16 + + + + imageViews + + + NSArray + NO + + 17 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + + 5 + 0 + + 5 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + + + 4 + + + + + 7 + 0 + + 0 + 1 + + 145 + + 1000 + + 3 + 9 + 1 + + + + 8 + 0 + + 0 + 1 + + 120 + + 1000 + + 3 + 9 + 1 + + + + + + 5 + + + + + 7 + 0 + + 0 + 1 + + 145 + + 1000 + + 3 + 9 + 1 + + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoCollageCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 17 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + UICollectionViewCell + UICollectionReusableView + + IBProjectSource + ./Classes/UICollectionViewCell.h + + + + WAPhotoCollageCell + UICollectionViewCell + + imageViews + + imageViews + UIImageView + NSArray + + + + IBProjectSource + ./Classes/WAPhotoCollageCell.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoCollageCell_Stack3.xib b/wammer/WAPhotoCollageCell_Stack3.xib new file mode 100644 index 00000000..fff66b8c --- /dev/null +++ b/wammer/WAPhotoCollageCell_Stack3.xib @@ -0,0 +1,551 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionViewCell + IBUIImageView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 1292 + + + + 1280 + + + + 1298 + {{10, 5}, {93, 80}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{113, 5}, {93, 80}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{216, 5}, {93, 80}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + {320, 90} + + + + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + {320, 90} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + + imageViews + + + NSArray + NO + + 22 + + + + imageViews + + + NSArray + NO + + 23 + + + + imageViews + + + NSArray + NO + + 24 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + + + 5 + 0 + + 5 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 9 + 0 + + 9 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 6 + 0 + + 6 + 1 + + 11 + + 1000 + + 3 + 9 + 3 + + + + + + 4 + + + + + 8 + 0 + + 0 + 1 + + 80 + + 1000 + + 3 + 9 + 1 + + + + 7 + 0 + + 0 + 1 + + 93 + + 1000 + + 3 + 9 + 1 + + + + + + 5 + + + + + 7 + 0 + + 0 + 1 + + 93 + + 1000 + + 3 + 9 + 1 + + + + + + 6 + + + + + 7 + 0 + + 0 + 1 + + 93 + + 1000 + + 3 + 9 + 1 + + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoCollageCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 24 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + UICollectionViewCell + UICollectionReusableView + + IBProjectSource + ./Classes/UICollectionViewCell.h + + + + WAPhotoCollageCell + UICollectionViewCell + + imageViews + + imageViews + UIImageView + NSArray + + + + IBProjectSource + ./Classes/WAPhotoCollageCell.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoCollageCell_Stack4.xib b/wammer/WAPhotoCollageCell_Stack4.xib new file mode 100644 index 00000000..30b1e230 --- /dev/null +++ b/wammer/WAPhotoCollageCell_Stack4.xib @@ -0,0 +1,678 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionViewCell + IBUIImageView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 1292 + + + + 1280 + + + + 1298 + {{10, 5}, {200, 200}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{220, 5}, {90, 60}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{220, 75}, {90, 60}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {{220, 145}, {90, 60}} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + {320, 210} + + + + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + {320, 210} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + + imageViews + + + NSArray + NO + + 28 + + + + imageViews + + + NSArray + NO + + 29 + + + + imageViews + + + NSArray + NO + + 30 + + + + imageViews + + + NSArray + NO + + 31 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + + + + 5 + 0 + + 5 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 6 + 0 + + 6 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 10 + 0 + + 10 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 5 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + + + 4 + + + + + 8 + 0 + + 0 + 1 + + 60 + + 1000 + + 3 + 9 + 1 + + + + + + 5 + + + + + 8 + 0 + + 0 + 1 + + 60 + + 1000 + + 3 + 9 + 1 + + + + + + 6 + + + + + 7 + 0 + + 0 + 1 + + 90 + + 1000 + + 3 + 9 + 1 + + + + 8 + 0 + + 0 + 1 + + 60 + + 1000 + + 3 + 9 + 1 + + + + + + 7 + + + + + 7 + 0 + + 0 + 1 + + 200 + + 1000 + + 3 + 9 + 1 + + + + + + 8 + + + + + 9 + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 14 + + + + + 15 + + + + + 16 + + + + + 17 + + + + + 18 + + + + + 19 + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoCollageCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 31 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + UICollectionViewCell + UICollectionReusableView + + IBProjectSource + ./Classes/UICollectionViewCell.h + + + + WAPhotoCollageCell + UICollectionViewCell + + imageViews + + imageViews + UIImageView + NSArray + + + + IBProjectSource + ./Classes/WAPhotoCollageCell.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoHighlightViewCell.h b/wammer/WAPhotoHighlightViewCell.h new file mode 100644 index 00000000..0874dc09 --- /dev/null +++ b/wammer/WAPhotoHighlightViewCell.h @@ -0,0 +1,22 @@ +// +// WAPhotoGroupViewCell.h +// wammer +// +// Created by Shen Steven on 4/4/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import +#import "WAGeoLocation.h" +#import + +@interface WAPhotoHighlightViewCell : UITableViewCell + +@property (nonatomic, weak) IBOutlet UIImageView *bgImageView; +@property (nonatomic, weak) IBOutlet UILabel *dateLabel; +@property (nonatomic, weak) IBOutlet UILabel *photoNumberLabel; +@property (nonatomic, weak) IBOutlet UILabel *locationLabel; +@property (nonatomic, strong) WAGeoLocation *geoLocation; +@property (nonatomic, strong) FBRequestConnection *fbRequest; + +@end diff --git a/wammer/WAPhotoHighlightViewCell.m b/wammer/WAPhotoHighlightViewCell.m new file mode 100644 index 00000000..71487b7c --- /dev/null +++ b/wammer/WAPhotoHighlightViewCell.m @@ -0,0 +1,40 @@ +// +// WAPhotoGroupViewCell.m +// wammer +// +// Created by Shen Steven on 4/4/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoHighlightViewCell.h" +#import + +@implementation WAPhotoHighlightViewCell + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier +{ + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + } + return self; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated +{ + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +- (void) awakeFromNib { + + CAGradientLayer *gradientLayer = [CAGradientLayer layer]; + gradientLayer.frame = (CGRect) {CGPointZero, self.bgImageView.frame.size}; + gradientLayer.colors = @[(id)[[UIColor colorWithWhite:0.0 alpha:0.0] CGColor], (id)[[UIColor colorWithWhite:0.0 alpha:0.8] CGColor]]; + + [self.bgImageView.layer insertSublayer:gradientLayer above:nil]; + +} + +@end diff --git a/wammer/WAPhotoHighlightViewCell.xib b/wammer/WAPhotoHighlightViewCell.xib new file mode 100644 index 00000000..67059628 --- /dev/null +++ b/wammer/WAPhotoHighlightViewCell.xib @@ -0,0 +1,660 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUIImageView + IBUILabel + IBUITableViewCell + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 292 + + + + 256 + + + + 292 + {320, 149} + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 292 + {{20, 100}, {264, 21}} + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Date + + 1 + MSAxIDEAA + + + 3 + MQA + + 0 + + Helvetica-Bold + Helvetica + 2 + 14 + + + Helvetica-Bold + 14 + 16 + + NO + + + + 292 + {{20, 79}, {280, 21}} + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + 0 + + + 0 + + Helvetica-Bold + Helvetica + 2 + 16 + + + Helvetica-Bold + 16 + 16 + + NO + + + + 292 + {{20, 120}, {264, 21}} + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Taipei + + + 0 + + Helvetica-Bold + Helvetica + 2 + 17 + + + Helvetica-Bold + 17 + 16 + + NO + + + {320, 149} + + + _NS:11 + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + {320, 150} + + _NS:9 + IBCocoaTouchFramework + + + + + + + + dateLabel + + + + 89 + + + + photoNumberLabel + + + + 90 + + + + locationLabel + + + + 153 + + + + bgImageView + + + + 185 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 9 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 29 + + 1000 + + 3 + 9 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 50 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + + + + 4 + + + + + 8 + 0 + + 0 + 1 + + 149 + + 1000 + + 3 + 9 + 1 + + + + + + 53 + + + + + 8 + 0 + + 0 + 1 + + 21 + + 1000 + + 3 + 9 + 1 + + + + + + 75 + + + + + 8 + 0 + + 0 + 1 + + 21 + + 1000 + + 3 + 9 + 1 + + + + + + 100 + + + + + 7 + 0 + + 0 + 1 + + 264 + + 1000 + + 3 + 9 + 1 + + + + + + 138 + + + + + 154 + + + + + 155 + + + + + 156 + + + + + 157 + + + + + 161 + + + + + 172 + + + + + 179 + + + + + 180 + + + + + 183 + + + + + 190 + + + + + 192 + + + + + 193 + + + + + 194 + + + + + 195 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoHighlightViewCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + 195 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoHighlightsViewController.h b/wammer/WAPhotoHighlightsViewController.h new file mode 100644 index 00000000..e4ddf875 --- /dev/null +++ b/wammer/WAPhotoHighlightsViewController.h @@ -0,0 +1,13 @@ +// +// WAPhotoGroupsViewController.h +// wammer +// +// Created by Shen Steven on 4/4/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPhotoHighlightsViewController : UITableViewController + +@end diff --git a/wammer/WAPhotoHighlightsViewController.m b/wammer/WAPhotoHighlightsViewController.m new file mode 100644 index 00000000..851c795c --- /dev/null +++ b/wammer/WAPhotoHighlightsViewController.m @@ -0,0 +1,300 @@ +// +// WAPhotoGroupsViewController.m +// wammer +// +// Created by Shen Steven on 4/4/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoHighlightsViewController.h" +#import "WAPhotoHighlightViewCell.h" +#import "WAAssetsLibraryManager.h" +#import "WAOverlayBezel.h" +#import "WAGeoLocation.h" +#import +#import "WAPhotoTimelineViewController.h" +#import "FBRequestConnection+WAAdditions.h" +#import "WADataStore.h" +#import "WACheckin.h" +#import + +#define GROUPING_THRESHOLD (30 * 60) + +@interface WAPhotoHighlightsViewController () + +@property (nonatomic, strong) NSArray *allTimeSortedAssets; +@property (nonatomic, strong) NSArray *photoGroups; +@property (nonatomic, strong) FBRequestConnection *fbConnection; +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; + +@end + +@implementation WAPhotoHighlightsViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.allTimeSortedAssets = @[]; + self.photoGroups = [@[] mutableCopy]; + + self.managedObjectContext = [[WADataStore defaultStore] disposableMOC]; + + [self.tableView registerNib:[UINib nibWithNibName:@"WAPhotoGroupViewCell" bundle:nil] forCellReuseIdentifier:@"WAPhotoGroupViewCell"]; + + __weak WAPhotoHighlightsViewController *wSelf = self; + WAOverlayBezel *busyBezel = [[WAOverlayBezel alloc] initWithStyle:WAActivityIndicatorBezelStyle]; + [busyBezel show]; + + [[WAAssetsLibraryManager defaultManager] retrieveTimeSortedPhotosWhenComplete:^(NSArray *result) { + wSelf.allTimeSortedAssets = result; + [busyBezel dismiss]; + + [wSelf.tableView reloadData]; + } onFailure:^(NSError *error) { + [busyBezel dismiss]; + + NSLog(@"error: %@", error); + }]; + + self.fbConnection = [FBRequestConnection startForUserCheckinsAfterId:nil + completeHandler:^(FBRequestConnection *connection, NSArray *result, NSError *error) { + + if (error) { + NSLog(@"fb request error: %@", error); + } else { +// NSLog(@"fb request success: %@", result); + + NSManagedObjectContext *context = [[WADataStore defaultStore] disposableMOC]; + NSMutableArray *changedIndexPaths = [NSMutableArray array]; + + for (NSDictionary *checkinItem in result) { + NSNumber *timestampNumber = checkinItem[@"timestamp"]; + NSDate *checkinDate = [NSDate dateWithTimeIntervalSince1970:timestampNumber.floatValue]; + + BOOL found = NO; + + [WACheckin insertOrUpdateObjectsUsingContext:context withRemoteResponse:result usingMapping:nil options:IRManagedObjectOptionIndividualOperations]; + + NSUInteger groupIndex = 0; + for (NSArray *group in self.photoGroups) { + NSDate *enddingDate = [NSDate dateWithTimeInterval:(30*60) sinceDate:[(ALAsset*)group[0] valueForProperty:ALAssetPropertyDate]]; + NSDate *beginningDate = [NSDate dateWithTimeInterval:(-30*60) sinceDate:[(ALAsset*)group.lastObject valueForProperty:ALAssetPropertyDate]]; + + if (groupIndex == 0) { + NSLog(@"%@ ~ %@", beginningDate, enddingDate); + } + if ([checkinDate compare:beginningDate] == NSOrderedAscending) { + groupIndex ++; + continue; + } + + if ([checkinDate compare:enddingDate] == NSOrderedAscending) { + found = YES; + } + + break; + + } + + if (found) { + [changedIndexPaths addObject:[NSIndexPath indexPathForRow:groupIndex inSection:0]]; + NSLog(@"found %@ at indexPath row: %d", checkinItem[@"name"],groupIndex); + } + } + + NSError *error = nil; + [context save:&error]; + if (error) { + NSLog(@"fail to save checkin for %@", error); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [wSelf.tableView reloadRowsAtIndexPaths:changedIndexPaths withRowAnimation:YES]; + }); + } + }]; + +} + + +- (NSArray*) photoGroups { + + if (_photoGroups.count > 0) + return _photoGroups; + + if (_allTimeSortedAssets.count == 0) + return @[]; + + NSMutableArray *sortedGroups = [NSMutableArray array]; + NSMutableArray *photoList = [NSMutableArray array]; + __block NSDate *previousDate = nil; + + [_allTimeSortedAssets enumerateObjectsUsingBlock:^(ALAsset *asset, NSUInteger idx, BOOL *stop) { + + if (!previousDate) { + [photoList addObject:asset]; + previousDate = [asset valueForProperty:ALAssetPropertyDate]; + + } else { + + NSDate *assetDate = [asset valueForProperty:ALAssetPropertyDate]; + NSTimeInterval assetInterval = [assetDate timeIntervalSince1970]; + NSTimeInterval previousInterval = [previousDate timeIntervalSince1970]; + if ((previousInterval - assetInterval) > GROUPING_THRESHOLD) { + + previousDate = assetDate; + [sortedGroups addObject:[photoList copy]]; + [photoList removeAllObjects]; + [photoList addObject:asset]; + + } else { + + previousDate = assetDate; + [photoList addObject:asset]; + + } + } + + }]; + + _photoGroups = [NSArray arrayWithArray:sortedGroups]; + return _photoGroups; +} + +- (BOOL) shouldAutorotate { + return YES; +} + +- (NSUInteger) supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return [self.photoGroups count]; +} + ++ (NSOperationQueue*)sharedImageDisplayingQueue { + + static NSOperationQueue *opQueue = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + opQueue = [[NSOperationQueue alloc] init]; + opQueue.maxConcurrentOperationCount = 1; + }); + + return opQueue; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"WAPhotoGroupViewCell"; + WAPhotoHighlightViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; + + NSArray *photoList = self.photoGroups[indexPath.row]; + ALAsset *asset = photoList[(NSInteger)(photoList.count/2)]; + NSDictionary *imageMeta = [[asset defaultRepresentation] metadata]; + NSDate *eventDate = [asset valueForProperty:ALAssetPropertyDate]; + NSDate *beginDate = [NSDate dateWithTimeInterval:(-30*60) sinceDate:[(ALAsset*)([(NSArray*)(self.photoGroups[indexPath.row]) lastObject]) valueForProperty:ALAssetPropertyDate]]; + NSDate *endDate = [NSDate dateWithTimeInterval:(30*60) sinceDate:[(ALAsset*)(self.photoGroups[indexPath.row][0]) valueForProperty:ALAssetPropertyDate]]; + + + cell.bgImageView.image = nil; + + NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + UIImage *image = [[UIImage imageWithCGImage:[asset thumbnail]] stackBlur:1]; + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + [(UIImageView*)cell.bgImageView setImage:image]; + }]; + }]; + [[[self class] sharedImageDisplayingQueue] addOperation:op]; + + cell.photoNumberLabel.text = [NSString stringWithFormat:@"%d Photos", photoList.count]; + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter = [[NSDateFormatter alloc] init]; + formatter.dateStyle = NSDateFormatterMediumStyle; + formatter.timeStyle = NSDateFormatterMediumStyle; + cell.dateLabel.text = [formatter stringFromDate:eventDate]; + + cell.locationLabel.text = @""; + + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WACheckin"]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"createDate >= %@ AND createDate <= %@", beginDate, endDate]; + [fetchRequest setPredicate:predicate]; + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createDate" ascending:NO]; + [fetchRequest setSortDescriptors:@[sortDescriptor]]; + + NSError *error = nil; + NSArray *checkins = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error]; + if (error) { + NSLog(@"error to query checkin db: %@", error); + } else if (checkins.count) { + cell.locationLabel.text = [[checkins valueForKeyPath:@"name"] componentsJoinedByString:@","]; + } else { + + if (imageMeta) { + NSDictionary *gps = imageMeta[@"{GPS}"]; + if (gps) { + CLLocationCoordinate2D coordinate; + coordinate.latitude = [(NSNumber*)gps[@"Latitude"] doubleValue]; + coordinate.longitude = [(NSNumber*)gps[@"Longitude"] doubleValue]; + cell.geoLocation = [[WAGeoLocation alloc] init]; + [cell.geoLocation identifyLocation:coordinate + onComplete:^(NSArray *results) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + cell.locationLabel.text = [NSString stringWithFormat:@"%@%@", cell.locationLabel.text, [results componentsJoinedByString:@","]]; + + }); + + } onError:^(NSError *error) { + + NSLog(@"geolocation error: %@", error); + + }]; + } + } + } + + + return cell; +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + + WAPhotoTimelineViewController *vc = [[WAPhotoTimelineViewController alloc] initWithAssets:self.photoGroups[indexPath.row]]; + + self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + self.modalPresentationStyle = UIModalPresentationCurrentContext; + [self presentViewController:vc animated:YES completion:nil]; + +} + +@end diff --git a/wammer/WAPhotoHighlightsViewController.xib b/wammer/WAPhotoHighlightsViewController.xib new file mode 100644 index 00000000..48164a54 --- /dev/null +++ b/wammer/WAPhotoHighlightsViewController.xib @@ -0,0 +1,145 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 548}} + + 1 + MCAwIDAAA + + NO + YES + NO + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + NO + 0 + YES + 150 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + WAPhotoHighlightsViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 7 + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoTimelineCover.h b/wammer/WAPhotoTimelineCover.h new file mode 100644 index 00000000..71431bbe --- /dev/null +++ b/wammer/WAPhotoTimelineCover.h @@ -0,0 +1,20 @@ +// +// WAPhotoTimelineCover.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import +#import + +@interface WAPhotoTimelineCover : UICollectionReusableView + +@property (nonatomic, weak) IBOutlet UIImageView *coverImageView; +@property (nonatomic, weak) IBOutlet UIView *gradientBackground; +@property (nonatomic, weak) IBOutlet UILabel *titleLabel; +@property (nonatomic, weak) IBOutlet UILabel *dateLabel; +@property (nonatomic, weak) IBOutlet GMSMapView *mapView; + +@end diff --git a/wammer/WAPhotoTimelineCover.m b/wammer/WAPhotoTimelineCover.m new file mode 100644 index 00000000..fa57f432 --- /dev/null +++ b/wammer/WAPhotoTimelineCover.m @@ -0,0 +1,46 @@ +// +// WAPhotoTimelineCover.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoTimelineCover.h" +#import + +@implementation WAPhotoTimelineCover + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void) awakeFromNib { + + CAGradientLayer *gradientLayer = [CAGradientLayer layer]; + gradientLayer.frame = (CGRect) {CGPointZero, self.gradientBackground.frame.size}; + gradientLayer.colors = @[(id)[[UIColor colorWithWhite:0.0 alpha:0.0] CGColor], (id)[[UIColor colorWithWhite:0.0 alpha:0.8] CGColor]]; + + [self.gradientBackground.layer insertSublayer:gradientLayer above:nil]; + + self.mapView.layer.borderWidth = 4; + self.mapView.layer.borderColor = [UIColor blackColor].CGColor; + self.mapView.layer.cornerRadius = 30; + self.mapView.layer.masksToBounds = YES; + +} +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/wammer/WAPhotoTimelineCover.xib b/wammer/WAPhotoTimelineCover.xib new file mode 100644 index 00000000..177b6292 --- /dev/null +++ b/wammer/WAPhotoTimelineCover.xib @@ -0,0 +1,1032 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionReusableView + IBUIImageView + IBUILabel + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 268 + + + + 292 + {320, 200} + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 292 + + + + 274 + + + + 292 + {{20, 42}, {192, 21}} + + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Date + + 1 + MSAxIDEAA + + + 0 + + Helvetica + Helvetica + 0 + 14 + + + Helvetica + 14 + 16 + + NO + + + + 292 + {{20, 20}, {280, 21}} + + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Location + + + 0 + + Helvetica-Bold + Helvetica + 2 + 17 + + + Helvetica-Bold + 17 + 16 + + NO + + + {320, 75} + + + + _NS:9 + IBCocoaTouchFramework + + + + 292 + + {{0, 75}, {320, 50}} + + + + _NS:9 + IBCocoaTouchFramework + + + + 274 + {{230, 45}, {60, 60}} + + + _NS:9 + + 3 + MC42NjY2NjY2NjY3AA + + IBCocoaTouchFramework + + + {{0, 125}, {320, 125}} + + + + _NS:9 + IBCocoaTouchFramework + + + {320, 250} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + titleLabel + + + + 92 + + + + mapView + + + + 93 + + + + gradientBackground + + + + 94 + + + + dateLabel + + + + 95 + + + + coverImageView + + + + 125 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 9 + 40 + 3 + + + + 4 + 0 + + 4 + 1 + + 50 + + 1000 + + 9 + 40 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 9 + 40 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + + 12 + + + + + 6 + 0 + + 6 + 1 + + 30 + + 1000 + + 3 + 9 + 3 + + + + 5 + 0 + + 5 + 1 + + 230 + + 1000 + + 3 + 9 + 3 + + + + 3 + 0 + + 3 + 1 + + 45 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 75 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 8 + 0 + + 0 + 1 + + 125 + + 1000 + + 9 + 40 + 1 + + + + + + + Cover Bottom + + + 14 + + + + + 15 + + + + + 17 + + + + + 18 + + + + + 3 + 0 + + 3 + 1 + + 42 + + 1000 + + 3 + 5 + 3 + + + + 4 + 0 + + 4 + 1 + + 12 + + 1000 + + 3 + 9 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + + + Gradient Background + + + 19 + + + + + 22 + + + + + 25 + + + + + 26 + + + + Information Bar + + + 33 + + + + + 34 + + + + + 35 + + + + + 36 + + + + + 37 + + + Map View + + + 64 + + + + + 65 + + + + + 70 + + + + + 71 + + + + + 88 + + + + + 117 + + + + + + 118 + + + + + 119 + + + + + 122 + + + + + 124 + + + + + 80 + + + + + 7 + 0 + + 0 + 1 + + 192 + + 1000 + + 3 + 9 + 1 + + + + 8 + 0 + + 0 + 1 + + 21 + + 1000 + + 3 + 9 + 1 + + + + + + 87 + + + + + 86 + + + + + 81 + + + + + 84 + + + + + 85 + + + + + 72 + + + Location Label + + + 79 + + + + + 78 + + + + + 77 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + WAPhotoTimelineCover + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + GMSMapView + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 140 + + + + + GMSMapView + UIView + + IBProjectSource + ./Classes/GMSMapView.h + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + WAPhotoTimelineCover + UICollectionReusableView + + UIImageView + UILabel + UIView + GMSMapView + UILabel + + + + coverImageView + UIImageView + + + dateLabel + UILabel + + + gradientBackground + UIView + + + mapView + GMSMapView + + + titleLabel + UILabel + + + + IBProjectSource + ./Classes/WAPhotoTimelineCover.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoTimelineLayout.h b/wammer/WAPhotoTimelineLayout.h new file mode 100644 index 00000000..2b29e768 --- /dev/null +++ b/wammer/WAPhotoTimelineLayout.h @@ -0,0 +1,13 @@ +// +// WAPhotoTimelineLayout.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPhotoTimelineLayout : UICollectionViewFlowLayout + +@end diff --git a/wammer/WAPhotoTimelineLayout.m b/wammer/WAPhotoTimelineLayout.m new file mode 100644 index 00000000..7c70238d --- /dev/null +++ b/wammer/WAPhotoTimelineLayout.m @@ -0,0 +1,46 @@ +// +// WAPhotoTimelineLayout.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoTimelineLayout.h" + +@implementation WAPhotoTimelineLayout { + CGRect origHeaderFrame; +} + +- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { + + NSArray *attrs = [super layoutAttributesForElementsInRect:rect]; + + [attrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *attr, NSUInteger idx, BOOL *stop) { + + if (attr.representedElementCategory == UICollectionElementCategorySupplementaryView) + if ([attr.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { + CGFloat newOffset = self.collectionView.contentOffset.y; + + if (newOffset < 0) { + + CGSize origSize = attr.size; + CGRect newFrame = CGRectMake(0, newOffset, origSize.width, (-newOffset) + origSize.height); + attr.frame = newFrame; + attr.size = newFrame.size; + + } + } + + }]; + + return attrs; + +} + +- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { + return YES; +} + + +@end diff --git a/wammer/WAPhotoTimelineNavigationBar.h b/wammer/WAPhotoTimelineNavigationBar.h new file mode 100644 index 00000000..43eb7504 --- /dev/null +++ b/wammer/WAPhotoTimelineNavigationBar.h @@ -0,0 +1,15 @@ +// +// WAPhotoTimelineNavigationBar.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPhotoTimelineNavigationBar : UINavigationBar + +@property (nonatomic, assign) BOOL solid; + +@end diff --git a/wammer/WAPhotoTimelineNavigationBar.m b/wammer/WAPhotoTimelineNavigationBar.m new file mode 100644 index 00000000..a3471e3e --- /dev/null +++ b/wammer/WAPhotoTimelineNavigationBar.m @@ -0,0 +1,74 @@ +// +// WAPhotoTimelineNavigationBar.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoTimelineNavigationBar.h" + +@implementation WAPhotoTimelineNavigationBar + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void)drawRect:(CGRect)rect +{ + if (self.solid) { + UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 250)]; + imageView.contentMode = UIViewContentModeScaleAspectFill; + imageView.image = [UIImage imageNamed:@"Cover1"]; + imageView.layer.opacity = 0.9; + imageView.layer.opaque = NO; + CALayer *darken = [[CALayer alloc] init]; + darken.frame = imageView.frame; + darken.opaque = NO; + darken.opacity = 0.6; + darken.backgroundColor = [UIColor blackColor].CGColor; + [imageView.layer insertSublayer:darken above:imageView.layer]; + // NSLog(@"%@", NSStringFromCGRect(rect)); + + UIGraphicsBeginImageContext(CGSizeMake(320, 250)); + CGContextRef context = UIGraphicsGetCurrentContext(); + // UIGraphicsPushContext(context); + [imageView.layer renderInContext:context]; + UIImage *renderingImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + // UIGraphicsPopContext(); + + if (!renderingImage) { + NSLog(@"unable to generate rendering image for navigation bar"); + return; + } + + context = UIGraphicsGetCurrentContext(); + + CGAffineTransform transform = CGAffineTransformIdentity; + + transform = CGAffineTransformTranslate(transform, 320, 250); + transform = CGAffineTransformRotate(transform, M_PI); + // transform = CGAffineTransformTranslate(transform, 320, 0); + // transform = CGAffineTransformScale(transform, -1, 1); + transform = CGAffineTransformTranslate(transform, 320, 0); + transform = CGAffineTransformScale(transform, -1, 1); + + CGContextConcatCTM(context, transform); + CGContextDrawImage(context, (CGRect){{0, 250-44}, {320, 250}}, renderingImage.CGImage); + } else { + + CGContextRef context = UIGraphicsGetCurrentContext(); + UIGraphicsPushContext(context); + CGContextClearRect(context, rect); + UIGraphicsPopContext(); + } + +} + +@end diff --git a/wammer/WAPhotoTimelineViewController.h b/wammer/WAPhotoTimelineViewController.h new file mode 100644 index 00000000..7d10e2b6 --- /dev/null +++ b/wammer/WAPhotoTimelineViewController.h @@ -0,0 +1,16 @@ +// +// WAPhotoTimelineViewController.h +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPhotoTimelineViewController : UIViewController + +- (id) initWithAssets:(NSArray*)assets; +- (id) initWithArticle:(NSManagedObjectID *)managedObjectID; + +@end diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m new file mode 100644 index 00000000..2e888cd1 --- /dev/null +++ b/wammer/WAPhotoTimelineViewController.m @@ -0,0 +1,404 @@ +// +// WAPhotoTimelineViewController.m +// wammer +// +// Created by Shen Steven on 4/5/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPhotoTimelineViewController.h" +#import "WAPhotoTimelineNavigationBar.h" +#import "WAPhotoTimelineCover.h" +#import "WAPhotoTimelineLayout.h" +#import "WAPhotoCollageCell.h" +#import "WAAssetsLibraryManager.h" +#import "WATimelineIndexView.h" +#import +#import "WAGeoLocation.h" +#import + + +@interface WAPhotoTimelineViewController () + +@property (nonatomic, strong) WAPhotoTimelineCover *headerView; +@property (nonatomic, strong) WAPhotoTimelineNavigationBar *navigationBar; +@property (nonatomic, weak) IBOutlet UICollectionView *collectionView; +@property (nonatomic, weak) IBOutlet WATimelineIndexView *indexView; +@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; +@property (nonatomic, strong) NSArray *allAssets; +@property (nonatomic, strong) WAGeoLocation *geoLocation; +@property (nonatomic, strong) NSDate *eventDate; +@property (nonatomic, strong) NSDate *beginDate; +@property (nonatomic, strong) NSDate *endDate; +@property (nonatomic, readonly) CLLocationCoordinate2D coordinate; + +@end + +@implementation WAPhotoTimelineViewController { + BOOL naviBarShown; + CLLocationCoordinate2D _coordinate; +} + +- (id) initWithAssets:(NSArray *)assets { + self = [super initWithNibName:@"WAPhotoTimelineViewController" bundle:nil]; + if (self) { + NSMutableArray *array = [NSMutableArray arrayWithCapacity:assets.count]; + NSEnumerator *enumerator = [assets reverseObjectEnumerator]; + for (id element in enumerator) { + [array addObject:element]; + } + self.allAssets = [NSArray arrayWithArray:array]; + _coordinate.latitude = 0; + _coordinate.longitude = 0; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + naviBarShown = NO; + + self.imageDisplayQueue = [[NSOperationQueue alloc] init]; + self.imageDisplayQueue.maxConcurrentOperationCount = 1; + + UIImage *backImage = [UIImage imageNamed:@"back"]; + UIButton *backButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, backImage.size}]; + [backButton addTarget:self action:@selector(backButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; + [backButton setImage:backImage forState:UIControlStateNormal]; + UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; + + UIImage *actionImage = [UIImage imageNamed:@"action"]; + UIButton *actionButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, actionImage.size}]; + [actionButton setImage:actionImage forState:UIControlStateNormal]; + UIBarButtonItem *actionItem = [[UIBarButtonItem alloc] initWithCustomView:actionButton]; + + self.navigationItem.leftBarButtonItem = backItem; + self.navigationItem.rightBarButtonItem = actionItem; + + self.navigationBar = [[WAPhotoTimelineNavigationBar alloc] initWithFrame:(CGRect)CGRectMake(0, 0, self.view.frame.size.width, 44)]; + self.navigationBar.barStyle = UIBarStyleDefault; + self.navigationBar.tintColor = [UIColor clearColor]; + self.navigationBar.backgroundColor = [UIColor clearColor]; + self.navigationBar.translucent = YES; + // self.navigationBar.items = @[backItem, actionItem]; + [self.navigationBar pushNavigationItem:self.navigationItem animated:NO]; + + [self.view addSubview:self.navigationBar]; + + [self.collectionView setBackgroundColor:[UIColor blackColor]]; + ((UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout).minimumLineSpacing = 0.0f; + + self.collectionView.showsVerticalScrollIndicator = NO; + + [self.collectionView registerNib:[UINib nibWithNibName:@"WAPhotoTimelineCover" bundle:nil] + forSupplementaryViewOfKind:UICollectionElementKindSectionHeader + withReuseIdentifier:@"PhotoTimelineCover"]; + + [self.collectionView registerNib:[UINib nibWithNibName:@"WAPhotoCollageCell_Stack4" bundle:nil] + forCellWithReuseIdentifier:@"CollectionItemCell4"]; + [self.collectionView registerNib:[UINib nibWithNibName:@"WAPhotoCollageCell_Stack3" bundle:nil] + forCellWithReuseIdentifier:@"CollectionItemCell3"]; + [self.collectionView registerNib:[UINib nibWithNibName:@"WAPhotoCollageCell_Stack2" bundle:nil] + forCellWithReuseIdentifier:@"CollectionItemCell2"]; + [self.collectionView registerNib:[UINib nibWithNibName:@"WAPhotoCollageCell_Stack1" bundle:nil] + forCellWithReuseIdentifier:@"CollectionItemCell1"]; + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter = [[NSDateFormatter alloc] init]; + formatter.dateStyle = NSDateFormatterNoStyle; + formatter.timeStyle = NSDateFormatterShortStyle; + + [self.indexView addIndex:0.01 label:[formatter stringFromDate:self.beginDate]]; + [self.indexView addIndex:0.99 label:[formatter stringFromDate:self.endDate]]; +} + +- (BOOL) shouldAutorotate { + + return YES; + +} + +- (NSUInteger) supportedInterfaceOrientations { + + return UIInterfaceOrientationMaskPortrait; + +} + +- (void) backButtonClicked:(id)sender { + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (CLLocationCoordinate2D)coordinate { + + if (_coordinate.latitude!=0 && _coordinate.longitude!=0) + return _coordinate; + + for (ALAsset *asset in self.allAssets) { + NSDictionary *meta = [asset defaultRepresentation].metadata; + if (meta) { + NSDictionary *gps = meta[@"{GPS}"]; + if (gps) { + _coordinate.latitude = [(NSNumber*)[gps valueForKey:@"Latitude"] doubleValue]; + _coordinate.longitude = [(NSNumber*)[gps valueForKey:@"Longitude"] doubleValue]; + break; + } + } + } + return _coordinate; +} + +- (NSDate*) eventDate { + + if (_eventDate) + return _eventDate; + + _eventDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; + return _eventDate; + +} + +- (NSDate *) beginDate { + if (_beginDate) + return _beginDate; + + _beginDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; + return _beginDate; +} + +- (NSDate *) endDate { + if (_endDate) + return _endDate; + + _endDate = [self.allAssets.lastObject valueForProperty:ALAssetPropertyDate]; + return _endDate; +} + +#pragma mark - UICollectionView datasource +- (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return 1; +} + +- (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + + NSUInteger totalItem = (self.allAssets.count / 10) * 4; + NSUInteger mod = self.allAssets.count % 10; + if (mod == 0) + return totalItem; + else if (mod < 4) + return totalItem + 1; + else if (mod < 7) + return totalItem + 2; + else if (mod < 9) + return totalItem + 3; + else + return totalItem + 4; + +} + +- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + + NSUInteger numOfPhotos = 4 - (indexPath.row % 4); + NSString *identifier = [NSString stringWithFormat:@"CollectionItemCell%d", numOfPhotos]; + + WAPhotoCollageCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath]; + + NSUInteger base = 0; + switch(indexPath.row % 4) { + case 3: + base = (indexPath.row / 4) * 10 + 9; + break; + case 2: + base = (indexPath.row / 4) * 10 + 7; + break; + case 1: + base = (indexPath.row / 4) * 10 + 4; + break; + case 0: + base = (indexPath.row / 4) * 10; + break; + } + + __weak WAPhotoTimelineViewController *wSelf = self; + for (NSUInteger i = 0; i < numOfPhotos && ((base+i) 0) + self.indexView.hidden = NO; + + if (!naviBarShown && scrollView.contentOffset.y >= (250-44-50)) { + + [self performSelectorOnMainThread:@selector(showingNavigationBar) withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; + naviBarShown = YES; + + } + + if (naviBarShown && scrollView.contentOffset.y <= (250-44-50)) { + [self performSelectorOnMainThread:@selector(hideNavigationBar) withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]]; + naviBarShown = NO; + } + + if (scrollView.contentOffset.y > 0) + self.indexView.percentage = (scrollView.contentOffset.y / scrollView.contentSize.height); + +} + +- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView { + if (!self.indexView.hidden) { + [UIView animateWithDuration:1 animations:^{ + self.indexView.hidden = YES; + + }]; + } +} + +@end diff --git a/wammer/WAPhotoTimelineViewController.xib b/wammer/WAPhotoTimelineViewController.xib new file mode 100644 index 00000000..c66bbbe6 --- /dev/null +++ b/wammer/WAPhotoTimelineViewController.xib @@ -0,0 +1,480 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionView + IBUICollectionViewLayout + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 1298 + + + {320, 548} + + + + _NS:9 + NO + YES + YES + IBCocoaTouchFramework + YES + 0.0 + 0.0 + + + + + + + + 292 + {{299, 62}, {11, 466}} + + + + _NS:9 + + 3 + MQA + + 2 + + + IBCocoaTouchFramework + + + {{0, 20}, {320, 548}} + + + + + 3 + MQA + + + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + + + + + + + view + + + + 3 + + + + collectionView + + + + 14 + + + + indexView + + + + 36 + + + + delegate + + + + 16 + + + + dataSource + + + + 17 + + + + + + 0 + + + + + + 1 + + + + + 5 + 0 + + 5 + 1 + + 299 + + 1000 + + 3 + 9 + 3 + + + + 4 + 0 + + 4 + 1 + + 20 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 62 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 10 + + 1000 + + 3 + 9 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + + 10 + + + + + 11 + + + + + 12 + + + + + 13 + + + + + 15 + + + + + 18 + + + + + 30 + + + + + 31 + + + + + 33 + + + + + 34 + + + + + + + WAPhotoTimelineViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WAPhotoTimelineLayout + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WATimelineIndexView + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + 36 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionViewFlowLayout + UICollectionViewLayout + + IBProjectSource + ./Classes/UICollectionViewFlowLayout.h + + + + UICollectionViewLayout + NSObject + + IBProjectSource + ./Classes/UICollectionViewLayout.h + + + + WAPhotoTimelineLayout + UICollectionViewFlowLayout + + IBProjectSource + ./Classes/WAPhotoTimelineLayout.h + + + + WAPhotoTimelineViewController + UIViewController + + UICollectionView + WATimelineIndexView + + + + collectionView + UICollectionView + + + indexView + WATimelineIndexView + + + + IBProjectSource + ./Classes/WAPhotoTimelineViewController.h + + + + WATimelineIndexView + UIView + + IBProjectSource + ./Classes/WATimelineIndexView.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WATimelineIndexView.h b/wammer/WATimelineIndexView.h new file mode 100644 index 00000000..1c4fae91 --- /dev/null +++ b/wammer/WATimelineIndexView.h @@ -0,0 +1,16 @@ +// +// WATimelineIndexView.h +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WATimelineIndexView : UIView + +@property (nonatomic, assign) CGFloat percentage; +- (void) addIndex:(CGFloat)index label:(NSString*)label; + +@end diff --git a/wammer/WATimelineIndexView.m b/wammer/WATimelineIndexView.m new file mode 100644 index 00000000..712d883a --- /dev/null +++ b/wammer/WATimelineIndexView.m @@ -0,0 +1,183 @@ +// +// WATimelineIndexView.m +// wammer +// +// Created by Shen Steven on 4/6/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WATimelineIndexView.h" + +@interface WATimelineIndexLabel : UILabel + +- (void) show; +- (void) hide; +@property (nonatomic, readonly) BOOL showing; + +@end + +@interface WATimelineIndexLabel () +@property (nonatomic, assign) BOOL showing; +@end + +@implementation WATimelineIndexLabel + +- (id) initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + + if (self) { + self.showing = NO; + self.alpha = 0.0f; + self.textAlignment = NSTextAlignmentCenter; + } + + return self; +} + +- (void) show { + if (!self.showing) { + + [UIView animateWithDuration:0.4 + delay:0 + options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionShowHideTransitionViews + animations:^{ + self.alpha = 1.0f; + } completion:^(BOOL finished) { + }]; + self.showing = YES; + + } +} + +- (void) hide { + if (self.showing) { + [UIView animateWithDuration:1 + delay:0 + options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionShowHideTransitionViews + animations:^{ + self.alpha = 0.0f; + } completion:^(BOOL finished) { + }]; + + self.showing = NO; + } +} + +@end + + + +@interface WATimelineIndexView () + +@property (nonatomic, strong) NSMutableArray *indexics; +@property (nonatomic, strong) NSMutableArray *labels; +@property (nonatomic, strong) UIView *dot; + +@end +@implementation WATimelineIndexView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void) awakeFromNib { + + self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6]; + self.layer.cornerRadius = self.frame.size.width/2; + self.dot = [[UIView alloc] initWithFrame:CGRectMake(self.frame.size.width/2-4, 10, 8, 8)]; + self.dot.layer.cornerRadius = self.dot.frame.size.width/2; + self.dot.backgroundColor = [UIColor colorWithWhite:120 alpha:0.8]; + [self addSubview:self.dot]; + + self.indexics = [NSMutableArray array]; + self.labels = [NSMutableArray array]; +} + + +- (void) addIndex:(CGFloat)index label:(NSString*)label { + + NSInteger i = 0; + for (NSNumber *value in self.indexics) { + if (index > [value floatValue]) { + break; + } + i++; + } + + [self.indexics insertObject:[NSNumber numberWithFloat:index] atIndex:i]; + + WATimelineIndexLabel *newLabel = [[WATimelineIndexLabel alloc] initWithFrame:CGRectMake(-100, 0, 90, 22)]; + newLabel.backgroundColor = [UIColor blackColor]; + newLabel.textColor = [UIColor whiteColor]; + newLabel.textAlignment = NSTextAlignmentCenter; + newLabel.text = label; + [newLabel sizeToFit]; + [self addSubview:newLabel]; + CGRect newFrame = newLabel.frame; + newFrame.origin.x = -10 - newFrame.size.width; + newLabel.frame = newFrame; + + [self.labels insertObject:newLabel atIndex:i]; + +} + +- (NSInteger) indexForPercentage:(CGFloat)percentage { + + int i = 0; + for (NSNumber *index in self.indexics) { + CGFloat max = [index floatValue] + 0.01; + CGFloat min = [index floatValue] - 0.005; + + if (percentage < max && percentage > min) { + return i; + } + i++; + } + + return NSNotFound; +} + +- (void) setPercentage:(CGFloat)percentage { + + CGFloat newY = self.frame.size.height * percentage; + CGRect newRect = CGRectMake(self.frame.size.width/2-4, newY, 8, 8); + [UIView animateWithDuration:0.2 animations:^{ + self.dot.frame = newRect; + }]; + + NSInteger indexInRange = [self indexForPercentage:percentage]; + if (indexInRange != NSNotFound) { + CGRect frame = ((WATimelineIndexLabel*)self.labels[indexInRange]).frame; + frame.origin.y = newY - 11; + ((WATimelineIndexLabel*)self.labels[indexInRange]).frame = frame; + + if (!((WATimelineIndexLabel*)self.labels[indexInRange]).showing) + [((WATimelineIndexLabel*)self.labels[indexInRange]) show]; + } + + NSInteger preIndexInRange = [self indexForPercentage:_percentage]; + if (preIndexInRange != NSNotFound && ((WATimelineIndexLabel*)self.labels[preIndexInRange]).showing ) { + [((WATimelineIndexLabel*)self.labels[preIndexInRange]) hide]; + } + + _percentage = percentage; + +} + + + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end From 5abf1b2757b5664c5aac90fe09185aa94e290602 Mon Sep 17 00:00:00 2001 From: syshen Date: Mon, 8 Apr 2013 18:16:19 +0800 Subject: [PATCH 005/278] fine tune the app launch flow --- wammer/WAAppDelegate_iOS.h | 1 + wammer/WAAppDelegate_iOS.m | 157 +++++++++++++++++++++-- wammer/WAPartioWelcomeViewController.m | 12 ++ wammer/WAPhotoHighlightsViewController.h | 2 + wammer/WAPhotoHighlightsViewController.m | 123 +++++++++--------- 5 files changed, 222 insertions(+), 73 deletions(-) diff --git a/wammer/WAAppDelegate_iOS.h b/wammer/WAAppDelegate_iOS.h index 6b08e5d0..c45a1891 100644 --- a/wammer/WAAppDelegate_iOS.h +++ b/wammer/WAAppDelegate_iOS.h @@ -18,5 +18,6 @@ @property (nonatomic, readonly, strong) WASlidingMenuViewController *slidingMenu; - (void) recreateViewHierarchy; ++ (void) backgroundLoginWithFacebookIDWithCompleteHandler:(void(^)(NSError *error))completionHandler; @end diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 538eb069..8edd4fca 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -126,6 +126,96 @@ @implementation WAAppDelegate_iOS @synthesize window = _window; @synthesize alreadyRequestingAuthentication; ++ (void) backgroundLoginWithFacebookIDWithCompleteHandler:(void(^)(NSError *error))completionHandler { + + WAOverlayBezel *busyBezel = [WAOverlayBezel bezelWithStyle:WAActivityIndicatorBezelStyle]; + [busyBezel showWithAnimation:WAOverlayBezelAnimationFade]; + + // http://stackoverflow.com/questions/12601191/facebook-sdk-3-1-error-validating-access-token + // This should and will be fixed from FB SDK + + ACAccountStore *accountStore; + ACAccountType *accountTypeFB; + if ((accountStore = [[ACAccountStore alloc] init]) && + (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){ + + NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB]; + id account; + if (fbAccounts && [fbAccounts count] > 0 && + (account = [fbAccounts objectAtIndex:0])){ + + [accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { + //we don't actually need to inspect renewResult or error. + if (error){ + + } + }]; + } + } + + + [FBSession + openActiveSessionWithReadPermissions:@[@"email", @"user_photos", @"user_videos", @"user_notes", @"user_status", @"user_likes", @"read_stream", @"friends_photos", @"friends_videos", @"friends_status", @"friends_notes", @"friends_likes"] + allowLoginUI:YES + completionHandler:^(FBSession *session, FBSessionState status, NSError *error) { + + if (error) { + + NSLog(@"Facebook auth error: %@", error); + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + if (completionHandler) + completionHandler(error); + + }); + + return; + } + + [[WARemoteInterface sharedInterface] + signupUserWithFacebookToken:session.accessTokenData.accessToken + withOptions:nil + onSuccess:^(NSString *token, NSDictionary *userRep, NSArray *groupReps) { + + WARemoteInterface * const ri = [WARemoteInterface sharedInterface]; + + NSString *userID = [userRep valueForKeyPath:@"user_id"]; + + NSString *primaryGroupID = [[[groupReps filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + + return [[evaluatedObject valueForKeyPath:@"creator_id"] isEqual:userID]; + + }]] lastObject] valueForKeyPath:@"group_id"]; + + + ri.userIdentifier = userID; + ri.userToken = token; + ri.primaryGroupIdentifier = primaryGroupID; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (completionHandler) + completionHandler(nil); + }); + + + } onFailure:^(NSError *error) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + + if (completionHandler) + completionHandler(error); + + }); + + }]; + + }]; + +} + - (void) bootstrap { [super bootstrap]; @@ -201,8 +291,9 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: [self recreateViewHierarchy]; -// } else if (![self hasAuthenticationData]) { -// + } else if (![self hasAuthenticationData]) { + + [self handlePartioAuthRequest]; // [self applicationRootViewControllerDidRequestReauthentication:nil]; } else { @@ -368,20 +459,28 @@ - (void) recreateViewHierarchy { // viewDeckController.delegate = self.slidingMenu; // viewDeckController.centerhiddenInteractivity = IIViewDeckCenterHiddenNotUserInteractiveWithTapToClose; - - __weak WAAppDelegate_iOS *wSelf = self; - WAPartioFirstUseViewController *partioFirstUse = [WAPartioFirstUseViewController firstUseViewControllerWithCompletionBlock:^{ - UIViewController *rootVC = self.window.rootViewController; + + if (![FBSession activeSession].isOpen) { + [[self class] backgroundLoginWithFacebookIDWithCompleteHandler:^(NSError *error) { - [rootVC zapModal]; + if (error) { + NSLog(@"failed to login facebook for error: %@", error); + + } else { - WAPhotoHighlightsViewController *photoGroupsVC = [[WAPhotoHighlightsViewController alloc] initWithStyle:UITableViewStylePlain]; - wSelf.window.rootViewController = photoGroupsVC; + WAPhotoHighlightsViewController *highlightVC = [[WAPhotoHighlightsViewController alloc] init]; + self.window.rootViewController = highlightVC; - } failure:^(NSError *error) { - NSLog(@"fail to sign up for error: %@", error); - }]; - self.window.rootViewController = partioFirstUse; + } + + }]; + } else { + + WAPhotoHighlightsViewController *highlightVC = [[WAPhotoHighlightsViewController alloc] init]; + self.window.rootViewController = highlightVC; + + } + UIViewController *vc = self.window.rootViewController; @@ -693,6 +792,38 @@ - (BOOL) presentAuthenticationRequestWithReason:(NSString *)aReason } +- (void) handlePartioAuthRequest { + + __weak WAAppDelegate_iOS *wSelf = self; + __block WAPartioFirstUseViewController *partioFirstUse = [WAPartioFirstUseViewController firstUseViewControllerWithCompletionBlock:^{ + + WARemoteInterface *ri = [WARemoteInterface sharedInterface]; + if (ri.userToken) { + [wSelf updateCurrentCredentialsWithUserIdentifier:ri.userIdentifier token:ri.userToken primaryGroup:ri.primaryGroupIdentifier]; + [wSelf bootstrapPersistentStoreWithUserIdentifier:ri.userIdentifier]; + } + [partioFirstUse popToRootViewControllerAnimated:NO]; + + [partioFirstUse dismissViewControllerAnimated:NO completion:^{ + wSelf.window.rootViewController = nil; + [wSelf recreateViewHierarchy]; + }]; + + WAPhotoHighlightsViewController *photoGroupsVC = [[WAPhotoHighlightsViewController alloc] init]; + wSelf.window.rootViewController = photoGroupsVC; + + } failure:^(NSError *error) { + NSLog(@"fail to sign up for error: %@", error); + IRAction *okAction = [IRAction actionWithTitle:NSLocalizedString(@"ACTION_OKAY", @"Alert Dismissal Action") block:nil]; + + IRAlertView *alertView = [IRAlertView alertViewWithTitle:nil message:@"Login failed" cancelAction:okAction otherActions:nil]; + [alertView show]; + + }]; + self.window.rootViewController = partioFirstUse; + +} + - (void) handleAuthRequest:(NSString *)reason withOptions:(NSDictionary *)options completion:(void(^)(BOOL didFinish, NSError *error))block { WARemoteInterface * const ri = [WARemoteInterface sharedInterface]; diff --git a/wammer/WAPartioWelcomeViewController.m b/wammer/WAPartioWelcomeViewController.m index 4a3c3aa0..fdcac262 100644 --- a/wammer/WAPartioWelcomeViewController.m +++ b/wammer/WAPartioWelcomeViewController.m @@ -101,7 +101,19 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath signupUserWithFacebookToken:session.accessTokenData.accessToken withOptions:nil onSuccess:^(NSString *token, NSDictionary *userRep, NSArray *groupReps) { + NSString *userID = [userRep valueForKeyPath:@"user_id"]; + NSString *primaryGroupID = [[[groupReps filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + + return [[evaluatedObject valueForKeyPath:@"creator_id"] isEqual:userID]; + + }]] lastObject] valueForKeyPath:@"group_id"]; + + WARemoteInterface *ri = [WARemoteInterface sharedInterface]; + ri.userIdentifier = userID; + ri.userToken = token; + ri.primaryGroupIdentifier = primaryGroupID; + dispatch_async(dispatch_get_main_queue(), ^{ if (firstUse.completionBlock) firstUse.completionBlock(); diff --git a/wammer/WAPhotoHighlightsViewController.h b/wammer/WAPhotoHighlightsViewController.h index e4ddf875..d2ef3020 100644 --- a/wammer/WAPhotoHighlightsViewController.h +++ b/wammer/WAPhotoHighlightsViewController.h @@ -10,4 +10,6 @@ @interface WAPhotoHighlightsViewController : UITableViewController +- (id) init; + @end diff --git a/wammer/WAPhotoHighlightsViewController.m b/wammer/WAPhotoHighlightsViewController.m index 851c795c..e534fdb1 100644 --- a/wammer/WAPhotoHighlightsViewController.m +++ b/wammer/WAPhotoHighlightsViewController.m @@ -31,10 +31,11 @@ @interface WAPhotoHighlightsViewController () @implementation WAPhotoHighlightsViewController -- (id)initWithStyle:(UITableViewStyle)style -{ - self = [super initWithStyle:style]; +- (id) init { + + self = [self initWithStyle:UITableViewStylePlain]; if (self) { + } return self; } @@ -48,7 +49,7 @@ - (void)viewDidLoad self.managedObjectContext = [[WADataStore defaultStore] disposableMOC]; - [self.tableView registerNib:[UINib nibWithNibName:@"WAPhotoGroupViewCell" bundle:nil] forCellReuseIdentifier:@"WAPhotoGroupViewCell"]; + [self.tableView registerNib:[UINib nibWithNibName:@"WAPhotoHighlightViewCell" bundle:nil] forCellReuseIdentifier:@"WAPhotoHighlightViewCell"]; __weak WAPhotoHighlightsViewController *wSelf = self; WAOverlayBezel *busyBezel = [[WAOverlayBezel alloc] initWithStyle:WAActivityIndicatorBezelStyle]; @@ -65,64 +66,66 @@ - (void)viewDidLoad NSLog(@"error: %@", error); }]; - self.fbConnection = [FBRequestConnection startForUserCheckinsAfterId:nil - completeHandler:^(FBRequestConnection *connection, NSArray *result, NSError *error) { + if ([FBSession activeSession].isOpen) { + self.fbConnection = [FBRequestConnection startForUserCheckinsAfterId:nil + completeHandler:^(FBRequestConnection *connection, NSArray *result, NSError *error) { - if (error) { - NSLog(@"fb request error: %@", error); - } else { -// NSLog(@"fb request success: %@", result); - - NSManagedObjectContext *context = [[WADataStore defaultStore] disposableMOC]; - NSMutableArray *changedIndexPaths = [NSMutableArray array]; - - for (NSDictionary *checkinItem in result) { - NSNumber *timestampNumber = checkinItem[@"timestamp"]; - NSDate *checkinDate = [NSDate dateWithTimeIntervalSince1970:timestampNumber.floatValue]; - - BOOL found = NO; - - [WACheckin insertOrUpdateObjectsUsingContext:context withRemoteResponse:result usingMapping:nil options:IRManagedObjectOptionIndividualOperations]; - - NSUInteger groupIndex = 0; - for (NSArray *group in self.photoGroups) { - NSDate *enddingDate = [NSDate dateWithTimeInterval:(30*60) sinceDate:[(ALAsset*)group[0] valueForProperty:ALAssetPropertyDate]]; - NSDate *beginningDate = [NSDate dateWithTimeInterval:(-30*60) sinceDate:[(ALAsset*)group.lastObject valueForProperty:ALAssetPropertyDate]]; - - if (groupIndex == 0) { - NSLog(@"%@ ~ %@", beginningDate, enddingDate); - } - if ([checkinDate compare:beginningDate] == NSOrderedAscending) { - groupIndex ++; - continue; - } - - if ([checkinDate compare:enddingDate] == NSOrderedAscending) { - found = YES; - } - - break; - - } - - if (found) { - [changedIndexPaths addObject:[NSIndexPath indexPathForRow:groupIndex inSection:0]]; - NSLog(@"found %@ at indexPath row: %d", checkinItem[@"name"],groupIndex); - } - } + if (error) { + NSLog(@"fb request error: %@", error); + } else { + // NSLog(@"fb request success: %@", result); - NSError *error = nil; - [context save:&error]; - if (error) { - NSLog(@"fail to save checkin for %@", error); - } + NSManagedObjectContext *context = [[WADataStore defaultStore] disposableMOC]; + NSMutableArray *changedIndexPaths = [NSMutableArray array]; - dispatch_async(dispatch_get_main_queue(), ^{ - [wSelf.tableView reloadRowsAtIndexPaths:changedIndexPaths withRowAnimation:YES]; - }); - } - }]; - + for (NSDictionary *checkinItem in result) { + NSNumber *timestampNumber = checkinItem[@"timestamp"]; + NSDate *checkinDate = [NSDate dateWithTimeIntervalSince1970:timestampNumber.floatValue]; + + BOOL found = NO; + + [WACheckin insertOrUpdateObjectsUsingContext:context withRemoteResponse:result usingMapping:nil options:IRManagedObjectOptionIndividualOperations]; + + NSUInteger groupIndex = 0; + for (NSArray *group in self.photoGroups) { + NSDate *enddingDate = [NSDate dateWithTimeInterval:(30*60) sinceDate:[(ALAsset*)group[0] valueForProperty:ALAssetPropertyDate]]; + NSDate *beginningDate = [NSDate dateWithTimeInterval:(-30*60) sinceDate:[(ALAsset*)group.lastObject valueForProperty:ALAssetPropertyDate]]; + + if (groupIndex == 0) { + NSLog(@"%@ ~ %@", beginningDate, enddingDate); + } + if ([checkinDate compare:beginningDate] == NSOrderedAscending) { + groupIndex ++; + continue; + } + + if ([checkinDate compare:enddingDate] == NSOrderedAscending) { + found = YES; + } + + break; + + } + + if (found) { + [changedIndexPaths addObject:[NSIndexPath indexPathForRow:groupIndex inSection:0]]; + NSLog(@"found %@ at indexPath row: %d", checkinItem[@"name"],groupIndex); + } + } + + NSError *error = nil; + [context save:&error]; + if (error) { + NSLog(@"fail to save checkin for %@", error); + } + + dispatch_async(dispatch_get_main_queue(), ^{ + [wSelf.tableView reloadRowsAtIndexPaths:changedIndexPaths withRowAnimation:YES]; + }); + } + }]; + + } } @@ -210,7 +213,7 @@ + (NSOperationQueue*)sharedImageDisplayingQueue { - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *CellIdentifier = @"WAPhotoGroupViewCell"; + static NSString *CellIdentifier = @"WAPhotoHighlightViewCell"; WAPhotoHighlightViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath]; NSArray *photoList = self.photoGroups[indexPath.row]; From 005b8a8ad283ff8fa66a0456ac64676bafd2bbb7 Mon Sep 17 00:00:00 2001 From: Greener Date: Mon, 8 Apr 2013 19:46:42 +0800 Subject: [PATCH 006/278] Integrate shared events view and contacts picker view into sharing flow --- WAContactPickerViewController.h | 18 ++ WAContactPickerViewController.m | 174 +++++++++++++++++ WAContactPickerViewController.xib | 160 ++++++++++++++++ WASharedEventViewController.h | 16 ++ WASharedEventViewController.m | 136 ++++++++++++++ WASharedEventViewController.xib | 149 +++++++++++++++ wammer.xcodeproj/project.pbxproj | 46 ++++- wammer/WAAppDelegate_iOS.m | 10 +- ...WACheckin+WARemoteInterfaceEntitySyncing.m | 4 +- wammer/WAContactPickerViewController.h | 18 ++ wammer/WAContactPickerViewController.m | 177 ++++++++++++++++++ wammer/WAContactPickerViewController.xib | 160 ++++++++++++++++ wammer/WAPartioFirstUse.storyboard | 11 -- .../WAPhotoCollageCell_Stack1.xib | 0 wammer/WAPhotoTimelineViewController.m | 11 ++ wammer/WASharedEventViewController.h | 16 ++ wammer/WASharedEventViewController.m | 148 +++++++++++++++ wammer/WASharedEventViewController.xib | 149 +++++++++++++++ wammer/en.lproj/Localizable.strings | 6 + wammer/zh-Hant.lproj/Localizable.strings | 6 + 20 files changed, 1395 insertions(+), 20 deletions(-) create mode 100644 WAContactPickerViewController.h create mode 100644 WAContactPickerViewController.m create mode 100644 WAContactPickerViewController.xib create mode 100644 WASharedEventViewController.h create mode 100644 WASharedEventViewController.m create mode 100644 WASharedEventViewController.xib create mode 100644 wammer/WAContactPickerViewController.h create mode 100644 wammer/WAContactPickerViewController.m create mode 100644 wammer/WAContactPickerViewController.xib rename WAPhotoCollageCell_Stack1.xib => wammer/WAPhotoCollageCell_Stack1.xib (100%) create mode 100644 wammer/WASharedEventViewController.h create mode 100644 wammer/WASharedEventViewController.m create mode 100644 wammer/WASharedEventViewController.xib diff --git a/WAContactPickerViewController.h b/WAContactPickerViewController.h new file mode 100644 index 00000000..042aed7b --- /dev/null +++ b/WAContactPickerViewController.h @@ -0,0 +1,18 @@ +// +// WAContactPickerViewController.h +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import +#import + +@interface WAContactPickerViewController : UITableViewController + +@property (nonatomic, strong) NSMutableArray *members; + +-(IBAction)showContactsPicker:(id)sender; + +@end diff --git a/WAContactPickerViewController.m b/WAContactPickerViewController.m new file mode 100644 index 00000000..e7034fa8 --- /dev/null +++ b/WAContactPickerViewController.m @@ -0,0 +1,174 @@ +// +// WAContactPickerViewController.m +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import "WAContactPickerViewController.h" + +@interface WAContactPickerViewController () + +@end + +@implementation WAContactPickerViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + // Custom initialization + _members = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)]; +} + +- (void)cancel +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)done +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 2; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + if (section == 0) { + return 2; + + } else { + return [_members count]; + + } +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section +{ + UIView *headerView = [super tableView:tableView viewForHeaderInSection:section]; + // Customize the header view + + return headerView; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; + } + + // Configure the cell... + if (indexPath.section == 0) { + if (indexPath.row == 0) { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = @"Facebook Contacts"; + cell.detailTextLabel.text = @"Share to your Facebook friends"; + + } else if (indexPath.row == 1) { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = @"Contacts"; + cell.detailTextLabel.text = @"Share to your contacts"; + cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; + + } + + } else { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = _members[indexPath.row][@"name"]; + cell.detailTextLabel.text = [NSString stringWithFormat:@"%@\n%@", + _members[indexPath.row][@"phone"], + ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; + cell.accessoryType = UITableViewCellAccessoryCheckmark; + + } + + return cell; +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (indexPath.section == 0 && indexPath.row == 1) { + ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; + abPicker.peoplePickerDelegate = self; + + [self presentViewController:abPicker animated:YES completion:nil]; + + } +} + +#pragma - Address Book Contacts Picker + +- (void)showContactsPicker:(id)sender +{ + ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; + abPicker.peoplePickerDelegate = self; + + [self presentViewController:abPicker animated:YES completion:nil]; +} + +- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person +{ + [self addIntoInvitedList:person]; + [self dismissViewControllerAnimated:YES completion:nil]; + [self.tableView reloadData]; + + return NO; +} + +- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier +{ + return NO; +} + +- (void)addIntoInvitedList:(ABRecordRef)person +{ + NSString *firstname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); + NSString *lastname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); + NSArray *email = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); + + NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(person, kABPersonPhoneProperty), 0);; + + NSDictionary *aPerson = @{@"name": [NSString stringWithFormat:@"%@ %@", firstname, lastname], + @"email": (email)? email : @[], + @"phone": (phone)? phone : @"[None]"}; + [_members addObject:aPerson]; + +} + +@end diff --git a/WAContactPickerViewController.xib b/WAContactPickerViewController.xib new file mode 100644 index 00000000..b2a5b64a --- /dev/null +++ b/WAContactPickerViewController.xib @@ -0,0 +1,160 @@ + + + + 1536 + 12A269 + 2835 + 1187 + 624.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1919 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 548}} + + + + + 3 + MQA + + NO + YES + NO + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 44 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + WAContactPickerViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 7 + + + + + WAContactPickerViewController + UITableViewController + + IBProjectSource + ./Classes/WAContactPickerViewController.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 1919 + + diff --git a/WASharedEventViewController.h b/WASharedEventViewController.h new file mode 100644 index 00000000..348867d6 --- /dev/null +++ b/WASharedEventViewController.h @@ -0,0 +1,16 @@ +// +// WAEventSharingViewController.h +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import + +@interface WASharedEventViewController : UITableViewController + + +@end + + diff --git a/WASharedEventViewController.m b/WASharedEventViewController.m new file mode 100644 index 00000000..a58821e7 --- /dev/null +++ b/WASharedEventViewController.m @@ -0,0 +1,136 @@ +// +// WAEventSharingViewController.m +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import "WASharedEventViewController.h" +#import "WAContactPickerViewController.h" +#import "WANavigationController.h" +#import "WALocation.h" +#import +#import "WADataStore.h" +#import "NSDate+WAAdditions.h" + +@interface WASharedEventViewController () + +@property (nonatomic, strong) NSFetchedResultsController *eventFetchedResultsController; +@property (nonatomic, strong) NSMutableArray *events; + +@end + +@implementation WASharedEventViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + // Custom initialization + self.events = [[NSMutableArray alloc] init]; + } + self.events = [[self loadEventsFrom:[NSDate date] forwardDays:100] copy]; + + return self; +} + +- (NSArray *)loadEventsFrom:(NSDate *)aDate forwardDays:(NSInteger)forwardDays +{ + NSManagedObjectContext *moc = [[WADataStore defaultStore] autoUpdatingMOC]; + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WAArticle"]; + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"eventStartDate" ascending:NO]; + [fetchRequest setSortDescriptors:@[sortDescriptor]]; + self.eventFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND hidden = FALSE AND files.@count > 0", [aDate dateOfPreviousNumOfDays:forwardDays], aDate]; + [self.eventFetchedResultsController.fetchRequest setPredicate:predicate]; + + NSError *Err; + if (![self.eventFetchedResultsController performFetch:&Err]) { + NSLog(@"Fetch WAArticle failed: %@", Err); + } + + return self.eventFetchedResultsController.fetchedObjects; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [self.navigationController setToolbarHidden:NO]; + UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addAttendees)]; + self.toolbarItems = @[flexibleSpace, addButton, flexibleSpace]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + return [self.events count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; + } + + // Configure the cell... + cell.backgroundColor = [UIColor greenColor]; + cell.backgroundView = [[UIImageView alloc] initWithImage:[[self.events[indexPath.row] representingFile] thumbnailImage]]; + cell.backgroundView.contentMode = UIViewContentModeScaleAspectFill; + cell.backgroundView.clipsToBounds = YES; + NSString *photoNumbers = [NSString stringWithFormat:([[self.events[indexPath.row] files] count] == 1)? + NSLocalizedString(@"EVENT_ONE_PHOTO_NUMBER_LABEL", @"EVENT_ONE_PHOTO_NUMBER_LABEL"): + NSLocalizedString(@"EVENT_PHOTO_NUMBER_LABEL", @"EVENT_PHOTO_NUMBER_LABEL"), + [[self.events[indexPath.row] files] count]]; + static NSDateFormatter *sharedDateFormatter; + sharedDateFormatter = [[NSDateFormatter alloc] init]; + [sharedDateFormatter setDateFormat:@"yyyy MM dd"]; + NSString *eventDate = [sharedDateFormatter stringFromDate:[self.events[indexPath.row] eventStartDate]]; + NSString *otherStr = [self.events[indexPath.row] description]; + cell.textLabel.text = [NSString stringWithFormat:@"%@\n%@\n%@", photoNumbers, eventDate, otherStr]; + [cell.textLabel setNumberOfLines:0]; + [cell.textLabel setBackgroundColor:[UIColor clearColor]]; + [cell.textLabel setTextColor:[UIColor whiteColor]]; + + UIButton *addBtn = [UIButton buttonWithType:UIButtonTypeContactAdd]; + cell.accessoryView = addBtn; + + return cell; +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:NO]; +} + +#pragma - toolbar + +- (void)addAttendees +{ + __weak WASharedEventViewController *wSelf = self; + WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; + WANavigationController *nav = [[WANavigationController alloc] initWithRootViewController:cpVC]; + [wSelf presentViewController:nav animated:YES completion:nil]; +} + +@end diff --git a/WASharedEventViewController.xib b/WASharedEventViewController.xib new file mode 100644 index 00000000..a5e2ebbf --- /dev/null +++ b/WASharedEventViewController.xib @@ -0,0 +1,149 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + {{0, 20}, {320, 504}} + + 3 + MQA + + NO + YES + NO + + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 148 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + + WASharedEventViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 11 + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index e1a1f31b..0d24d7db 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -230,7 +230,6 @@ 80090B60170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */; }; 80090B62170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */; }; 80090B64170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */; }; - 80090B66170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */; }; 80092D3916AFD5A000020F64 /* WADataPlanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80092D3816AFD5A000020F64 /* WADataPlanViewController.m */; }; 800D9A9216719B5D0034CDF6 /* MKMapView+ZoomLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 800D9A9116719B5D0034CDF6 /* MKMapView+ZoomLevel.m */; }; 800E4FCE1671DD0C00F50E0B /* WATimelineViewCell-Checkin.xib in Resources */ = {isa = PBXBuildFile; fileRef = 800E4FCD1671DD0C00F50E0B /* WATimelineViewCell-Checkin.xib */; }; @@ -409,6 +408,13 @@ 80FA833816F9E79B003BF983 /* WAEventPhotoAddingCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80FA833716F9E79B003BF983 /* WAEventPhotoAddingCell.m */; }; 94EB57761411451780C24560 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D215E734098A44479DEC4F88 /* libPods.a */; }; DE46FC17165E228300CC4FFF /* WACalendarPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE46FC16165E228300CC4FFF /* WACalendarPickerViewController.m */; }; + DE67A4A21712BA0500099106 /* AddressBook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE67A4A01712BA0400099106 /* AddressBook.framework */; }; + DE67A4A31712BA0500099106 /* AddressBookUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DE67A4A11712BA0400099106 /* AddressBookUI.framework */; }; + DE67A4BF1712BB7700099106 /* WAContactPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE67A4BD1712BB7700099106 /* WAContactPickerViewController.m */; }; + DE67A4C01712BB7700099106 /* WAContactPickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE67A4BE1712BB7700099106 /* WAContactPickerViewController.xib */; }; + DE67A4C41712BB9300099106 /* WASharedEventViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DE67A4C21712BB9300099106 /* WASharedEventViewController.m */; }; + DE67A4C51712BB9300099106 /* WASharedEventViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE67A4C31712BB9300099106 /* WASharedEventViewController.xib */; }; + DE67A4C71712BE4100099106 /* WAPhotoCollageCell_Stack1.xib in Resources */ = {isa = PBXBuildFile; fileRef = DE67A4C61712BE4100099106 /* WAPhotoCollageCell_Stack1.xib */; }; DE696E011675D020008DC3F6 /* WASnsConnectSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = DE696E001675D020008DC3F6 /* WASnsConnectSwitch.m */; }; DE696E051675D0AC008DC3F6 /* WATwitterConnectSwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = DE696E041675D0AC008DC3F6 /* WATwitterConnectSwitch.m */; }; DE7B35151654B7FC00718262 /* TempAvatar.png in Resources */ = {isa = PBXBuildFile; fileRef = DE7B35131654B7FC00718262 /* TempAvatar.png */; }; @@ -1208,7 +1214,6 @@ 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack4.xib; path = wammer/WAPhotoCollageCell_Stack4.xib; sourceTree = ""; }; 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack3.xib; path = wammer/WAPhotoCollageCell_Stack3.xib; sourceTree = ""; }; 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack2.xib; path = wammer/WAPhotoCollageCell_Stack2.xib; sourceTree = ""; }; - 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WAPhotoCollageCell_Stack1.xib; sourceTree = ""; }; 80092D3716AFD5A000020F64 /* WADataPlanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WADataPlanViewController.h; path = wammer/WADataPlanViewController.h; sourceTree = ""; }; 80092D3816AFD5A000020F64 /* WADataPlanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WADataPlanViewController.m; path = wammer/WADataPlanViewController.m; sourceTree = ""; }; 800D9A9016719B5D0034CDF6 /* MKMapView+ZoomLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MKMapView+ZoomLevel.h"; path = "wammer/MKMapView+ZoomLevel.h"; sourceTree = ""; }; @@ -1410,7 +1415,7 @@ 80C768E617105CFC000F10A8 /* WAPartioWelcomeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPartioWelcomeViewController.m; path = wammer/WAPartioWelcomeViewController.m; sourceTree = ""; }; 80C768E81710789D000F10A8 /* FBRequestConnection+WAAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "FBRequestConnection+WAAdditions.h"; path = "wammer/FBRequestConnection+WAAdditions.h"; sourceTree = ""; }; 80C768E91710789D000F10A8 /* FBRequestConnection+WAAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "FBRequestConnection+WAAdditions.m"; path = "wammer/FBRequestConnection+WAAdditions.m"; sourceTree = ""; }; - 80C768EB1711B84B000F10A8 /* WAModel 44.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = file; path = "WAModel 44.xcdatamodel"; sourceTree = ""; }; + 80C768EB1711B84B000F10A8 /* WAModel 44.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WAModel 44.xcdatamodel"; sourceTree = ""; }; 80C768EC1711B9D5000F10A8 /* WACheckin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WACheckin.h; sourceTree = ""; }; 80C768ED1711B9D5000F10A8 /* WACheckin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACheckin.m; sourceTree = ""; }; 80C768F01711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WACheckin+WARemoteInterfaceEntitySyncing.h"; sourceTree = ""; }; @@ -1456,6 +1461,15 @@ DE2BBDD616761AC100EEF922 /* Kal.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Kal.xcodeproj; path = external/Kal/src/Kal.xcodeproj; sourceTree = SOURCE_ROOT; }; DE46FC15165E228300CC4FFF /* WACalendarPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WACalendarPickerViewController.h; path = wammer/WACalendarPickerViewController.h; sourceTree = ""; }; DE46FC16165E228300CC4FFF /* WACalendarPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WACalendarPickerViewController.m; path = wammer/WACalendarPickerViewController.m; sourceTree = ""; }; + DE67A4A01712BA0400099106 /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; }; + DE67A4A11712BA0400099106 /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; }; + DE67A4BC1712BB7700099106 /* WAContactPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAContactPickerViewController.h; path = wammer/WAContactPickerViewController.h; sourceTree = ""; }; + DE67A4BD1712BB7700099106 /* WAContactPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAContactPickerViewController.m; path = wammer/WAContactPickerViewController.m; sourceTree = ""; }; + DE67A4BE1712BB7700099106 /* WAContactPickerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAContactPickerViewController.xib; path = wammer/WAContactPickerViewController.xib; sourceTree = ""; }; + DE67A4C11712BB9300099106 /* WASharedEventViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WASharedEventViewController.h; path = wammer/WASharedEventViewController.h; sourceTree = ""; }; + DE67A4C21712BB9300099106 /* WASharedEventViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WASharedEventViewController.m; path = wammer/WASharedEventViewController.m; sourceTree = ""; }; + DE67A4C31712BB9300099106 /* WASharedEventViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WASharedEventViewController.xib; path = wammer/WASharedEventViewController.xib; sourceTree = ""; }; + DE67A4C61712BE4100099106 /* WAPhotoCollageCell_Stack1.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPhotoCollageCell_Stack1.xib; path = wammer/WAPhotoCollageCell_Stack1.xib; sourceTree = ""; }; DE696DFF1675D020008DC3F6 /* WASnsConnectSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WASnsConnectSwitch.h; path = wammer/WASnsConnectSwitch.h; sourceTree = ""; }; DE696E001675D020008DC3F6 /* WASnsConnectSwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WASnsConnectSwitch.m; path = wammer/WASnsConnectSwitch.m; sourceTree = ""; }; DE696E031675D0AC008DC3F6 /* WATwitterConnectSwitch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WATwitterConnectSwitch.h; path = wammer/WATwitterConnectSwitch.h; sourceTree = ""; }; @@ -1942,6 +1956,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DE67A4A21712BA0500099106 /* AddressBook.framework in Frameworks */, + DE67A4A31712BA0500099106 /* AddressBookUI.framework in Frameworks */, 80B0A38D16D75C5400E391D2 /* OpenGLES.framework in Frameworks */, 80B0A38B16D75C3E00E391D2 /* ImageIO.framework in Frameworks */, 80B0A38916D75C2500E391D2 /* GLKit.framework in Frameworks */, @@ -2400,7 +2416,7 @@ 80090B5F170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib */, 80090B61170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib */, 80090B63170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib */, - 80090B65170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib */, + DE67A4C61712BE4100099106 /* WAPhotoCollageCell_Stack1.xib */, 8027264D1710078800BB1733 /* WATimelineIndexView.h */, 8027264E1710078800BB1733 /* WATimelineIndexView.m */, ); @@ -2573,6 +2589,19 @@ name = "Sliding Menu"; sourceTree = ""; }; + DE67A4B11712BA7800099106 /* Shared Events */ = { + isa = PBXGroup; + children = ( + DE67A4C11712BB9300099106 /* WASharedEventViewController.h */, + DE67A4C21712BB9300099106 /* WASharedEventViewController.m */, + DE67A4C31712BB9300099106 /* WASharedEventViewController.xib */, + DE67A4BC1712BB7700099106 /* WAContactPickerViewController.h */, + DE67A4BD1712BB7700099106 /* WAContactPickerViewController.m */, + DE67A4BE1712BB7700099106 /* WAContactPickerViewController.xib */, + ); + name = "Shared Events"; + sourceTree = ""; + }; DE7B38A0165CBB9900718262 /* Calendar Picker */ = { isa = PBXGroup; children = ( @@ -2855,6 +2884,7 @@ children = ( 80C768DC17105683000F10A8 /* Partio Welcome */, 80090B48170EC74A005AF6B8 /* New Event View */, + DE67A4B11712BA7800099106 /* Shared Events */, 80B1137D170DD08D0087EBC4 /* Photo Groups */, DE7B38A0165CBB9900718262 /* Calendar Picker */, 7D0CDD04162E5A080027D35F /* StreamTests */, @@ -2914,6 +2944,8 @@ D215E734098A44479DEC4F88 /* libPods.a */, 80B0A38E16D75F2300E391D2 /* GoogleMaps.bundle */, 4BAD7581164DED1700ADDE56 /* libsqlite3.dylib */, + DE67A4A01712BA0400099106 /* AddressBook.framework */, + DE67A4A11712BA0400099106 /* AddressBookUI.framework */, 7D9B1D8C162BB1DE000E5350 /* Accounts.framework */, 7D9B1D8E162BB1E8000E5350 /* AdSupport.framework */, 13222F4E16806B22000C57A7 /* CoreImage.framework */, @@ -4195,8 +4227,10 @@ 80090B60170ECE45005AF6B8 /* WAPhotoCollageCell_Stack4.xib in Resources */, 80090B62170ECE5A005AF6B8 /* WAPhotoCollageCell_Stack3.xib in Resources */, 80090B64170ECE6D005AF6B8 /* WAPhotoCollageCell_Stack2.xib in Resources */, - 80090B66170ECE79005AF6B8 /* WAPhotoCollageCell_Stack1.xib in Resources */, 80C768DE17105789000F10A8 /* WAPartioFirstUse.storyboard in Resources */, + DE67A4C01712BB7700099106 /* WAContactPickerViewController.xib in Resources */, + DE67A4C51712BB9300099106 /* WASharedEventViewController.xib in Resources */, + DE67A4C71712BE4100099106 /* WAPhotoCollageCell_Stack1.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4694,6 +4728,8 @@ 80C768EA1710789D000F10A8 /* FBRequestConnection+WAAdditions.m in Sources */, 80C768EE1711B9D5000F10A8 /* WACheckin.m in Sources */, 80C768F21711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m in Sources */, + DE67A4BF1712BB7700099106 /* WAContactPickerViewController.m in Sources */, + DE67A4C41712BB9300099106 /* WASharedEventViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 8edd4fca..619953c4 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -30,6 +30,7 @@ #import "WAUserInfoViewController.h" #import "WAOverlayBezel.h" +#import "WASharedEventViewController.h" #import "WAPhotoHighlightsViewController.h" #import "WAPartioFirstUseViewController.h" @@ -459,6 +460,7 @@ - (void) recreateViewHierarchy { // viewDeckController.delegate = self.slidingMenu; // viewDeckController.centerhiddenInteractivity = IIViewDeckCenterHiddenNotUserInteractiveWithTapToClose; + __weak WAAppDelegate_iOS *wSelf = self; if (![FBSession activeSession].isOpen) { [[self class] backgroundLoginWithFacebookIDWithCompleteHandler:^(NSError *error) { @@ -468,8 +470,12 @@ - (void) recreateViewHierarchy { } else { - WAPhotoHighlightsViewController *highlightVC = [[WAPhotoHighlightsViewController alloc] init]; - self.window.rootViewController = highlightVC; +// WAPhotoHighlightsViewController *highlightVC = [[WAPhotoHighlightsViewController alloc] init]; +// self.window.rootViewController = highlightVC; + + + WASharedEventViewController *sharedEventsVC = [[WASharedEventViewController alloc] initWithStyle:UITableViewStylePlain]; + wSelf.window.rootViewController = sharedEventsVC; } diff --git a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m index e4db532d..b576bee3 100644 --- a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m @@ -59,9 +59,9 @@ + (id) transformedValue:(id)aValue fromRemoteKeyPath:(NSString *)aRemoteKeyPath toLocalKeyPath:(NSString *)aLocalKeyPath { - if ( [aLocalKeyPath isEqualToString:@"checkin_id"] ) + if ( [aRemoteKeyPath isEqualToString:@"checkin_id"] ) return [NSString stringWithFormat:@"%@", aValue]; - if ( [aLocalKeyPath isEqualToString:@"tagged_uids"]) + if ( [aRemoteKeyPath isEqualToString:@"tagged_uids"]) return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:(NSArray*)aValue options:0 error:nil] encoding:NSUTF8StringEncoding]; diff --git a/wammer/WAContactPickerViewController.h b/wammer/WAContactPickerViewController.h new file mode 100644 index 00000000..042aed7b --- /dev/null +++ b/wammer/WAContactPickerViewController.h @@ -0,0 +1,18 @@ +// +// WAContactPickerViewController.h +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import +#import + +@interface WAContactPickerViewController : UITableViewController + +@property (nonatomic, strong) NSMutableArray *members; + +-(IBAction)showContactsPicker:(id)sender; + +@end diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m new file mode 100644 index 00000000..0337cc4e --- /dev/null +++ b/wammer/WAContactPickerViewController.m @@ -0,0 +1,177 @@ +// +// WAContactPickerViewController.m +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import "WAContactPickerViewController.h" + +@interface WAContactPickerViewController () + +@end + +@implementation WAContactPickerViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + // Custom initialization + _members = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)]; +} + +- (void)cancel +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)done +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 2; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + if (section == 0) { + return 3; + + } else { + return [_members count]; + + } +} + +- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section +{ + UIView *headerView = [super tableView:tableView viewForHeaderInSection:section]; + // Customize the header view + + return headerView; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; + } + + // Configure the cell... + if (indexPath.section == 0) { + if (indexPath.row == 0) { + cell.textLabel.text = NSLocalizedString(@"INPUT_RECEIVER_EMAIL", @"INPUT_RECEIVER_EMAIL"); + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + + } else if (indexPath.row == 1) { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = @"Contacts"; + cell.detailTextLabel.text = @"Find friends from your contacts."; + + } else if (indexPath.row == 2) { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = @"Facebook"; + cell.detailTextLabel.text = @"Find friends from Facebook."; + + } + + } else { + cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; + cell.textLabel.text = _members[indexPath.row][@"name"]; + cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@", + _members[indexPath.row][@"phone"], + ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; + cell.accessoryType = UITableViewCellAccessoryCheckmark; + + } + + return cell; +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:YES]; + + if (indexPath.section == 0 && indexPath.row == 1) { + ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; + abPicker.peoplePickerDelegate = self; + + [self presentViewController:abPicker animated:YES completion:nil]; + + } +} + +#pragma - Address Book Contacts Picker + +- (void)showContactsPicker:(id)sender +{ + ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; + abPicker.peoplePickerDelegate = self; + + [self presentViewController:abPicker animated:YES completion:nil]; +} + +- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker +{ + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person +{ + [self addIntoInvitedList:person]; + [self dismissViewControllerAnimated:YES completion:nil]; + [self.tableView reloadData]; + + return NO; +} + +- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier +{ + return NO; +} + +- (void)addIntoInvitedList:(ABRecordRef)person +{ + NSString *firstname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); + NSString *lastname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); + NSArray *email = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); + + NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(person, kABPersonPhoneProperty), 0);; + + NSDictionary *aPerson = @{@"name": [NSString stringWithFormat:@"%@ %@", firstname, lastname], + @"email": (email)? email : @[], + @"phone": (phone)? phone : @"[None]"}; + [_members addObject:aPerson]; + +} + +@end diff --git a/wammer/WAContactPickerViewController.xib b/wammer/WAContactPickerViewController.xib new file mode 100644 index 00000000..b2a5b64a --- /dev/null +++ b/wammer/WAContactPickerViewController.xib @@ -0,0 +1,160 @@ + + + + 1536 + 12A269 + 2835 + 1187 + 624.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 1919 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + {{0, 20}, {320, 548}} + + + + + 3 + MQA + + NO + YES + NO + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 44 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + WAContactPickerViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 7 + + + + + WAContactPickerViewController + UITableViewController + + IBProjectSource + ./Classes/WAContactPickerViewController.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 1919 + + diff --git a/wammer/WAPartioFirstUse.storyboard b/wammer/WAPartioFirstUse.storyboard index bd6e95f9..529233c7 100644 --- a/wammer/WAPartioFirstUse.storyboard +++ b/wammer/WAPartioFirstUse.storyboard @@ -98,17 +98,6 @@ - - - - - - - - - - - diff --git a/WAPhotoCollageCell_Stack1.xib b/wammer/WAPhotoCollageCell_Stack1.xib similarity index 100% rename from WAPhotoCollageCell_Stack1.xib rename to wammer/WAPhotoCollageCell_Stack1.xib diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m index 2e888cd1..a3598d8a 100644 --- a/wammer/WAPhotoTimelineViewController.m +++ b/wammer/WAPhotoTimelineViewController.m @@ -13,6 +13,7 @@ #import "WAPhotoCollageCell.h" #import "WAAssetsLibraryManager.h" #import "WATimelineIndexView.h" +#import "WAContactPickerViewController.h" #import #import "WAGeoLocation.h" #import @@ -71,6 +72,7 @@ - (void)viewDidLoad UIImage *actionImage = [UIImage imageNamed:@"action"]; UIButton *actionButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, actionImage.size}]; + [actionButton addTarget:self action:@selector(actionButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [actionButton setImage:actionImage forState:UIControlStateNormal]; UIBarButtonItem *actionItem = [[UIBarButtonItem alloc] initWithCustomView:actionButton]; @@ -130,6 +132,15 @@ - (void) backButtonClicked:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } +- (void)actionButtonClicked:(id)sender +{ + __weak WAPhotoTimelineViewController *wSelf = self; + WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; + UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:cpVC]; + [wSelf presentViewController:nav animated:YES completion:nil]; + +} + - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; diff --git a/wammer/WASharedEventViewController.h b/wammer/WASharedEventViewController.h new file mode 100644 index 00000000..348867d6 --- /dev/null +++ b/wammer/WASharedEventViewController.h @@ -0,0 +1,16 @@ +// +// WAEventSharingViewController.h +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import + +@interface WASharedEventViewController : UITableViewController + + +@end + + diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m new file mode 100644 index 00000000..9611bbd5 --- /dev/null +++ b/wammer/WASharedEventViewController.m @@ -0,0 +1,148 @@ +// +// WAEventSharingViewController.m +// wammer +// +// Created by Greener Chen on 13/4/2. +// Copyright (c) 2013年 Waveface. All rights reserved. +// + +#import "WASharedEventViewController.h" +#import "WAPhotoHighlightsViewController.h" +#import "WAPhotoTimelineViewController.h" +#import "WALocation.h" +#import +#import "WADataStore.h" +#import "NSDate+WAAdditions.h" + +@interface WASharedEventViewController () + +@property (nonatomic, strong) NSFetchedResultsController *eventFetchedResultsController; +@property (nonatomic, strong) NSMutableArray *events; + +@end + +@implementation WASharedEventViewController + +- (id)initWithStyle:(UITableViewStyle)style +{ + self = [super initWithStyle:style]; + if (self) { + // Custom initialization + self.events = [[NSMutableArray alloc] init]; + } + self.events = [[self loadEventsFrom:[NSDate date] toPreviousDays:100] copy]; + + return self; +} + +- (NSArray *)loadEventsFrom:(NSDate *)aDate toPreviousDays:(NSInteger)days +{ + NSManagedObjectContext *moc = [[WADataStore defaultStore] autoUpdatingMOC]; + NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WAArticle"]; + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"eventStartDate" ascending:NO]; + [fetchRequest setSortDescriptors:@[sortDescriptor]]; + self.eventFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND hidden = FALSE AND files.@count > 0", [aDate dateOfPreviousNumOfDays:days], aDate]; + [self.eventFetchedResultsController.fetchRequest setPredicate:predicate]; + + NSError *Err; + if (![self.eventFetchedResultsController performFetch:&Err]) { + NSLog(@"Fetch WAArticle failed: %@", Err); + } + + return self.eventFetchedResultsController.fetchedObjects; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + [self.navigationController setToolbarHidden:NO]; + UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(shareNewEventFromHighlight)]; + self.toolbarItems = @[flexibleSpace, addButton, flexibleSpace]; +} + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + if (![self.events count]) { + [self shareNewEventFromHighlight]; + + } +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + // Return the number of sections. + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + // Return the number of rows in the section. + return [self.events count]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *CellIdentifier = @"Cell"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; + } + + // Configure the cell... + cell.backgroundView = [[UIImageView alloc] initWithImage:[[self.events[indexPath.row] representingFile] thumbnailImage]]; + cell.backgroundView.contentMode = UIViewContentModeScaleAspectFill; + cell.backgroundView.clipsToBounds = YES; + NSString *photoNumbers = [NSString stringWithFormat:([[self.events[indexPath.row] files] count] == 1)? + NSLocalizedString(@"EVENT_ONE_PHOTO_NUMBER_LABEL", @"EVENT_ONE_PHOTO_NUMBER_LABEL"): + NSLocalizedString(@"EVENT_PHOTO_NUMBER_LABEL", @"EVENT_PHOTO_NUMBER_LABEL"), + [[self.events[indexPath.row] files] count]]; + static NSDateFormatter *sharedDateFormatter; + sharedDateFormatter = [[NSDateFormatter alloc] init]; + [sharedDateFormatter setDateFormat:@"yyyy MM dd"]; + NSString *eventDate = [sharedDateFormatter stringFromDate:[self.events[indexPath.row] eventStartDate]]; + NSString *location = [[self.events[indexPath.row] description] substringFromIndex:3]; + cell.textLabel.text = [NSString stringWithFormat:@"%@\n%@\n%@", photoNumbers, eventDate, location]; + [cell.textLabel setNumberOfLines:0]; + [cell.textLabel setBackgroundColor:[UIColor clearColor]]; + [cell.textLabel setTextColor:[UIColor whiteColor]]; + + return cell; + + +} + +#pragma mark - Table view delegate + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + [tableView deselectRowAtIndexPath:indexPath animated:NO]; +// __weak WASharedEventViewController *wSelf = self; +// WAPhotoTimelineViewController *ptVC = [[WAPhotoTimelineViewController alloc] initWithArticle:[self.events[indexPath.row] objectID]]; +// WANavigationController *nav = [[WANavigationController alloc] initWithRootViewController:ptVC]; +// [wSelf presentViewController:nav animated:YES completion:nil]; +} + +#pragma - toolbar + +- (void)shareNewEventFromHighlight +{ + __weak WASharedEventViewController *wSelf = self; + WAPhotoHighlightsViewController *phVC = [[WAPhotoHighlightsViewController alloc] init]; + UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:phVC]; + [self presentViewController:nav animated:YES completion:nil]; +} + +@end diff --git a/wammer/WASharedEventViewController.xib b/wammer/WASharedEventViewController.xib new file mode 100644 index 00000000..a5e2ebbf --- /dev/null +++ b/wammer/WASharedEventViewController.xib @@ -0,0 +1,149 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBProxyObject + IBUITableView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + {{0, 20}, {320, 504}} + + 3 + MQA + + NO + YES + NO + + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + NO + 1 + 0 + YES + 148 + 22 + 22 + + + + + + + view + + + + 5 + + + + dataSource + + + + 6 + + + + delegate + + + + 7 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 4 + + + + + + + + WASharedEventViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 11 + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/en.lproj/Localizable.strings b/wammer/en.lproj/Localizable.strings index 62e55cf2..ae406746 100644 --- a/wammer/en.lproj/Localizable.strings +++ b/wammer/en.lproj/Localizable.strings @@ -260,6 +260,9 @@ /* Event description for photo information only */ "EVENT_DESCRIPTION_PHOTOS_ONLY" = "%d photos in this event."; +/* EVENT_ONE_PHOTO_NUMBER_LABEL */ +"EVENT_ONE_PHOTO_NUMBER_LABEL" = "EVENT_ONE_PHOTO_NUMBER_LABEL"; + /* EVENT_PHOTO_NUMBER_LABEL */ "EVENT_PHOTO_NUMBER_LABEL" = "%d PHOTOS"; @@ -368,6 +371,9 @@ /* No comment provided by engineer. */ "HOUR_SINGULAR" = "%d hour"; +/* INPUT_RECEIVER_EMAIL */ +"INPUT_RECEIVER_EMAIL" = "Input a reciever email"; + /* Title on introduction pages */ "INTRODUCTION_TITLE" = "What is aostream?"; diff --git a/wammer/zh-Hant.lproj/Localizable.strings b/wammer/zh-Hant.lproj/Localizable.strings index dcd792d1..b6ac7875 100644 --- a/wammer/zh-Hant.lproj/Localizable.strings +++ b/wammer/zh-Hant.lproj/Localizable.strings @@ -260,6 +260,9 @@ /* Event description for photo information only */ "EVENT_DESCRIPTION_PHOTOS_ONLY" = "動態裡有 %d 張照片。"; +/* EVENT_ONE_PHOTO_NUMBER_LABEL */ +"EVENT_ONE_PHOTO_NUMBER_LABEL" = "EVENT_ONE_PHOTO_NUMBER_LABEL"; + /* EVENT_PHOTO_NUMBER_LABEL */ "EVENT_PHOTO_NUMBER_LABEL" = "%d 張照片"; @@ -368,6 +371,9 @@ /* No comment provided by engineer. */ "HOUR_SINGULAR" = "%d小時"; +/* INPUT_RECEIVER_EMAIL */ +"INPUT_RECEIVER_EMAIL" = "輸入收件人的 Email"; + /* Title on introduction pages */ "INTRODUCTION_TITLE" = "aostream 是什麼?"; From d2be22d49deb3a790cf5995b751f8efac6f01cb9 Mon Sep 17 00:00:00 2001 From: Greener Date: Mon, 8 Apr 2013 20:04:12 +0800 Subject: [PATCH 007/278] Localized string for 1 PHOTO --- wammer/en.lproj/Localizable.strings | 2 +- wammer/zh-Hant.lproj/Localizable.strings | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/wammer/en.lproj/Localizable.strings b/wammer/en.lproj/Localizable.strings index ae406746..3526153c 100644 --- a/wammer/en.lproj/Localizable.strings +++ b/wammer/en.lproj/Localizable.strings @@ -261,7 +261,7 @@ "EVENT_DESCRIPTION_PHOTOS_ONLY" = "%d photos in this event."; /* EVENT_ONE_PHOTO_NUMBER_LABEL */ -"EVENT_ONE_PHOTO_NUMBER_LABEL" = "EVENT_ONE_PHOTO_NUMBER_LABEL"; +"EVENT_ONE_PHOTO_NUMBER_LABEL" = "%d PHOTO"; /* EVENT_PHOTO_NUMBER_LABEL */ "EVENT_PHOTO_NUMBER_LABEL" = "%d PHOTOS"; diff --git a/wammer/zh-Hant.lproj/Localizable.strings b/wammer/zh-Hant.lproj/Localizable.strings index b6ac7875..2f76d3bc 100644 --- a/wammer/zh-Hant.lproj/Localizable.strings +++ b/wammer/zh-Hant.lproj/Localizable.strings @@ -261,7 +261,7 @@ "EVENT_DESCRIPTION_PHOTOS_ONLY" = "動態裡有 %d 張照片。"; /* EVENT_ONE_PHOTO_NUMBER_LABEL */ -"EVENT_ONE_PHOTO_NUMBER_LABEL" = "EVENT_ONE_PHOTO_NUMBER_LABEL"; +"EVENT_ONE_PHOTO_NUMBER_LABEL" = "%d 張照片"; /* EVENT_PHOTO_NUMBER_LABEL */ "EVENT_PHOTO_NUMBER_LABEL" = "%d 張照片"; From ef372bddc7bda008e3dade779f53753ae4f0e34f Mon Sep 17 00:00:00 2001 From: syshen Date: Mon, 8 Apr 2013 21:34:53 +0800 Subject: [PATCH 008/278] allow PhotoTimeline to load from WAArticle --- ...WACheckin+WARemoteInterfaceEntitySyncing.m | 4 +- wammer/WAPhotoTimelineViewController.h | 2 +- wammer/WAPhotoTimelineViewController.m | 133 +++++++++++++----- 3 files changed, 103 insertions(+), 36 deletions(-) diff --git a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m index e4db532d..b576bee3 100644 --- a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m @@ -59,9 +59,9 @@ + (id) transformedValue:(id)aValue fromRemoteKeyPath:(NSString *)aRemoteKeyPath toLocalKeyPath:(NSString *)aLocalKeyPath { - if ( [aLocalKeyPath isEqualToString:@"checkin_id"] ) + if ( [aRemoteKeyPath isEqualToString:@"checkin_id"] ) return [NSString stringWithFormat:@"%@", aValue]; - if ( [aLocalKeyPath isEqualToString:@"tagged_uids"]) + if ( [aRemoteKeyPath isEqualToString:@"tagged_uids"]) return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:(NSArray*)aValue options:0 error:nil] encoding:NSUTF8StringEncoding]; diff --git a/wammer/WAPhotoTimelineViewController.h b/wammer/WAPhotoTimelineViewController.h index 7d10e2b6..d7ade9f1 100644 --- a/wammer/WAPhotoTimelineViewController.h +++ b/wammer/WAPhotoTimelineViewController.h @@ -11,6 +11,6 @@ @interface WAPhotoTimelineViewController : UIViewController - (id) initWithAssets:(NSArray*)assets; -- (id) initWithArticle:(NSManagedObjectID *)managedObjectID; +- (id) initWithArticleID:(NSManagedObjectID *)articleID; @end diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m index 2e888cd1..7c4132da 100644 --- a/wammer/WAPhotoTimelineViewController.m +++ b/wammer/WAPhotoTimelineViewController.m @@ -13,23 +13,28 @@ #import "WAPhotoCollageCell.h" #import "WAAssetsLibraryManager.h" #import "WATimelineIndexView.h" +#import "WAArticle.h" +#import "WADataStore.h" #import #import "WAGeoLocation.h" +#import "WAFile+LazyImages.h" #import @interface WAPhotoTimelineViewController () +@property (nonatomic, strong) WAArticle *representingArticle; @property (nonatomic, strong) WAPhotoTimelineCover *headerView; @property (nonatomic, strong) WAPhotoTimelineNavigationBar *navigationBar; @property (nonatomic, weak) IBOutlet UICollectionView *collectionView; @property (nonatomic, weak) IBOutlet WATimelineIndexView *indexView; -@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; @property (nonatomic, strong) NSArray *allAssets; @property (nonatomic, strong) WAGeoLocation *geoLocation; @property (nonatomic, strong) NSDate *eventDate; @property (nonatomic, strong) NSDate *beginDate; @property (nonatomic, strong) NSDate *endDate; +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @end @@ -44,16 +49,28 @@ - (id) initWithAssets:(NSArray *)assets { if (self) { NSMutableArray *array = [NSMutableArray arrayWithCapacity:assets.count]; NSEnumerator *enumerator = [assets reverseObjectEnumerator]; - for (id element in enumerator) { + for (ALAsset *element in enumerator) { [array addObject:element]; } self.allAssets = [NSArray arrayWithArray:array]; + _coordinate.latitude = 0; _coordinate.longitude = 0; } return self; } +- (id) initWithArticleID:(NSManagedObjectID *)articleID { + self = [super initWithNibName:@"WAPhotoTimelineViewController" bundle:nil]; + if (self) { + + self.representingArticle = (WAArticle*)[self.managedObjectContext objectWithID:articleID]; + self.allAssets = @[]; + + } + return self; +} + - (void)viewDidLoad { [super viewDidLoad]; @@ -120,6 +137,15 @@ - (BOOL) shouldAutorotate { } +- (NSManagedObjectContext*)managedObjectContext { + if (_managedObjectContext) + return _managedObjectContext; + + _managedObjectContext = [[WADataStore defaultStore] disposableMOC]; + return _managedObjectContext; + +} + - (NSUInteger) supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; @@ -140,15 +166,20 @@ - (CLLocationCoordinate2D)coordinate { if (_coordinate.latitude!=0 && _coordinate.longitude!=0) return _coordinate; - - for (ALAsset *asset in self.allAssets) { - NSDictionary *meta = [asset defaultRepresentation].metadata; - if (meta) { - NSDictionary *gps = meta[@"{GPS}"]; - if (gps) { - _coordinate.latitude = [(NSNumber*)[gps valueForKey:@"Latitude"] doubleValue]; - _coordinate.longitude = [(NSNumber*)[gps valueForKey:@"Longitude"] doubleValue]; - break; + + if (self.representingArticle) { + _coordinate.latitude = [self.representingArticle.location.latitude floatValue]; + _coordinate.longitude = [self.representingArticle.location.longitude floatValue]; + } else { + for (ALAsset *asset in self.allAssets) { + NSDictionary *meta = [asset defaultRepresentation].metadata; + if (meta) { + NSDictionary *gps = meta[@"{GPS}"]; + if (gps) { + _coordinate.latitude = [(NSNumber*)[gps valueForKey:@"Latitude"] doubleValue]; + _coordinate.longitude = [(NSNumber*)[gps valueForKey:@"Longitude"] doubleValue]; + break; + } } } } @@ -159,8 +190,11 @@ - (NSDate*) eventDate { if (_eventDate) return _eventDate; - - _eventDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; + + if (self.representingArticle) + _eventDate = self.representingArticle.eventStartDate; + else + _eventDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; return _eventDate; } @@ -168,8 +202,11 @@ - (NSDate*) eventDate { - (NSDate *) beginDate { if (_beginDate) return _beginDate; - - _beginDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; + + if (self.representingArticle) + _beginDate = self.representingArticle.eventStartDate; + else + _beginDate = [self.allAssets[0] valueForProperty:ALAssetPropertyDate]; return _beginDate; } @@ -177,7 +214,10 @@ - (NSDate *) endDate { if (_endDate) return _endDate; - _endDate = [self.allAssets.lastObject valueForProperty:ALAssetPropertyDate]; + if (self.representingArticle) + _endDate = self.representingArticle.eventEndDate; + else + _endDate = [self.allAssets.lastObject valueForProperty:ALAssetPropertyDate]; return _endDate; } @@ -188,8 +228,11 @@ - (NSInteger) numberOfSectionsInCollectionView:(UICollectionView *)collectionVie - (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { - NSUInteger totalItem = (self.allAssets.count / 10) * 4; - NSUInteger mod = self.allAssets.count % 10; + NSUInteger numOfPhotos = self.allAssets.count; + if (self.representingArticle) + numOfPhotos = self.representingArticle.files.count; + NSUInteger totalItem = (numOfPhotos / 10) * 4; + NSUInteger mod = numOfPhotos % 10; if (mod == 0) return totalItem; else if (mod < 4) @@ -205,6 +248,10 @@ - (NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInS - (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + NSUInteger totalNumber = self.allAssets.count; + if (self.representingArticle) + totalNumber = self.representingArticle.files.count; + NSUInteger numOfPhotos = 4 - (indexPath.row % 4); NSString *identifier = [NSString stringWithFormat:@"CollectionItemCell%d", numOfPhotos]; @@ -227,18 +274,28 @@ - (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellF } __weak WAPhotoTimelineViewController *wSelf = self; - for (NSUInteger i = 0; i < numOfPhotos && ((base+i) Date: Tue, 9 Apr 2013 15:20:09 +0800 Subject: [PATCH 009/278] day photo picker and change the colour of navigation bar --- wammer.xcodeproj/project.pbxproj | 38 +- wammer/WAAppDelegate_iOS.m | 3 +- wammer/WAAppearance.h | 1 + wammer/WAAppearance.m | 4 + wammer/WADayPhotoPickerSectionHeaderView.h | 15 + wammer/WADayPhotoPickerSectionHeaderView.m | 31 ++ wammer/WADayPhotoPickerSectionHeaderView.xib | 292 +++++++++++++ wammer/WADayPhotoPickerViewCell.h | 15 + wammer/WADayPhotoPickerViewCell.m | 57 +++ wammer/WADayPhotoPickerViewCell.xib | 417 +++++++++++++++++++ wammer/WADayPhotoPickerViewController.h | 15 + wammer/WADayPhotoPickerViewController.m | 215 ++++++++++ wammer/WADayPhotoPickerViewController.xib | 343 +++++++++++++++ wammer/WAPhotoHighlightsViewController.m | 20 +- wammer/en.lproj/Localizable.strings | 6 + wammer/zh-Hant.lproj/Localizable.strings | 6 + 16 files changed, 1470 insertions(+), 8 deletions(-) create mode 100644 wammer/WADayPhotoPickerSectionHeaderView.h create mode 100644 wammer/WADayPhotoPickerSectionHeaderView.m create mode 100644 wammer/WADayPhotoPickerSectionHeaderView.xib create mode 100644 wammer/WADayPhotoPickerViewCell.h create mode 100644 wammer/WADayPhotoPickerViewCell.m create mode 100644 wammer/WADayPhotoPickerViewCell.xib create mode 100644 wammer/WADayPhotoPickerViewController.h create mode 100644 wammer/WADayPhotoPickerViewController.m create mode 100644 wammer/WADayPhotoPickerViewController.xib diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 0d24d7db..20db3db0 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -240,6 +240,12 @@ 8023BAF216770D2B00E6BED2 /* pindrop@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8023BAF016770D2A00E6BED2 /* pindrop@2x.png */; }; 802427091689E1AF002454A7 /* WACollection.m in Sources */ = {isa = PBXBuildFile; fileRef = 802427081689E1AF002454A7 /* WACollection.m */; }; 8027264F1710078800BB1733 /* WATimelineIndexView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8027264E1710078800BB1733 /* WATimelineIndexView.m */; }; + 802835541713009A00E0A187 /* WADayPhotoPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 802835521713009A00E0A187 /* WADayPhotoPickerViewController.m */; }; + 802835551713009A00E0A187 /* WADayPhotoPickerViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 802835531713009A00E0A187 /* WADayPhotoPickerViewController.xib */; }; + 80283557171302B900E0A187 /* WADayPhotoPickerViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80283556171302B900E0A187 /* WADayPhotoPickerViewCell.xib */; }; + 8028355A1713037900E0A187 /* WADayPhotoPickerViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 802835591713037900E0A187 /* WADayPhotoPickerViewCell.m */; }; + 8028355D1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8028355C1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m */; }; + 8028355F1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8028355E1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib */; }; 802FFDA816DF642A00237762 /* downloadStation.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA516DF642A00237762 /* downloadStation.png */; }; 802FFDA916DF642A00237762 /* Intro1.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA616DF642A00237762 /* Intro1.png */; }; 802FFDAA16DF642A00237762 /* Intro2.png in Resources */ = {isa = PBXBuildFile; fileRef = 802FFDA716DF642A00237762 /* Intro2.png */; }; @@ -1231,6 +1237,15 @@ 802427081689E1AF002454A7 /* WACollection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACollection.m; sourceTree = ""; }; 8027264D1710078800BB1733 /* WATimelineIndexView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WATimelineIndexView.h; path = wammer/WATimelineIndexView.h; sourceTree = ""; }; 8027264E1710078800BB1733 /* WATimelineIndexView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WATimelineIndexView.m; path = wammer/WATimelineIndexView.m; sourceTree = ""; }; + 802835511713009A00E0A187 /* WADayPhotoPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WADayPhotoPickerViewController.h; path = wammer/WADayPhotoPickerViewController.h; sourceTree = ""; }; + 802835521713009A00E0A187 /* WADayPhotoPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WADayPhotoPickerViewController.m; path = wammer/WADayPhotoPickerViewController.m; sourceTree = ""; }; + 802835531713009A00E0A187 /* WADayPhotoPickerViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WADayPhotoPickerViewController.xib; path = wammer/WADayPhotoPickerViewController.xib; sourceTree = ""; }; + 80283556171302B900E0A187 /* WADayPhotoPickerViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WADayPhotoPickerViewCell.xib; path = wammer/WADayPhotoPickerViewCell.xib; sourceTree = ""; }; + 802835581713037900E0A187 /* WADayPhotoPickerViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WADayPhotoPickerViewCell.h; path = wammer/WADayPhotoPickerViewCell.h; sourceTree = ""; }; + 802835591713037900E0A187 /* WADayPhotoPickerViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WADayPhotoPickerViewCell.m; path = wammer/WADayPhotoPickerViewCell.m; sourceTree = ""; }; + 8028355B1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WADayPhotoPickerSectionHeaderView.h; path = wammer/WADayPhotoPickerSectionHeaderView.h; sourceTree = ""; }; + 8028355C1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WADayPhotoPickerSectionHeaderView.m; path = wammer/WADayPhotoPickerSectionHeaderView.m; sourceTree = ""; }; + 8028355E1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WADayPhotoPickerSectionHeaderView.xib; path = wammer/WADayPhotoPickerSectionHeaderView.xib; sourceTree = ""; }; 802FFDA516DF642A00237762 /* downloadStation.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = downloadStation.png; path = Resources/downloadStation.png; sourceTree = ""; }; 802FFDA616DF642A00237762 /* Intro1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Intro1.png; path = Resources/Intro1.png; sourceTree = ""; }; 802FFDA716DF642A00237762 /* Intro2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Intro2.png; path = Resources/Intro2.png; sourceTree = ""; }; @@ -2522,7 +2537,7 @@ name = "Event View"; sourceTree = ""; }; - 80B1137D170DD08D0087EBC4 /* Photo Groups */ = { + 80B1137D170DD08D0087EBC4 /* Photo Highlights */ = { isa = PBXGroup; children = ( 80090B45170E8BBF005AF6B8 /* WAGeoLocation.h */, @@ -2535,8 +2550,17 @@ 80B11390170DD1280087EBC4 /* WAPhotoHighlightViewCell.xib */, 80B11392170DD1450087EBC4 /* WAPhotoHighlightViewCell.h */, 80B11393170DD1450087EBC4 /* WAPhotoHighlightViewCell.m */, - ); - name = "Photo Groups"; + 802835511713009A00E0A187 /* WADayPhotoPickerViewController.h */, + 802835521713009A00E0A187 /* WADayPhotoPickerViewController.m */, + 8028355B1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.h */, + 8028355C1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m */, + 8028355E1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib */, + 802835581713037900E0A187 /* WADayPhotoPickerViewCell.h */, + 802835591713037900E0A187 /* WADayPhotoPickerViewCell.m */, + 80283556171302B900E0A187 /* WADayPhotoPickerViewCell.xib */, + 802835531713009A00E0A187 /* WADayPhotoPickerViewController.xib */, + ); + name = "Photo Highlights"; sourceTree = ""; }; 80C768DC17105683000F10A8 /* Partio Welcome */ = { @@ -2885,7 +2909,7 @@ 80C768DC17105683000F10A8 /* Partio Welcome */, 80090B48170EC74A005AF6B8 /* New Event View */, DE67A4B11712BA7800099106 /* Shared Events */, - 80B1137D170DD08D0087EBC4 /* Photo Groups */, + 80B1137D170DD08D0087EBC4 /* Photo Highlights */, DE7B38A0165CBB9900718262 /* Calendar Picker */, 7D0CDD04162E5A080027D35F /* StreamTests */, 4B8CA96F14BBE7BA006E06BB /* UnitTests */, @@ -4231,6 +4255,9 @@ DE67A4C01712BB7700099106 /* WAContactPickerViewController.xib in Resources */, DE67A4C51712BB9300099106 /* WASharedEventViewController.xib in Resources */, DE67A4C71712BE4100099106 /* WAPhotoCollageCell_Stack1.xib in Resources */, + 802835551713009A00E0A187 /* WADayPhotoPickerViewController.xib in Resources */, + 80283557171302B900E0A187 /* WADayPhotoPickerViewCell.xib in Resources */, + 8028355F1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4730,6 +4757,9 @@ 80C768F21711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m in Sources */, DE67A4BF1712BB7700099106 /* WAContactPickerViewController.m in Sources */, DE67A4C41712BB9300099106 /* WASharedEventViewController.m in Sources */, + 802835541713009A00E0A187 /* WADayPhotoPickerViewController.m in Sources */, + 8028355A1713037900E0A187 /* WADayPhotoPickerViewCell.m in Sources */, + 8028355D1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 619953c4..e48c028a 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -278,7 +278,8 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: [self bootstrap]; - WADefaultAppearance(); +// WADefaultAppearance(); + WAPartioDefaultAppearance(); self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor colorWithRed:0.87 green:0.87 blue:0.84 alpha:1.0]; diff --git a/wammer/WAAppearance.h b/wammer/WAAppearance.h index 074f41af..3e0fbcee 100644 --- a/wammer/WAAppearance.h +++ b/wammer/WAAppearance.h @@ -16,6 +16,7 @@ @class IRBarButtonItem, IRBorder, IRShadow; +extern void WAPartioDefaultAppearance(void); extern void WADefaultAppearance(void); extern void WADefaultBarButtonInitialize (void); diff --git a/wammer/WAAppearance.m b/wammer/WAAppearance.m index 2d2ba7ab..f3b2e7e4 100644 --- a/wammer/WAAppearance.m +++ b/wammer/WAAppearance.m @@ -55,6 +55,10 @@ void WADefaultAppearance(void) { } +void WAPartioDefaultAppearance(void) { + [[UINavigationBar appearance] setTintColor:[UIColor blackColor]]; +} + #pragma mark - Origianl appearance settings void WADefaultBarButtonInitialize (void) { diff --git a/wammer/WADayPhotoPickerSectionHeaderView.h b/wammer/WADayPhotoPickerSectionHeaderView.h new file mode 100644 index 00000000..e22a0ff2 --- /dev/null +++ b/wammer/WADayPhotoPickerSectionHeaderView.h @@ -0,0 +1,15 @@ +// +// WADayPhotoPickerSectionHeaderView.h +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WADayPhotoPickerSectionHeaderView : UICollectionReusableView + +@property (nonatomic, weak) IBOutlet UILabel *titleLabel; + +@end diff --git a/wammer/WADayPhotoPickerSectionHeaderView.m b/wammer/WADayPhotoPickerSectionHeaderView.m new file mode 100644 index 00000000..287af9b7 --- /dev/null +++ b/wammer/WADayPhotoPickerSectionHeaderView.m @@ -0,0 +1,31 @@ +// +// WADayPhotoPickerSectionHeaderView.m +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WADayPhotoPickerSectionHeaderView.h" + +@implementation WADayPhotoPickerSectionHeaderView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code +} +*/ + +@end diff --git a/wammer/WADayPhotoPickerSectionHeaderView.xib b/wammer/WADayPhotoPickerSectionHeaderView.xib new file mode 100644 index 00000000..5ffde0a2 --- /dev/null +++ b/wammer/WADayPhotoPickerSectionHeaderView.xib @@ -0,0 +1,292 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionReusableView + IBUILabel + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 268 + + + + 292 + {300, 50} + + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Label + + 1 + MCAwIDAAA + darkTextColor + + + 0 + 1 + + Helvetica + Helvetica + 0 + 17 + + + Helvetica + 17 + 16 + + NO + + + {300, 50} + + + + _NS:9 + + 1 + MC45Njg2Mjc0NTEgMC45Njg2Mjc0NTEgMC45Njg2Mjc0NTEAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + titleLabel + + + + 13 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + 4 + + + + + + 8 + + + + + 9 + + + + + 11 + + + + + 12 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WADayPhotoPickerSectionHeaderView + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 13 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + WADayPhotoPickerSectionHeaderView + UICollectionReusableView + + titleLabel + UILabel + + + titleLabel + + titleLabel + UILabel + + + + IBProjectSource + ./Classes/WADayPhotoPickerSectionHeaderView.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WADayPhotoPickerViewCell.h b/wammer/WADayPhotoPickerViewCell.h new file mode 100644 index 00000000..14259794 --- /dev/null +++ b/wammer/WADayPhotoPickerViewCell.h @@ -0,0 +1,15 @@ +// +// WADayPhotoPickerViewCell.h +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WADayPhotoPickerViewCell : UICollectionViewCell + +@property (nonatomic, weak) IBOutlet UIImageView *imageView; +@property (nonatomic, weak) IBOutlet UIImageView *checkMarkView; +@end diff --git a/wammer/WADayPhotoPickerViewCell.m b/wammer/WADayPhotoPickerViewCell.m new file mode 100644 index 00000000..cda9d3e2 --- /dev/null +++ b/wammer/WADayPhotoPickerViewCell.m @@ -0,0 +1,57 @@ +// +// WADayPhotoPickerViewCell.m +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WADayPhotoPickerViewCell.h" +@interface WADayPhotoPickerViewCell () +@property (nonatomic, strong) CALayer *transparentLayer; +@end + +@implementation WADayPhotoPickerViewCell + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + } + return self; +} + +- (void) awakeFromNib { + + self.checkMarkView.hidden = YES; + +} + +- (void) setSelected:(BOOL)selected { + [super setSelected:selected]; + + if (selected) { + self.checkMarkView.hidden = NO; + self.checkMarkView.image = [UIImage imageNamed:@"IRAQ-Checkmark"]; + + if (!self.transparentLayer) { + self.transparentLayer = [CALayer layer]; + self.transparentLayer.opacity = 0.5; + self.transparentLayer.opaque = NO; + self.transparentLayer.backgroundColor = [UIColor whiteColor].CGColor; + self.transparentLayer.frame = (CGRect){CGPointZero, self.imageView.frame.size}; + + [self.imageView.layer addSublayer:self.transparentLayer]; + } + + } else { + self.checkMarkView.hidden = YES; + self.checkMarkView.image = nil; + [self.transparentLayer removeFromSuperlayer]; + self.transparentLayer = nil; + } +} + + +@end diff --git a/wammer/WADayPhotoPickerViewCell.xib b/wammer/WADayPhotoPickerViewCell.xib new file mode 100644 index 00000000..36e21df4 --- /dev/null +++ b/wammer/WADayPhotoPickerViewCell.xib @@ -0,0 +1,417 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionViewCell + IBUIImageView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 1292 + + + + 1280 + + + + 1298 + {50, 50} + + + + _NS:9 + YES + 2 + NO + IBCocoaTouchFramework + + + + 1316 + {50, 50} + + + _NS:9 + 4 + NO + IBCocoaTouchFramework + + + {50, 50} + + + + + 3 + MCAwAA + + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + {50, 50} + + + + _NS:9 + NO + YES + 4 + YES + IBCocoaTouchFramework + + + + + + + + imageView + + + + 9 + + + + checkMarkView + + + + 17 + + + + + + 0 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 10 + + + + + + 11 + + + + + 12 + + + + + 15 + + + + + 16 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + WADayPhotoPickerViewCell + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 17 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionReusableView + UIView + + IBProjectSource + ./Classes/UICollectionReusableView.h + + + + UICollectionViewCell + UICollectionReusableView + + IBProjectSource + ./Classes/UICollectionViewCell.h + + + + WADayPhotoPickerViewCell + UICollectionViewCell + + UIImageView + UIImageView + + + + checkMarkView + UIImageView + + + imageView + UIImageView + + + + IBProjectSource + ./Classes/WADayPhotoPickerViewCell.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WADayPhotoPickerViewController.h b/wammer/WADayPhotoPickerViewController.h new file mode 100644 index 00000000..3feec790 --- /dev/null +++ b/wammer/WADayPhotoPickerViewController.h @@ -0,0 +1,15 @@ +// +// WADayPhotoPickerViewController.h +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WADayPhotoPickerViewController : UIViewController + +- (id) initWithSelectedAssets:(NSArray *)assets; + +@end diff --git a/wammer/WADayPhotoPickerViewController.m b/wammer/WADayPhotoPickerViewController.m new file mode 100644 index 00000000..43ff1f99 --- /dev/null +++ b/wammer/WADayPhotoPickerViewController.m @@ -0,0 +1,215 @@ +// +// WADayPhotoPickerViewController.m +// wammer +// +// Created by Shen Steven on 4/8/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WADayPhotoPickerViewController.h" +#import "WAAssetsLibraryManager.h" +#import "WADayPhotoPickerViewCell.h" +#import "WADayPhotoPickerSectionHeaderView.h" +#import "WAOverlayBezel.h" +#import "NSDate+WAAdditions.h" +#import + +@interface WADayPhotoPickerViewController () + +@property (nonatomic, weak) IBOutlet UICollectionView *collectionView; +@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; +@property (nonatomic, strong) NSArray *photoGroups; +@property (nonatomic, strong) NSArray *selectedAssets; +@property (nonatomic, strong) NSArray *allTimeSortedAssets; + +@end + +@implementation WADayPhotoPickerViewController + + +- (id) initWithSelectedAssets:(NSArray *)assets { + self = [super initWithNibName:nil bundle:nil]; + if (self) { + self.selectedAssets = assets; + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + self.title = NSLocalizedString(@"TITLE_OF_DAY_PHOTO_PICKER", @"Title of the day photo picker view"); + self.imageDisplayQueue = [[NSOperationQueue alloc] init]; + self.imageDisplayQueue.maxConcurrentOperationCount = 1; + + if (self.navigationController) { + UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:@"Create" style:UIBarButtonItemStyleBordered handler:^(id sender) { + + }]; + + self.navigationItem.rightBarButtonItem = buttonItem; + } + + self.collectionView.allowsMultipleSelection = YES; + [self.collectionView registerNib:[UINib nibWithNibName:@"WADayPhotoPickerViewCell" bundle:nil] forCellWithReuseIdentifier:@"WADayPhotoPickerViewCell"]; + [self.collectionView registerNib:[UINib nibWithNibName:@"WADayPhotoPickerSectionHeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"WADayPhotoPickerSectionHeaderView"]; +} +- (void) viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + __weak WADayPhotoPickerViewController *wSelf = self; + WAOverlayBezel *busyBezel = [[WAOverlayBezel alloc] initWithStyle:WAActivityIndicatorBezelStyle]; + [busyBezel show]; + + [[WAAssetsLibraryManager defaultManager] retrieveTimeSortedPhotosWhenComplete:^(NSArray *result) { + wSelf.allTimeSortedAssets = result; + [busyBezel dismiss]; + + [wSelf.collectionView reloadData]; + + if (wSelf.selectedAssets.count) + [wSelf scrollToDate:[(ALAsset*)wSelf.selectedAssets[0] valueForProperty:ALAssetPropertyDate]]; + } onFailure:^(NSError *error) { + [busyBezel dismiss]; + + NSLog(@"error: %@", error); + }]; + +} + +- (void) viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + [self.imageDisplayQueue cancelAllOperations]; +} + +- (BOOL) shouldAutorotate { + return YES; +} + +- (NSUInteger) supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +- (NSArray*) photoGroups { + + if (_photoGroups.count > 0) + return _photoGroups; + + if (_allTimeSortedAssets.count == 0) + return @[]; + + NSMutableArray *sortedGroups = [NSMutableArray array]; + NSMutableArray *photoList = [NSMutableArray array]; + __block NSDate *previousDate = nil; + + [_allTimeSortedAssets enumerateObjectsUsingBlock:^(ALAsset *asset, NSUInteger idx, BOOL *stop) { + + if (!previousDate) { + [photoList addObject:asset]; + previousDate = [asset valueForProperty:ALAssetPropertyDate]; + + } else { + + NSDate *assetDate = [asset valueForProperty:ALAssetPropertyDate]; + + if(!isSameDay(assetDate, previousDate)) { + + previousDate = assetDate; + [sortedGroups addObject:[photoList copy]]; + [photoList removeAllObjects]; + [photoList addObject:asset]; + + } else { + + previousDate = assetDate; + [photoList addObject:asset]; + + } + } + + }]; + + _photoGroups = [NSArray arrayWithArray:sortedGroups]; + return _photoGroups; +} + +- (void) scrollToDate:(NSDate*)targetDate { + + NSInteger index = 0; + + for (NSArray *group in self.photoGroups) { + NSDate *date = [(ALAsset*)group[0] valueForProperty:ALAssetPropertyDate]; + if (isSameDay(targetDate, date)) + break; + + if ([targetDate compare:date] == NSOrderedDescending) + break; + + index ++; + } + + [self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:index] atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:YES]; +} + + +- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { + return self.photoGroups.count; +} + +- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { + + return [self.photoGroups[section] count]; + +} + +- (UICollectionViewCell*)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { + + __weak WADayPhotoPickerViewController *wSelf = self; + WADayPhotoPickerViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"WADayPhotoPickerViewCell" forIndexPath:indexPath]; + + NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + + UIImage *image = [UIImage imageWithCGImage:[(ALAsset*)wSelf.photoGroups[indexPath.section][indexPath.row] thumbnail]]; + + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + cell.imageView.image = image; + ALAsset *asset = self.photoGroups[indexPath.section][indexPath.row]; + if (wSelf.selectedAssets != nil && [wSelf.selectedAssets indexOfObject:asset] != NSNotFound) { + [wSelf.collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone]; + } + + }]; + }]; + [self.imageDisplayQueue addOperation:op]; + + + return cell; +} + +- (UICollectionReusableView*)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { + + if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { + WADayPhotoPickerSectionHeaderView * header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"WADayPhotoPickerSectionHeaderView" forIndexPath:indexPath]; + + ALAsset *asset = self.photoGroups[indexPath.section][0]; + NSDate *date = [asset valueForProperty:ALAssetPropertyDate]; + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter = [[NSDateFormatter alloc] init]; + formatter.dateStyle = NSDateFormatterMediumStyle; + formatter.timeStyle = NSDateFormatterNoStyle; + header.titleLabel.text = [formatter stringFromDate:date]; + + return header; + } + + return nil; +} + +@end diff --git a/wammer/WADayPhotoPickerViewController.xib b/wammer/WADayPhotoPickerViewController.xib new file mode 100644 index 00000000..326b220a --- /dev/null +++ b/wammer/WADayPhotoPickerViewController.xib @@ -0,0 +1,343 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUICollectionView + IBUICollectionViewFlowLayout + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 1298 + + + {320, 548} + + + _NS:9 + NO + YES + YES + IBCocoaTouchFramework + NO + 0.0 + 0.0 + + + {92, 92} + {320, 24} + 10 + 10 + 10 + 10 + 10 + 10 + + + + + {{0, 20}, {320, 548}} + + + + + 3 + MQA + + 2 + + + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + + + + + + + view + + + + 3 + + + + collectionView + + + + 25 + + + + dataSource + + + + 26 + + + + delegate + + + + 27 + + + + + + 0 + + + + + + 1 + + + + + + 3 + 0 + + 3 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 4 + 0 + + 4 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 8 + 29 + 3 + + + + + + -1 + + + File's Owner + + + -2 + + + + + 19 + + + + + + + + 20 + + + + + 21 + + + + + 22 + + + + + 23 + + + + + 24 + + + + + + + WADayPhotoPickerViewController + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + 27 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + UICollectionViewFlowLayout + UICollectionViewLayout + + IBProjectSource + ./Classes/UICollectionViewFlowLayout.h + + + + UICollectionViewLayout + NSObject + + IBProjectSource + ./Classes/UICollectionViewLayout.h + + + + WADayPhotoPickerViewController + UIViewController + + collectionView + UICollectionView + + + collectionView + + collectionView + UICollectionView + + + + IBProjectSource + ./Classes/WADayPhotoPickerViewController.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoHighlightsViewController.m b/wammer/WAPhotoHighlightsViewController.m index e534fdb1..418f2723 100644 --- a/wammer/WAPhotoHighlightsViewController.m +++ b/wammer/WAPhotoHighlightsViewController.m @@ -8,6 +8,7 @@ #import "WAPhotoHighlightsViewController.h" #import "WAPhotoHighlightViewCell.h" +#import "WADayPhotoPickerViewController.h" #import "WAAssetsLibraryManager.h" #import "WAOverlayBezel.h" #import "WAGeoLocation.h" @@ -16,7 +17,7 @@ #import "FBRequestConnection+WAAdditions.h" #import "WADataStore.h" #import "WACheckin.h" -#import +#import #define GROUPING_THRESHOLD (30 * 60) @@ -47,6 +48,17 @@ - (void)viewDidLoad self.allTimeSortedAssets = @[]; self.photoGroups = [@[] mutableCopy]; + self.title = NSLocalizedString(@"TITLE_OF_HIGHLIGHTS", @"The title of highlight view"); + + if (self.navigationController) { + __weak WAPhotoHighlightsViewController *wSelf = self; + UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:@"By Date" style:UIBarButtonItemStyleBordered handler:^(id sender) { + WADayPhotoPickerViewController *picker = [[WADayPhotoPickerViewController alloc] initWithSelectedAssets:nil]; + [wSelf.navigationController pushViewController:picker animated:YES]; + }]; + self.navigationItem.rightBarButtonItem = buttonItem; + } + self.managedObjectContext = [[WADataStore defaultStore] disposableMOC]; [self.tableView registerNib:[UINib nibWithNibName:@"WAPhotoHighlightViewCell" bundle:nil] forCellReuseIdentifier:@"WAPhotoHighlightViewCell"]; @@ -291,13 +303,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - + /* WAPhotoTimelineViewController *vc = [[WAPhotoTimelineViewController alloc] initWithAssets:self.photoGroups[indexPath.row]]; self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; self.modalPresentationStyle = UIModalPresentationCurrentContext; [self presentViewController:vc animated:YES completion:nil]; - + */ + WADayPhotoPickerViewController *picker = [[WADayPhotoPickerViewController alloc] initWithSelectedAssets:self.photoGroups[indexPath.row]]; + [self.navigationController pushViewController:picker animated:YES]; } @end diff --git a/wammer/en.lproj/Localizable.strings b/wammer/en.lproj/Localizable.strings index 3526153c..1b920ea9 100644 --- a/wammer/en.lproj/Localizable.strings +++ b/wammer/en.lproj/Localizable.strings @@ -566,6 +566,12 @@ /* Title of Canlendar */ "TITLE_CALENDAR" = "Calendar"; +/* Title of the day photo picker view */ +"TITLE_OF_DAY_PHOTO_PICKER" = "Select Photos"; + +/* The title of highlight view */ +"TITLE_OF_HIGHLIGHTS" = "Highlights"; + /* Alert on no location service enabled when open photo library */ "TURN_ON_LOCATION_SERVICE" = "Turn on Location Services to allow aostream to access your Photo Library."; diff --git a/wammer/zh-Hant.lproj/Localizable.strings b/wammer/zh-Hant.lproj/Localizable.strings index 2f76d3bc..2cc59362 100644 --- a/wammer/zh-Hant.lproj/Localizable.strings +++ b/wammer/zh-Hant.lproj/Localizable.strings @@ -566,6 +566,12 @@ /* Title of Canlendar */ "TITLE_CALENDAR" = "月曆"; +/* Title of the day photo picker view */ +"TITLE_OF_DAY_PHOTO_PICKER" = "挑選照片"; + +/* The title of highlight view */ +"TITLE_OF_HIGHLIGHTS" = "小確性"; + /* Alert on no location service enabled when open photo library */ "TURN_ON_LOCATION_SERVICE" = "aostream 須開啟定位服務才能存取相簿的內容"; From e1c407f98d9f25da3cb5812e57e411abcb80b3fe Mon Sep 17 00:00:00 2001 From: Greener Date: Tue, 9 Apr 2013 15:37:05 +0800 Subject: [PATCH 010/278] Update code file location --- WAContactPickerViewController.h | 18 --- WAContactPickerViewController.m | 174 ------------------------- WAContactPickerViewController.xib | 160 ----------------------- WASharedEventViewController.h | 16 --- WASharedEventViewController.m | 136 ------------------- WASharedEventViewController.xib | 149 --------------------- wammer/WAContactPickerViewController.m | 14 +- 7 files changed, 10 insertions(+), 657 deletions(-) delete mode 100644 WAContactPickerViewController.h delete mode 100644 WAContactPickerViewController.m delete mode 100644 WAContactPickerViewController.xib delete mode 100644 WASharedEventViewController.h delete mode 100644 WASharedEventViewController.m delete mode 100644 WASharedEventViewController.xib diff --git a/WAContactPickerViewController.h b/WAContactPickerViewController.h deleted file mode 100644 index 042aed7b..00000000 --- a/WAContactPickerViewController.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// WAContactPickerViewController.h -// wammer -// -// Created by Greener Chen on 13/4/2. -// Copyright (c) 2013年 Waveface. All rights reserved. -// - -#import -#import - -@interface WAContactPickerViewController : UITableViewController - -@property (nonatomic, strong) NSMutableArray *members; - --(IBAction)showContactsPicker:(id)sender; - -@end diff --git a/WAContactPickerViewController.m b/WAContactPickerViewController.m deleted file mode 100644 index e7034fa8..00000000 --- a/WAContactPickerViewController.m +++ /dev/null @@ -1,174 +0,0 @@ -// -// WAContactPickerViewController.m -// wammer -// -// Created by Greener Chen on 13/4/2. -// Copyright (c) 2013年 Waveface. All rights reserved. -// - -#import "WAContactPickerViewController.h" - -@interface WAContactPickerViewController () - -@end - -@implementation WAContactPickerViewController - -- (id)initWithStyle:(UITableViewStyle)style -{ - self = [super initWithStyle:style]; - if (self) { - // Custom initialization - _members = [[NSMutableArray alloc] init]; - } - return self; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)]; -} - -- (void)cancel -{ - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)done -{ - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -#pragma mark - Table view data source - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView -{ - // Return the number of sections. - return 2; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - // Return the number of rows in the section. - if (section == 0) { - return 2; - - } else { - return [_members count]; - - } -} - -- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section -{ - UIView *headerView = [super tableView:tableView viewForHeaderInSection:section]; - // Customize the header view - - return headerView; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString *CellIdentifier = @"Cell"; - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; - if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; - } - - // Configure the cell... - if (indexPath.section == 0) { - if (indexPath.row == 0) { - cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; - cell.textLabel.text = @"Facebook Contacts"; - cell.detailTextLabel.text = @"Share to your Facebook friends"; - - } else if (indexPath.row == 1) { - cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; - cell.textLabel.text = @"Contacts"; - cell.detailTextLabel.text = @"Share to your contacts"; - cell.accessoryType = UITableViewCellAccessoryDetailDisclosureButton; - - } - - } else { - cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; - cell.textLabel.text = _members[indexPath.row][@"name"]; - cell.detailTextLabel.text = [NSString stringWithFormat:@"%@\n%@", - _members[indexPath.row][@"phone"], - ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; - cell.accessoryType = UITableViewCellAccessoryCheckmark; - - } - - return cell; -} - -#pragma mark - Table view delegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [tableView deselectRowAtIndexPath:indexPath animated:YES]; - - if (indexPath.section == 0 && indexPath.row == 1) { - ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; - abPicker.peoplePickerDelegate = self; - - [self presentViewController:abPicker animated:YES completion:nil]; - - } -} - -#pragma - Address Book Contacts Picker - -- (void)showContactsPicker:(id)sender -{ - ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; - abPicker.peoplePickerDelegate = self; - - [self presentViewController:abPicker animated:YES completion:nil]; -} - -- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker -{ - [self dismissViewControllerAnimated:YES completion:nil]; -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person -{ - [self addIntoInvitedList:person]; - [self dismissViewControllerAnimated:YES completion:nil]; - [self.tableView reloadData]; - - return NO; -} - -- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier -{ - return NO; -} - -- (void)addIntoInvitedList:(ABRecordRef)person -{ - NSString *firstname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); - NSString *lastname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); - NSArray *email = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); - - NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(person, kABPersonPhoneProperty), 0);; - - NSDictionary *aPerson = @{@"name": [NSString stringWithFormat:@"%@ %@", firstname, lastname], - @"email": (email)? email : @[], - @"phone": (phone)? phone : @"[None]"}; - [_members addObject:aPerson]; - -} - -@end diff --git a/WAContactPickerViewController.xib b/WAContactPickerViewController.xib deleted file mode 100644 index b2a5b64a..00000000 --- a/WAContactPickerViewController.xib +++ /dev/null @@ -1,160 +0,0 @@ - - - - 1536 - 12A269 - 2835 - 1187 - 624.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1919 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - {{0, 20}, {320, 548}} - - - - - 3 - MQA - - NO - YES - NO - - - IBUIScreenMetrics - - YES - - - - - - {320, 568} - {568, 320} - - - IBCocoaTouchFramework - Retina 4 Full Screen - 2 - - IBCocoaTouchFramework - NO - 1 - 0 - YES - 44 - 22 - 22 - - - - - - - view - - - - 5 - - - - dataSource - - - - 6 - - - - delegate - - - - 7 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - WAContactPickerViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 7 - - - - - WAContactPickerViewController - UITableViewController - - IBProjectSource - ./Classes/WAContactPickerViewController.h - - - - - 0 - IBCocoaTouchFramework - YES - 3 - YES - 1919 - - diff --git a/WASharedEventViewController.h b/WASharedEventViewController.h deleted file mode 100644 index 348867d6..00000000 --- a/WASharedEventViewController.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// WAEventSharingViewController.h -// wammer -// -// Created by Greener Chen on 13/4/2. -// Copyright (c) 2013年 Waveface. All rights reserved. -// - -#import - -@interface WASharedEventViewController : UITableViewController - - -@end - - diff --git a/WASharedEventViewController.m b/WASharedEventViewController.m deleted file mode 100644 index a58821e7..00000000 --- a/WASharedEventViewController.m +++ /dev/null @@ -1,136 +0,0 @@ -// -// WAEventSharingViewController.m -// wammer -// -// Created by Greener Chen on 13/4/2. -// Copyright (c) 2013年 Waveface. All rights reserved. -// - -#import "WASharedEventViewController.h" -#import "WAContactPickerViewController.h" -#import "WANavigationController.h" -#import "WALocation.h" -#import -#import "WADataStore.h" -#import "NSDate+WAAdditions.h" - -@interface WASharedEventViewController () - -@property (nonatomic, strong) NSFetchedResultsController *eventFetchedResultsController; -@property (nonatomic, strong) NSMutableArray *events; - -@end - -@implementation WASharedEventViewController - -- (id)initWithStyle:(UITableViewStyle)style -{ - self = [super initWithStyle:style]; - if (self) { - // Custom initialization - self.events = [[NSMutableArray alloc] init]; - } - self.events = [[self loadEventsFrom:[NSDate date] forwardDays:100] copy]; - - return self; -} - -- (NSArray *)loadEventsFrom:(NSDate *)aDate forwardDays:(NSInteger)forwardDays -{ - NSManagedObjectContext *moc = [[WADataStore defaultStore] autoUpdatingMOC]; - NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WAArticle"]; - NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"eventStartDate" ascending:NO]; - [fetchRequest setSortDescriptors:@[sortDescriptor]]; - self.eventFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND hidden = FALSE AND files.@count > 0", [aDate dateOfPreviousNumOfDays:forwardDays], aDate]; - [self.eventFetchedResultsController.fetchRequest setPredicate:predicate]; - - NSError *Err; - if (![self.eventFetchedResultsController performFetch:&Err]) { - NSLog(@"Fetch WAArticle failed: %@", Err); - } - - return self.eventFetchedResultsController.fetchedObjects; -} - -- (void)viewDidLoad -{ - [super viewDidLoad]; - - [self.navigationController setToolbarHidden:NO]; - UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addAttendees)]; - self.toolbarItems = @[flexibleSpace, addButton, flexibleSpace]; -} - -- (void)didReceiveMemoryWarning -{ - [super didReceiveMemoryWarning]; - // Dispose of any resources that can be recreated. -} - -#pragma mark - Table view data source - -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView -{ - // Return the number of sections. - return 1; -} - -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section -{ - // Return the number of rows in the section. - return [self.events count]; -} - -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath -{ - static NSString *CellIdentifier = @"Cell"; - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; - if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; - } - - // Configure the cell... - cell.backgroundColor = [UIColor greenColor]; - cell.backgroundView = [[UIImageView alloc] initWithImage:[[self.events[indexPath.row] representingFile] thumbnailImage]]; - cell.backgroundView.contentMode = UIViewContentModeScaleAspectFill; - cell.backgroundView.clipsToBounds = YES; - NSString *photoNumbers = [NSString stringWithFormat:([[self.events[indexPath.row] files] count] == 1)? - NSLocalizedString(@"EVENT_ONE_PHOTO_NUMBER_LABEL", @"EVENT_ONE_PHOTO_NUMBER_LABEL"): - NSLocalizedString(@"EVENT_PHOTO_NUMBER_LABEL", @"EVENT_PHOTO_NUMBER_LABEL"), - [[self.events[indexPath.row] files] count]]; - static NSDateFormatter *sharedDateFormatter; - sharedDateFormatter = [[NSDateFormatter alloc] init]; - [sharedDateFormatter setDateFormat:@"yyyy MM dd"]; - NSString *eventDate = [sharedDateFormatter stringFromDate:[self.events[indexPath.row] eventStartDate]]; - NSString *otherStr = [self.events[indexPath.row] description]; - cell.textLabel.text = [NSString stringWithFormat:@"%@\n%@\n%@", photoNumbers, eventDate, otherStr]; - [cell.textLabel setNumberOfLines:0]; - [cell.textLabel setBackgroundColor:[UIColor clearColor]]; - [cell.textLabel setTextColor:[UIColor whiteColor]]; - - UIButton *addBtn = [UIButton buttonWithType:UIButtonTypeContactAdd]; - cell.accessoryView = addBtn; - - return cell; -} - -#pragma mark - Table view delegate - -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath -{ - [tableView deselectRowAtIndexPath:indexPath animated:NO]; -} - -#pragma - toolbar - -- (void)addAttendees -{ - __weak WASharedEventViewController *wSelf = self; - WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; - WANavigationController *nav = [[WANavigationController alloc] initWithRootViewController:cpVC]; - [wSelf presentViewController:nav animated:YES completion:nil]; -} - -@end diff --git a/WASharedEventViewController.xib b/WASharedEventViewController.xib deleted file mode 100644 index a5e2ebbf..00000000 --- a/WASharedEventViewController.xib +++ /dev/null @@ -1,149 +0,0 @@ - - - - 1552 - 12D78 - 3084 - 1187.37 - 626.00 - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 2083 - - - IBProxyObject - IBUITableView - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - PluginDependencyRecalculationVersion - - - - - IBFilesOwner - IBCocoaTouchFramework - - - IBFirstResponder - IBCocoaTouchFramework - - - - 274 - - {{0, 20}, {320, 504}} - - 3 - MQA - - NO - YES - NO - - - - IBUIScreenMetrics - - YES - - - - - - {320, 568} - {568, 320} - - - IBCocoaTouchFramework - Retina 4 Full Screen - 2 - - IBCocoaTouchFramework - NO - 1 - 0 - YES - 148 - 22 - 22 - - - - - - - view - - - - 5 - - - - dataSource - - - - 6 - - - - delegate - - - - 7 - - - - - - 0 - - - - - - -1 - - - File's Owner - - - -2 - - - - - 4 - - - - - - - - WASharedEventViewController - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - UIResponder - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - - - - 11 - - - 0 - IBCocoaTouchFramework - YES - 3 - YES - 2083 - - diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index 0337cc4e..dc9ec027 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -104,7 +104,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else { cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; - cell.textLabel.text = _members[indexPath.row][@"name"]; + //TODO: first name then last name, or last name then first name by system settings + cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", _members[indexPath.row][@"firstName"], _members[indexPath.row][@"lastName"]]; cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@", _members[indexPath.row][@"phone"], ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; @@ -165,12 +166,17 @@ - (void)addIntoInvitedList:(ABRecordRef)person NSString *lastname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); NSArray *email = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); + //TODO: pick mobile phone numbers NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(person, kABPersonPhoneProperty), 0);; - NSDictionary *aPerson = @{@"name": [NSString stringWithFormat:@"%@ %@", firstname, lastname], + NSDictionary *aPerson = @{@"firstName": firstname, + @"lastName": lastname, @"email": (email)? email : @[], - @"phone": (phone)? phone : @"[None]"}; - [_members addObject:aPerson]; + @"phone": (phone)? phone : @"[N/A]"}; + + if (![_members containsObject:aPerson]) { + [_members addObject:aPerson]; + } } From 2b2e1fddd126cdedc0a3f86c63f7141526602621 Mon Sep 17 00:00:00 2001 From: syshen Date: Tue, 9 Apr 2013 15:55:58 +0800 Subject: [PATCH 011/278] change icon --- wammer.xcodeproj/project.pbxproj | 4 ++++ wammer/Resources/partioIcon.png | Bin 0 -> 31183 bytes wammer/WAAppDelegate_iOS.m | 12 +++++----- wammer/WADayPhotoPickerViewController.m | 30 +++++++++++++++++++++--- wammer/WAPartioFirstUse.storyboard | 14 ++++++++++- wammer/wammer-iOS-Info.plist | 8 +++---- 6 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 wammer/Resources/partioIcon.png diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 20db3db0..9b951255 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -389,6 +389,7 @@ 80C768EE1711B9D5000F10A8 /* WACheckin.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768ED1711B9D5000F10A8 /* WACheckin.m */; }; 80C768F21711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m in Sources */ = {isa = PBXBuildFile; fileRef = 80C768F11711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m */; }; 80C979F71649796A004F0CF4 /* EventCardBG.png in Resources */ = {isa = PBXBuildFile; fileRef = 80C979F61649796A004F0CF4 /* EventCardBG.png */; }; + 80CBC7721713FBDE0056D9CF /* partioIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 80CBC7711713FBDE0056D9CF /* partioIcon.png */; }; 80DA984F16496FED0030CA21 /* WAEventHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DA984216496FED0030CA21 /* WAEventHeaderView.m */; }; 80DA985116496FED0030CA21 /* WAEventLinkViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DA984516496FED0030CA21 /* WAEventLinkViewCell.m */; }; 80DA985216496FED0030CA21 /* WAEventLinkViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80DA984616496FED0030CA21 /* WAEventLinkViewCell.xib */; }; @@ -1436,6 +1437,7 @@ 80C768F01711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WACheckin+WARemoteInterfaceEntitySyncing.h"; sourceTree = ""; }; 80C768F11711BBF4000F10A8 /* WACheckin+WARemoteInterfaceEntitySyncing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WACheckin+WARemoteInterfaceEntitySyncing.m"; sourceTree = ""; }; 80C979F61649796A004F0CF4 /* EventCardBG.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = EventCardBG.png; path = Resources/EventCardBG.png; sourceTree = ""; }; + 80CBC7711713FBDE0056D9CF /* partioIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = partioIcon.png; path = Resources/partioIcon.png; sourceTree = ""; }; 80DA984116496FED0030CA21 /* WAEventHeaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAEventHeaderView.h; path = wammer/WAEventHeaderView.h; sourceTree = ""; }; 80DA984216496FED0030CA21 /* WAEventHeaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAEventHeaderView.m; path = wammer/WAEventHeaderView.m; sourceTree = ""; }; 80DA984416496FED0030CA21 /* WAEventLinkViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAEventLinkViewCell.h; path = wammer/WAEventLinkViewCell.h; sourceTree = ""; }; @@ -3225,6 +3227,7 @@ FFC2E04C13DD706600816EA1 /* iOS Resources */ = { isa = PBXGroup; children = ( + 80CBC7711713FBDE0056D9CF /* partioIcon.png */, 13D1397016DB467F00A41F86 /* WelcomeLogo.png */, 13D1397116DB467F00A41F86 /* WelcomeLogo@2x.png */, 13D1397416DB474000A41F86 /* WelcomeBackgroundPattern.png */, @@ -4258,6 +4261,7 @@ 802835551713009A00E0A187 /* WADayPhotoPickerViewController.xib in Resources */, 80283557171302B900E0A187 /* WADayPhotoPickerViewCell.xib in Resources */, 8028355F1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib in Resources */, + 80CBC7721713FBDE0056D9CF /* partioIcon.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/Resources/partioIcon.png b/wammer/Resources/partioIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd07e8fecbea528fdbb8a2dba47d1c17b716a32 GIT binary patch literal 31183 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 @interface WADayPhotoPickerViewController () @@ -19,7 +20,7 @@ @interface WADayPhotoPickerViewController () - + + @@ -98,6 +99,17 @@ + + + + + + + + + + + diff --git a/wammer/wammer-iOS-Info.plist b/wammer/wammer-iOS-Info.plist index 60dd11a5..9f76b03f 100644 --- a/wammer/wammer-iOS-Info.plist +++ b/wammer/wammer-iOS-Info.plist @@ -16,10 +16,10 @@ CFBundleIconFiles - Icon${STREAM_ICON_NAME_SUFFIX}.png - Icon-72${STREAM_ICON_NAME_SUFFIX}.png - Icon${STREAM_ICON_NAME_SUFFIX}@2x.png - Icon-72${STREAM_ICON_NAME_SUFFIX}@2x.png + partioIcon.png + partioIcon.png + partioIcon.png + partioIcon.png UIPrerenderedIcon From fe58612938776afbc9b93e02778e1cb34a92d036 Mon Sep 17 00:00:00 2001 From: Greener Date: Tue, 9 Apr 2013 16:00:09 +0800 Subject: [PATCH 012/278] Fix location string --- wammer/WASharedEventViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 9611bbd5..3bc71d09 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -113,7 +113,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N sharedDateFormatter = [[NSDateFormatter alloc] init]; [sharedDateFormatter setDateFormat:@"yyyy MM dd"]; NSString *eventDate = [sharedDateFormatter stringFromDate:[self.events[indexPath.row] eventStartDate]]; - NSString *location = [[self.events[indexPath.row] description] substringFromIndex:3]; + NSString *location = [self.events[indexPath.row] description]; cell.textLabel.text = [NSString stringWithFormat:@"%@\n%@\n%@", photoNumbers, eventDate, location]; [cell.textLabel setNumberOfLines:0]; [cell.textLabel setBackgroundColor:[UIColor clearColor]]; From fab5a520c42480ddde0b09c8edac4e5aaa87a25c Mon Sep 17 00:00:00 2001 From: Greener Date: Tue, 9 Apr 2013 16:41:23 +0800 Subject: [PATCH 013/278] Add public onNextHandler property --- wammer/WAContactPickerViewController.h | 1 + wammer/WAContactPickerViewController.m | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/wammer/WAContactPickerViewController.h b/wammer/WAContactPickerViewController.h index 042aed7b..9a24bd5a 100644 --- a/wammer/WAContactPickerViewController.h +++ b/wammer/WAContactPickerViewController.h @@ -12,6 +12,7 @@ @interface WAContactPickerViewController : UITableViewController @property (nonatomic, strong) NSMutableArray *members; +@property (copy) void (^onNextHandler)(NSArray *selectedContacts); -(IBAction)showContactsPicker:(id)sender; diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index dc9ec027..85242974 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -39,6 +39,10 @@ - (void)cancel - (void)done { + if (self.onNextHandler) { + self.onNextHandler(_members); + } + [self dismissViewControllerAnimated:YES completion:nil]; } From f3067cfdf4ff4f32e6264725a34200236bdf4063 Mon Sep 17 00:00:00 2001 From: Greener Date: Tue, 9 Apr 2013 16:48:46 +0800 Subject: [PATCH 014/278] Take off the cancel button for a back button in contact picker view --- wammer/WAContactPickerViewController.m | 6 ------ 1 file changed, 6 deletions(-) diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index 85242974..6782fde0 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -28,15 +28,9 @@ - (void)viewDidLoad { [super viewDidLoad]; - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel)]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(done)]; } -- (void)cancel -{ - [self dismissViewControllerAnimated:YES completion:nil]; -} - - (void)done { if (self.onNextHandler) { From f02f950eeae52c11758b4f272ca7dfbe1a928ee3 Mon Sep 17 00:00:00 2001 From: syshen Date: Tue, 9 Apr 2013 22:17:56 +0800 Subject: [PATCH 015/278] partio api connection --- wammer.xcodeproj/project.pbxproj | 10 + wammer/WAAppDelegate_iOS.m | 16 +- ...WAArticle+WARemoteInterfaceEntitySyncing.m | 7 +- wammer/WAArticle.h | 4 +- wammer/WADayPhotoPickerViewController.m | 2 + wammer/WAFetchManager.m | 2 +- .../WAFile+WARemoteInterfaceEntitySyncing.m | 8 +- wammer/WAPartioSignupViewController.h | 15 + wammer/WAPartioSignupViewController.m | 48 +++ wammer/WAPartioSignupViewController.xib | 385 ++++++++++++++++++ wammer/WAPhotoTimelineViewController.m | 177 +++++++- wammer/WARemoteInterface+Attachments.m | 12 +- wammer/WARemoteInterface+Posts.m | 10 +- wammer/WASyncManager+DirtyArticleSync.m | 6 +- wammer/WASyncManager+FileMetadataSync.m | 6 +- wammer/WASyncManager+FullQualityFileSync.m | 6 +- wammer/WASyncManager.m | 4 +- 17 files changed, 663 insertions(+), 55 deletions(-) create mode 100644 wammer/WAPartioSignupViewController.h create mode 100644 wammer/WAPartioSignupViewController.m create mode 100644 wammer/WAPartioSignupViewController.xib diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index 9b951255..e4a91f82 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -400,6 +400,8 @@ 80DAA57D16BA7C2400A4E352 /* TWAPIManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DAA57A16BA7C2400A4E352 /* TWAPIManager.m */; }; 80DAA57E16BA7C2400A4E352 /* TWSignedRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 80DAA57C16BA7C2400A4E352 /* TWSignedRequest.m */; }; 80E5173C1670F3B200E1C3AD /* WALocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 80E5173B1670F3B200E1C3AD /* WALocation.m */; }; + 80F2752D171410B400C49FAB /* WAPartioSignupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80F2752C171410B400C49FAB /* WAPartioSignupViewController.m */; }; + 80F2753C171410D500C49FAB /* WAPartioSignupViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 80F2753B171410D500C49FAB /* WAPartioSignupViewController.xib */; }; 80F42C0215F70EDF00C8A72B /* WAWebSocket.m in Sources */ = {isa = PBXBuildFile; fileRef = 809D428F15F5CE4300CB4F89 /* WAWebSocket.m */; }; 80F5223316C0FAD8003A06D5 /* WARemoteInterface+Summary.m in Sources */ = {isa = PBXBuildFile; fileRef = 80F5223216C0FAD8003A06D5 /* WARemoteInterface+Summary.m */; }; 80F800F615C2624C00132A96 /* IRAQ-Checkmark.png in Resources */ = {isa = PBXBuildFile; fileRef = 80F800F415C2624C00132A96 /* IRAQ-Checkmark.png */; }; @@ -1457,6 +1459,9 @@ 80DAA57C16BA7C2400A4E352 /* TWSignedRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TWSignedRequest.m; path = external/TWReverseAuth/Source/Classes/TWSignedRequest.m; sourceTree = ""; }; 80E5173A1670F3B200E1C3AD /* WALocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WALocation.h; sourceTree = ""; }; 80E5173B1670F3B200E1C3AD /* WALocation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WALocation.m; sourceTree = ""; }; + 80F2752B171410B400C49FAB /* WAPartioSignupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAPartioSignupViewController.h; path = wammer/WAPartioSignupViewController.h; sourceTree = ""; }; + 80F2752C171410B400C49FAB /* WAPartioSignupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAPartioSignupViewController.m; path = wammer/WAPartioSignupViewController.m; sourceTree = ""; }; + 80F2753B171410D500C49FAB /* WAPartioSignupViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAPartioSignupViewController.xib; path = wammer/WAPartioSignupViewController.xib; sourceTree = ""; }; 80F5223116C0FAD8003A06D5 /* WARemoteInterface+Summary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WARemoteInterface+Summary.h"; sourceTree = ""; }; 80F5223216C0FAD8003A06D5 /* WARemoteInterface+Summary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "WARemoteInterface+Summary.m"; sourceTree = ""; }; 80F800F415C2624C00132A96 /* IRAQ-Checkmark.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "IRAQ-Checkmark.png"; sourceTree = ""; }; @@ -2436,6 +2441,9 @@ DE67A4C61712BE4100099106 /* WAPhotoCollageCell_Stack1.xib */, 8027264D1710078800BB1733 /* WATimelineIndexView.h */, 8027264E1710078800BB1733 /* WATimelineIndexView.m */, + 80F2752B171410B400C49FAB /* WAPartioSignupViewController.h */, + 80F2752C171410B400C49FAB /* WAPartioSignupViewController.m */, + 80F2753B171410D500C49FAB /* WAPartioSignupViewController.xib */, ); name = "New Event View"; sourceTree = ""; @@ -4262,6 +4270,7 @@ 80283557171302B900E0A187 /* WADayPhotoPickerViewCell.xib in Resources */, 8028355F1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib in Resources */, 80CBC7721713FBDE0056D9CF /* partioIcon.png in Resources */, + 80F2753C171410D500C49FAB /* WAPartioSignupViewController.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4764,6 +4773,7 @@ 802835541713009A00E0A187 /* WADayPhotoPickerViewController.m in Sources */, 8028355A1713037900E0A187 /* WADayPhotoPickerViewCell.m in Sources */, 8028355D1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m in Sources */, + 80F2752D171410B400C49FAB /* WAPartioSignupViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 1c8dfe43..59ecd9fc 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -305,9 +305,6 @@ - (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions: if (lastAuthenticatedUserIdentifier) [self bootstrapPersistentStoreWithUserIdentifier:lastAuthenticatedUserIdentifier]; -// self.fetchManager = [[WAFetchManager alloc] init]; -// self.syncManager = [[WASyncManager alloc] init]; - [self recreateViewHierarchy]; } @@ -470,21 +467,22 @@ - (void) recreateViewHierarchy { NSLog(@"failed to login facebook for error: %@", error); } else { - -// WAPhotoHighlightsViewController *highlightVC = [[WAPhotoHighlightsViewController alloc] init]; -// self.window.rootViewController = highlightVC; - WASharedEventViewController *sharedEventsVC = [[WASharedEventViewController alloc] initWithStyle:UITableViewStylePlain]; - wSelf.window.rootViewController = sharedEventsVC; + UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:sharedEventsVC]; + wSelf.window.rootViewController = navVC; + wSelf.fetchManager = [[WAFetchManager alloc] init]; + wSelf.syncManager = [[WASyncManager alloc] init]; + } }]; } else { WASharedEventViewController *sharedEventsVC = [[WASharedEventViewController alloc] initWithStyle:UITableViewStylePlain]; - wSelf.window.rootViewController = sharedEventsVC; + UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:sharedEventsVC]; + wSelf.window.rootViewController = navVC; } diff --git a/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m b/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m index 7a345ac7..507dd5e4 100644 --- a/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m @@ -1,4 +1,4 @@ -// + // // WAArticle+WARemoteInterfaceEntitySyncing.m // wammer // @@ -281,6 +281,7 @@ - (void) synchronizeWithOptions:(NSDictionary *)options completion:(WAEntitySync BOOL isFavorite = [self.favorite isEqualToNumber:(id)kCFBooleanTrue]; BOOL isHidden = [self.hidden isEqualToNumber:(id)kCFBooleanTrue]; BOOL isEvent = [self.event isEqualToNumber:(id)kCFBooleanTrue]; + BOOL isSharedEvent = [self.eventType isEqualToNumber:[NSNumber numberWithInt:WAEventArticleSharedType]]; if (!isDraft) { @@ -471,7 +472,7 @@ - (void) synchronizeWithOptions:(NSDictionary *)options completion:(WAEntitySync [ri createPostInGroup:groupID withContentText:postText attachments:attachments - type:isEvent?WAArticleTypeEvent:WAArticleTypeImport + type:isEvent?(isSharedEvent?WAArticleTypeSharedEvent:WAArticleTypeEvent):WAArticleTypeImport postId:postID createTime:postCreationDate updateTime:postModificationDate @@ -526,7 +527,7 @@ - (void) synchronizeWithOptions:(NSDictionary *)options completion:(WAEntitySync withText:postText attachments:attachments mainAttachment:postCoverPhotoID - type:isEvent?WAArticleTypeEvent:WAArticleTypeImport + type:isEvent?(isSharedEvent?WAArticleTypeSharedEvent:WAArticleTypeEvent):WAArticleTypeImport favorite:isFavorite hidden:isHidden replacingDataWithDate:lastPostModDate diff --git a/wammer/WAArticle.h b/wammer/WAArticle.h index 649583ff..f0935831 100644 --- a/wammer/WAArticle.h +++ b/wammer/WAArticle.h @@ -12,12 +12,14 @@ typedef NS_ENUM(NSUInteger, WAArticleType) { WAArticleTypeEvent = 0, - WAArticleTypeImport = 1 + WAArticleTypeImport = 1, + WAArticleTypeSharedEvent = 2 }; typedef NS_ENUM(NSUInteger, WAEventArticleType) { WAEventArticleUnknownType = 0, WAEventArticlePhotoType = 1, + WAEventArticleSharedType = 2 }; @class WAEventDay, WAFile, WAGroup, WALocation, WAPeople, WATag, WATagGroup, WAUser; diff --git a/wammer/WADayPhotoPickerViewController.m b/wammer/WADayPhotoPickerViewController.m index c45d0785..b22386ef 100644 --- a/wammer/WADayPhotoPickerViewController.m +++ b/wammer/WADayPhotoPickerViewController.m @@ -50,6 +50,7 @@ - (void)viewDidLoad __weak WADayPhotoPickerViewController *wSelf = self; UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithTitle:@"Create" style:UIBarButtonItemStyleBordered handler:^(id sender) { WAPhotoTimelineViewController *photoTimeline = [[WAPhotoTimelineViewController alloc] initWithAssets:wSelf.selectedAssets]; + [wSelf.navigationController pushViewController:photoTimeline animated:YES]; }]; @@ -61,6 +62,7 @@ - (void)viewDidLoad [self.collectionView registerNib:[UINib nibWithNibName:@"WADayPhotoPickerSectionHeaderView" bundle:nil] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"WADayPhotoPickerSectionHeaderView"]; } - (void) viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; __weak WADayPhotoPickerViewController *wSelf = self; diff --git a/wammer/WAFetchManager.m b/wammer/WAFetchManager.m index 4e9d291d..395a372d 100644 --- a/wammer/WAFetchManager.m +++ b/wammer/WAFetchManager.m @@ -47,7 +47,7 @@ - (id)init { [self.recurrenceMachine.queue setMaxConcurrentOperationCount:1]; self.recurrenceMachine.recurrenceInterval = 10; - [self.recurrenceMachine addRecurringOperation:[self remoteCollectionFetchOperationPrototype]]; +// [self.recurrenceMachine addRecurringOperation:[self remoteCollectionFetchOperationPrototype]]; [self.recurrenceMachine addRecurringOperation:[self remoteIndexFetchOperationPrototype]]; [self.recurrenceMachine addRecurringOperation:[self remoteChangeFetchOperationPrototype]]; [self.recurrenceMachine addRecurringOperation:[self remoteFileMetadataFetchOperationPrototype]]; diff --git a/wammer/WAFile+WARemoteInterfaceEntitySyncing.m b/wammer/WAFile+WARemoteInterfaceEntitySyncing.m index b24de3d8..e21c01ef 100644 --- a/wammer/WAFile+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WAFile+WARemoteInterfaceEntitySyncing.m @@ -432,10 +432,10 @@ - (void) synchronizeWithOptions:(NSDictionary *)options completion:(WAEntitySync NSCParameterAssert(fileURL); - if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { - callback(WAFileEntitySyncingError(WAFileSyncingErrorCodePhotoImportDisabled, @"Photo import is disabled, stop sync files", nil)); - return; - } +// if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { +// callback(WAFileEntitySyncingError(WAFileSyncingErrorCodePhotoImportDisabled, @"Photo import is disabled, stop sync files", nil)); +// return; +// } if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAUseCellularEnabled] && ![[WARemoteInterface sharedInterface] hasWiFiConnection]) { callback(WAFileEntitySyncingError(WAFileSyncingErrorCodeSyncNotAllowed, @"Syncing is not allowed, stop sync files", nil)); diff --git a/wammer/WAPartioSignupViewController.h b/wammer/WAPartioSignupViewController.h new file mode 100644 index 00000000..d1832fdb --- /dev/null +++ b/wammer/WAPartioSignupViewController.h @@ -0,0 +1,15 @@ +// +// WAPartioSignupViewController.h +// wammer +// +// Created by Shen Steven on 4/9/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import + +@interface WAPartioSignupViewController : UIViewController + +- (id) init; + +@end diff --git a/wammer/WAPartioSignupViewController.m b/wammer/WAPartioSignupViewController.m new file mode 100644 index 00000000..19633ab5 --- /dev/null +++ b/wammer/WAPartioSignupViewController.m @@ -0,0 +1,48 @@ +// +// WAPartioSignupViewController.m +// wammer +// +// Created by Shen Steven on 4/9/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAPartioSignupViewController.h" + +@interface WAPartioSignupViewController () + +@end + +@implementation WAPartioSignupViewController + +- (id) init { + + self = [super initWithNibName:nil bundle:nil]; + if (self) { + + } + return self; + +} + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +@end diff --git a/wammer/WAPartioSignupViewController.xib b/wammer/WAPartioSignupViewController.xib new file mode 100644 index 00000000..a92b959b --- /dev/null +++ b/wammer/WAPartioSignupViewController.xib @@ -0,0 +1,385 @@ + + + + 1552 + 12D78 + 3084 + 1187.37 + 626.00 + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + 2083 + + + IBNSLayoutConstraint + IBProxyObject + IBUIButton + IBUILabel + IBUIView + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + PluginDependencyRecalculationVersion + + + + + IBFilesOwner + IBCocoaTouchFramework + + + IBFirstResponder + IBCocoaTouchFramework + + + + 274 + + + + 292 + {{57, 370}, {206, 44}} + + + _NS:9 + NO + IBCocoaTouchFramework + 0 + 0 + 1 + Signup With Facebook + + 3 + MQA + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 3 + MC41AA + + + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + + + + 292 + {{57, 63}, {206, 254}} + + + _NS:9 + NO + YES + 7 + NO + IBCocoaTouchFramework + Why you need an account? + + 1 + MCAwIDAAA + darkTextColor + + + 0 + 1 + 0 + + 1 + 17 + + + Helvetica + 17 + 16 + + NO + + + {{0, 20}, {320, 548}} + + + + 3 + MQA + + 2 + + + + + IBUIScreenMetrics + + YES + + + + + + {320, 568} + {568, 320} + + + IBCocoaTouchFramework + Retina 4 Full Screen + 2 + + IBCocoaTouchFramework + + + + + + + + 0 + + + + + + 1 + + + + + 9 + 0 + + 9 + 1 + + 0.0 + + 1000 + + 5 + 22 + 2 + + + + 5 + 0 + + 5 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 4 + 0 + + 4 + 1 + + 135 + + 1000 + + 3 + 9 + 3 + + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 3 + 0 + + 3 + 1 + + 63 + + 1000 + + 3 + 9 + 3 + + + + + + + + -1 + + + File's Owner + + + -2 + + + + + 3 + + + + + + 8 + + + + + 9 + + + + + 8 + 0 + + 0 + 1 + + 254 + + 1000 + + 3 + 9 + 1 + + + + 7 + 0 + + 0 + 1 + + 206 + + 1000 + + 3 + 9 + 1 + + + + + + 11 + + + + + 13 + + + + + 16 + + + + + 18 + + + + + 20 + + + + + 22 + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + UIResponder + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + + + + + + 22 + + + + + NSLayoutConstraint + NSObject + + IBProjectSource + ./Classes/NSLayoutConstraint.h + + + + + 0 + IBCocoaTouchFramework + YES + 3 + YES + 2083 + + diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m index 12c36e17..e2852536 100644 --- a/wammer/WAPhotoTimelineViewController.m +++ b/wammer/WAPhotoTimelineViewController.m @@ -10,32 +10,44 @@ #import "WAPhotoTimelineNavigationBar.h" #import "WAPhotoTimelineCover.h" #import "WAPhotoTimelineLayout.h" +#import "WATimelineIndexView.h" + #import "WAPhotoCollageCell.h" +#import "WADefines.h" + #import "WAAssetsLibraryManager.h" -#import "WATimelineIndexView.h" #import "WAArticle.h" #import "WADataStore.h" +#import "WAFile.h" +#import "WAFile+LazyImages.h" +#import "WAFileExif.h" +#import "WAFileExif+WAAdditions.h" + #import "WAContactPickerViewController.h" -#import #import "WAGeoLocation.h" -#import "WAFile+LazyImages.h" +#import #import +#import +#import "WARemoteInterface.h" @interface WAPhotoTimelineViewController () -@property (nonatomic, strong) WAArticle *representingArticle; @property (nonatomic, strong) WAPhotoTimelineCover *headerView; @property (nonatomic, strong) WAPhotoTimelineNavigationBar *navigationBar; @property (nonatomic, weak) IBOutlet UICollectionView *collectionView; @property (nonatomic, weak) IBOutlet WATimelineIndexView *indexView; + +@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; +@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; + +@property (nonatomic, strong) WAArticle *representingArticle; @property (nonatomic, strong) NSArray *allAssets; +@property (nonatomic, strong) NSArray *importedImageIDArray; @property (nonatomic, strong) WAGeoLocation *geoLocation; @property (nonatomic, strong) NSDate *eventDate; @property (nonatomic, strong) NSDate *beginDate; @property (nonatomic, strong) NSDate *endDate; -@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext; -@property (nonatomic, strong) NSOperationQueue *imageDisplayQueue; @property (nonatomic, readonly) CLLocationCoordinate2D coordinate; @end @@ -81,11 +93,11 @@ - (void)viewDidLoad self.imageDisplayQueue = [[NSOperationQueue alloc] init]; self.imageDisplayQueue.maxConcurrentOperationCount = 1; - UIImage *backImage = [UIImage imageNamed:@"back"]; - UIButton *backButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, backImage.size}]; - [backButton addTarget:self action:@selector(backButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; - [backButton setImage:backImage forState:UIControlStateNormal]; - UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; +// UIImage *backImage = [UIImage imageNamed:@"back"]; +// UIButton *backButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, backImage.size}]; +// [backButton addTarget:self action:@selector(backButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; +// [backButton setImage:backImage forState:UIControlStateNormal]; +// UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backButton]; UIImage *actionImage = [UIImage imageNamed:@"action"]; UIButton *actionButton = [[UIButton alloc] initWithFrame:(CGRect){CGPointZero, actionImage.size}]; @@ -93,7 +105,7 @@ - (void)viewDidLoad [actionButton setImage:actionImage forState:UIControlStateNormal]; UIBarButtonItem *actionItem = [[UIBarButtonItem alloc] initWithCustomView:actionButton]; - self.navigationItem.leftBarButtonItem = backItem; +// self.navigationItem.leftBarButtonItem = backItem; self.navigationItem.rightBarButtonItem = actionItem; self.navigationBar = [[WAPhotoTimelineNavigationBar alloc] initWithFrame:(CGRect)CGRectMake(0, 0, self.view.frame.size.width, 44)]; @@ -131,6 +143,11 @@ - (void)viewDidLoad [self.indexView addIndex:0.01 label:[formatter stringFromDate:self.beginDate]]; [self.indexView addIndex:0.99 label:[formatter stringFromDate:self.endDate]]; + + + if ([WARemoteInterface sharedInterface].userToken) { + [self startImportSelectedPhotos]; + } } - (BOOL) shouldAutorotate { @@ -139,6 +156,104 @@ - (BOOL) shouldAutorotate { } ++ (NSOperationQueue *)sharedImportPhotoOperationQueue { + + static NSOperationQueue *opq = nil; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + opq = [[NSOperationQueue alloc] init]; + opq.maxConcurrentOperationCount = 1; + }); + + return opq; +} + +- (void) startImportSelectedPhotos { + + __weak WAPhotoTimelineViewController *wSelf = self; + NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ + NSDate *importTime = [NSDate date]; + + NSManagedObjectContext *moc = [[WADataStore defaultStore] disposableMOC]; + WAArticle *article = [WAArticle objectInsertingIntoContext:moc withRemoteDictionary:@{}]; + NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:wSelf.allAssets.count]; + + for (ALAsset *asset in self.allAssets) { + @autoreleasepool { + + NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:@"WAFile"]; + fr.predicate = [NSPredicate predicateWithFormat:@"assetURL = %@", [[[asset defaultRepresentation] url] absoluteString]]; + NSError *error = nil; + NSArray *result = [moc executeFetchRequest:fr error:&error]; + if (result.count) { + [imageArray addObject:result[0]]; + continue; + } + + WAFile *file = (WAFile *)[WAFile objectInsertingIntoContext:moc withRemoteDictionary:@{}]; + CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); + if (theUUID) + file.identifier = [((__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID)) lowercaseString]; + CFRelease(theUUID); + file.dirty = (id)kCFBooleanTrue; + + [[article mutableOrderedSetValueForKey:@"files"] addObject:file]; + + UIImage *extraSmallThumbnailImage = [UIImage imageWithCGImage:[asset thumbnail]]; + file.extraSmallThumbnailFilePath = [[[WADataStore defaultStore] persistentFileURLForData:UIImageJPEGRepresentation(extraSmallThumbnailImage, 0.85f) extension:@"jpeg"] path]; + + file.assetURL = [[[asset defaultRepresentation] url] absoluteString]; + file.resourceType = (NSString *)kUTTypeImage; + file.timestamp = [asset valueForProperty:ALAssetPropertyDate]; + file.created = file.timestamp; + file.importTime = importTime; + + WAFileExif *exif = (WAFileExif *)[WAFileExif objectInsertingIntoContext:moc withRemoteDictionary:@{}]; + NSDictionary *metadata = [[asset defaultRepresentation] metadata]; + [exif initWithExif:metadata[@"{Exif}"] tiff:metadata[@"{TIFF}"] gps:metadata[@"{GPS}"]]; + + file.exif = exif; + + [imageArray addObject:file]; + + if (!article.creationDate) { + article.creationDate = file.timestamp; + } else { + if ([file.timestamp compare:article.creationDate] == NSOrderedDescending) { + article.creationDate = file.timestamp; + } + } + + } + } + + article.event = @NO; + article.draft = (id)kCFBooleanFalse; + CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); + if (theUUID) + article.identifier = [((__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID)) lowercaseString]; + CFRelease(theUUID); + article.dirty = (id)kCFBooleanTrue; + article.creationDeviceName = [UIDevice currentDevice].name; + + NSError *savingError = nil; + if ([moc save:&savingError]) { + NSMutableArray *idList = [NSMutableArray array]; + for (WAFile *file in imageArray) { + [idList addObject:file.objectID]; + } + wSelf.importedImageIDArray = [NSArray arrayWithArray:idList]; + } else { + NSLog(@"error on creating a new import post for error: %@", savingError); + } + + }]; + + [[[self class] sharedImportPhotoOperationQueue] addOperation:op]; + +} + - (NSManagedObjectContext*)managedObjectContext { if (_managedObjectContext) return _managedObjectContext; @@ -160,11 +275,41 @@ - (void) backButtonClicked:(id)sender { - (void)actionButtonClicked:(id)sender { - __weak WAPhotoTimelineViewController *wSelf = self; - WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; - UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:cpVC]; - [wSelf presentViewController:nav animated:YES completion:nil]; + if (!self.importedImageIDArray || !self.importedImageIDArray.count) { + // importing + } else { + WAArticle *article = [WAArticle objectInsertingIntoContext:self.managedObjectContext withRemoteDictionary:@{}]; + article.event = (id)kCFBooleanTrue; + article.eventType = [NSNumber numberWithInt:WAEventArticleSharedType]; + article.draft = (id)kCFBooleanFalse; + CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); + if (theUUID) + article.identifier = [((__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID)) lowercaseString]; + CFRelease(theUUID); + article.dirty = (id)kCFBooleanTrue; + article.creationDeviceName = [UIDevice currentDevice].name; + article.creationDate = [NSDate date]; + + for(NSManagedObjectID *objectID in self.importedImageIDArray) { + WAFile *file = (WAFile*)[self.managedObjectContext objectWithID:objectID]; + if (file) { + [[article mutableOrderedSetValueForKey:@"files"] addObject:file]; + } else { + NSLog(@"nil file: %@", objectID); + } + } + + NSError *error = nil; + [self.managedObjectContext save:&error]; + if (error) { + NSLog(@"failed to create a sharing event for error: %@", error); + } + [self.navigationController popToRootViewControllerAnimated:NO]; + } +// WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; +// [self.navigationController pushViewController:cpVC animated:YES]; + } - (void)didReceiveMemoryWarning diff --git a/wammer/WARemoteInterface+Attachments.m b/wammer/WARemoteInterface+Attachments.m index 321334f4..6d380b05 100644 --- a/wammer/WARemoteInterface+Attachments.m +++ b/wammer/WARemoteInterface+Attachments.m @@ -144,7 +144,7 @@ - (void) createAttachmentWithFileData:(NSData *)fileData name:(NSString *)aFileN stitch(fileImportTime, @"import_time"); stitch(timezone, @"timezone"); - [self.engine fireAPIRequestNamed:@"attachments/upload" withArguments:nil options:[NSDictionary dictionaryWithObjectsAndKeys: + [self.engine fireAPIRequestNamed:@"pio_attachments/upload" withArguments:nil options:[NSDictionary dictionaryWithObjectsAndKeys: sentRemoteOptions, kIRWebAPIEngineRequestContextFormMultipartFieldsKey, @"POST", kIRWebAPIEngineRequestHTTPMethod, @@ -165,7 +165,7 @@ - (void) createAttachmentWithFileData:(NSData *)fileData name:(NSString *)aFileN - (void) retrieveAttachment:(NSString *)anIdentifier onSuccess:(void(^)(NSDictionary *attachmentRep))successBlock onFailure:(void(^)(NSError *error))failureBlock { - [self.engine fireAPIRequestNamed:@"attachments/get" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: + [self.engine fireAPIRequestNamed:@"pio_attachments/get" withArguments:[NSDictionary dictionaryWithObjectsAndKeys: anIdentifier, @"object_id", @@ -185,7 +185,7 @@ - (void) deleteAttachments:(NSArray *)identifiers onSuccess:(void(^)(NSArray *su NSError *error = nil; NSData *sentIdentifiers = [NSJSONSerialization dataWithJSONObject:identifiers options:0 error:&error]; NSString *sentIdentifiersString = [[NSString alloc] initWithData:sentIdentifiers encoding:NSUTF8StringEncoding]; - [self.engine fireAPIRequestNamed:@"attachments/delete" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary([NSDictionary dictionaryWithObjectsAndKeys: + [self.engine fireAPIRequestNamed:@"pio_attachments/delete" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary([NSDictionary dictionaryWithObjectsAndKeys: sentIdentifiersString, @"object_ids", @@ -201,7 +201,7 @@ - (void) deleteAttachments:(NSArray *)identifiers onSuccess:(void(^)(NSArray *su - (void) retrieveThumbnailForAttachment:(NSString *)anIdentifier ofType:(WARemoteAttachmentType)aType onSuccess:(void(^)(NSURL *aThumbnailURL))successBlock onFailure:(void(^)(NSError *error))failureBlock { NSDictionary *arguments = @{@"object_id": anIdentifier, @"image_meta":@"large"}; - [self.engine fireAPIRequestNamed:@"attachments/view" + [self.engine fireAPIRequestNamed:@"pio_attachments/view" withArguments:nil options:@{kIRWebAPIEngineRequestContextFormURLEncodingFieldsKey:arguments ,kIRWebAPIEngineRequestHTTPMethod: @"POST"} validator:WARemoteInterfaceGenericNoErrorValidator() @@ -295,7 +295,7 @@ - (void)retrieveMetaForAttachments:(NSArray *)identifiers onSuccess:(void(^)(NSA kIRWebAPIEngineRequestHTTPMethod:@"POST" }; - [self.engine fireAPIRequestNamed:@"attachments/multiple_get" + [self.engine fireAPIRequestNamed:@"pio_attachments/multiple_get" withArguments:nil options:apiOptions validator:WARemoteInterfaceGenericNoErrorValidator() @@ -324,7 +324,7 @@ - (void)hideAttachments:(NSArray *)identifiers onSuccess:(void (^)(NSArray *succ kIRWebAPIEngineRequestHTTPMethod:@"POST" }; - [self.engine fireAPIRequestNamed:@"attachments/hide" + [self.engine fireAPIRequestNamed:@"pio_attachments/hide" withArguments:nil options:apiOptions validator:WARemoteInterfaceGenericNoErrorValidator() diff --git a/wammer/WARemoteInterface+Posts.m b/wammer/WARemoteInterface+Posts.m index f5c621f0..c32d6864 100644 --- a/wammer/WARemoteInterface+Posts.m +++ b/wammer/WARemoteInterface+Posts.m @@ -38,6 +38,8 @@ + (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *) sentData[@"type"] = @"event"; else if (postType == WAArticleTypeImport) sentData[@"type"] = @"import"; + else if (postType == WAArticleTypeSharedEvent) + sentData[@"type"] = @"partio"; // This is fubar, we should NOT use 1 to 5 for fave and string literals for hidden status @@ -146,7 +148,7 @@ - (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSStrin NSDictionary *postEntity = [[self class] postEntityWithGroupID:aGroupIdentifier postID:postID text:contentTextOrNil attachments:attachmentIdentifiersOrNil mainAttachment:nil type:postType isFavorite:isFavorite isHidden:NO createTime:createTime updateTime:updateTime]; - [self.engine fireAPIRequestNamed:@"posts/new" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary(postEntity, nil) validator:WARemoteInterfaceGenericNoErrorValidator() successHandler:^(NSDictionary *inResponseOrNil, IRWebAPIRequestContext *inResponseContext) { + [self.engine fireAPIRequestNamed:@"pio_posts/new" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary(postEntity, nil) validator:WARemoteInterfaceGenericNoErrorValidator() successHandler:^(NSDictionary *inResponseOrNil, IRWebAPIRequestContext *inResponseContext) { if (!successBlock) return; @@ -222,7 +224,7 @@ - (void) createCommentForPost:(NSString *)aPostIdentifier inGroup:(NSString *)aG - (void)retrievePostsInGroup:(NSString *)aGroupIdentifier usingSequenceNumber:(NSNumber *)aSequenceNumber withLimit:(NSNumber *)aLimit onSuccess:(void (^)(NSArray *, NSNumber *, NSNumber *))successBlock onFailure:(void (^)(NSError *))failureBlock { - [self.engine fireAPIRequestNamed:@"posts/fetchBySeq" withArguments:@{@"group_id":aGroupIdentifier, @"datum":aSequenceNumber, @"limit":aLimit, @"component_options": [@[@"content"] JSONString]} options:nil validator:WARemoteInterfaceGenericNoErrorValidator() successHandler:^(NSDictionary *response, IRWebAPIRequestContext *context) { + [self.engine fireAPIRequestNamed:@"pio_posts/fetchBySeq" withArguments:@{@"group_id":aGroupIdentifier, @"datum":aSequenceNumber, @"limit":aLimit, @"component_options": [@[@"content"] JSONString]} options:nil validator:WARemoteInterfaceGenericNoErrorValidator() successHandler:^(NSDictionary *response, IRWebAPIRequestContext *context) { if (!successBlock) return; @@ -254,7 +256,7 @@ - (void) retrievePostsInGroup:(NSString *)aGroupIdentifier arguments[@"component_options"] = [@[@"content"] JSONString]; [self.engine - fireAPIRequestNamed:@"posts/fetchByFilter" + fireAPIRequestNamed:@"pio_posts/fetchByFilter" withArguments:arguments options:nil validator:WARemoteInterfaceGenericNoErrorValidator() @@ -286,7 +288,7 @@ - (void) retrievePostsInGroup:(NSString *)groupID nil]; [self.engine - fireAPIRequestNamed:@"posts/fetchByFilter" + fireAPIRequestNamed:@"pio_posts/fetchByFilter" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary(postListEntity, nil) validator:WARemoteInterfaceGenericNoErrorValidator() diff --git a/wammer/WASyncManager+DirtyArticleSync.m b/wammer/WASyncManager+DirtyArticleSync.m index 93b5c30e..0cc83fc7 100644 --- a/wammer/WASyncManager+DirtyArticleSync.m +++ b/wammer/WASyncManager+DirtyArticleSync.m @@ -118,9 +118,9 @@ - (IRAsyncOperation *) dirtyArticleSyncOperationPrototype { - (BOOL)canPerformArticleSync { - if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { - return NO; - } +// if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { +// return NO; +// } WARemoteInterface * const ri = [WARemoteInterface sharedInterface]; if (!ri.userToken) { diff --git a/wammer/WASyncManager+FileMetadataSync.m b/wammer/WASyncManager+FileMetadataSync.m index 05c4342d..40b2e5cc 100644 --- a/wammer/WASyncManager+FileMetadataSync.m +++ b/wammer/WASyncManager+FileMetadataSync.m @@ -257,9 +257,9 @@ - (IRAsyncOperation *)fileMetadataSyncOperationPrototype { - (BOOL)canPerformMetaSync { - if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { - return NO; - } +// if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { +// return NO; +// } WARemoteInterface * const ri = [WARemoteInterface sharedInterface]; if (!ri.userToken) { diff --git a/wammer/WASyncManager+FullQualityFileSync.m b/wammer/WASyncManager+FullQualityFileSync.m index d76c288b..4a9eb1c3 100644 --- a/wammer/WASyncManager+FullQualityFileSync.m +++ b/wammer/WASyncManager+FullQualityFileSync.m @@ -121,9 +121,9 @@ - (IRAsyncOperation *) fullQualityFileSyncOperationPrototype { - (BOOL) canPerformBlobSync { - if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { - return NO; - } +// if (![[NSUserDefaults standardUserDefaults] boolForKey:kWAPhotoImportEnabled]) { +// return NO; +// } WARemoteInterface * const ri = [WARemoteInterface sharedInterface]; if (!ri.userToken) { diff --git a/wammer/WASyncManager.m b/wammer/WASyncManager.m index 91f00f18..f86d10f3 100644 --- a/wammer/WASyncManager.m +++ b/wammer/WASyncManager.m @@ -63,10 +63,10 @@ - (id) init { wSelf.needingSyncFilesCount = 0; wSelf.syncedFilesCount = 0; }]]; - [self.recurrenceMachine addRecurringOperation:[self photoImportOperationPrototype]]; +// [self.recurrenceMachine addRecurringOperation:[self photoImportOperationPrototype]]; [self.recurrenceMachine addRecurringOperation:[self fileMetadataSyncOperationPrototype]]; [self.recurrenceMachine addRecurringOperation:[self dirtyArticleSyncOperationPrototype]]; - [self.recurrenceMachine addRecurringOperation:[self fullQualityFileSyncOperationPrototype]]; +// [self.recurrenceMachine addRecurringOperation:[self fullQualityFileSyncOperationPrototype]]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUserDefaultsChanged:) name:NSUserDefaultsDidChangeNotification object:nil]; From 61d34b79ab78c6e36bddeeb503cf1fb572b0ca86 Mon Sep 17 00:00:00 2001 From: syshen Date: Wed, 10 Apr 2013 16:46:58 +0800 Subject: [PATCH 016/278] create sharing post to cloud --- ...WAArticle+WARemoteInterfaceEntitySyncing.m | 21 ++-- wammer/WAPartioWelcomeViewController.m | 12 +- wammer/WAPhotoTimelineViewController.m | 104 +++++------------- 3 files changed, 50 insertions(+), 87 deletions(-) diff --git a/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m b/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m index 507dd5e4..a1d3e66e 100644 --- a/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WAArticle+WARemoteInterfaceEntitySyncing.m @@ -145,6 +145,11 @@ + (NSDictionary *) transformedRepresentationForRemoteRepresentation:(NSDictionar [returnedDictionary setValue:@NO forKey:@"event"]; } + if ([type isEqualToString:@"partio"]) { + [returnedDictionary setValue:@YES forKey:@"event"]; + [returnedDictionary setValue:@(WAEventArticleSharedType) forKey:@"eventType"]; + } + if ([incomingRepresentation[@"event_type"] isEqualToString:@"photo"]) { [returnedDictionary setValue:@(WAEventArticlePhotoType) forKey:@"eventType"]; } @@ -206,14 +211,14 @@ + (NSDictionary *) transformedRepresentationForRemoteRepresentation:(NSDictionar returnedDictionary[@"tags"] = transformedTags; } - - NSString *event_start_time = incomingRepresentation[@"event_start_time"]; - if (event_start_time && [returnedDictionary[@"event"] isEqual:@YES]) { // It is an event, we record its event day - - [returnedDictionary setValue:@{@"day" : [[NSDate dateFromISO8601String:event_start_time] dayBegin]} - forKey:@"eventDay"]; - - } + +// NSString *event_start_time = incomingRepresentation[@"event_start_time"]; +// if (event_start_time && ![event_start_time isKindOfClass:[NSNull class]] &&[returnedDictionary[@"event"] isEqual:@YES]) { // It is an event, we record its event day +// +// [returnedDictionary setValue:@{@"day" : [[NSDate dateFromISO8601String:event_start_time] dayBegin]} +// forKey:@"eventDay"]; +// +// } return returnedDictionary; diff --git a/wammer/WAPartioWelcomeViewController.m b/wammer/WAPartioWelcomeViewController.m index fdcac262..d0db26e3 100644 --- a/wammer/WAPartioWelcomeViewController.m +++ b/wammer/WAPartioWelcomeViewController.m @@ -10,6 +10,7 @@ #import "WAPartioFirstUseViewController.h" #import "WAOverlayBezel.h" #import "WARemoteInterface.h" +#import "UIKit+IRAdditions.h" #import #import @@ -48,8 +49,15 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath WAPartioFirstUseViewController *firstUse = (WAPartioFirstUseViewController*)self.navigationController; if (indexPath.row == 0) { - if (firstUse.completionBlock) - firstUse.completionBlock(); + IRAction *cancelAction = [IRAction actionWithTitle:@"OK" block:nil]; + + [[IRAlertView alertViewWithTitle:@"Not support yet" + message:@"Current version requires you to login with Facebook account first. 'Try' scenario will be implemented in the near future." + cancelAction:cancelAction + otherActions:nil] show]; + +// if (firstUse.completionBlock) +// firstUse.completionBlock(); } else if (indexPath.row == 1) { WAOverlayBezel *busyBezel = [WAOverlayBezel bezelWithStyle:WAActivityIndicatorBezelStyle]; diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m index e2852536..906fc8c2 100644 --- a/wammer/WAPhotoTimelineViewController.m +++ b/wammer/WAPhotoTimelineViewController.m @@ -43,7 +43,6 @@ @interface WAPhotoTimelineViewController () Date: Wed, 10 Apr 2013 16:54:21 +0800 Subject: [PATCH 017/278] go into shared event view when signup from first use case --- wammer/WAAppDelegate_iOS.m | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/wammer/WAAppDelegate_iOS.m b/wammer/WAAppDelegate_iOS.m index 59ecd9fc..6ff471ef 100644 --- a/wammer/WAAppDelegate_iOS.m +++ b/wammer/WAAppDelegate_iOS.m @@ -814,9 +814,14 @@ - (void) handlePartioAuthRequest { [wSelf recreateViewHierarchy]; }]; - WAPhotoHighlightsViewController *photoGroupsVC = [[WAPhotoHighlightsViewController alloc] init]; - wSelf.window.rootViewController = photoGroupsVC; - + WASharedEventViewController *sharedEventsVC = [[WASharedEventViewController alloc] initWithStyle:UITableViewStylePlain]; + UINavigationController *navVC = [[UINavigationController alloc] initWithRootViewController:sharedEventsVC]; + wSelf.window.rootViewController = navVC; + + if (ri.userToken) { + wSelf.fetchManager = [[WAFetchManager alloc] init]; + wSelf.syncManager = [[WASyncManager alloc] init]; + } } failure:^(NSError *error) { NSLog(@"fail to sign up for error: %@", error); IRAction *okAction = [IRAction actionWithTitle:NSLocalizedString(@"ACTION_OKAY", @"Alert Dismissal Action") block:nil]; From 362b21774062788a0cae96bc7fff694762b032d9 Mon Sep 17 00:00:00 2001 From: syshen Date: Wed, 10 Apr 2013 16:57:34 +0800 Subject: [PATCH 018/278] allow highlight view to be able to cancel --- wammer/WAPhotoHighlightsViewController.m | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/wammer/WAPhotoHighlightsViewController.m b/wammer/WAPhotoHighlightsViewController.m index 418f2723..f309cb97 100644 --- a/wammer/WAPhotoHighlightsViewController.m +++ b/wammer/WAPhotoHighlightsViewController.m @@ -56,6 +56,11 @@ - (void)viewDidLoad WADayPhotoPickerViewController *picker = [[WADayPhotoPickerViewController alloc] initWithSelectedAssets:nil]; [wSelf.navigationController pushViewController:picker animated:YES]; }]; + + UIBarButtonItem *cancelItem = [[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleBordered handler:^(id sender) { + [wSelf dismissViewControllerAnimated:YES completion:nil]; + }]; + self.navigationItem.leftBarButtonItem = cancelItem; self.navigationItem.rightBarButtonItem = buttonItem; } From 2b7203fea812a59f66f0ef213b1cffa8d76551c5 Mon Sep 17 00:00:00 2001 From: syshen Date: Wed, 10 Apr 2013 17:01:53 +0800 Subject: [PATCH 019/278] typo --- wammer/zh-Hant.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wammer/zh-Hant.lproj/Localizable.strings b/wammer/zh-Hant.lproj/Localizable.strings index 2cc59362..b91352a9 100644 --- a/wammer/zh-Hant.lproj/Localizable.strings +++ b/wammer/zh-Hant.lproj/Localizable.strings @@ -570,7 +570,7 @@ "TITLE_OF_DAY_PHOTO_PICKER" = "挑選照片"; /* The title of highlight view */ -"TITLE_OF_HIGHLIGHTS" = "小確性"; +"TITLE_OF_HIGHLIGHTS" = "小確幸"; /* Alert on no location service enabled when open photo library */ "TURN_ON_LOCATION_SERVICE" = "aostream 須開啟定位服務才能存取相簿的內容"; From f34410ae966a779defe84992dda1e3b7da935aed Mon Sep 17 00:00:00 2001 From: Greener Date: Wed, 10 Apr 2013 19:10:28 +0800 Subject: [PATCH 020/278] Update shared event query predicate on eventType --- wammer/WASharedEventViewController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 3bc71d09..38e2b9bd 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -37,12 +37,13 @@ - (id)initWithStyle:(UITableViewStyle)style - (NSArray *)loadEventsFrom:(NSDate *)aDate toPreviousDays:(NSInteger)days { + //TODO: when to load more events NSManagedObjectContext *moc = [[WADataStore defaultStore] autoUpdatingMOC]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WAArticle"]; NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"eventStartDate" ascending:NO]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.eventFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND hidden = FALSE AND files.@count > 0", [aDate dateOfPreviousNumOfDays:days], aDate]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND eventType = %d AND files.@count > 0", [aDate dateOfPreviousNumOfDays:days], aDate, WAEventArticleSharedType]; [self.eventFetchedResultsController.fetchRequest setPredicate:predicate]; NSError *Err; From 7e5a5b672a6a7a298ea50a4a0cc7db3f64be74f3 Mon Sep 17 00:00:00 2001 From: Greener Date: Wed, 10 Apr 2013 19:27:59 +0800 Subject: [PATCH 021/278] Polish contact picker UI --- wammer/WAContactPickerViewController.m | 19 +++++++++++- wammer/WAContactPickerViewController.xib | 37 +++++++++--------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index 6782fde0..bdb68c53 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -82,6 +82,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier]; } + [cell.textLabel setTextColor:[UIColor whiteColor]]; + // Configure the cell... if (indexPath.section == 0) { if (indexPath.row == 0) { @@ -92,18 +94,33 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; cell.textLabel.text = @"Contacts"; cell.detailTextLabel.text = @"Find friends from your contacts."; + [cell.detailTextLabel setTextColor:[UIColor lightGrayColor]]; } else if (indexPath.row == 2) { cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; cell.textLabel.text = @"Facebook"; + [cell.textLabel setTextColor:[UIColor whiteColor]]; cell.detailTextLabel.text = @"Find friends from Facebook."; + [cell.detailTextLabel setTextColor:[UIColor lightGrayColor]]; } } else { cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; //TODO: first name then last name, or last name then first name by system settings - cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", _members[indexPath.row][@"firstName"], _members[indexPath.row][@"lastName"]]; + + if (_members[indexPath.row][@"firstName"] && _members[indexPath.row][@"lastName"]) { + cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", + _members[indexPath.row][@"firstName"], + _members[indexPath.row][@"lastName"]]; + } else if (_members[indexPath.row][@"firstName"]) { + cell.textLabel.text = _members[indexPath.row][@"firstName"]; + + } else if (_members[indexPath.row][@"lastName"]) { + cell.textLabel.text = _members[indexPath.row][@"lastName"]; + + } + cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@", _members[indexPath.row][@"phone"], ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; diff --git a/wammer/WAContactPickerViewController.xib b/wammer/WAContactPickerViewController.xib index b2a5b64a..b39fb7e2 100644 --- a/wammer/WAContactPickerViewController.xib +++ b/wammer/WAContactPickerViewController.xib @@ -1,14 +1,14 @@ - 1536 - 12A269 - 2835 - 1187 - 624.00 + 1552 + 12D78 + 3084 + 1187.37 + 626.00 com.apple.InterfaceBuilder.IBCocoaTouchPlugin - 1919 + 2083 IBProxyObject @@ -35,11 +35,9 @@ 274 {{0, 20}, {320, 548}} - - - 3 - MQA + 2 + MC4xNjg2Mjc0NTU4IDAuMTY4NjI3NDU1OCAwLjE2ODYyNzQ1NTgAA NO YES @@ -65,6 +63,10 @@ IBCocoaTouchFramework NO 1 + + 2 + MC4yNDcwNTg4Mzg2IDAuMjQ3MDU4ODM4NiAwLjI0NzA1ODgzODYAA + 0 YES 44 @@ -138,23 +140,12 @@ 7 - - - - WAContactPickerViewController - UITableViewController - - IBProjectSource - ./Classes/WAContactPickerViewController.h - - - - + 0 IBCocoaTouchFramework YES 3 YES - 1919 + 2083 From e1dd4f3e71702ee065fab5a636f42ef3ffc591b8 Mon Sep 17 00:00:00 2001 From: Greener Date: Wed, 10 Apr 2013 19:31:25 +0800 Subject: [PATCH 022/278] Select a shared event then show new event view --- wammer/WASharedEventViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 38e2b9bd..8c75e6df 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -130,10 +130,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; -// __weak WASharedEventViewController *wSelf = self; -// WAPhotoTimelineViewController *ptVC = [[WAPhotoTimelineViewController alloc] initWithArticle:[self.events[indexPath.row] objectID]]; -// WANavigationController *nav = [[WANavigationController alloc] initWithRootViewController:ptVC]; -// [wSelf presentViewController:nav animated:YES completion:nil]; + __weak WASharedEventViewController *wSelf = self; + WAPhotoTimelineViewController *ptVC = [[WAPhotoTimelineViewController alloc] initWithArticleID:[self.events[indexPath.row] objectID]]; + UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:ptVC]; + [wSelf presentViewController:nav animated:YES completion:nil]; } #pragma - toolbar From 183df305dd119db539165ee95fdadcc18efbb561 Mon Sep 17 00:00:00 2001 From: Greener Date: Thu, 11 Apr 2013 14:46:52 +0800 Subject: [PATCH 023/278] Fix possible empty firstname/lastname --- wammer/WAContactPickerViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index bdb68c53..3d0032b7 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -108,7 +108,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else { cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; //TODO: first name then last name, or last name then first name by system settings - + //FIXME: use fullname if (_members[indexPath.row][@"firstName"] && _members[indexPath.row][@"lastName"]) { cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", _members[indexPath.row][@"firstName"], From 6ce024f4b1599eddd00b10a476740fa5b12f163b Mon Sep 17 00:00:00 2001 From: Greener Date: Thu, 11 Apr 2013 14:49:06 +0800 Subject: [PATCH 024/278] Change to use NSFetchedResultsController to manage according tableview cell change --- wammer/WASharedEventViewController.m | 104 ++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 19 deletions(-) diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 8c75e6df..de281818 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -9,7 +9,7 @@ #import "WASharedEventViewController.h" #import "WAPhotoHighlightsViewController.h" #import "WAPhotoTimelineViewController.h" -#import "WALocation.h" +#import "WAGeoLocation.h" #import #import "WADataStore.h" #import "NSDate+WAAdditions.h" @@ -17,7 +17,6 @@ @interface WASharedEventViewController () @property (nonatomic, strong) NSFetchedResultsController *eventFetchedResultsController; -@property (nonatomic, strong) NSMutableArray *events; @end @@ -28,22 +27,20 @@ - (id)initWithStyle:(UITableViewStyle)style self = [super initWithStyle:style]; if (self) { // Custom initialization - self.events = [[NSMutableArray alloc] init]; + [self loadEvents]; } - self.events = [[self loadEventsFrom:[NSDate date] toPreviousDays:100] copy]; return self; } -- (NSArray *)loadEventsFrom:(NSDate *)aDate toPreviousDays:(NSInteger)days +- (NSArray *)loadEvents { - //TODO: when to load more events NSManagedObjectContext *moc = [[WADataStore defaultStore] autoUpdatingMOC]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"WAArticle"]; - NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"eventStartDate" ascending:NO]; + NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"creationDate" ascending:NO]; [fetchRequest setSortDescriptors:@[sortDescriptor]]; self.eventFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]; - NSPredicate *predicate = [NSPredicate predicateWithFormat:@"eventStartDate >= %@ AND eventStartDate <= %@ AND event = TRUE AND eventType = %d AND files.@count > 0", [aDate dateOfPreviousNumOfDays:days], aDate, WAEventArticleSharedType]; + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"event = TRUE AND eventType = %d AND hidden = FALSE", WAEventArticleSharedType]; [self.eventFetchedResultsController.fetchRequest setPredicate:predicate]; NSError *Err; @@ -68,7 +65,7 @@ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - if (![self.events count]) { + if (![self.eventFetchedResultsController.fetchedObjects count]) { [self shareNewEventFromHighlight]; } @@ -80,6 +77,66 @@ - (void)didReceiveMemoryWarning // Dispose of any resources that can be recreated. } +#pragma mark - NSFetchedResultsControllerDelegate + +- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller +{ + [self.tableView beginUpdates]; +} + +- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo + atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type { + + switch(type) { + case NSFetchedResultsChangeInsert: + [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] + withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeDelete: + [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] + withRowAnimation:UITableViewRowAnimationFade]; + break; + } +} + + +- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject + atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type + newIndexPath:(NSIndexPath *)newIndexPath { + + UITableView *tableView = self.tableView; + + switch(type) { + + case NSFetchedResultsChangeInsert: + [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] + withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeDelete: + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] + withRowAnimation:UITableViewRowAnimationFade]; + break; + + case NSFetchedResultsChangeUpdate: + //TODO: update info: photo number, checkin number, date, location + break; + + case NSFetchedResultsChangeMove: + [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] + withRowAnimation:UITableViewRowAnimationFade]; + [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] + withRowAnimation:UITableViewRowAnimationFade]; + break; + } +} + + +- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller { + [self.tableView endUpdates]; +} + #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView @@ -91,7 +148,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. - return [self.events count]; + return [self.eventFetchedResultsController.fetchedObjects count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath @@ -103,18 +160,29 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } // Configure the cell... - cell.backgroundView = [[UIImageView alloc] initWithImage:[[self.events[indexPath.row] representingFile] thumbnailImage]]; cell.backgroundView.contentMode = UIViewContentModeScaleAspectFill; cell.backgroundView.clipsToBounds = YES; - NSString *photoNumbers = [NSString stringWithFormat:([[self.events[indexPath.row] files] count] == 1)? + + UIImage *backgroundImage = [[[self.eventFetchedResultsController objectAtIndexPath:indexPath] valueForKeyPath:@"representingFile"] thumbnailImage]; + cell.backgroundView = [[UIImageView alloc] initWithImage:backgroundImage]; + + NSInteger fileNumbers = [[[self.eventFetchedResultsController objectAtIndexPath:indexPath] valueForKey:@"files"] count]; + NSString *photoNumbers = [NSString stringWithFormat:(fileNumbers == 1)? NSLocalizedString(@"EVENT_ONE_PHOTO_NUMBER_LABEL", @"EVENT_ONE_PHOTO_NUMBER_LABEL"): NSLocalizedString(@"EVENT_PHOTO_NUMBER_LABEL", @"EVENT_PHOTO_NUMBER_LABEL"), - [[self.events[indexPath.row] files] count]]; + fileNumbers]; static NSDateFormatter *sharedDateFormatter; sharedDateFormatter = [[NSDateFormatter alloc] init]; [sharedDateFormatter setDateFormat:@"yyyy MM dd"]; - NSString *eventDate = [sharedDateFormatter stringFromDate:[self.events[indexPath.row] eventStartDate]]; - NSString *location = [self.events[indexPath.row] description]; + NSString *eventDate = [sharedDateFormatter stringFromDate:[[self.eventFetchedResultsController objectAtIndexPath:indexPath] valueForKey:@"eventStartDate"]]; + + NSString *location = @""; + NSArray *checkins = [[self.eventFetchedResultsController objectAtIndexPath:indexPath] valueForKeyPath:@"checkins"]; + if ([checkins count]) { + location = [[checkins valueForKeyPath:@"name"] componentsJoinedByString:@", "]; + + } + cell.textLabel.text = [NSString stringWithFormat:@"%@\n%@\n%@", photoNumbers, eventDate, location]; [cell.textLabel setNumberOfLines:0]; [cell.textLabel setBackgroundColor:[UIColor clearColor]]; @@ -130,10 +198,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [tableView deselectRowAtIndexPath:indexPath animated:NO]; - __weak WASharedEventViewController *wSelf = self; - WAPhotoTimelineViewController *ptVC = [[WAPhotoTimelineViewController alloc] initWithArticleID:[self.events[indexPath.row] objectID]]; - UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:ptVC]; - [wSelf presentViewController:nav animated:YES completion:nil]; + WAPhotoTimelineViewController *ptVC = [[WAPhotoTimelineViewController alloc] initWithArticleID:[[self.eventFetchedResultsController objectAtIndexPath:indexPath] objectID]]; + [self.navigationController pushViewController:ptVC animated:YES]; } #pragma - toolbar From db3a73cedcd702cf489aa48b6c08d5fd400abe5a Mon Sep 17 00:00:00 2001 From: syshen Date: Thu, 11 Apr 2013 14:51:04 +0800 Subject: [PATCH 025/278] create sharing event to cloud, including the emails to be invited --- wammer.xcodeproj/project.pbxproj | 32 +- wammer/Resources/HighlightAddEventBtn.png | Bin 0 -> 2307 bytes wammer/Resources/HighlightAddEventBtn@2x.png | Bin 0 -> 3200 bytes wammer/WAAppDelegate_iOS.m | 6 + wammer/WAArticle+WAAdditions.m | 7 +- ...WAArticle+WARemoteInterfaceEntitySyncing.m | 24 + wammer/WADayPhotoPickerViewController.m | 37 +- wammer/WAFacebookSignupViewController.h | 13 + wammer/WAFacebookSignupViewController.m | 134 +++++ .../WAModel 44.xcdatamodel/contents | 5 +- wammer/WAPartioFirstUse.storyboard | 55 +- wammer/WAPartioWelcomeViewController.m | 91 +--- wammer/WAPeople.h | 6 +- wammer/WAPeople.m | 5 +- wammer/WAPhotoHighlightViewCell.h | 1 + wammer/WAPhotoHighlightViewCell.m | 16 +- wammer/WAPhotoHighlightViewCell.xib | 468 +++++++++++++----- wammer/WAPhotoHighlightsViewController.m | 18 +- wammer/WAPhotoHighlightsViewController.xib | 19 +- wammer/WAPhotoTimelineViewController.m | 83 +++- wammer/WARemoteInterface+Posts.h | 5 +- wammer/WARemoteInterface+Posts.m | 30 +- wammer/WASharedEventViewController.m | 8 + wammer/en.lproj/Localizable.strings | 2 +- wammer/zh-Hant.lproj/Localizable.strings | 2 +- 25 files changed, 786 insertions(+), 281 deletions(-) create mode 100644 wammer/Resources/HighlightAddEventBtn.png create mode 100644 wammer/Resources/HighlightAddEventBtn@2x.png create mode 100644 wammer/WAFacebookSignupViewController.h create mode 100644 wammer/WAFacebookSignupViewController.m diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index e4a91f82..d8d307ba 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -275,6 +275,7 @@ 8037A21616D76E0B00BE7581 /* GoogleLogo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8037A21216D76E0B00BE7581 /* GoogleLogo@2x.png */; }; 8037A21716D76E0B00BE7581 /* twitterLogo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8037A21316D76E0B00BE7581 /* twitterLogo@2x.png */; }; 8037A21916D76E1B00BE7581 /* PicasaLogo@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8037A21816D76E1B00BE7581 /* PicasaLogo@2x.png */; }; + 8040F2261715697F0074072E /* WAPeople.m in Sources */ = {isa = PBXBuildFile; fileRef = 8040F2251715697F0074072E /* WAPeople.m */; }; 8042891B16B2C67F00796F09 /* WAArticle.m in Sources */ = {isa = PBXBuildFile; fileRef = 80BF4D6B16B28A7000501E69 /* WAArticle.m */; }; 8042891C16B2C73100796F09 /* WACollection+RemoteOperations.m in Sources */ = {isa = PBXBuildFile; fileRef = 4BB6A9041696BBA300AB5F14 /* WACollection+RemoteOperations.m */; }; 8042891D16B2C77600796F09 /* WADefines.m in Sources */ = {isa = PBXBuildFile; fileRef = FF0B2A2C14388FF000309F0E /* WADefines.m */; }; @@ -285,7 +286,6 @@ 8056C9881682C4CC001C9199 /* WAWebPreviewViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8056C9871682C4CC001C9199 /* WAWebPreviewViewController.xib */; }; 80638BF2164CA663005695E3 /* WATag.m in Sources */ = {isa = PBXBuildFile; fileRef = 80638BF1164CA663005695E3 /* WATag.m */; }; 80638BFC164CA7DA005695E3 /* WATagGroup.m in Sources */ = {isa = PBXBuildFile; fileRef = 80638BFB164CA7DA005695E3 /* WATagGroup.m */; }; - 80638BFD164CA852005695E3 /* WAPeople.m in Sources */ = {isa = PBXBuildFile; fileRef = 80638BF7164CA6A8005695E3 /* WAPeople.m */; }; 806A5C851623C6C500867E56 /* WAContextMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 806A5C841623C6C500867E56 /* WAContextMenuViewController.m */; }; 806A5C9C16241E2800867E56 /* Cal.png in Resources */ = {isa = PBXBuildFile; fileRef = 806A5C8A16241E2800867E56 /* Cal.png */; }; 806A5C9D16241E2800867E56 /* Cal@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 806A5C8B16241E2800867E56 /* Cal@2x.png */; }; @@ -321,6 +321,9 @@ 8090AB2A1646AE79007E2AC0 /* back@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 8090AB261646AE79007E2AC0 /* back@2x.png */; }; 8093C6F116F3236F00C7D001 /* WACollectionPickerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8093C6F016F3236F00C7D001 /* WACollectionPickerCell.m */; }; 8093C70216F3239700C7D001 /* WACollectionPickerCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8093C70116F3239700C7D001 /* WACollectionPickerCell.xib */; }; + 8095504F17166FE100BEDDE0 /* WAFacebookSignupViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8095504E17166FE100BEDDE0 /* WAFacebookSignupViewController.m */; }; + 809550521716710700BEDDE0 /* HighlightAddEventBtn.png in Resources */ = {isa = PBXBuildFile; fileRef = 80955050171670DA00BEDDE0 /* HighlightAddEventBtn.png */; }; + 809550531716710700BEDDE0 /* HighlightAddEventBtn@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 80955051171670ED00BEDDE0 /* HighlightAddEventBtn@2x.png */; }; 809C6D26160583A00016E196 /* IIViewDeckController.m in Sources */ = {isa = PBXBuildFile; fileRef = 809C6D23160583A00016E196 /* IIViewDeckController.m */; }; 809C6D27160583A00016E196 /* WrapController.m in Sources */ = {isa = PBXBuildFile; fileRef = 809C6D25160583A00016E196 /* WrapController.m */; }; 809C6D2B1605845A0016E196 /* WASlidingMenuViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 809C6D291605845A0016E196 /* WASlidingMenuViewController.m */; }; @@ -1290,6 +1293,8 @@ 8037A21216D76E0B00BE7581 /* GoogleLogo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "GoogleLogo@2x.png"; path = "Resources/GoogleLogo@2x.png"; sourceTree = ""; }; 8037A21316D76E0B00BE7581 /* twitterLogo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "twitterLogo@2x.png"; path = "Resources/twitterLogo@2x.png"; sourceTree = ""; }; 8037A21816D76E1B00BE7581 /* PicasaLogo@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "PicasaLogo@2x.png"; path = "Resources/PicasaLogo@2x.png"; sourceTree = ""; }; + 8040F2241715697F0074072E /* WAPeople.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAPeople.h; sourceTree = ""; }; + 8040F2251715697F0074072E /* WAPeople.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WAPeople.m; sourceTree = ""; }; 8046F44F16BB66DA00B0EEEB /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 80499B1016718F0400842788 /* WAEventHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = WAEventHeaderView.xib; path = wammer/WAEventHeaderView.xib; sourceTree = ""; }; 80557BA715FDE38000336F3C /* WARemoteInterface+RemoteNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "WARemoteInterface+RemoteNotifications.h"; sourceTree = ""; }; @@ -1299,8 +1304,6 @@ 8056C9871682C4CC001C9199 /* WAWebPreviewViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WAWebPreviewViewController.xib; sourceTree = ""; }; 80638BF0164CA663005695E3 /* WATag.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WATag.h; sourceTree = ""; }; 80638BF1164CA663005695E3 /* WATag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WATag.m; sourceTree = ""; }; - 80638BF6164CA6A8005695E3 /* WAPeople.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WAPeople.h; sourceTree = ""; }; - 80638BF7164CA6A8005695E3 /* WAPeople.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WAPeople.m; sourceTree = ""; }; 80638BFA164CA7DA005695E3 /* WATagGroup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WATagGroup.h; sourceTree = ""; }; 80638BFB164CA7DA005695E3 /* WATagGroup.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WATagGroup.m; sourceTree = ""; }; 806A5C831623C6C500867E56 /* WAContextMenuViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WAContextMenuViewController.h; sourceTree = ""; }; @@ -1349,6 +1352,10 @@ 8093C6EF16F3236F00C7D001 /* WACollectionPickerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WACollectionPickerCell.h; sourceTree = ""; }; 8093C6F016F3236F00C7D001 /* WACollectionPickerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACollectionPickerCell.m; sourceTree = ""; }; 8093C70116F3239700C7D001 /* WACollectionPickerCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WACollectionPickerCell.xib; sourceTree = ""; }; + 8095504D17166FE100BEDDE0 /* WAFacebookSignupViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAFacebookSignupViewController.h; path = wammer/WAFacebookSignupViewController.h; sourceTree = ""; }; + 8095504E17166FE100BEDDE0 /* WAFacebookSignupViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAFacebookSignupViewController.m; path = wammer/WAFacebookSignupViewController.m; sourceTree = ""; }; + 80955050171670DA00BEDDE0 /* HighlightAddEventBtn.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = HighlightAddEventBtn.png; path = Resources/HighlightAddEventBtn.png; sourceTree = ""; }; + 80955051171670ED00BEDDE0 /* HighlightAddEventBtn@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "HighlightAddEventBtn@2x.png"; path = "Resources/HighlightAddEventBtn@2x.png"; sourceTree = ""; }; 809C6D22160583A00016E196 /* IIViewDeckController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IIViewDeckController.h; path = external/ViewDeck/ViewDeck/IIViewDeckController.h; sourceTree = ""; }; 809C6D23160583A00016E196 /* IIViewDeckController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = IIViewDeckController.m; path = external/ViewDeck/ViewDeck/IIViewDeckController.m; sourceTree = ""; }; 809C6D24160583A00016E196 /* WrapController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WrapController.h; path = external/ViewDeck/ViewDeck/WrapController.h; sourceTree = ""; }; @@ -2579,6 +2586,8 @@ 80C768DD17105789000F10A8 /* WAPartioFirstUse.storyboard */, 80C768DF17105BEA000F10A8 /* WAPartioFirstUseViewController.h */, 80C768E017105BEA000F10A8 /* WAPartioFirstUseViewController.m */, + 8095504D17166FE100BEDDE0 /* WAFacebookSignupViewController.h */, + 8095504E17166FE100BEDDE0 /* WAFacebookSignupViewController.m */, 80C768E517105CFC000F10A8 /* WAPartioWelcomeViewController.h */, 80C768E617105CFC000F10A8 /* WAPartioWelcomeViewController.m */, ); @@ -2798,8 +2807,8 @@ 80E5173B1670F3B200E1C3AD /* WALocation.m */, 80638BFA164CA7DA005695E3 /* WATagGroup.h */, 80638BFB164CA7DA005695E3 /* WATagGroup.m */, - 80638BF6164CA6A8005695E3 /* WAPeople.h */, - 80638BF7164CA6A8005695E3 /* WAPeople.m */, + 8040F2241715697F0074072E /* WAPeople.h */, + 8040F2251715697F0074072E /* WAPeople.m */, 80638BF0164CA663005695E3 /* WATag.h */, 80638BF1164CA663005695E3 /* WATag.m */, FF88E14314E8D7DC00B347A8 /* WAArticle+WAAdditions.h */, @@ -3300,6 +3309,8 @@ 803302481688539200004891 /* facebook@2x.png */, FFCCDE4B15B41B0000AEBB85 /* FacebookLogo.png */, 8037A20016D76AF000BE7581 /* FacebookLogo@2x.png */, + 80955050171670DA00BEDDE0 /* HighlightAddEventBtn.png */, + 80955051171670ED00BEDDE0 /* HighlightAddEventBtn@2x.png */, 80C6FD8D16D766E700D450D3 /* FlickrLogo.png */, 80C6FD8E16D766E700D450D3 /* PicasaLogo.png */, 80C6FD9116D766F100D450D3 /* FourSquareLogo.png */, @@ -3395,9 +3406,6 @@ FFCCDEDB15B41B0000AEBB85 /* WACompositionBackgroundPattern.png */, FFCCDEDC15B41B0000AEBB85 /* WACompositionBackgroundPattern@2x.png */, FFCCDEE215B41B0000AEBB85 /* WACornerCloseButton.png */, - 4B85823A15F7ABCF00EE11AC /* WADefaults.develop.plist */, - FFCCDEE615B41B0000AEBB85 /* WADefaults.plist */, - 4B16701115FDCE9900990F4B /* WADefaults.staging.plist */, FFCCDEEB15B41B0000AEBB85 /* WAFilter.png */, FFCCDEEC15B41B0000AEBB85 /* WAFilter@2x.png */, FFCCDEF115B41B0000AEBB85 /* WAFloatingButtonBackdrop.png */, @@ -3482,6 +3490,9 @@ FFC6200A149CF0310097C377 /* WADefines+Mac.m */, FFC6200C149CF03A0097C377 /* WADefines+iOS.h */, FFC6200D149CF03A0097C377 /* WADefines+iOS.m */, + 4B85823A15F7ABCF00EE11AC /* WADefaults.develop.plist */, + FFCCDEE615B41B0000AEBB85 /* WADefaults.plist */, + 4B16701115FDCE9900990F4B /* WADefaults.staging.plist */, FF73A54A13D6C2CD00D54EC6 /* wammer-iOS-Info.plist */, FF73A55013D6C2CD00D54EC6 /* wammer-iOS-Prefix.pch */, FFC6483D1445E8D700593E5E /* wammer-OSX-Info.plist */, @@ -4271,6 +4282,8 @@ 8028355F1713047A00E0A187 /* WADayPhotoPickerSectionHeaderView.xib in Resources */, 80CBC7721713FBDE0056D9CF /* partioIcon.png in Resources */, 80F2753C171410D500C49FAB /* WAPartioSignupViewController.xib in Resources */, + 809550521716710700BEDDE0 /* HighlightAddEventBtn.png in Resources */, + 809550531716710700BEDDE0 /* HighlightAddEventBtn@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4518,7 +4531,6 @@ files = ( 80C65D03167B0BB9000E61DB /* WAEventDay.m in Sources */, 800770E016797AE70085E525 /* WATimelineViewCell.m in Sources */, - 80638BFD164CA852005695E3 /* WAPeople.m in Sources */, FFCFE086142111E100B9E6AF /* main.m in Sources */, FFCFE087142111E100B9E6AF /* WAAppDelegate.m in Sources */, FFCFE089142111E100B9E6AF /* WACompositionViewController.m in Sources */, @@ -4774,6 +4786,8 @@ 8028355A1713037900E0A187 /* WADayPhotoPickerViewCell.m in Sources */, 8028355D1713046100E0A187 /* WADayPhotoPickerSectionHeaderView.m in Sources */, 80F2752D171410B400C49FAB /* WAPartioSignupViewController.m in Sources */, + 8040F2261715697F0074072E /* WAPeople.m in Sources */, + 8095504F17166FE100BEDDE0 /* WAFacebookSignupViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/Resources/HighlightAddEventBtn.png b/wammer/Resources/HighlightAddEventBtn.png new file mode 100644 index 0000000000000000000000000000000000000000..3287e2c5454b3b94c6718d775aeb37b764a1494a GIT binary patch literal 2307 zcmbVOX;c$g77hfLgdmX?iNPg=MG#4fCf|+do&~kM95-NO0bn78e0XG zh^P=mX+^|oL=@;gMuChdN{a~Cpx}ZFBRFb{(-9XGr%-U_ho^r`om2JRyYGH?`R={v z)Q%;Qi=41TEDD8k5{2<4$Vx}vz{wMl@2yS#(a16b7R18Q>LfT_s)bOYa&;m^5-Fw0 zkOY#-GuAdk3s5L@iXtW!jul66WNIZvI;um_D>Vojg<24z*GOfl5KKyhk`=08@{4l~ zWRgN2OkTkd17ZyiN>PMu&_dB0B4cD5Qe|v8IbS09}R( zmg)mkI?r(nd`KtLDm1V{ts;$DlqRaz!NFuC($6U!z$evQ3z#Jy;MU5DF9We z9L?*Kwhop+{|)1-+Patw4MdedI`ulO45>$w=QtSQ?#~^KDk9NvqO=O6DAF{(TDDFJ zsbCR5n2g*|X!%`OBLqOCOJ<0s%yj=tR(mzL5tc!z^PmWxi$ zI+b;_)62`HcglI}!AYu)2g)s(Gse0P)ZYr0Rn=^%LOkCLmz?JK>pm%)+~oz~3zMdiln z9qLLNz7%s+Fwzk8syAQ5Jf`uYZk$N4Evg5&M>^aLIzKlz+Vd8lLnU|Tl!RFP9tUXZ z{jH1kZ47g1c{TAuH8T*ryAKEC+TYGfiaKJJZwE4uKM6R=AMjqy5zTf@B<7%Z8;0_Y zHA8a^2d++aX+DV_0SKKj-%eajUZ%~sQdu^H#sn`uaZhQoUpA?NAvJbYnQPpQrp7!- ziTChmzwUfzqDTIZ_WP^L%)IiPWqt64mLS|e$*b`Xr>9hV{rp>0d6A(6zc=g<(P_&p za(9Wk`jEJZy?3S0DP6=*TXNhyyV!y*p}W35$gZRIL`F#AO|C<7AW39l%xt&0ZtZz8 zm!6w<+A}f{MC&Q4?x<8>R;kPucM;e7puT@tOmSNAEV%Q!%*Jk`0w(|F3OYgR(Zk*yYF}06SBHWU9qq<@R z)`?pdrmHXKoj=@$zkWbCBYQ^co~nOK3nK5S3eTC&pfii+Ma35m9mINitr;$K+J4@S zd?_m<9F$aqKd-o)wd(xy%_Wmz)1JzJWBb!6oW8}<-5uDDp?)*LIg7Icc3!ki?&W>UpJG%pzjoNRgeiuzWzB8sl ze&Zq&PdXD3WyZbPo!ESa>YG~u50idbSETTHrRqu*hg<{dSZ!-P?>N`-z7Ia;K6M@O zAi|raJ%t literal 0 HcmV?d00001 diff --git a/wammer/Resources/HighlightAddEventBtn@2x.png b/wammer/Resources/HighlightAddEventBtn@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..581fea822852e5e38dfa461e55840832f85ff205 GIT binary patch literal 3200 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 + +@interface WAFacebookSignupViewController : UIViewController + +@end diff --git a/wammer/WAFacebookSignupViewController.m b/wammer/WAFacebookSignupViewController.m new file mode 100644 index 00000000..c9b2d13f --- /dev/null +++ b/wammer/WAFacebookSignupViewController.m @@ -0,0 +1,134 @@ +// +// WAFacebookSignupViewController.m +// wammer +// +// Created by Shen Steven on 4/11/13. +// Copyright (c) 2013 Waveface. All rights reserved. +// + +#import "WAFacebookSignupViewController.h" +#import "WAOverlayBezel.h" +#import "WARemoteInterface.h" +#import "UIKit+IRAdditions.h" +#import "WAPartioFirstUseViewController.h" +#import +#import + + +@interface WAFacebookSignupViewController () + +@end + +@implementation WAFacebookSignupViewController + +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil +{ + self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; + if (self) { + // Custom initialization + } + return self; +} + +- (void)viewDidLoad +{ + [super viewDidLoad]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning +{ + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + + +- (IBAction)facebookSignupButtonClicked:(id)sender { + WAPartioFirstUseViewController *firstUse = (WAPartioFirstUseViewController*)self.navigationController; + + WAOverlayBezel *busyBezel = [WAOverlayBezel bezelWithStyle:WAActivityIndicatorBezelStyle]; + [busyBezel showWithAnimation:WAOverlayBezelAnimationFade]; + + // http://stackoverflow.com/questions/12601191/facebook-sdk-3-1-error-validating-access-token + // This should and will be fixed from FB SDK + + ACAccountStore *accountStore; + ACAccountType *accountTypeFB; + if ((accountStore = [[ACAccountStore alloc] init]) && + (accountTypeFB = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook] ) ){ + + NSArray *fbAccounts = [accountStore accountsWithAccountType:accountTypeFB]; + id account; + if (fbAccounts && [fbAccounts count] > 0 && + (account = [fbAccounts objectAtIndex:0])){ + + [accountStore renewCredentialsForAccount:account completion:^(ACAccountCredentialRenewResult renewResult, NSError *error) { + //we don't actually need to inspect renewResult or error. + if (error){ + + } + }]; + } + } + + [FBSession + openActiveSessionWithReadPermissions:@[@"email", @"user_photos", @"user_videos", @"user_notes", @"user_status", @"user_likes", @"read_stream", @"friends_photos", @"friends_videos", @"friends_status", @"friends_notes", @"friends_likes"] + allowLoginUI:YES + completionHandler:^(FBSession *session, FBSessionState status, NSError *error) { + + if (error) { + + NSLog(@"Facebook auth error: %@", error); + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + if (firstUse.failureBlock) + firstUse.failureBlock(error); + + }); + + + return; + } + + [[WARemoteInterface sharedInterface] + signupUserWithFacebookToken:session.accessTokenData.accessToken + withOptions:nil + onSuccess:^(NSString *token, NSDictionary *userRep, NSArray *groupReps) { + NSString *userID = [userRep valueForKeyPath:@"user_id"]; + + NSString *primaryGroupID = [[[groupReps filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { + + return [[evaluatedObject valueForKeyPath:@"creator_id"] isEqual:userID]; + + }]] lastObject] valueForKeyPath:@"group_id"]; + + WARemoteInterface *ri = [WARemoteInterface sharedInterface]; + ri.userIdentifier = userID; + ri.userToken = token; + ri.primaryGroupIdentifier = primaryGroupID; + + dispatch_async(dispatch_get_main_queue(), ^{ + if (firstUse.completionBlock) + firstUse.completionBlock(); + }); + + + } onFailure:^(NSError *error) { + + dispatch_async(dispatch_get_main_queue(), ^{ + + [busyBezel dismissWithAnimation:WAOverlayBezelAnimationFade]; + + if (firstUse.failureBlock) + firstUse.failureBlock(error); + + }); + + }]; + + }]; + +} + +@end diff --git a/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents b/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents index da4d2289..b5200cf9 100644 --- a/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents +++ b/wammer/WAModel.xcdatamodeld/WAModel 44.xcdatamodel/contents @@ -215,6 +215,7 @@ + @@ -308,6 +309,7 @@ + @@ -317,7 +319,7 @@ - + @@ -325,6 +327,5 @@ - \ No newline at end of file diff --git a/wammer/WAPartioFirstUse.storyboard b/wammer/WAPartioFirstUse.storyboard index 45021a04..15c2739d 100644 --- a/wammer/WAPartioFirstUse.storyboard +++ b/wammer/WAPartioFirstUse.storyboard @@ -50,7 +50,7 @@ - - + 292 @@ -44,8 +45,10 @@ 292 - {320, 149} + {320, 120} + + _NS:9 YES 2 @@ -55,9 +58,10 @@ 292 - {{20, 100}, {264, 21}} + {{20, 49}, {221, 21}} - + + _NS:9 NO YES @@ -78,11 +82,11 @@ Helvetica-Bold Helvetica 2 - 14 + 22 Helvetica-Bold - 14 + 22 16 NO @@ -90,8 +94,10 @@ 292 - {{20, 79}, {280, 21}} + {{20, 26}, {221, 21}} + + _NS:9 NO YES @@ -103,14 +109,14 @@ 0 - Helvetica-Bold + Helvetica Helvetica - 2 - 16 + 0 + 14 - Helvetica-Bold - 16 + Helvetica + 14 16 NO @@ -118,9 +124,9 @@ 292 - {{20, 120}, {264, 21}} + {{20, 72}, {221, 21}} - + _NS:9 NO YES @@ -132,21 +138,57 @@ 0 - Helvetica-Bold + Helvetica Helvetica - 2 - 17 + 0 + 16 - Helvetica-Bold - 17 + Helvetica + 16 16 NO + + + 292 + {{244, 32}, {56, 56}} + + + + _NS:9 + NO + IBCocoaTouchFramework + 0 + 0 + + + 1 + MC4xOTYwNzg0MzQ2IDAuMzA5ODAzOTMyOSAwLjUyMTU2ODY1NgA + + + 3 + MC41AA + + + NSImage + HighlightAddEventBtn.png + + + 2 + 15 + + + Helvetica-Bold + 15 + 16 + + - {320, 149} + {320, 119} + _NS:11 @@ -160,11 +202,14 @@ IBCocoaTouchFramework - {320, 150} + {320, 120} + + _NS:9 IBCocoaTouchFramework + @@ -201,6 +246,14 @@ 185 + + + addButton + + + + 225 + @@ -225,12 +278,28 @@ 3 - - - 5 + + + 10 0 - - 5 + + 10 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + + + + 6 + 0 + + 6 1 20 @@ -241,6 +310,22 @@ 29 3 + + + 4 + 0 + + 4 + 1 + + 27 + + 1000 + + 3 + 9 + 3 + 6 @@ -257,31 +342,31 @@ 24 2 - - - 4 + + + 5 0 - - 4 + + 5 1 - 9 + 20 1000 - 3 - 9 + 8 + 29 3 - - - 4 + + + 3 0 - - 4 + + 3 1 - 29 + 49 1000 @@ -289,6 +374,22 @@ 9 3 + + + 6 + 0 + + 6 + 1 + + 0.0 + + 1000 + + 6 + 24 + 2 + 5 @@ -305,20 +406,20 @@ 29 3 - - - 6 + + + 3 0 - - 6 + + 3 1 - 20 + 26 1000 - 8 - 29 + 3 + 9 3 @@ -337,20 +438,20 @@ 29 3 - - + + 4 0 - + 4 1 - 50 + 0.0 1000 - 3 - 9 + 9 + 40 3 @@ -381,8 +482,8 @@ 1000 - 8 - 29 + 9 + 40 3 @@ -402,8 +503,9 @@ 3 - + + @@ -411,24 +513,7 @@ 4 - - - - 8 - 0 - - 0 - 1 - - 149 - - 1000 - - 3 - 9 - 1 - - + @@ -458,6 +543,22 @@ 75 + + + 7 + 0 + + 0 + 1 + + 221 + + 1000 + + 3 + 9 + 1 + 8 @@ -470,8 +571,8 @@ 1000 - 3 - 9 + 9 + 40 1 @@ -481,15 +582,15 @@ 100 - + - 7 + 8 0 0 1 - 264 + 21 1000 @@ -500,11 +601,6 @@ - - 138 - - - 154 @@ -515,11 +611,6 @@ - - 156 - - - 157 @@ -536,43 +627,117 @@ - 179 - + 180 + - 180 - + 195 + - 183 + 212 + + + + + 8 + 0 + + 0 + 1 + + 56 + + 1000 + + 3 + 9 + 1 + + + + 7 + 0 + + 0 + 1 + + 56 + + 1000 + + 3 + 9 + 1 + + + + + + 218 + + + + + 221 + + + + + 224 - 190 - + 241 + + + + + 242 + + + + + 244 + + + + + 245 + + + + + 255 + - 192 + 257 - 193 - + 258 + - 194 - + 259 + - 195 - + 261 + + + + + 262 + @@ -582,53 +747,65 @@ UIResponder com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - + + - com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - com.apple.InterfaceBuilder.IBCocoaTouchPlugin com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + com.apple.InterfaceBuilder.IBCocoaTouchPlugin WAPhotoHighlightViewCell com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + - + - - - + + + + + + com.apple.InterfaceBuilder.IBCocoaTouchPlugin - - - com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + com.apple.InterfaceBuilder.IBCocoaTouchPlugin - + + @@ -636,7 +813,7 @@ - 195 + 262 @@ -648,12 +825,53 @@ ./Classes/NSLayoutConstraint.h + + WAPhotoHighlightViewCell + UITableViewCell + + UIButton + UIImageView + UILabel + UILabel + UILabel + + + + addButton + UIButton + + + bgImageView + UIImageView + + + dateLabel + UILabel + + + locationLabel + UILabel + + + photoNumberLabel + UILabel + + + + IBProjectSource + ./Classes/WAPhotoHighlightViewCell.h + + 0 IBCocoaTouchFramework YES 3 + + HighlightAddEventBtn.png + {52, 51} + YES 2083 diff --git a/wammer/WAPhotoHighlightsViewController.m b/wammer/WAPhotoHighlightsViewController.m index f309cb97..16e8b23a 100644 --- a/wammer/WAPhotoHighlightsViewController.m +++ b/wammer/WAPhotoHighlightsViewController.m @@ -256,7 +256,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter = [[NSDateFormatter alloc] init]; formatter.dateStyle = NSDateFormatterMediumStyle; - formatter.timeStyle = NSDateFormatterMediumStyle; + formatter.timeStyle = NSDateFormatterNoStyle; cell.dateLabel.text = [formatter stringFromDate:eventDate]; cell.locationLabel.text = @""; @@ -300,6 +300,12 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } } + __weak WAPhotoHighlightsViewController *wSelf = self; + [cell.addButton removeEventHandlersForControlEvents:UIControlEventTouchUpInside]; + [cell.addButton addEventHandler:^(id sender) { + WADayPhotoPickerViewController *picker = [[WADayPhotoPickerViewController alloc] initWithSelectedAssets:wSelf.photoGroups[indexPath.row]]; + [wSelf.navigationController pushViewController:picker animated:YES]; + } forControlEvents:UIControlEventTouchUpInside]; return cell; } @@ -308,15 +314,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - /* + WAPhotoTimelineViewController *vc = [[WAPhotoTimelineViewController alloc] initWithAssets:self.photoGroups[indexPath.row]]; + + [self.navigationController pushViewController:vc animated:YES]; - self.modalTransitionStyle = UIModalTransitionStyleCoverVertical; - self.modalPresentationStyle = UIModalPresentationCurrentContext; - [self presentViewController:vc animated:YES completion:nil]; - */ - WADayPhotoPickerViewController *picker = [[WADayPhotoPickerViewController alloc] initWithSelectedAssets:self.photoGroups[indexPath.row]]; - [self.navigationController pushViewController:picker animated:YES]; } @end diff --git a/wammer/WAPhotoHighlightsViewController.xib b/wammer/WAPhotoHighlightsViewController.xib index 48164a54..4874efc8 100644 --- a/wammer/WAPhotoHighlightsViewController.xib +++ b/wammer/WAPhotoHighlightsViewController.xib @@ -31,9 +31,11 @@ IBCocoaTouchFramework - + 274 {{0, 20}, {320, 548}} + + 1 MCAwIDAAA @@ -63,7 +65,7 @@ NO 0 YES - 150 + 120 22 22 @@ -134,7 +136,18 @@ 7 - + + + + WAPhotoHighlightsViewController + UITableViewController + + IBProjectSource + ./Classes/WAPhotoHighlightsViewController.h + + + + 0 IBCocoaTouchFramework YES diff --git a/wammer/WAPhotoTimelineViewController.m b/wammer/WAPhotoTimelineViewController.m index 906fc8c2..d0b4a9f5 100644 --- a/wammer/WAPhotoTimelineViewController.m +++ b/wammer/WAPhotoTimelineViewController.m @@ -22,6 +22,8 @@ #import "WAFile+LazyImages.h" #import "WAFileExif.h" #import "WAFileExif+WAAdditions.h" +#import "WAPeople.h" +#import "WALocation.h" #import "WAContactPickerViewController.h" #import "WAGeoLocation.h" @@ -164,7 +166,7 @@ + (NSOperationQueue *)sharedImportPhotoOperationQueue { return opq; } -- (void) finishCreatingSharingEvent { +- (void) finishCreatingSharingEventForSharingTargets:(NSArray *)contacts { // __weak WAPhotoTimelineViewController *wSelf = self; NSDate *importTime = [NSDate date]; @@ -212,29 +214,59 @@ - (void) finishCreatingSharingEvent { } } - - article.event = (id)kCFBooleanTrue; - article.eventType = [NSNumber numberWithInt:WAEventArticleSharedType]; - article.draft = (id)kCFBooleanFalse; - CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); - if (theUUID) - article.identifier = [((__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID)) lowercaseString]; - CFRelease(theUUID); - article.dirty = (id)kCFBooleanTrue; - article.creationDeviceName = [UIDevice currentDevice].name; - article.creationDate = [NSDate date]; - - NSError *savingError = nil; - if ([moc save:&savingError]) { - NSLog(@"Sharing event successfully created"); - } else { - NSLog(@"error on creating a new import post for error: %@", savingError); + } + + article.event = (id)kCFBooleanTrue; + article.eventType = [NSNumber numberWithInt:WAEventArticleSharedType]; + article.draft = (id)kCFBooleanFalse; + CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault); + if (theUUID) + article.identifier = [((__bridge_transfer NSString *)CFUUIDCreateString(kCFAllocatorDefault, theUUID)) lowercaseString]; + CFRelease(theUUID); + article.dirty = (id)kCFBooleanTrue; + article.creationDeviceName = [UIDevice currentDevice].name; + article.creationDate = [NSDate date]; + + NSArray *emailsFromContacts = [contacts valueForKey:@"email"]; + NSMutableArray *invitingEmails = [NSMutableArray array]; + for (NSArray *contactEmails in emailsFromContacts) { + [invitingEmails addObjectsFromArray:contactEmails]; + } + NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:@"WAPeople"]; + fr.predicate = [NSPredicate predicateWithFormat:@"email IN %@", invitingEmails]; + NSError *error = nil; + NSArray *peopleFound = [moc executeFetchRequest:fr error:&error]; + if (peopleFound.count) { + for (WAPeople *person in peopleFound) { + [[article mutableSetValueForKey:@"people"] addObject:person]; + if ([invitingEmails indexOfObject:person.email] != NSNotFound) { + [invitingEmails removeObject:person.email]; + } } } + for (NSString *email in invitingEmails) { + WAPeople *person = (WAPeople*)[WAPeople objectInsertingIntoContext:moc withRemoteDictionary:@{}]; + person.email = email; + [[article mutableSetValueForKey:@"people"] addObject:person]; + } + + WALocation *location = (WALocation*)[WALocation objectInsertingIntoContext:moc withRemoteDictionary:@{}]; + location.latitude = [NSNumber numberWithFloat:self.coordinate.latitude]; + location.longitude = [NSNumber numberWithFloat:self.coordinate.longitude]; + location.name = @""; // TBD + article.location = location; + + NSError *savingError = nil; + if ([moc save:&savingError]) { + NSLog(@"Sharing event successfully created"); + } else { + NSLog(@"error on creating a new import post for error: %@", savingError); + } } - (NSManagedObjectContext*)managedObjectContext { + if (_managedObjectContext) return _managedObjectContext; @@ -255,8 +287,19 @@ - (void) backButtonClicked:(id)sender { - (void)actionButtonClicked:(id)sender { - [self finishCreatingSharingEvent]; - [self.navigationController popToRootViewControllerAnimated:NO]; + + __weak WAPhotoTimelineViewController *wSelf = self; + WAContactPickerViewController *contactPicker = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; + if (self.navigationController) { + + contactPicker.onNextHandler = ^(NSArray *results) { + [wSelf finishCreatingSharingEventForSharingTargets:results]; + [wSelf.navigationController popToRootViewControllerAnimated:NO]; + }; + [self.navigationController pushViewController:contactPicker animated:YES]; + + } + // WAContactPickerViewController *cpVC = [[WAContactPickerViewController alloc] initWithStyle:UITableViewStylePlain]; // [self.navigationController pushViewController:cpVC animated:YES]; diff --git a/wammer/WARemoteInterface+Posts.h b/wammer/WARemoteInterface+Posts.h index 8bddc535..02c85a41 100644 --- a/wammer/WARemoteInterface+Posts.h +++ b/wammer/WARemoteInterface+Posts.h @@ -8,10 +8,11 @@ #import "WARemoteInterface.h" #import "WADataStore.h" +#import @interface WARemoteInterface (Posts) -+ (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *)postID text:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType isFavorite:(BOOL)isFavorite isHidden:(BOOL)isHidden createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime; ++ (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *)postID text:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType isFavorite:(BOOL)isFavorite isHidden:(BOOL)isHidden createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime invitingEmails:(NSArray*)emails; // GET posts/getSingle - (void) retrievePost:(NSString *)anIdentifier inGroup:(NSString *)aGroupIdentifier onSuccess:(void(^)(NSDictionary *postRep))successBlock onFailure:(void(^)(NSError *error))failureBlock; @@ -23,7 +24,7 @@ - (void) retrieveLatestPostsInGroup:(NSString *)aGroupIdentifier withBatchLimit:(NSUInteger)maxNumberOfReturnedPosts onSuccess:(void(^)(NSArray *postReps))successBlock onFailure:(void(^)(NSError *error))failureBlock; // POST posts/new -- (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSString *)contentTextOrNil attachments:(NSArray *)attachmentIdentifiersOrNil type:(WAArticleType)postType postId:(NSString *)postID createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime favorite:(BOOL)isFavorite onSuccess:(void(^)(NSDictionary *postRep))successBlock onFailure:(void(^)(NSError *error))failureBlock; +- (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSString *)contentTextOrNil attachments:(NSArray *)attachmentIdentifiersOrNil type:(WAArticleType)postType postId:(NSString *)postID createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime favorite:(BOOL)isFavorite invitingEmails:(NSArray*)emails location:(NSDictionary*)location checkins:(NSArray*)checkins onSuccess:(void(^)(NSDictionary *postRep))successBlock onFailure:(void(^)(NSError *error))failureBlock; // POST posts/update - (void) updatePost:(NSString *)postID inGroup:(NSString *)groupID withText:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType favorite:(BOOL)isFavorite hidden:(BOOL)isHidden replacingDataWithDate:(NSDate *)lastKnownModificationDate updateTime:(NSDate *)updateTime onSuccess:(void(^)(NSDictionary *postRep))successBlock onFailure:(void(^)(NSError *error))failureBlock; diff --git a/wammer/WARemoteInterface+Posts.m b/wammer/WARemoteInterface+Posts.m index c32d6864..8d228f3d 100644 --- a/wammer/WARemoteInterface+Posts.m +++ b/wammer/WARemoteInterface+Posts.m @@ -11,7 +11,7 @@ @implementation WARemoteInterface (Posts) -+ (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *)postID text:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType isFavorite:(BOOL)isFavorite isHidden:(BOOL)isHidden createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime { ++ (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *)postID text:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType isFavorite:(BOOL)isFavorite isHidden:(BOOL)isHidden createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime invitingEmails:(NSArray*)emails location:(NSDictionary*)location checkins:(NSArray*)checkins { NSMutableDictionary *sentData = [NSMutableDictionary dictionary]; @@ -63,6 +63,28 @@ + (NSDictionary *) postEntityWithGroupID:(NSString *)groupID postID:(NSString *) } + if (emails) { + NSError *error = nil; + NSData *emailsDataInJSON = [NSJSONSerialization dataWithJSONObject:emails options:0 error:&error]; + sentData[@"shared_email_list"] = [[NSString alloc] initWithData:emailsDataInJSON encoding:NSUTF8StringEncoding]; + } + + if (location) { + NSMutableDictionary *gps = [@{ + @"latitude": location[@"latitude"], + @"longitude": location[@"longitude"] + } mutableCopy]; + + if (location[@"name"]) + gps[@"name"] = location[@"name"]; + + if (location[@"tags"]) + gps[@"region_tags"] = location[@"tags"]; + + NSError *error = nil; + sentData[@"gps"] = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:gps options:0 error:&error] encoding:NSUTF8StringEncoding]; + } + return sentData; } @@ -142,11 +164,11 @@ - (void) retrieveLatestPostsInGroup:(NSString *)aGroupIdentifier withBatchLimit: } -- (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSString *)contentTextOrNil attachments:(NSArray *)attachmentIdentifiersOrNil type:(WAArticleType)postType postId:(NSString *)postID createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime favorite:(BOOL)isFavorite onSuccess:(void (^)(NSDictionary *))successBlock onFailure:(void (^)(NSError *))failureBlock { +- (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSString *)contentTextOrNil attachments:(NSArray *)attachmentIdentifiersOrNil type:(WAArticleType)postType postId:(NSString *)postID createTime:(NSDate *)createTime updateTime:(NSDate *)updateTime favorite:(BOOL)isFavorite invitingEmails:(NSArray *)emails location:(NSDictionary*)location checkins:(NSArray*)checkins onSuccess:(void (^)(NSDictionary *))successBlock onFailure:(void (^)(NSError *))failureBlock { NSParameterAssert(aGroupIdentifier); - NSDictionary *postEntity = [[self class] postEntityWithGroupID:aGroupIdentifier postID:postID text:contentTextOrNil attachments:attachmentIdentifiersOrNil mainAttachment:nil type:postType isFavorite:isFavorite isHidden:NO createTime:createTime updateTime:updateTime]; + NSDictionary *postEntity = [[self class] postEntityWithGroupID:aGroupIdentifier postID:postID text:contentTextOrNil attachments:attachmentIdentifiersOrNil mainAttachment:nil type:postType isFavorite:isFavorite isHidden:NO createTime:createTime updateTime:updateTime invitingEmails:emails]; [self.engine fireAPIRequestNamed:@"pio_posts/new" withArguments:nil options:WARemoteInterfaceEnginePostFormEncodedOptionsDictionary(postEntity, nil) validator:WARemoteInterfaceGenericNoErrorValidator() successHandler:^(NSDictionary *inResponseOrNil, IRWebAPIRequestContext *inResponseContext) { @@ -163,7 +185,7 @@ - (void) createPostInGroup:(NSString *)aGroupIdentifier withContentText:(NSStrin - (void) updatePost:(NSString *)postID inGroup:(NSString *)groupID withText:(NSString *)text attachments:(NSArray *)attachmentIDs mainAttachment:(NSString *)mainAttachmentID type:(WAArticleType)postType favorite:(BOOL)isFavorite hidden:(BOOL)isHidden replacingDataWithDate:(NSDate *)lastKnownModificationDate updateTime:(NSDate *)updateTime onSuccess:(void(^)(NSDictionary *postRep))successBlock onFailure:(void(^)(NSError *error))failureBlock { - NSMutableDictionary *postEntity = [[[self class] postEntityWithGroupID:groupID postID:postID text:text attachments:attachmentIDs mainAttachment:mainAttachmentID type:postType isFavorite:isFavorite isHidden:isHidden createTime:nil updateTime:updateTime] mutableCopy]; + NSMutableDictionary *postEntity = [[[self class] postEntityWithGroupID:groupID postID:postID text:text attachments:attachmentIDs mainAttachment:mainAttachmentID type:postType isFavorite:isFavorite isHidden:isHidden createTime:nil updateTime:updateTime invitingEmails:nil] mutableCopy]; if (lastKnownModificationDate) { diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 3bc71d09..c9635d6b 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -79,6 +79,14 @@ - (void)didReceiveMemoryWarning // Dispose of any resources that can be recreated. } +- (BOOL) shouldAutorotate { + return YES; +} + +- (NSUInteger) supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} + #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView diff --git a/wammer/en.lproj/Localizable.strings b/wammer/en.lproj/Localizable.strings index 1b920ea9..91b7047a 100644 --- a/wammer/en.lproj/Localizable.strings +++ b/wammer/en.lproj/Localizable.strings @@ -570,7 +570,7 @@ "TITLE_OF_DAY_PHOTO_PICKER" = "Select Photos"; /* The title of highlight view */ -"TITLE_OF_HIGHLIGHTS" = "Highlights"; +"TITLE_OF_HIGHLIGHTS" = "Highlights For Share"; /* Alert on no location service enabled when open photo library */ "TURN_ON_LOCATION_SERVICE" = "Turn on Location Services to allow aostream to access your Photo Library."; diff --git a/wammer/zh-Hant.lproj/Localizable.strings b/wammer/zh-Hant.lproj/Localizable.strings index b91352a9..09383e7a 100644 --- a/wammer/zh-Hant.lproj/Localizable.strings +++ b/wammer/zh-Hant.lproj/Localizable.strings @@ -570,7 +570,7 @@ "TITLE_OF_DAY_PHOTO_PICKER" = "挑選照片"; /* The title of highlight view */ -"TITLE_OF_HIGHLIGHTS" = "小確幸"; +"TITLE_OF_HIGHLIGHTS" = "分享選輯"; /* Alert on no location service enabled when open photo library */ "TURN_ON_LOCATION_SERVICE" = "aostream 須開啟定位服務才能存取相簿的內容"; From 75dca04b49986592dd37037cd7c4afdd8cd77040 Mon Sep 17 00:00:00 2001 From: Greener Date: Thu, 11 Apr 2013 16:02:35 +0800 Subject: [PATCH 026/278] Fix modal view presentation --- wammer/WASharedEventViewController.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/wammer/WASharedEventViewController.m b/wammer/WASharedEventViewController.m index 2ef5b921..e411e460 100644 --- a/wammer/WASharedEventViewController.m +++ b/wammer/WASharedEventViewController.m @@ -210,11 +210,10 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self.navigationController pushViewController:ptVC animated:YES]; } -#pragma - toolbar +#pragma mark - toolbar - (void)shareNewEventFromHighlight { - __weak WASharedEventViewController *wSelf = self; WAPhotoHighlightsViewController *phVC = [[WAPhotoHighlightsViewController alloc] init]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:phVC]; [self presentViewController:nav animated:YES completion:nil]; From 9e80a79427bf6f21c0aab159c10909978f5a4d6c Mon Sep 17 00:00:00 2001 From: Greener Date: Thu, 11 Apr 2013 16:03:27 +0800 Subject: [PATCH 027/278] Fix checkin id --- wammer/WACheckin+WARemoteInterfaceEntitySyncing.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m index b576bee3..dcabba8d 100644 --- a/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m +++ b/wammer/WACheckin+WARemoteInterfaceEntitySyncing.m @@ -33,7 +33,7 @@ + (NSDictionary *) remoteDictionaryConfigurationMapping { mapping = @{ @"name": @"name", @"message": @"message", - @"checkin_id": @"identifier", + @"identifier": @"identifier", @"create_time": @"createDate", @"tagged_uids": @"taggedUsers" }; @@ -51,7 +51,12 @@ + (NSDictionary *) transformedRepresentationForRemoteRepresentation:(NSDictionar if (timestampNumber) { returnedDictionary[@"create_time"] = [NSDate dateWithTimeIntervalSince1970:timestampNumber.intValue]; } - + + NSNumber *checkinID = incomingDictionary[@"checkin_id"]; + if (checkinID) { + returnedDictionary[@"identifier"] = [NSString stringWithFormat:@"%@", checkinID]; + } + return returnedDictionary; } @@ -59,8 +64,6 @@ + (id) transformedValue:(id)aValue fromRemoteKeyPath:(NSString *)aRemoteKeyPath toLocalKeyPath:(NSString *)aLocalKeyPath { - if ( [aRemoteKeyPath isEqualToString:@"checkin_id"] ) - return [NSString stringWithFormat:@"%@", aValue]; if ( [aRemoteKeyPath isEqualToString:@"tagged_uids"]) return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:(NSArray*)aValue options:0 error:nil] encoding:NSUTF8StringEncoding]; From fdaec0e33c9a3fea269f34df44f172e176ed8efa Mon Sep 17 00:00:00 2001 From: Greener Date: Thu, 11 Apr 2013 16:51:49 +0800 Subject: [PATCH 028/278] Refactor contact elements --- wammer/WAContactPickerViewController.m | 68 +++++++++++++++++--------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/wammer/WAContactPickerViewController.m b/wammer/WAContactPickerViewController.m index 3d0032b7..645bb05d 100644 --- a/wammer/WAContactPickerViewController.m +++ b/wammer/WAContactPickerViewController.m @@ -107,23 +107,17 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else { cell.imageView.image = [UIImage imageNamed:@"FacebookLogo"]; - //TODO: first name then last name, or last name then first name by system settings - //FIXME: use fullname - if (_members[indexPath.row][@"firstName"] && _members[indexPath.row][@"lastName"]) { - cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", - _members[indexPath.row][@"firstName"], - _members[indexPath.row][@"lastName"]]; - } else if (_members[indexPath.row][@"firstName"]) { - cell.textLabel.text = _members[indexPath.row][@"firstName"]; - - } else if (_members[indexPath.row][@"lastName"]) { - cell.textLabel.text = _members[indexPath.row][@"lastName"]; - + + NSString *name = _members[indexPath.row][@"name"]; + if (name) { + cell.textLabel.text = name; + } + + NSString *email = _members[indexPath.row][@"email"]; + if (email) { + cell.detailTextLabel.text = email; } - cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ %@", - _members[indexPath.row][@"phone"], - ([_members[indexPath.row][@"email"] count])? _members[indexPath.row][@"email"][0]: @""]; cell.accessoryType = UITableViewCellAccessoryCheckmark; } @@ -179,15 +173,45 @@ - (void)addIntoInvitedList:(ABRecordRef)person { NSString *firstname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty); NSString *lastname = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty); - NSArray *email = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); + NSString *name = @""; + + if (firstname && lastname) { + if (ABPersonGetCompositeNameFormat() == kABPersonCompositeNameFormatFirstNameFirst) { + name = [NSString stringWithFormat:@"%@ %@", firstname, lastname]; + + } else { + name = [NSString stringWithFormat:@"%@ %@", lastname, firstname]; + + } + + } else if (firstname && !lastname) { + name = firstname; - //TODO: pick mobile phone numbers - NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(ABRecordCopyValue(person, kABPersonPhoneProperty), 0);; + } else if (!firstname && lastname) { + name = lastname; + + } + + NSString *email = @""; + NSArray *allEmail = (__bridge_transfer NSArray*)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty)); + if ([allEmail count]) { + email = allEmail[0]; + + } else { + //TODO: prompt dialog to input email + } + + NSString *phone = @""; + ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); + if (ABMultiValueGetCount(phoneNumbers) > 0) { + phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, 0); + + } + CFRelease(phoneNumbers); - NSDictionary *aPerson = @{@"firstName": firstname, - @"lastName": lastname, - @"email": (email)? email : @[], - @"phone": (phone)? phone : @"[N/A]"}; + NSDictionary *aPerson = @{@"name": name, + @"email": email, + @"phone": phone}; if (![_members containsObject:aPerson]) { [_members addObject:aPerson]; From 4b7a5245db3e2ada5e531e21078bef9e02cd2b77 Mon Sep 17 00:00:00 2001 From: syshen Date: Thu, 11 Apr 2013 16:59:10 +0800 Subject: [PATCH 029/278] retrieve old posts --- wammer.xcodeproj/project.pbxproj | 40 +- wammer/Resources/Checked.png | Bin 0 -> 1726 bytes wammer/Resources/Checked@2x.png | Bin 0 -> 1979 bytes wammer/Resources/PartioLogin.png | Bin 0 -> 144174 bytes wammer/Resources/PartioLogin@2x.png | Bin 0 -> 563847 bytes wammer/Resources/PartioSplashPage.png | Bin 0 -> 170690 bytes wammer/Resources/PartioSplashPage@2x.png | Bin 0 -> 676236 bytes ...WACheckin+WARemoteInterfaceEntitySyncing.m | 9 +- wammer/WADayPhotoPickerViewCell.m | 2 +- wammer/WAFetchManager+RemoteArticlesFetch.h | 16 + wammer/WAFetchManager+RemoteArticlesFetch.m | 150 +++++ wammer/WAFetchManager.m | 4 +- wammer/WAPartioFirstUse.storyboard | 100 +--- wammer/WAPhotoHighlightViewCell.xib | 12 +- wammer/WAPhotoTimelineCover.xib | 562 +++++++++--------- wammer/WAPhotoTimelineViewController.m | 3 - 16 files changed, 532 insertions(+), 366 deletions(-) create mode 100644 wammer/Resources/Checked.png create mode 100644 wammer/Resources/Checked@2x.png create mode 100644 wammer/Resources/PartioLogin.png create mode 100644 wammer/Resources/PartioLogin@2x.png create mode 100644 wammer/Resources/PartioSplashPage.png create mode 100644 wammer/Resources/PartioSplashPage@2x.png create mode 100644 wammer/WAFetchManager+RemoteArticlesFetch.h create mode 100644 wammer/WAFetchManager+RemoteArticlesFetch.m diff --git a/wammer.xcodeproj/project.pbxproj b/wammer.xcodeproj/project.pbxproj index d8d307ba..6da12fba 100644 --- a/wammer.xcodeproj/project.pbxproj +++ b/wammer.xcodeproj/project.pbxproj @@ -302,6 +302,13 @@ 80719CFC167B03B900E9729F /* WAPhotoDay+WARemoteInterfaceEntitySyncing.m in Sources */ = {isa = PBXBuildFile; fileRef = 80719CFB167B03B900E9729F /* WAPhotoDay+WARemoteInterfaceEntitySyncing.m */; }; 8074EF8816AD0ABA0033E99A /* WACalendarPopupViewController_phone.m in Sources */ = {isa = PBXBuildFile; fileRef = 8074EF8716AD0ABA0033E99A /* WACalendarPopupViewController_phone.m */; }; 80762CF216F1C05800DDA5A7 /* WACollectionPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 80762CF116F1C05800DDA5A7 /* WACollectionPickerViewController.m */; }; + 808A33681716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.m in Sources */ = {isa = PBXBuildFile; fileRef = 808A33671716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.m */; }; + 808A337B1716ABC100CF5C8D /* PartioLogin.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A33771716ABC100CF5C8D /* PartioLogin.png */; }; + 808A337C1716ABC100CF5C8D /* PartioLogin@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A33781716ABC100CF5C8D /* PartioLogin@2x.png */; }; + 808A337D1716ABC100CF5C8D /* PartioSplashPage.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A33791716ABC100CF5C8D /* PartioSplashPage.png */; }; + 808A337E1716ABC100CF5C8D /* PartioSplashPage@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A337A1716ABC100CF5C8D /* PartioSplashPage@2x.png */; }; + 808A33811716AC3F00CF5C8D /* Checked.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A337F1716AC3F00CF5C8D /* Checked.png */; }; + 808A33821716AC3F00CF5C8D /* Checked@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 808A33801716AC3F00CF5C8D /* Checked@2x.png */; }; 808DAA0C167597C9003652BB /* WAEventPeopleListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 808DAA0B167597C9003652BB /* WAEventPeopleListViewController.m */; }; 808DAA0F1675B1D2003652BB /* WAEventPeopleCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 808DAA0E1675B1D2003652BB /* WAEventPeopleCell.m */; }; 808DAA111675B1E8003652BB /* WAEventPeopleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 808DAA101675B1E8003652BB /* WAEventPeopleCell.xib */; }; @@ -1330,6 +1337,14 @@ 8074EF8716AD0ABA0033E99A /* WACalendarPopupViewController_phone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WACalendarPopupViewController_phone.m; path = wammer/WACalendarPopupViewController_phone.m; sourceTree = ""; }; 80762CF016F1C05800DDA5A7 /* WACollectionPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WACollectionPickerViewController.h; sourceTree = ""; }; 80762CF116F1C05800DDA5A7 /* WACollectionPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WACollectionPickerViewController.m; sourceTree = ""; }; + 808A33661716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "WAFetchManager+RemoteArticlesFetch.h"; path = "wammer/WAFetchManager+RemoteArticlesFetch.h"; sourceTree = ""; }; + 808A33671716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "WAFetchManager+RemoteArticlesFetch.m"; path = "wammer/WAFetchManager+RemoteArticlesFetch.m"; sourceTree = ""; }; + 808A33771716ABC100CF5C8D /* PartioLogin.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PartioLogin.png; path = Resources/PartioLogin.png; sourceTree = ""; }; + 808A33781716ABC100CF5C8D /* PartioLogin@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "PartioLogin@2x.png"; path = "Resources/PartioLogin@2x.png"; sourceTree = ""; }; + 808A33791716ABC100CF5C8D /* PartioSplashPage.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = PartioSplashPage.png; path = Resources/PartioSplashPage.png; sourceTree = ""; }; + 808A337A1716ABC100CF5C8D /* PartioSplashPage@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "PartioSplashPage@2x.png"; path = "Resources/PartioSplashPage@2x.png"; sourceTree = ""; }; + 808A337F1716AC3F00CF5C8D /* Checked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Checked.png; path = Resources/Checked.png; sourceTree = ""; }; + 808A33801716AC3F00CF5C8D /* Checked@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "Checked@2x.png"; path = "Resources/Checked@2x.png"; sourceTree = ""; }; 808DAA0A167597C9003652BB /* WAEventPeopleListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAEventPeopleListViewController.h; path = wammer/WAEventPeopleListViewController.h; sourceTree = ""; }; 808DAA0B167597C9003652BB /* WAEventPeopleListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = WAEventPeopleListViewController.m; path = wammer/WAEventPeopleListViewController.m; sourceTree = ""; }; 808DAA0D1675B1D2003652BB /* WAEventPeopleCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WAEventPeopleCell.h; path = wammer/WAEventPeopleCell.h; sourceTree = ""; }; @@ -2098,6 +2113,8 @@ 13CCDE64168C308A00962625 /* WAFetchManager.m */, 13CCDE66168C33A300962625 /* WAFetchManager+RemoteIndexFetch.h */, 13CCDE67168C33A400962625 /* WAFetchManager+RemoteIndexFetch.m */, + 808A33661716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.h */, + 808A33671716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.m */, 13CCDE69168C384200962625 /* WAFetchManager+RemoteCollectionFetch.h */, 13CCDE6A168C384200962625 /* WAFetchManager+RemoteCollectionFetch.m */, 13CCDE6C168C3C9300962625 /* WAFetchManager+RemoteFileMetadataFetch.h */, @@ -2493,6 +2510,20 @@ path = external/IRAQPhotoPicker; sourceTree = ""; }; + 808A33761716ABAB00CF5C8D /* Partio */ = { + isa = PBXGroup; + children = ( + 808A337F1716AC3F00CF5C8D /* Checked.png */, + 808A33801716AC3F00CF5C8D /* Checked@2x.png */, + 808A33771716ABC100CF5C8D /* PartioLogin.png */, + 808A33781716ABC100CF5C8D /* PartioLogin@2x.png */, + 808A33791716ABC100CF5C8D /* PartioSplashPage.png */, + 808A337A1716ABC100CF5C8D /* PartioSplashPage@2x.png */, + 80CBC7711713FBDE0056D9CF /* partioIcon.png */, + ); + name = Partio; + sourceTree = ""; + }; 808DAA121675C4B7003652BB /* Event People List */ = { isa = PBXGroup; children = ( @@ -3244,7 +3275,7 @@ FFC2E04C13DD706600816EA1 /* iOS Resources */ = { isa = PBXGroup; children = ( - 80CBC7711713FBDE0056D9CF /* partioIcon.png */, + 808A33761716ABAB00CF5C8D /* Partio */, 13D1397016DB467F00A41F86 /* WelcomeLogo.png */, 13D1397116DB467F00A41F86 /* WelcomeLogo@2x.png */, 13D1397416DB474000A41F86 /* WelcomeBackgroundPattern.png */, @@ -4284,6 +4315,12 @@ 80F2753C171410D500C49FAB /* WAPartioSignupViewController.xib in Resources */, 809550521716710700BEDDE0 /* HighlightAddEventBtn.png in Resources */, 809550531716710700BEDDE0 /* HighlightAddEventBtn@2x.png in Resources */, + 808A337B1716ABC100CF5C8D /* PartioLogin.png in Resources */, + 808A337C1716ABC100CF5C8D /* PartioLogin@2x.png in Resources */, + 808A337D1716ABC100CF5C8D /* PartioSplashPage.png in Resources */, + 808A337E1716ABC100CF5C8D /* PartioSplashPage@2x.png in Resources */, + 808A33811716AC3F00CF5C8D /* Checked.png in Resources */, + 808A33821716AC3F00CF5C8D /* Checked@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4788,6 +4825,7 @@ 80F2752D171410B400C49FAB /* WAPartioSignupViewController.m in Sources */, 8040F2261715697F0074072E /* WAPeople.m in Sources */, 8095504F17166FE100BEDDE0 /* WAFacebookSignupViewController.m in Sources */, + 808A33681716979D00CF5C8D /* WAFetchManager+RemoteArticlesFetch.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/wammer/Resources/Checked.png b/wammer/Resources/Checked.png new file mode 100644 index 0000000000000000000000000000000000000000..c504b9f2d65e0c342064ff2f6cac0696215bb72d GIT binary patch literal 1726 zcmaJ?X;2eq7!C$vIdtS20TH)r0U1elHzbg(LV0z!9kzcLB@Pb^N2|*kYji(S<5)DQPl;O!3AXG|HF)=2Q z=`*fl{uB!J14T?65hn^mrMQwIG5IibN;Qe5Q2YaQYKb%rBYG1^jg=Nub0C37}J^tF)+&2hQ-KC4P@@o(m6gTF@?qebR0!d6xe&~Rm`pn9LD%Y4ghWSIX;;oM@G-4a zqfiqHTm_gICCPXu!2?O9Z&FaI=V?{i*)ov@gLD!#gfL)JN^_1P(f_+DmGjZ z_pQX*7`+;U#F!S()JVz3rK~iCQlr5dOhVwA7#vTZt74=aCvdGCR|CP(Yz6{|BvOUS zWSK#TM5s`uB_t{-Cgk%#l7pd8$WVkUKwuUU$PMJO5k$b`2!dDw797G2VFrZ=_^dfB zAD3n-F%>a~m62FK4wJ*@!kl+vO~as6lacwDMzI-_g=lakFq1T@c(;~!^UY#qZ_zTF z2lt&?AW{ruYVChoJ!c~4$F!XvT=FnK`k0EGcMUn%?dPbOKps*u@zz zS9HJ54{$9TE)95U?(Gq8do#+F2=AHi#;7dWwBe)dj8&RKE^KZk9$$|&S<(l zby@2d(~-~C8{5NZ9QMua$I^Siq58Ja!)4W;&77~cF{1|J1y21NI^D7@k5rgjR;|KB zRQCO;iHCCjBd_Mzm@Xv3-Er{2s=T87!i0?O8d@U;sVaF(`hJZI-@Roy>qY8;j>^23 zqh=rV*my5l4h<&Jy3lg8{X)1O`$c1P^hQsi_(trL1loD&{r#7ppK6Lp8Uo#VZFk=~ z;miDyE+$-XjX6>+(Z3VN(A+F|PRiYlVcU|3utM7mMgjgQ zZ9(#$?EP0gQjx;_a9dMX|42}^^7iUZgktEiQTv;}x}Ea9duRL0Ze~KF@r1Y+ywL9o zwMNjXyNzj@<`~u00|ko*&07}x^^CVv-kF*(v~x#mM)Sb9$sKp#5|$)r%cb(hHkFHY zxLg^T@HDJesi=C${v&E+={<8FTdT-D!eS0oms+$mj!i93E_#|)lHdD?Xcv4}pK^Ae zzu7tg))BH{Ve$BA-b9<(tz|Z+EsS;?uY_Hrp5+TSS)ccG$^Tksxj9#x(0`u`%>{#~}q(>o{%hMDf?VJ)wS5eckj&5emZjbwQhQ{{fIco2~!= literal 0 HcmV?d00001 diff --git a/wammer/Resources/Checked@2x.png b/wammer/Resources/Checked@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b1ead32cc21eb32304165d6bd68c03979fa1093f GIT binary patch literal 1979 zcmaJ?eNuL)C068j>pNOv^=JzEM{ynDL@-x1;V1i^!gl1uR5-kFR%Fs*%j8aMDNFpMU zTATU_3kw~)<49rC2N;MCf`0^|SDrG!q zBU{K2YQhnPGO|F6hzjDw(t>O$M+OB4fq{B1PM|_C38+`)sC8UD4|>AO#rNhg9Ri=E zVA(wAsi1YJ;`oA02F#$tOgbZg3NyIu04@UtpFI#> zO)JadCh{Ym)xu9aNP%G*E}fp2mq*L6Pz@L^V$)zy zD3L1F=ExI-P{@r^>oAF0ibU~w5Y9nUDrH=lBY+t!*q;;1VZ*S1xlRzq60jH%oCs!E zgn-YQ$MR8Wt_o3O^H|vnY`}t8vl&zxyfPorD&Ih45n5CQK53e(Tv!WhLB3~L*}_`b z3u5WG7`l11{~Gmt2=|Y9``ozr;koq@HSTvUZfviBsjUEDNsZ!%iuFH@r=&%SLmfR+ z>`w?9+kOD4SL2z@-ag&MhqhLB-dX8`JNvJmP6+02eowg9d1&VTZRj_4YeE zKu2MWVe?9O?}`r=S9SGY>p$mn?~I>rtiS(G@#M{)|G0N%=F#YopM11m=<4Bth+Lv< zhz_I`cFxm+zUi_k>g-Uh0lwY?ca(`o8f?Crvl_o#1as{!knUNi2}^+@|3~dh+)De5 zH}$MTCH(3^xxMf5dz7g@**On`LvzjHS$*+{FvEJXW5;ZTx>{xY$OyFA)?_vi{7Q3; zw2bDMgtx{znjX6Q*cs#hwroin=K3c*u;>7*NKJ_f$S-r?y-MKvt)-XMK$&#O$ztEq zb2plY4)vA9j)*oBmW+Hbq=_vjI6s(ilH~a+B=zcAJN%qKSduU&%Kq2HLCIlTGjlAP6~4m@fVCC}GW~!@HKZhn*A= zeFP4M(si+E?I#Eu4*R5VUn!Rdc#(UWM~PbD_;k^rysg1Ecx~;Mj1$8Tco{SM&KL_0 zyyP8_Rwzh^W2Ub5-_B_&1am@;_L%I+6R#g1x!_f=KF$9gh;{FcU3SU-@w*A2ETlE< z!EVabx5wa*?P`2Y)Ia!s#^8#s@?Fp;I|*T;RAtYaoVZP8M@>|=;BNS7$n@&c3A>_V zcYSZI#lckud4s)?cmKWWpu2NpWX`T|R(zp8^&1s1v!tf}>&NlE<;T~27;@3Fx|>p# z3InAQFPDdk&WGcL`?}U&aqKGzy4?8A*|~sA^k12wjkBTl#3rUo?c}W(>vo&kE=rK$ z2g2~D@`CTKcO%;(rgpxOKrE9rmYlcjGuhLTQR1eW?be_oEV=O48?9bNr@AS%NZB`w z>gsbFBE3mBYrCbhGZ&o)ph35*2ikmkKM@6*%B}=|Z0Af!PugPji*Ud@NWu2VswOU8 zcJ1u?%yg$!zt27HVTuM{%bv5YKj7}vVe!{0H^Od1`KApU2gx>**M7`9)g`_Ae*5)` zv7Uj~oW1}_9l&2Loq#VT+Y}qm$L|6`w_qvo#0P=8m~^?9p527PY#S z=!vPS$hafTP0K3(Jic##gZ>rY_O`u>-q}9{b4#Vzy67HAG z)Op5U**sNl42upsLo=M8A>BV3leBlc_$*yR-nsqna9c`d&EBEtXe@eqj~lw%Qt4RH z<+3tWQF>`?%Wc;QZ9&d(lI>K)QY7w%mSX_HFfq=f}BNs$BhRoQ%^djoVww9 sH|yoBy5SI0ch3%j4e{{jgsoQ2K;86aS7>Ix-uyd_62$Ra!!ox017S=CXaE2J literal 0 HcmV?d00001 diff --git a/wammer/Resources/PartioLogin.png b/wammer/Resources/PartioLogin.png new file mode 100644 index 0000000000000000000000000000000000000000..fe8ea8e45558ce627ba385e0ed8d86bba5acbd30 GIT binary patch literal 144174 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

S?m zAwPA{ZkrEEEEI7Bf2IA*PO)hEpn1&cU68|B%#2MTOnbKP1l?Bp0`c<^ZH<1|5#z?% zD)ia_q^FmA0#Y+X9psi4e>`9&n*7R~YO36h(Z>2bw*zw87sBo*bC{S%6^p5=;`T0L zNA~AtE-ENI9xt9D2>Kk_ZjAL3MA1DZ5MjZ-N(z8^eK*8IDhNrV$D=R)H4MjL#4&~(ivptyE{1{&)HZL z+u}@qdVqMk&9S_D+FK58dhKT2>iQVpQJ@0N#gPmZoq!Ie zPYI_t7=f)m)oN!e-bnw16-OPk8cb=I!z&kuyV$bUU1k#$r8k8$h0@!QuHd2R=smddVD8w*hN@ORP*vi93NSN-*WN*c@?x(kPHxkCfF$~4jV^69&?&Phe? z>oHuhV!WMG+%s(;2fqNAutw_bkwj&SDR3|a@zIqD!sLyXdGt&9lF8OQL|RJ94t_-@ zROE1I!FIy~9`hw-^hc-NQCd^NE4TOcA?^+Na|pi=gJ&4oL3lFU7`WD9iw~ZU#solR z`Y4~EQ{@u`jC6i+U2y+vREmSv8H%x#fGtsKs*3{=F@UP>(JI?Lvp0k{(I|kMwU3t~ zuB#p)c5MC9*YyLR)j|}gmRhNi_(lwxQ1st&4_pSNE)^Y18(5U~M>Bg#u?aD90Rw1^;*&=t+zt5;zj0itFexSv

GhPp$x@RI>gd1S;a-I52+iqjS$W^8 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