mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Add 'submodules/AsyncDisplayKit/' from commit '02bedc12816e251ad71777f9d2578329b6d2bef6'
git-subtree-dir: submodules/AsyncDisplayKit git-subtree-mainline:d06f423e0egit-subtree-split:02bedc1281
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '9.0'
|
||||
target 'Sample' do
|
||||
pod 'Texture', :path => '../..'
|
||||
end
|
||||
@@ -0,0 +1,412 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 46;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
25FDEC921BF31EE700CEB123 /* ItemNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 25FDEC911BF31EE700CEB123 /* ItemNode.m */; };
|
||||
7A83848E1C34359D002CDD08 /* ItemViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A83848D1C34359D002CDD08 /* ItemViewModel.m */; };
|
||||
7A8384941C343680002CDD08 /* BlurbNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A8384921C343680002CDD08 /* BlurbNode.m */; };
|
||||
7A8384971C344057002CDD08 /* ItemStyles.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A8384961C344057002CDD08 /* ItemStyles.m */; };
|
||||
7ACD5F891C415B7500E7BE16 /* LoadingNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ACD5F881C415B7500E7BE16 /* LoadingNode.m */; };
|
||||
7ACD5F961C4847C000E7BE16 /* PlaceholderNetworkImageNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ACD5F951C4847C000E7BE16 /* PlaceholderNetworkImageNode.m */; };
|
||||
91C402838901BD02685337A8 /* libPods-Sample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F1E539014E1F516F00A8F167 /* libPods-Sample.a */; };
|
||||
9BA2CEA11BB2579C00D18414 /* Launchboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9BA2CEA01BB2579C00D18414 /* Launchboard.storyboard */; };
|
||||
AC3C4A641A11F47200143C57 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A631A11F47200143C57 /* main.m */; };
|
||||
AC3C4A671A11F47200143C57 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A661A11F47200143C57 /* AppDelegate.m */; };
|
||||
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = AC3C4A691A11F47200143C57 /* ViewController.m */; };
|
||||
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AC3C4A8D1A11F80C00143C57 /* Images.xcassets */; };
|
||||
CC142599219742CA009851B7 /* ASDisplayNode+CatDeals.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC142598219742CA009851B7 /* ASDisplayNode+CatDeals.mm */; };
|
||||
FC3FCA801C2B1564009F6D6D /* PresentingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
25FDEC901BF31EE700CEB123 /* ItemNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ItemNode.h; sourceTree = "<group>"; };
|
||||
25FDEC911BF31EE700CEB123 /* ItemNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ItemNode.m; sourceTree = "<group>"; };
|
||||
65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.release.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.release.xcconfig"; sourceTree = "<group>"; };
|
||||
7A83848C1C34359D002CDD08 /* ItemViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ItemViewModel.h; sourceTree = "<group>"; };
|
||||
7A83848D1C34359D002CDD08 /* ItemViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ItemViewModel.m; sourceTree = "<group>"; };
|
||||
7A8384911C343680002CDD08 /* BlurbNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlurbNode.h; sourceTree = "<group>"; };
|
||||
7A8384921C343680002CDD08 /* BlurbNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlurbNode.m; sourceTree = "<group>"; };
|
||||
7A8384951C344057002CDD08 /* ItemStyles.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ItemStyles.h; sourceTree = "<group>"; };
|
||||
7A8384961C344057002CDD08 /* ItemStyles.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ItemStyles.m; sourceTree = "<group>"; };
|
||||
7ACD5F871C415B7500E7BE16 /* LoadingNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingNode.h; sourceTree = "<group>"; };
|
||||
7ACD5F881C415B7500E7BE16 /* LoadingNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingNode.m; sourceTree = "<group>"; };
|
||||
7ACD5F941C4847C000E7BE16 /* PlaceholderNetworkImageNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlaceholderNetworkImageNode.h; sourceTree = "<group>"; };
|
||||
7ACD5F951C4847C000E7BE16 /* PlaceholderNetworkImageNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PlaceholderNetworkImageNode.m; sourceTree = "<group>"; };
|
||||
9BA2CEA01BB2579C00D18414 /* Launchboard.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Launchboard.storyboard; sourceTree = "<group>"; };
|
||||
AC3C4A5E1A11F47200143C57 /* Sample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sample.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
AC3C4A621A11F47200143C57 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
AC3C4A631A11F47200143C57 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
AC3C4A651A11F47200143C57 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
AC3C4A661A11F47200143C57 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
AC3C4A681A11F47200143C57 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
|
||||
AC3C4A691A11F47200143C57 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
|
||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||
CC142598219742CA009851B7 /* ASDisplayNode+CatDeals.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASDisplayNode+CatDeals.mm"; sourceTree = "<group>"; };
|
||||
CC14259A219746C2009851B7 /* ASDisplayNode+CatDeals.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+CatDeals.h"; sourceTree = "<group>"; };
|
||||
F1E539014E1F516F00A8F167 /* libPods-Sample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Sample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Sample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Sample/Pods-Sample.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FC3FCA7E1C2B1564009F6D6D /* PresentingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PresentingViewController.h; sourceTree = "<group>"; };
|
||||
FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PresentingViewController.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
AC3C4A5B1A11F47200143C57 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
91C402838901BD02685337A8 /* libPods-Sample.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
90A2B9C5397C46134C8A793B /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */,
|
||||
65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A551A11F47200143C57 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A601A11F47200143C57 /* Sample */,
|
||||
AC3C4A5F1A11F47200143C57 /* Products */,
|
||||
90A2B9C5397C46134C8A793B /* Pods */,
|
||||
D6E38FF0CB18E3F55CF06437 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A5F1A11F47200143C57 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A5E1A11F47200143C57 /* Sample.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AC3C4A601A11F47200143C57 /* Sample */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A651A11F47200143C57 /* AppDelegate.h */,
|
||||
AC3C4A661A11F47200143C57 /* AppDelegate.m */,
|
||||
AC3C4A681A11F47200143C57 /* ViewController.h */,
|
||||
AC3C4A691A11F47200143C57 /* ViewController.m */,
|
||||
CC14259A219746C2009851B7 /* ASDisplayNode+CatDeals.h */,
|
||||
CC142598219742CA009851B7 /* ASDisplayNode+CatDeals.mm */,
|
||||
7ACD5F941C4847C000E7BE16 /* PlaceholderNetworkImageNode.h */,
|
||||
7ACD5F951C4847C000E7BE16 /* PlaceholderNetworkImageNode.m */,
|
||||
FC3FCA7E1C2B1564009F6D6D /* PresentingViewController.h */,
|
||||
FC3FCA7F1C2B1564009F6D6D /* PresentingViewController.m */,
|
||||
AC3C4A8D1A11F80C00143C57 /* Images.xcassets */,
|
||||
AC3C4A611A11F47200143C57 /* Supporting Files */,
|
||||
25FDEC901BF31EE700CEB123 /* ItemNode.h */,
|
||||
25FDEC911BF31EE700CEB123 /* ItemNode.m */,
|
||||
7A8384951C344057002CDD08 /* ItemStyles.h */,
|
||||
7A8384961C344057002CDD08 /* ItemStyles.m */,
|
||||
7A83848C1C34359D002CDD08 /* ItemViewModel.h */,
|
||||
7A83848D1C34359D002CDD08 /* ItemViewModel.m */,
|
||||
7A8384911C343680002CDD08 /* BlurbNode.h */,
|
||||
7A8384921C343680002CDD08 /* BlurbNode.m */,
|
||||
7ACD5F871C415B7500E7BE16 /* LoadingNode.h */,
|
||||
7ACD5F881C415B7500E7BE16 /* LoadingNode.m */,
|
||||
);
|
||||
indentWidth = 2;
|
||||
path = Sample;
|
||||
sourceTree = "<group>";
|
||||
tabWidth = 2;
|
||||
usesTabs = 0;
|
||||
};
|
||||
AC3C4A611A11F47200143C57 /* Supporting Files */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AC3C4A621A11F47200143C57 /* Info.plist */,
|
||||
AC3C4A631A11F47200143C57 /* main.m */,
|
||||
9BA2CEA01BB2579C00D18414 /* Launchboard.storyboard */,
|
||||
);
|
||||
name = "Supporting Files";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D6E38FF0CB18E3F55CF06437 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F1E539014E1F516F00A8F167 /* libPods-Sample.a */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
AC3C4A5D1A11F47200143C57 /* Sample */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = AC3C4A811A11F47200143C57 /* Build configuration list for PBXNativeTarget "Sample" */;
|
||||
buildPhases = (
|
||||
F868CFBB21824CC9521B6588 /* [CP] Check Pods Manifest.lock */,
|
||||
AC3C4A5A1A11F47200143C57 /* Sources */,
|
||||
AC3C4A5B1A11F47200143C57 /* Frameworks */,
|
||||
AC3C4A5C1A11F47200143C57 /* Resources */,
|
||||
A6902C454C7661D0D277AC62 /* [CP] Copy Pods Resources */,
|
||||
B4CD33E927E6F4EE5DD6CCF0 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Sample;
|
||||
productName = Sample;
|
||||
productReference = AC3C4A5E1A11F47200143C57 /* Sample.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
AC3C4A561A11F47200143C57 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0610;
|
||||
ORGANIZATIONNAME = Facebook;
|
||||
TargetAttributes = {
|
||||
AC3C4A5D1A11F47200143C57 = {
|
||||
CreatedOnToolsVersion = 6.1;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = AC3C4A591A11F47200143C57 /* Build configuration list for PBXProject "Sample" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = AC3C4A551A11F47200143C57;
|
||||
productRefGroup = AC3C4A5F1A11F47200143C57 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
AC3C4A5D1A11F47200143C57 /* Sample */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
AC3C4A5C1A11F47200143C57 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9BA2CEA11BB2579C00D18414 /* Launchboard.storyboard in Resources */,
|
||||
AC3C4A8E1A11F80C00143C57 /* Images.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
A6902C454C7661D0D277AC62 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B4CD33E927E6F4EE5DD6CCF0 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Sample/Pods-Sample-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
F868CFBB21824CC9521B6588 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||
"${PODS_ROOT}/Manifest.lock",
|
||||
);
|
||||
name = "[CP] Check Pods Manifest.lock";
|
||||
outputPaths = (
|
||||
"$(DERIVED_FILE_DIR)/Pods-Sample-checkManifestLockResult.txt",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
AC3C4A5A1A11F47200143C57 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CC142599219742CA009851B7 /* ASDisplayNode+CatDeals.mm in Sources */,
|
||||
25FDEC921BF31EE700CEB123 /* ItemNode.m in Sources */,
|
||||
7ACD5F891C415B7500E7BE16 /* LoadingNode.m in Sources */,
|
||||
AC3C4A6A1A11F47200143C57 /* ViewController.m in Sources */,
|
||||
7A8384971C344057002CDD08 /* ItemStyles.m in Sources */,
|
||||
FC3FCA801C2B1564009F6D6D /* PresentingViewController.m in Sources */,
|
||||
7A8384941C343680002CDD08 /* BlurbNode.m in Sources */,
|
||||
7A83848E1C34359D002CDD08 /* ItemViewModel.m in Sources */,
|
||||
AC3C4A671A11F47200143C57 /* AppDelegate.m in Sources */,
|
||||
7ACD5F961C4847C000E7BE16 /* PlaceholderNetworkImageNode.m in Sources */,
|
||||
AC3C4A641A11F47200143C57 /* main.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
AC3C4A7F1A11F47200143C57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AC3C4A801A11F47200143C57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = YES;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
AC3C4A821A11F47200143C57 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = F3A72D578C378357FF56486A /* Pods-Sample.debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
AC3C4A831A11F47200143C57 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 65F7AC562A910A742522053C /* Pods-Sample.release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
|
||||
INFOPLIST_FILE = Sample/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
AC3C4A591A11F47200143C57 /* Build configuration list for PBXProject "Sample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
AC3C4A7F1A11F47200143C57 /* Debug */,
|
||||
AC3C4A801A11F47200143C57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
AC3C4A811A11F47200143C57 /* Build configuration list for PBXNativeTarget "Sample" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
AC3C4A821A11F47200143C57 /* Debug */,
|
||||
AC3C4A831A11F47200143C57 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = AC3C4A561A11F47200143C57 /* Project object */;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:Sample.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0620"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "AC3C4A5D1A11F47200143C57"
|
||||
BuildableName = "Sample.app"
|
||||
BlueprintName = "Sample"
|
||||
ReferencedContainer = "container:Sample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// ASDisplayNode+CatDeals.h
|
||||
// Sample
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ASDisplayNode (CatDeals)
|
||||
|
||||
@property (nullable, copy) NSString *catsLoggingID;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// ASDisplayNode+CatDeals.mm
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
#import "ASDisplayNode+CatDeals.h"
|
||||
|
||||
#import <AsyncDisplayKit/ASThread.h>
|
||||
|
||||
// A place to store info on any display node in this app.
|
||||
struct CatDealsNodeContext {
|
||||
NSString *loggingID = nil;
|
||||
};
|
||||
|
||||
// Convenience to cast _displayNodeContext into our struct reference.
|
||||
NS_INLINE CatDealsNodeContext &GetNodeContext(ASDisplayNode *node) {
|
||||
return *static_cast<CatDealsNodeContext *>(node->_displayNodeContext);
|
||||
}
|
||||
|
||||
@implementation ASDisplayNode (CatDeals)
|
||||
|
||||
- (void)baseDidInit
|
||||
{
|
||||
_displayNodeContext = new CatDealsNodeContext;
|
||||
}
|
||||
|
||||
- (void)baseWillDealloc
|
||||
{
|
||||
delete &GetNodeContext(self);
|
||||
}
|
||||
|
||||
- (void)setCatsLoggingID:(NSString *)catsLoggingID
|
||||
{
|
||||
NSString *copy = [catsLoggingID copy];
|
||||
ASLockScopeSelf();
|
||||
GetNodeContext(self).loggingID = copy;
|
||||
}
|
||||
|
||||
- (NSString *)catsLoggingID
|
||||
{
|
||||
ASLockScopeSelf();
|
||||
return GetNodeContext(self).loggingID;
|
||||
}
|
||||
|
||||
- (void)didEnterVisibleState
|
||||
{
|
||||
if (NSString *loggingID = self.catsLoggingID) {
|
||||
NSLog(@"Visible: %@", loggingID);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didExitVisibleState
|
||||
{
|
||||
if (NSString *loggingID = self.catsLoggingID) {
|
||||
NSLog(@"NotVisible: %@", loggingID);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AppDelegate.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#define SIMULATE_WEB_RESPONSE 0
|
||||
|
||||
@interface AppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// AppDelegate.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
#import "PresentingViewController.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@implementation AppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
self.window.backgroundColor = [UIColor whiteColor];
|
||||
self.window.rootViewController = [[UINavigationController alloc] init];
|
||||
|
||||
[self pushNewViewControllerAnimated:NO];
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)pushNewViewControllerAnimated:(BOOL)animated
|
||||
{
|
||||
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
|
||||
|
||||
#if SIMULATE_WEB_RESPONSE
|
||||
UIViewController *viewController = [[PresentingViewController alloc] init];
|
||||
#else
|
||||
UIViewController *viewController = [[ViewController alloc] init];
|
||||
viewController.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Push Another Copy" style:UIBarButtonItemStylePlain target:self action:@selector(pushNewViewController)];
|
||||
#endif
|
||||
|
||||
[navController pushViewController:viewController animated:animated];
|
||||
}
|
||||
|
||||
- (void)pushNewViewController
|
||||
{
|
||||
[self pushNewViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// BlurbNode.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
/**
|
||||
* Simple node that displays a placekitten.com attribution.
|
||||
*/
|
||||
@interface BlurbNode : ASCellNode
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,104 @@
|
||||
//
|
||||
// BlurbNode.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "BlurbNode.h"
|
||||
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||
#import <AsyncDisplayKit/ASHighlightOverlayLayer.h>
|
||||
|
||||
#import <AsyncDisplayKit/ASInsetLayoutSpec.h>
|
||||
#import <AsyncDisplayKit/ASCenterLayoutSpec.h>
|
||||
|
||||
static CGFloat kTextPadding = 10.0f;
|
||||
|
||||
@interface BlurbNode () <ASTextNodeDelegate>
|
||||
{
|
||||
ASTextNode *_textNode;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation BlurbNode
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark ASCellNode.
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
self.backgroundColor = [UIColor lightGrayColor];
|
||||
// create a text node
|
||||
_textNode = [[ASTextNode alloc] init];
|
||||
_textNode.maximumNumberOfLines = 2;
|
||||
|
||||
// configure the node to support tappable links
|
||||
_textNode.delegate = self;
|
||||
_textNode.userInteractionEnabled = YES;
|
||||
|
||||
// generate an attributed string using the custom link attribute specified above
|
||||
NSString *blurb = @"Kittens courtesy lorempixel.com \U0001F638 \nTitles courtesy of catipsum.com";
|
||||
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:blurb];
|
||||
[string addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"HelveticaNeue-Light" size:16.0f] range:NSMakeRange(0, blurb.length)];
|
||||
[string addAttributes:@{
|
||||
NSLinkAttributeName: [NSURL URLWithString:@"http://lorempixel.com/"],
|
||||
NSForegroundColorAttributeName: [UIColor blueColor],
|
||||
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot),
|
||||
} range:[blurb rangeOfString:@"lorempixel.com"]];
|
||||
[string addAttributes:@{
|
||||
NSLinkAttributeName: [NSURL URLWithString:@"http://www.catipsum.com/"],
|
||||
NSForegroundColorAttributeName: [UIColor blueColor],
|
||||
NSUnderlineStyleAttributeName: @(NSUnderlineStyleSingle | NSUnderlinePatternDot),
|
||||
} range:[blurb rangeOfString:@"catipsum.com"]];
|
||||
_textNode.attributedText = string;
|
||||
|
||||
// add it as a subnode, and we're done
|
||||
[self addSubnode:_textNode];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didLoad
|
||||
{
|
||||
// enable highlighting now that self.layer has loaded -- see ASHighlightOverlayLayer.h
|
||||
self.layer.as_allowsHighlightDrawing = YES;
|
||||
|
||||
[super didLoad];
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
ASCenterLayoutSpec *centerSpec = [[ASCenterLayoutSpec alloc] init];
|
||||
centerSpec.centeringOptions = ASCenterLayoutSpecCenteringX;
|
||||
centerSpec.sizingOptions = ASCenterLayoutSpecSizingOptionMinimumY;
|
||||
centerSpec.child = _textNode;
|
||||
|
||||
UIEdgeInsets padding = UIEdgeInsetsMake(kTextPadding, kTextPadding, kTextPadding, kTextPadding);
|
||||
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:padding child:centerSpec];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark ASTextNodeDelegate methods.
|
||||
|
||||
- (BOOL)textNode:(ASTextNode *)richTextNode shouldHighlightLinkAttribute:(NSString *)attribute value:(id)value atPoint:(CGPoint)point
|
||||
{
|
||||
// opt into link highlighting -- tap and hold the link to try it! must enable highlighting on a layer, see -didLoad
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textNode:(ASTextNode *)richTextNode tappedLinkAttribute:(NSString *)attribute value:(NSURL *)URL atPoint:(CGPoint)point textRange:(NSRange)textRange
|
||||
{
|
||||
// the node tapped a link, open it
|
||||
[[UIApplication sharedApplication] openURL:URL];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"images" : [
|
||||
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "cat_face.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
<key>NSExceptionDomains</key>
|
||||
<dict>
|
||||
<key>http://lorempixel.com</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIcons</key>
|
||||
<dict/>
|
||||
<key>CFBundleIcons~ipad</key>
|
||||
<dict/>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>com.facebook.AsyncDisplayKit.$(PRODUCT_NAME:rfc1034identifier)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>Launchboard</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// ItemNode.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import "ItemViewModel.h"
|
||||
|
||||
@interface ItemNode : ASCellNode
|
||||
|
||||
+ (CGSize)sizeForWidth:(CGFloat)width;
|
||||
+ (CGSize)preferredViewSize;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,393 @@
|
||||
//
|
||||
// ItemNode.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "ItemNode.h"
|
||||
|
||||
#import "ASDisplayNode+CatDeals.h"
|
||||
#import "ItemStyles.h"
|
||||
#import "PlaceholderNetworkImageNode.h"
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
|
||||
static CGFloat ASIsRTL()
|
||||
{
|
||||
static BOOL __isRTL = NO;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
__isRTL = [UIApplication sharedApplication].userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
|
||||
});
|
||||
return __isRTL;
|
||||
}
|
||||
|
||||
const CGFloat kFixedLabelsAreaHeight = 96.0;
|
||||
const CGFloat kDesignWidth = 320.0;
|
||||
const CGFloat kDesignHeight = 299.0;
|
||||
const CGFloat kBadgeHeight = 34.0;
|
||||
const CGFloat kSoldOutGBHeight = 50.0;
|
||||
|
||||
@interface ItemNode() <ASNetworkImageNodeDelegate>
|
||||
|
||||
@property (nonatomic, strong) ItemViewModel *nodeModel;
|
||||
|
||||
@property (nonatomic, strong) PlaceholderNetworkImageNode *dealImageView;
|
||||
|
||||
@property (nonatomic, strong) ASTextNode *titleLabel;
|
||||
@property (nonatomic, strong) ASTextNode *firstInfoLabel;
|
||||
@property (nonatomic, strong) ASTextNode *distanceLabel;
|
||||
@property (nonatomic, strong) ASTextNode *secondInfoLabel;
|
||||
@property (nonatomic, strong) ASTextNode *originalPriceLabel;
|
||||
@property (nonatomic, strong) ASTextNode *finalPriceLabel;
|
||||
@property (nonatomic, strong) ASTextNode *soldOutLabelFlat;
|
||||
@property (nonatomic, strong) ASDisplayNode *soldOutLabelBackground;
|
||||
@property (nonatomic, strong) ASDisplayNode *soldOutOverlay;
|
||||
@property (nonatomic, strong) ASTextNode *badge;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ItemNode
|
||||
// Defined on ASCellNode
|
||||
@dynamic nodeModel;
|
||||
|
||||
+ (void)load
|
||||
{
|
||||
// Need to happen on main thread.
|
||||
ASIsRTL();
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
[self setupNodes];
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setNodeModel:(ItemViewModel *)nodeModel
|
||||
{
|
||||
[super setNodeModel:nodeModel];
|
||||
|
||||
self.catsLoggingID = [NSString stringWithFormat:@"CatDeal#%ld", (long)nodeModel.identifier];
|
||||
[self updateLabels];
|
||||
[self updateAccessibilityIdentifier];
|
||||
}
|
||||
|
||||
- (void)setupNodes
|
||||
{
|
||||
self.dealImageView = [[PlaceholderNetworkImageNode alloc] init];
|
||||
self.dealImageView.delegate = self;
|
||||
self.dealImageView.placeholderEnabled = YES;
|
||||
self.dealImageView.placeholderImageOverride = [ItemStyles placeholderImage];
|
||||
self.dealImageView.defaultImage = [ItemStyles placeholderImage];
|
||||
self.dealImageView.contentMode = UIViewContentModeScaleToFill;
|
||||
self.dealImageView.placeholderFadeDuration = 0.0;
|
||||
self.dealImageView.layerBacked = YES;
|
||||
|
||||
self.titleLabel = [[ASTextNode alloc] init];
|
||||
self.titleLabel.maximumNumberOfLines = 2;
|
||||
self.titleLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
self.titleLabel.style.flexGrow = 1.0;
|
||||
self.titleLabel.layerBacked = YES;
|
||||
|
||||
self.firstInfoLabel = [[ASTextNode alloc] init];
|
||||
self.firstInfoLabel.maximumNumberOfLines = 1;
|
||||
self.firstInfoLabel.layerBacked = YES;
|
||||
|
||||
self.secondInfoLabel = [[ASTextNode alloc] init];
|
||||
self.secondInfoLabel.maximumNumberOfLines = 1;
|
||||
self.secondInfoLabel.layerBacked = YES;
|
||||
|
||||
self.distanceLabel = [[ASTextNode alloc] init];
|
||||
self.distanceLabel.maximumNumberOfLines = 1;
|
||||
self.distanceLabel.layerBacked = YES;
|
||||
|
||||
self.originalPriceLabel = [[ASTextNode alloc] init];
|
||||
self.originalPriceLabel.maximumNumberOfLines = 1;
|
||||
self.originalPriceLabel.layerBacked = YES;
|
||||
|
||||
self.finalPriceLabel = [[ASTextNode alloc] init];
|
||||
self.finalPriceLabel.maximumNumberOfLines = 1;
|
||||
self.finalPriceLabel.layerBacked = YES;
|
||||
|
||||
self.badge = [[ASTextNode alloc] init];
|
||||
self.badge.hidden = YES;
|
||||
self.badge.layerBacked = YES;
|
||||
|
||||
self.soldOutLabelFlat = [[ASTextNode alloc] init];
|
||||
self.soldOutLabelFlat.layerBacked = YES;
|
||||
|
||||
self.soldOutLabelBackground = [[ASDisplayNode alloc] init];
|
||||
self.soldOutLabelBackground.style.width = ASDimensionMakeWithFraction(1.0);
|
||||
self.soldOutLabelBackground.style.height = ASDimensionMakeWithPoints(kSoldOutGBHeight);
|
||||
self.soldOutLabelBackground.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.9];
|
||||
self.soldOutLabelBackground.style.flexGrow = 1.0;
|
||||
self.soldOutLabelBackground.layerBacked = YES;
|
||||
|
||||
self.soldOutOverlay = [[ASDisplayNode alloc] init];
|
||||
self.soldOutOverlay.style.flexGrow = 1.0;
|
||||
self.soldOutOverlay.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.5];
|
||||
self.soldOutOverlay.layerBacked = YES;
|
||||
|
||||
[self addSubnode:self.dealImageView];
|
||||
[self addSubnode:self.titleLabel];
|
||||
[self addSubnode:self.firstInfoLabel];
|
||||
[self addSubnode:self.secondInfoLabel];
|
||||
[self addSubnode:self.originalPriceLabel];
|
||||
[self addSubnode:self.finalPriceLabel];
|
||||
[self addSubnode:self.distanceLabel];
|
||||
[self addSubnode:self.badge];
|
||||
|
||||
[self addSubnode:self.soldOutLabelBackground];
|
||||
[self addSubnode:self.soldOutLabelFlat];
|
||||
[self addSubnode:self.soldOutOverlay];
|
||||
self.soldOutOverlay.hidden = YES;
|
||||
self.soldOutLabelBackground.hidden = YES;
|
||||
self.soldOutLabelFlat.hidden = YES;
|
||||
|
||||
if (ASIsRTL()) {
|
||||
self.titleLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
self.firstInfoLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
self.distanceLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
self.secondInfoLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
self.originalPriceLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
self.finalPriceLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
} else {
|
||||
self.firstInfoLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
self.distanceLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
self.secondInfoLabel.style.alignSelf = ASStackLayoutAlignSelfStart;
|
||||
self.originalPriceLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
self.finalPriceLabel.style.alignSelf = ASStackLayoutAlignSelfEnd;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updateLabels
|
||||
{
|
||||
// Set Title text
|
||||
if (self.nodeModel.titleText) {
|
||||
self.titleLabel.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.titleText attributes:[ItemStyles titleStyle]];
|
||||
}
|
||||
if (self.nodeModel.firstInfoText) {
|
||||
self.firstInfoLabel.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.firstInfoText attributes:[ItemStyles subtitleStyle]];
|
||||
}
|
||||
|
||||
if (self.nodeModel.secondInfoText) {
|
||||
self.secondInfoLabel.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.secondInfoText attributes:[ItemStyles secondInfoStyle]];
|
||||
}
|
||||
if (self.nodeModel.originalPriceText) {
|
||||
self.originalPriceLabel.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.originalPriceText attributes:[ItemStyles originalPriceStyle]];
|
||||
}
|
||||
if (self.nodeModel.finalPriceText) {
|
||||
self.finalPriceLabel.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.finalPriceText attributes:[ItemStyles finalPriceStyle]];
|
||||
}
|
||||
if (self.nodeModel.distanceLabelText) {
|
||||
NSString *format = ASIsRTL() ? @"%@ •" : @"• %@";
|
||||
NSString *distanceText = [NSString stringWithFormat:format, self.nodeModel.distanceLabelText];
|
||||
|
||||
self.distanceLabel.attributedText = [[NSAttributedString alloc] initWithString:distanceText attributes:[ItemStyles distanceStyle]];
|
||||
}
|
||||
|
||||
BOOL isSoldOut = self.nodeModel.soldOutText != nil;
|
||||
|
||||
if (isSoldOut) {
|
||||
NSString *soldOutText = self.nodeModel.soldOutText;
|
||||
self.soldOutLabelFlat.attributedText = [[NSAttributedString alloc] initWithString:soldOutText attributes:[ItemStyles soldOutStyle]];
|
||||
}
|
||||
self.soldOutOverlay.hidden = !isSoldOut;
|
||||
self.soldOutLabelFlat.hidden = !isSoldOut;
|
||||
self.soldOutLabelBackground.hidden = !isSoldOut;
|
||||
|
||||
BOOL hasBadge = self.nodeModel.badgeText != nil;
|
||||
if (hasBadge) {
|
||||
self.badge.attributedText = [[NSAttributedString alloc] initWithString:self.nodeModel.badgeText attributes:[ItemStyles badgeStyle]];
|
||||
self.badge.backgroundColor = [ItemStyles badgeColor];
|
||||
}
|
||||
self.badge.hidden = !hasBadge;
|
||||
}
|
||||
|
||||
- (void)updateAccessibilityIdentifier
|
||||
{
|
||||
ASSetDebugName(self, @"Item #%zd", self.nodeModel.identifier);
|
||||
self.accessibilityIdentifier = self.nodeModel.titleText;
|
||||
}
|
||||
|
||||
- (void)updateBackgroundColor
|
||||
{
|
||||
if (self.highlighted) {
|
||||
self.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3];
|
||||
} else if (self.selected) {
|
||||
self.backgroundColor = [UIColor lightGrayColor];
|
||||
} else {
|
||||
self.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected
|
||||
{
|
||||
[super setSelected:selected];
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
|
||||
- (void)setHighlighted:(BOOL)highlighted
|
||||
{
|
||||
[super setHighlighted:highlighted];
|
||||
[self updateBackgroundColor];
|
||||
}
|
||||
|
||||
#pragma mark - ASDisplayNode
|
||||
|
||||
- (void)displayWillStart
|
||||
{
|
||||
[super displayWillStart];
|
||||
[self didEnterPreloadState];
|
||||
}
|
||||
|
||||
- (void)didEnterPreloadState
|
||||
{
|
||||
[super didEnterPreloadState];
|
||||
if (self.nodeModel) {
|
||||
[self loadImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize {
|
||||
|
||||
ASLayoutSpec *textSpec = [self textSpec];
|
||||
ASLayoutSpec *imageSpec = [self imageSpecWithSize:constrainedSize];
|
||||
ASOverlayLayoutSpec *soldOutOverImage = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:imageSpec overlay:[self soldOutLabelSpec]];
|
||||
|
||||
NSArray *stackChildren = @[soldOutOverImage, textSpec];
|
||||
|
||||
ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsStretch children:stackChildren];
|
||||
|
||||
ASOverlayLayoutSpec *soldOutOverlay = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:mainStack overlay:self.soldOutOverlay];
|
||||
|
||||
return soldOutOverlay;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)textSpec
|
||||
{
|
||||
CGFloat kInsetHorizontal = 16.0;
|
||||
CGFloat kInsetTop = 6.0;
|
||||
CGFloat kInsetBottom = 0.0;
|
||||
|
||||
UIEdgeInsets textInsets = UIEdgeInsetsMake(kInsetTop, kInsetHorizontal, kInsetBottom, kInsetHorizontal);
|
||||
|
||||
ASLayoutSpec *verticalSpacer = [[ASLayoutSpec alloc] init];
|
||||
verticalSpacer.style.flexGrow = 1.0;
|
||||
|
||||
ASLayoutSpec *horizontalSpacer1 = [[ASLayoutSpec alloc] init];
|
||||
horizontalSpacer1.style.flexGrow = 1.0;
|
||||
|
||||
ASLayoutSpec *horizontalSpacer2 = [[ASLayoutSpec alloc] init];
|
||||
horizontalSpacer2.style.flexGrow = 1.0;
|
||||
|
||||
NSArray *info1Children = @[self.firstInfoLabel, self.distanceLabel, horizontalSpacer1, self.originalPriceLabel];
|
||||
NSArray *info2Children = @[self.secondInfoLabel, horizontalSpacer2, self.finalPriceLabel];
|
||||
if (ASIsRTL()) {
|
||||
info1Children = [[info1Children reverseObjectEnumerator] allObjects];
|
||||
info2Children = [[info2Children reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
ASStackLayoutSpec *info1Stack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:1.0 justifyContent:ASStackLayoutJustifyContentStart alignItems:ASStackLayoutAlignItemsBaselineLast children:info1Children];
|
||||
|
||||
ASStackLayoutSpec *info2Stack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0.0 justifyContent:ASStackLayoutJustifyContentCenter alignItems:ASStackLayoutAlignItemsBaselineLast children:info2Children];
|
||||
|
||||
ASStackLayoutSpec *textStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:0.0 justifyContent:ASStackLayoutJustifyContentEnd alignItems:ASStackLayoutAlignItemsStretch children:@[self.titleLabel, verticalSpacer, info1Stack, info2Stack]];
|
||||
|
||||
ASInsetLayoutSpec *textWrapper = [ASInsetLayoutSpec insetLayoutSpecWithInsets:textInsets child:textStack];
|
||||
textWrapper.style.flexGrow = 1.0;
|
||||
|
||||
return textWrapper;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)imageSpecWithSize:(ASSizeRange)constrainedSize
|
||||
{
|
||||
CGFloat imageRatio = [self imageRatioFromSize:constrainedSize.max];
|
||||
|
||||
ASRatioLayoutSpec *imagePlace = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:imageRatio child:self.dealImageView];
|
||||
|
||||
self.badge.style.layoutPosition = CGPointMake(0, constrainedSize.max.height - kFixedLabelsAreaHeight - kBadgeHeight);
|
||||
self.badge.style.height = ASDimensionMakeWithPoints(kBadgeHeight);
|
||||
ASAbsoluteLayoutSpec *badgePosition = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[self.badge]];
|
||||
|
||||
ASOverlayLayoutSpec *badgeOverImage = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:imagePlace overlay:badgePosition];
|
||||
badgeOverImage.style.flexGrow = 1.0;
|
||||
|
||||
return badgeOverImage;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)soldOutLabelSpec {
|
||||
ASCenterLayoutSpec *centerSoldOutLabel = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionMinimumXY child:self.soldOutLabelFlat];
|
||||
ASCenterLayoutSpec *centerSoldOut = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:self.soldOutLabelBackground];
|
||||
ASBackgroundLayoutSpec *soldOutLabelOverBackground = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:centerSoldOutLabel background:centerSoldOut];
|
||||
return soldOutLabelOverBackground;
|
||||
}
|
||||
|
||||
+ (CGSize)sizeForWidth:(CGFloat)width
|
||||
{
|
||||
CGFloat height = [self scaledHeightForPreferredSize:[self preferredViewSize] scaledWidth:width];
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
|
||||
+ (CGSize)preferredViewSize
|
||||
{
|
||||
return CGSizeMake(kDesignWidth, kDesignHeight);
|
||||
}
|
||||
|
||||
+ (CGFloat)scaledHeightForPreferredSize:(CGSize)preferredSize scaledWidth:(CGFloat)scaledWidth
|
||||
{
|
||||
CGFloat scale = scaledWidth / kDesignWidth;
|
||||
CGFloat scaledHeight = ceilf(scale * (kDesignHeight - kFixedLabelsAreaHeight)) + kFixedLabelsAreaHeight;
|
||||
|
||||
return scaledHeight;
|
||||
}
|
||||
|
||||
#pragma mark - Image
|
||||
|
||||
- (CGFloat)imageRatioFromSize:(CGSize)size
|
||||
{
|
||||
CGFloat imageHeight = size.height - kFixedLabelsAreaHeight;
|
||||
CGFloat imageRatio = imageHeight / size.width;
|
||||
|
||||
return imageRatio;
|
||||
}
|
||||
|
||||
- (CGSize)imageSize
|
||||
{
|
||||
if (!CGSizeEqualToSize(self.dealImageView.frame.size, CGSizeZero)) {
|
||||
return self.dealImageView.frame.size;
|
||||
} else if (!CGSizeEqualToSize(self.calculatedSize, CGSizeZero)) {
|
||||
CGFloat imageRatio = [self imageRatioFromSize:self.calculatedSize];
|
||||
CGFloat imageWidth = self.calculatedSize.width;
|
||||
return CGSizeMake(imageWidth, imageRatio * imageWidth);
|
||||
} else {
|
||||
return CGSizeZero;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadImage
|
||||
{
|
||||
CGSize imageSize = [self imageSize];
|
||||
if (CGSizeEqualToSize(CGSizeZero, imageSize)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NSURL *url = [self.nodeModel imageURLWithSize:imageSize];
|
||||
|
||||
// if we're trying to set the deal image to what it already was, skip the work
|
||||
if ([[url absoluteString] isEqualToString:[self.dealImageView.URL absoluteString]]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the flag that says we've loaded our image
|
||||
[self.dealImageView setURL:url];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// ItemStyles.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ItemStyles : NSObject
|
||||
+ (NSDictionary *)titleStyle;
|
||||
+ (NSDictionary *)subtitleStyle;
|
||||
+ (NSDictionary *)distanceStyle;
|
||||
+ (NSDictionary *)secondInfoStyle;
|
||||
+ (NSDictionary *)originalPriceStyle;
|
||||
+ (NSDictionary *)finalPriceStyle;
|
||||
+ (NSDictionary *)soldOutStyle;
|
||||
+ (NSDictionary *)badgeStyle;
|
||||
+ (UIColor *)badgeColor;
|
||||
+ (UIImage *)placeholderImage;
|
||||
@end
|
||||
@@ -0,0 +1,95 @@
|
||||
//
|
||||
// ItemStyles.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "ItemStyles.h"
|
||||
|
||||
const CGFloat kTitleFontSize = 20.0;
|
||||
const CGFloat kInfoFontSize = 14.0;
|
||||
|
||||
UIColor *kTitleColor;
|
||||
UIColor *kInfoColor;
|
||||
UIColor *kFinalPriceColor;
|
||||
UIFont *kTitleFont;
|
||||
UIFont *kInfoFont;
|
||||
|
||||
@implementation ItemStyles
|
||||
|
||||
+ (void)initialize {
|
||||
if (self == [ItemStyles class]) {
|
||||
kTitleColor = [UIColor darkGrayColor];
|
||||
kInfoColor = [UIColor grayColor];
|
||||
kFinalPriceColor = [UIColor greenColor];
|
||||
kTitleFont = [UIFont boldSystemFontOfSize:kTitleFontSize];
|
||||
kInfoFont = [UIFont systemFontOfSize:kInfoFontSize];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSDictionary *)titleStyle {
|
||||
// Title Label
|
||||
return @{ NSFontAttributeName:kTitleFont,
|
||||
NSForegroundColorAttributeName:kTitleColor };
|
||||
}
|
||||
|
||||
+ (NSDictionary *)subtitleStyle {
|
||||
// First Subtitle
|
||||
return @{ NSFontAttributeName:kInfoFont,
|
||||
NSForegroundColorAttributeName:kInfoColor };
|
||||
}
|
||||
|
||||
+ (NSDictionary *)distanceStyle {
|
||||
// Distance Label
|
||||
return @{ NSFontAttributeName:kInfoFont,
|
||||
NSForegroundColorAttributeName:kInfoColor};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)secondInfoStyle {
|
||||
// Second Subtitle
|
||||
return @{ NSFontAttributeName:kInfoFont,
|
||||
NSForegroundColorAttributeName:kInfoColor};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)originalPriceStyle {
|
||||
// Original price
|
||||
return @{ NSFontAttributeName:kInfoFont,
|
||||
NSForegroundColorAttributeName:kInfoColor,
|
||||
NSStrikethroughStyleAttributeName:@(NSUnderlineStyleSingle)};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)finalPriceStyle {
|
||||
// Discounted / Claimable price label
|
||||
return @{ NSFontAttributeName:kTitleFont,
|
||||
NSForegroundColorAttributeName:kFinalPriceColor};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)soldOutStyle {
|
||||
// Setup Sold Out Label
|
||||
return @{ NSFontAttributeName:kTitleFont,
|
||||
NSForegroundColorAttributeName:kTitleColor};
|
||||
}
|
||||
|
||||
+ (NSDictionary *)badgeStyle {
|
||||
// Setup Sold Out Label
|
||||
return @{ NSFontAttributeName:kTitleFont,
|
||||
NSForegroundColorAttributeName:[UIColor whiteColor]};
|
||||
}
|
||||
|
||||
+ (UIColor *)badgeColor {
|
||||
return [[UIColor purpleColor] colorWithAlphaComponent:0.4];
|
||||
}
|
||||
|
||||
+ (UIImage *)placeholderImage {
|
||||
static UIImage *__catFace = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once (&onceToken, ^{
|
||||
__catFace = [UIImage imageNamed:@"cat_face"];
|
||||
});
|
||||
return __catFace;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// ItemViewModel.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ItemViewModel : NSObject
|
||||
|
||||
+ (ItemViewModel *)randomItem;
|
||||
|
||||
@property (nonatomic, readonly) NSInteger identifier;
|
||||
@property (nonatomic, copy) NSString *titleText;
|
||||
@property (nonatomic, copy) NSString *firstInfoText;
|
||||
@property (nonatomic, copy) NSString *secondInfoText;
|
||||
@property (nonatomic, copy) NSString *originalPriceText;
|
||||
@property (nonatomic, copy) NSString *finalPriceText;
|
||||
@property (nonatomic, copy) NSString *soldOutText;
|
||||
@property (nonatomic, copy) NSString *distanceLabelText;
|
||||
@property (nonatomic, copy) NSString *badgeText;
|
||||
|
||||
- (NSURL *)imageURLWithSize:(CGSize)size;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// ItemViewModel.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "ItemViewModel.h"
|
||||
#import <stdatomic.h>
|
||||
|
||||
NSArray *titles;
|
||||
NSArray *firstInfos;
|
||||
NSArray *badges;
|
||||
|
||||
@interface ItemViewModel()
|
||||
|
||||
@property (nonatomic, assign) NSInteger catNumber;
|
||||
@property (nonatomic, assign) NSInteger labelNumber;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ItemViewModel
|
||||
|
||||
+ (ItemViewModel *)randomItem {
|
||||
return [[ItemViewModel alloc] init];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
static _Atomic(NSInteger) nextID = ATOMIC_VAR_INIT(1);
|
||||
_identifier = atomic_fetch_add(&nextID, 1);
|
||||
_titleText = [self randomObjectFromArray:titles];
|
||||
_firstInfoText = [self randomObjectFromArray:firstInfos];
|
||||
_secondInfoText = [NSString stringWithFormat:@"%zd+ bought", [self randomNumberInRange:5 to:6000]];
|
||||
_originalPriceText = [NSString stringWithFormat:@"$%zd", [self randomNumberInRange:40 to:90]];
|
||||
_finalPriceText = [NSString stringWithFormat:@"$%zd", [self randomNumberInRange:5 to:30]];
|
||||
_soldOutText = (arc4random() % 5 == 0) ? @"SOLD OUT" : nil;
|
||||
_distanceLabelText = [NSString stringWithFormat:@"%zd mi", [self randomNumberInRange:1 to:20]];
|
||||
if (arc4random() % 2 == 0) {
|
||||
_badgeText = [self randomObjectFromArray:badges];
|
||||
}
|
||||
_catNumber = [self randomNumberInRange:1 to:10];
|
||||
_labelNumber = [self randomNumberInRange:1 to:10000];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSURL *)imageURLWithSize:(CGSize)size
|
||||
{
|
||||
NSString *imageText = [NSString stringWithFormat:@"Fun cat pic %zd", self.labelNumber];
|
||||
NSString *urlString = [NSString stringWithFormat:@"http://lorempixel.com/%zd/%zd/cats/%zd/%@",
|
||||
(NSInteger)roundl(size.width),
|
||||
(NSInteger)roundl(size.height), self.catNumber, imageText];
|
||||
|
||||
urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
|
||||
return [NSURL URLWithString:urlString];
|
||||
}
|
||||
|
||||
// titles courtesy of http://www.catipsum.com/
|
||||
+ (void)initialize
|
||||
{
|
||||
titles = @[@"Leave fur on owners clothes intrigued by the shower",
|
||||
@"Meowwww",
|
||||
@"Immediately regret falling into bathtub stare out the window",
|
||||
@"Jump launch to pounce upon little yarn mouse, bare fangs at toy run hide in litter box until treats are fed",
|
||||
@"Sleep nap",
|
||||
@"Lick butt",
|
||||
@"Chase laser lick arm hair present belly, scratch hand when stroked"];
|
||||
firstInfos = @[@"Kitty Shop",
|
||||
@"Cat's r us",
|
||||
@"Fantastic Felines",
|
||||
@"The Cat Shop",
|
||||
@"Cat in a hat",
|
||||
@"Cat-tastic"
|
||||
];
|
||||
|
||||
badges = @[@"ADORABLE",
|
||||
@"BOUNCES",
|
||||
@"HATES CUCUMBERS",
|
||||
@"SCRATCHY"
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
- (id)randomObjectFromArray:(NSArray *)strings
|
||||
{
|
||||
u_int32_t ipsumCount = (u_int32_t)[strings count];
|
||||
u_int32_t location = arc4random_uniform(ipsumCount);
|
||||
|
||||
return strings[location];
|
||||
}
|
||||
|
||||
- (uint32_t)randomNumberInRange:(uint32_t)start to:(uint32_t)end {
|
||||
|
||||
return start + arc4random_uniform(end - start);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6211" systemVersion="14A298i" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6204"/>
|
||||
</dependencies>
|
||||
<scenes/>
|
||||
</document>
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// LoadingNode.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
@interface LoadingNode : ASCellNode
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// LoadingNode.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "LoadingNode.h"
|
||||
|
||||
#import <AsyncDisplayKit/ASCenterLayoutSpec.h>
|
||||
|
||||
@implementation LoadingNode {
|
||||
ASDisplayNode *_loadingSpinner;
|
||||
}
|
||||
|
||||
#pragma mark - ASCellNode
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super init]))
|
||||
return nil;
|
||||
|
||||
_loadingSpinner = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull{
|
||||
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
|
||||
[spinner startAnimating];
|
||||
return spinner;
|
||||
}];
|
||||
_loadingSpinner.style.preferredSize = CGSizeMake(50, 50);
|
||||
|
||||
// add it as a subnode, and we're done
|
||||
[self addSubnode:_loadingSpinner];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
|
||||
{
|
||||
ASCenterLayoutSpec *centerSpec = [[ASCenterLayoutSpec alloc] init];
|
||||
centerSpec.centeringOptions = ASCenterLayoutSpecCenteringXY;
|
||||
centerSpec.sizingOptions = ASCenterLayoutSpecSizingOptionDefault;
|
||||
centerSpec.child = _loadingSpinner;
|
||||
return centerSpec;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// PlaceholderNetworkImageNode.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
@interface PlaceholderNetworkImageNode : ASNetworkImageNode
|
||||
|
||||
@property (nonatomic, strong) UIImage *placeholderImageOverride;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// PlaceholderNetworkImageNode.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PlaceholderNetworkImageNode.h"
|
||||
|
||||
@implementation PlaceholderNetworkImageNode
|
||||
|
||||
- (UIImage *)placeholderImage
|
||||
{
|
||||
return self.placeholderImageOverride;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// PresentingViewController.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface PresentingViewController : UIViewController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// PresentingViewController.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "PresentingViewController.h"
|
||||
#import "ViewController.h"
|
||||
|
||||
@interface PresentingViewController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation PresentingViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Push Details" style:UIBarButtonItemStylePlain target:self action:@selector(pushNewViewController)];
|
||||
}
|
||||
|
||||
- (void)pushNewViewController
|
||||
{
|
||||
ViewController *controller = [[ViewController alloc] init];
|
||||
[self.navigationController pushViewController:controller animated:true];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// ViewController.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
@interface ViewController : ASViewController
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,221 @@
|
||||
//
|
||||
// ViewController.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
#import "ItemNode.h"
|
||||
#import "BlurbNode.h"
|
||||
#import "LoadingNode.h"
|
||||
|
||||
static const NSTimeInterval kWebResponseDelay = 1.0;
|
||||
static const BOOL kSimulateWebResponse = YES;
|
||||
static const NSInteger kBatchSize = 20;
|
||||
|
||||
static const CGFloat kHorizontalSectionPadding = 10.0f;
|
||||
|
||||
@interface ViewController () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionDelegateFlowLayout>
|
||||
{
|
||||
ASCollectionNode *_collectionNode;
|
||||
NSMutableArray *_data;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIViewController.
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
_collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:layout];
|
||||
|
||||
self = [super initWithNode:_collectionNode];
|
||||
|
||||
if (self) {
|
||||
self.title = @"Cat Deals";
|
||||
|
||||
_collectionNode.dataSource = self;
|
||||
_collectionNode.delegate = self;
|
||||
_collectionNode.backgroundColor = [UIColor grayColor];
|
||||
_collectionNode.accessibilityIdentifier = @"Cat deals list";
|
||||
|
||||
ASRangeTuningParameters preloadTuning;
|
||||
preloadTuning.leadingBufferScreenfuls = 2;
|
||||
preloadTuning.trailingBufferScreenfuls = 1;
|
||||
[_collectionNode setTuningParameters:preloadTuning forRangeType:ASLayoutRangeTypePreload];
|
||||
|
||||
ASRangeTuningParameters displayTuning;
|
||||
displayTuning.leadingBufferScreenfuls = 1;
|
||||
displayTuning.trailingBufferScreenfuls = 0.5;
|
||||
[_collectionNode setTuningParameters:displayTuning forRangeType:ASLayoutRangeTypeDisplay];
|
||||
|
||||
[_collectionNode registerSupplementaryNodeOfKind:UICollectionElementKindSectionHeader];
|
||||
[_collectionNode registerSupplementaryNodeOfKind:UICollectionElementKindSectionFooter];
|
||||
|
||||
_data = [[NSMutableArray alloc] init];
|
||||
|
||||
self.navigationItem.leftItemsSupplementBackButton = YES;
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(reloadTapped)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// set any collectionView properties here (once the node's backing view is loaded)
|
||||
_collectionNode.leadingScreensForBatching = 2;
|
||||
[self fetchMoreCatsWithCompletion:nil];
|
||||
}
|
||||
|
||||
- (void)fetchMoreCatsWithCompletion:(void (^)(BOOL))completion
|
||||
{
|
||||
if (kSimulateWebResponse) {
|
||||
__weak typeof(self) weakSelf = self;
|
||||
void(^mockWebService)() = ^{
|
||||
NSLog(@"ViewController \"got data from a web service\"");
|
||||
ViewController *strongSelf = weakSelf;
|
||||
if (strongSelf != nil)
|
||||
{
|
||||
[strongSelf appendMoreItems:kBatchSize completion:completion];
|
||||
}
|
||||
else {
|
||||
NSLog(@"ViewController is nil - won't update collection");
|
||||
}
|
||||
};
|
||||
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kWebResponseDelay * NSEC_PER_SEC)), dispatch_get_main_queue(), mockWebService);
|
||||
} else {
|
||||
[self appendMoreItems:kBatchSize completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)appendMoreItems:(NSInteger)numberOfNewItems completion:(void (^)(BOOL))completion
|
||||
{
|
||||
NSArray *newData = [self getMoreData:numberOfNewItems];
|
||||
[_collectionNode performBatchAnimated:YES updates:^{
|
||||
[_data addObjectsFromArray:newData];
|
||||
NSArray *addedIndexPaths = [self indexPathsForObjects:newData];
|
||||
[_collectionNode insertItemsAtIndexPaths:addedIndexPaths];
|
||||
} completion:completion];
|
||||
}
|
||||
|
||||
- (NSArray *)getMoreData:(NSInteger)count
|
||||
{
|
||||
NSMutableArray *data = [NSMutableArray array];
|
||||
for (int i = 0; i < count; i++) {
|
||||
[data addObject:[ItemViewModel randomItem]];
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSArray *)indexPathsForObjects:(NSArray *)data
|
||||
{
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
NSInteger section = 0;
|
||||
for (ItemViewModel *viewModel in data) {
|
||||
NSInteger item = [_data indexOfObject:viewModel];
|
||||
NSAssert(item < [_data count] && item != NSNotFound, @"Item should be in _data");
|
||||
[indexPaths addObject:[NSIndexPath indexPathForItem:item inSection:section]];
|
||||
}
|
||||
return indexPaths;
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
|
||||
{
|
||||
[_collectionNode.view.collectionViewLayout invalidateLayout];
|
||||
}
|
||||
|
||||
- (void)reloadTapped
|
||||
{
|
||||
[_collectionNode reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - ASCollectionNodeDelegate / ASCollectionNodeDataSource
|
||||
|
||||
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return ^{
|
||||
return [[ItemNode alloc] init];
|
||||
};
|
||||
}
|
||||
|
||||
- (id)collectionNode:(ASCollectionNode *)collectionNode nodeModelForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return _data[indexPath.item];
|
||||
}
|
||||
|
||||
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if ([kind isEqualToString:UICollectionElementKindSectionHeader] && indexPath.section == 0) {
|
||||
return [[BlurbNode alloc] init];
|
||||
} else if ([kind isEqualToString:UICollectionElementKindSectionFooter] && indexPath.section == 0) {
|
||||
return [[LoadingNode alloc] init];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode constrainedSizeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
CGFloat collectionViewWidth = CGRectGetWidth(self.view.frame) - 2 * kHorizontalSectionPadding;
|
||||
CGFloat oneItemWidth = [ItemNode preferredViewSize].width;
|
||||
NSInteger numColumns = floor(collectionViewWidth / oneItemWidth);
|
||||
// Number of columns should be at least 1
|
||||
numColumns = MAX(1, numColumns);
|
||||
|
||||
CGFloat totalSpaceBetweenColumns = (numColumns - 1) * kHorizontalSectionPadding;
|
||||
CGFloat itemWidth = ((collectionViewWidth - totalSpaceBetweenColumns) / numColumns);
|
||||
CGSize itemSize = [ItemNode sizeForWidth:itemWidth];
|
||||
return ASSizeRangeMake(itemSize, itemSize);
|
||||
}
|
||||
|
||||
- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return [_data count];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode willBeginBatchFetchWithContext:(ASBatchContext *)context
|
||||
{
|
||||
[self fetchMoreCatsWithCompletion:^(BOOL finished){
|
||||
[context completeBatchFetching:YES];
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - ASCollectionDelegateFlowLayout
|
||||
|
||||
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return ASSizeRangeUnconstrained;
|
||||
} else {
|
||||
return ASSizeRangeZero;
|
||||
}
|
||||
}
|
||||
|
||||
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return ASSizeRangeUnconstrained;
|
||||
} else {
|
||||
return ASSizeRangeZero;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// main.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
|
||||
// Changes after 4/13/2017 are: Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user