mirror of
https://github.com/TextureGroup/Texture.git
synced 2026-04-07 19:17:39 +00:00
Merge remote-tracking branch 'upstream/master' into rmalik/tvos-example
This commit is contained in:
@@ -7,10 +7,12 @@ on:
|
||||
|
||||
jobs:
|
||||
cocoapods-lint:
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer
|
||||
name: Verify that podspec lints
|
||||
runs-on: macOS-10.14
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Checkout the Git repository
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v2
|
||||
- name: Run build.sh with cocoapods-lint mode
|
||||
run: ./build.sh cocoapods-lint
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
name: CI (pull-requests-only jobs)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
buildsh:
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer
|
||||
strategy:
|
||||
matrix:
|
||||
mode: [cocoapods-lint-default-subspecs, cocoapods-lint-other-subspecs]
|
||||
include:
|
||||
- mode: cocoapods-lint-default-subspecs
|
||||
name: Verify that default subspecs lint
|
||||
- mode: cocoapods-lint-other-subspecs
|
||||
name: Verify that other subspecs lint
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Checkout the Git repository
|
||||
uses: actions/checkout@v2
|
||||
- name: Run build script
|
||||
run: ./build.sh ${{ matrix.mode }}
|
||||
@@ -4,6 +4,8 @@ on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
buildsh:
|
||||
env:
|
||||
DEVELOPER_DIR: /Applications/Xcode_11.4.1.app/Contents/Developer
|
||||
strategy:
|
||||
matrix:
|
||||
mode: [tests, framework, life-without-cocoapods, carthage, examples-pt1, examples-pt2, examples-pt3, examples-pt4]
|
||||
@@ -25,8 +27,9 @@ jobs:
|
||||
- mode: examples-pt4
|
||||
name: Build examples (examples-pt4)
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: macOS-10.14
|
||||
runs-on: macOS-latest
|
||||
steps:
|
||||
- name: Checkout the Git repository
|
||||
uses: actions/checkout@v1
|
||||
- run: ./build.sh ${{ matrix.mode }}
|
||||
uses: actions/checkout@v2
|
||||
- name: Run build script
|
||||
run: ./build.sh ${{ matrix.mode }}
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
name: Danger
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
danger:
|
||||
name: Danger JS
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout the Git repository
|
||||
uses: actions/checkout@v1
|
||||
# TODO: Figure out why GITHUB_TOKEN isn't enough for Danger JS to create a comment.
|
||||
# Our dangerfile.js escalates any warnings as failures to get more attention.
|
||||
#
|
||||
# Here is the error response from GitHub API:
|
||||
#
|
||||
# Request failed [403]: https://api.github.com/repos/TextureGroup/Texture/issues/1635/comments
|
||||
# Response: {
|
||||
# "message": "Resource not accessible by integration",
|
||||
# "documentation_url": "https://developer.github.com/v3/issues/comments/#create-a-comment"
|
||||
# }
|
||||
#
|
||||
# https://github.com/TextureGroup/Texture/pull/1635/checks?check_run_id=200541353
|
||||
- name: Danger
|
||||
uses: danger/danger-js@9.1.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DANGER_DISABLE_TRANSPILATION: true
|
||||
@@ -30,8 +30,6 @@
|
||||
058D0A40195D057000B7D73C /* ASTextNodeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A36195D057000B7D73C /* ASTextNodeTests.mm */; };
|
||||
058D0A41195D057000B7D73C /* ASTextNodeWordKernerTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 058D0A37195D057000B7D73C /* ASTextNodeWordKernerTests.mm */; };
|
||||
05EA6FE71AC0966E00E35788 /* ASSnapshotTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */; };
|
||||
0FAFDF7520EC1C90003A51C0 /* ASLayout+IGListKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
0FAFDF7620EC1C90003A51C0 /* ASLayout+IGListKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */; };
|
||||
18C2ED7F1B9B7DE800F627B3 /* ASCollectionNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
18C2ED831B9B7DE800F627B3 /* ASCollectionNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = 18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */; };
|
||||
1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A6C000B1FAB4E2000D05926 /* ASCornerLayoutSpec.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -100,8 +98,11 @@
|
||||
3917EBD41E9C2FC400D04A01 /* _ASCollectionReusableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 3917EBD21E9C2FC400D04A01 /* _ASCollectionReusableView.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
3917EBD51E9C2FC400D04A01 /* _ASCollectionReusableView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3917EBD31E9C2FC400D04A01 /* _ASCollectionReusableView.mm */; };
|
||||
3C9C128519E616EF00E942A0 /* ASTableViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */; };
|
||||
407B8BAE2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */; };
|
||||
4080D66C2350384400CDC199 /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 68355B391CB57A5A001D4E68 /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
471D04B1224CB98600649215 /* ASImageNodeBackingSizeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */; };
|
||||
4E9127691F64157600499623 /* ASRunLoopQueueTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4E9127681F64157600499623 /* ASRunLoopQueueTests.mm */; };
|
||||
4EE3813FF44E20C399ACB962 /* Pods_AsyncDisplayKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */; };
|
||||
509E68601B3AED8E009B9150 /* ASScrollDirection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E111B371BD7007741D0 /* ASScrollDirection.mm */; };
|
||||
509E68611B3AEDA0009B9150 /* ASAbstractLayoutController.h in Headers */ = {isa = PBXBuildFile; fileRef = 205F0E171B37339C007741D0 /* ASAbstractLayoutController.h */; };
|
||||
509E68621B3AEDA5009B9150 /* ASAbstractLayoutController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 205F0E181B37339C007741D0 /* ASAbstractLayoutController.mm */; };
|
||||
@@ -215,7 +216,6 @@
|
||||
9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */; };
|
||||
9F98C0261DBE29E000476D92 /* ASControlTargetAction.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */; };
|
||||
9F98C0271DBE29FC00476D92 /* ASControlTargetAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
A37320101C571B740011FC94 /* ASTextNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = A373200E1C571B050011FC94 /* ASTextNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
AC026B581BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */; };
|
||||
AC026B701BD57DBF00BBC17E /* _ASHierarchyChangeSet.h in Headers */ = {isa = PBXBuildFile; fileRef = AC026B6D1BD57DBF00BBC17E /* _ASHierarchyChangeSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
@@ -337,7 +337,6 @@
|
||||
CC0F88621E4281E200576FED /* ASSectionController.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B1E1E313EA7006AEBBB /* ASSectionController.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC0F88631E4281E700576FED /* ASSupplementaryNodeSource.h in Headers */ = {isa = PBXBuildFile; fileRef = CCE04B2B1E314A32006AEBBB /* ASSupplementaryNodeSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC0F886C1E4286FA00576FED /* ReferenceImages_64 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F88691E4286FA00576FED /* ReferenceImages_64 */; };
|
||||
CC0F886D1E4286FA00576FED /* ReferenceImages_iOS_10 in Resources */ = {isa = PBXBuildFile; fileRef = CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */; };
|
||||
CC11F97A1DB181180024D77B /* ASNetworkImageNodeTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.mm */; };
|
||||
CC18248C200D49C800875940 /* ASTextNodeCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = CC18248B200D49C800875940 /* ASTextNodeCommon.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC224E962066CA6D00BBA57F /* configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = CC224E952066CA6D00BBA57F /* configuration.json */; };
|
||||
@@ -364,6 +363,7 @@
|
||||
CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.mm */; };
|
||||
CC3B20901C3F892D00798563 /* ASBridgedPropertiesTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC3B208F1C3F892D00798563 /* ASBridgedPropertiesTests.mm */; };
|
||||
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.mm */; };
|
||||
CC4E8DAF232C2883007C3182 /* ASGraphicsContextTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */; };
|
||||
CC54A81C1D70079800296A24 /* ASDispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = CC54A81B1D70077A00296A24 /* ASDispatch.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
CC54A81E1D7008B300296A24 /* ASDispatchTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC54A81D1D7008B300296A24 /* ASDispatchTests.mm */; };
|
||||
CC55A70D1E529FA200594372 /* UIResponder+AsyncDisplayKit.h in Headers */ = {isa = PBXBuildFile; fileRef = CC55A70B1E529FA200594372 /* UIResponder+AsyncDisplayKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -379,6 +379,7 @@
|
||||
CC583AD81EF9BDC300134156 /* OCMockObject+ASAdditions.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC583AC71EF9BAB400134156 /* OCMockObject+ASAdditions.mm */; };
|
||||
CC583AD91EF9BDC600134156 /* ASDisplayNode+OCMock.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC583AC01EF9BAB400134156 /* ASDisplayNode+OCMock.mm */; };
|
||||
CC58AA4B1E398E1D002C8CB4 /* ASBlockTypes.h in Headers */ = {isa = PBXBuildFile; fileRef = CC58AA4A1E398E1D002C8CB4 /* ASBlockTypes.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC698827247855F200487428 /* UIImage+ASConvenienceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */; };
|
||||
CC6AA2DA1E9F03B900978E87 /* ASDisplayNode+Ancestry.h in Headers */ = {isa = PBXBuildFile; fileRef = CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CC6AA2DB1E9F03B900978E87 /* ASDisplayNode+Ancestry.mm in Sources */ = {isa = PBXBuildFile; fileRef = CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */; };
|
||||
CC7AF196200D9BD500A21BDE /* ASExperimentalFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = CC7AF195200D9BD500A21BDE /* ASExperimentalFeatures.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
@@ -434,7 +435,7 @@
|
||||
CCCCCCE41EC3EF060087FE10 /* NSParagraphStyle+ASText.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCD41EC3EF060087FE10 /* NSParagraphStyle+ASText.mm */; };
|
||||
CCCCCCE71EC3F0FC0087FE10 /* NSAttributedString+ASText.h in Headers */ = {isa = PBXBuildFile; fileRef = CCCCCCE51EC3F0FC0087FE10 /* NSAttributedString+ASText.h */; };
|
||||
CCCCCCE81EC3F0FC0087FE10 /* NSAttributedString+ASText.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCCCCCE61EC3F0FC0087FE10 /* NSAttributedString+ASText.mm */; };
|
||||
CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */; };
|
||||
CCDC9B4D200991D10063C1F8 /* ASGraphicsContext.h in Headers */ = {isa = PBXBuildFile; fileRef = CCDC9B4B200991D10063C1F8 /* ASGraphicsContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCDC9B4C200991D10063C1F8 /* ASGraphicsContext.mm */; };
|
||||
CCDD148B1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCDD148A1EEDCD9D0020834E /* ASCollectionModernDataSourceTests.mm */; };
|
||||
CCE4F9B31F0D60AC00062E4E /* ASIntegerMapTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CCE4F9B21F0D60AC00062E4E /* ASIntegerMapTests.mm */; };
|
||||
@@ -453,8 +454,8 @@
|
||||
CCF18FF41D2575E300DF5895 /* NSIndexSet+ASHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
CCF1FF5E20C4785000AAD8FC /* ASLocking.h in Headers */ = {isa = PBXBuildFile; fileRef = CCF1FF5D20C4785000AAD8FC /* ASLocking.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D933F041224AD17F00FF495E /* ASTransactionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = D933F040224AD17F00FF495E /* ASTransactionTests.mm */; };
|
||||
D99F9158232990F30083CC8E /* ASImageNodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = D99F9157232990F30083CC8E /* ASImageNodeTests.m */; };
|
||||
DB55C2671C641AE4004EDCF5 /* ASContextTransitioning.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
|
||||
DB78412E1C6BCE1600A9E2B4 /* _ASTransitionContext.mm in Sources */ = {isa = PBXBuildFile; fileRef = DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.mm */; };
|
||||
DBABFAFC1C6A8D2F0039EA4A /* _ASTransitionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
|
||||
DBC452DE1C5C6A6A00B16017 /* ArrayDiffingTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = DBC452DD1C5C6A6A00B16017 /* ArrayDiffingTests.mm */; };
|
||||
@@ -472,6 +473,8 @@
|
||||
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||
DEFAD8131CC48914000527C4 /* ASVideoNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = AEEC47E01C20C2DD00EC1693 /* ASVideoNode.mm */; };
|
||||
E517F9C823BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */; };
|
||||
E517F9C923BF14BC006E40E0 /* ASLayout+IGListDiffKit.h in Headers */ = {isa = PBXBuildFile; fileRef = E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E51B78BF1F028ABF00E32604 /* ASLayoutFlatteningTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.mm */; };
|
||||
E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
E54E81FC1EB357BD00FFE8E1 /* ASPageTable.h in Headers */ = {isa = PBXBuildFile; fileRef = E54E81FA1EB357BD00FFE8E1 /* ASPageTable.h */; };
|
||||
@@ -620,8 +623,6 @@
|
||||
058D0A44195D058D00B7D73C /* ASBaseDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBaseDefines.h; sourceTree = "<group>"; };
|
||||
05EA6FE61AC0966E00E35788 /* ASSnapshotTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASSnapshotTestCase.mm; sourceTree = "<group>"; };
|
||||
05F20AA31A15733C00DCA68A /* ASImageProtocols.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageProtocols.h; sourceTree = "<group>"; };
|
||||
0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASLayout+IGListKit.h"; sourceTree = "<group>"; };
|
||||
0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASLayout+IGListKit.mm"; sourceTree = "<group>"; };
|
||||
18C2ED7C1B9B7DE800F627B3 /* ASCollectionNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionNode.h; sourceTree = "<group>"; };
|
||||
18C2ED7D1B9B7DE800F627B3 /* ASCollectionNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionNode.mm; sourceTree = "<group>"; };
|
||||
1950C4481A3BB5C1005C8279 /* ASEqualityHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASEqualityHelpers.h; sourceTree = "<group>"; };
|
||||
@@ -677,6 +678,7 @@
|
||||
3917EBD21E9C2FC400D04A01 /* _ASCollectionReusableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASCollectionReusableView.h; sourceTree = "<group>"; };
|
||||
3917EBD31E9C2FC400D04A01 /* _ASCollectionReusableView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASCollectionReusableView.mm; sourceTree = "<group>"; };
|
||||
3C9C128419E616EF00E942A0 /* ASTableViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASTableViewTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutSpecUtilitiesTests.mm; sourceTree = "<group>"; };
|
||||
464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDataController.h; sourceTree = "<group>"; };
|
||||
4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDataController.mm; sourceTree = "<group>"; };
|
||||
4640521B1A3F83C40061C0BA /* ASTableLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTableLayoutController.h; sourceTree = "<group>"; };
|
||||
@@ -684,6 +686,7 @@
|
||||
4640521D1A3F83C40061C0BA /* ASLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutController.h; sourceTree = "<group>"; };
|
||||
471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASImageNodeBackingSizeTests.mm; sourceTree = "<group>"; };
|
||||
4E9127681F64157600499623 /* ASRunLoopQueueTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASRunLoopQueueTests.mm; sourceTree = "<group>"; };
|
||||
5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AsyncDisplayKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
68355B2E1CB5799E001D4E68 /* ASImageNode+AnimatedImage.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASImageNode+AnimatedImage.mm"; sourceTree = "<group>"; };
|
||||
68355B361CB57A5A001D4E68 /* ASPINRemoteImageDownloader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASPINRemoteImageDownloader.mm; sourceTree = "<group>"; };
|
||||
68355B371CB57A5A001D4E68 /* ASImageContainerProtocolCategories.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASImageContainerProtocolCategories.h; sourceTree = "<group>"; };
|
||||
@@ -787,8 +790,6 @@
|
||||
9F06E5CC1B4CAF4200F015D8 /* ASCollectionViewTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionViewTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
9F98C0231DBDF2A300476D92 /* ASControlTargetAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASControlTargetAction.h; sourceTree = "<group>"; };
|
||||
9F98C0241DBDF2A300476D92 /* ASControlTargetAction.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASControlTargetAction.mm; sourceTree = "<group>"; };
|
||||
A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASPINRemoteImageDownloader.h; path = Details/ASPINRemoteImageDownloader.h; sourceTree = "<group>"; };
|
||||
A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ASPINRemoteImageDownloader.mm; path = Details/ASPINRemoteImageDownloader.mm; sourceTree = "<group>"; };
|
||||
A32FEDD31C501B6A004F642A /* ASTextKitFontSizeAdjuster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASTextKitFontSizeAdjuster.h; path = TextKit/ASTextKitFontSizeAdjuster.h; sourceTree = "<group>"; };
|
||||
A373200E1C571B050011FC94 /* ASTextNode+Beta.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ASTextNode+Beta.h"; sourceTree = "<group>"; };
|
||||
AC026B571BD3F61800BBC17E /* ASAbsoluteLayoutSpecSnapshotTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASAbsoluteLayoutSpecSnapshotTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
@@ -865,7 +866,6 @@
|
||||
CC0F885D1E4280B800576FED /* _ASCollectionViewCell.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = _ASCollectionViewCell.mm; sourceTree = "<group>"; };
|
||||
CC0F885E1E4280B800576FED /* _ASCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _ASCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
CC0F88691E4286FA00576FED /* ReferenceImages_64 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_64; sourceTree = "<group>"; };
|
||||
CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */ = {isa = PBXFileReference; lastKnownFileType = folder; path = ReferenceImages_iOS_10; sourceTree = "<group>"; };
|
||||
CC11F9791DB181180024D77B /* ASNetworkImageNodeTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASNetworkImageNodeTests.mm; sourceTree = "<group>"; };
|
||||
CC18248B200D49C800875940 /* ASTextNodeCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASTextNodeCommon.h; sourceTree = "<group>"; };
|
||||
CC224E952066CA6D00BBA57F /* configuration.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = configuration.json; sourceTree = "<group>"; };
|
||||
@@ -891,6 +891,7 @@
|
||||
CC4981B21D1A02BE004E13CC /* ASTableViewThrashTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTableViewThrashTests.mm; sourceTree = "<group>"; };
|
||||
CC4981BA1D1C7F65004E13CC /* NSIndexSet+ASHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSIndexSet+ASHelpers.h"; sourceTree = "<group>"; };
|
||||
CC4981BB1D1C7F65004E13CC /* NSIndexSet+ASHelpers.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSIndexSet+ASHelpers.mm"; sourceTree = "<group>"; };
|
||||
CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASGraphicsContextTests.mm; sourceTree = "<group>"; };
|
||||
CC512B841DAC45C60054848E /* ASTableView+Undeprecated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASTableView+Undeprecated.h"; sourceTree = "<group>"; };
|
||||
CC54A81B1D70077A00296A24 /* ASDispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASDispatch.h; sourceTree = "<group>"; };
|
||||
CC54A81D1D7008B300296A24 /* ASDispatchTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDispatchTests.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
@@ -910,6 +911,7 @@
|
||||
CC583AC61EF9BAB400134156 /* OCMockObject+ASAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "OCMockObject+ASAdditions.h"; sourceTree = "<group>"; };
|
||||
CC583AC71EF9BAB400134156 /* OCMockObject+ASAdditions.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "OCMockObject+ASAdditions.mm"; sourceTree = "<group>"; };
|
||||
CC58AA4A1E398E1D002C8CB4 /* ASBlockTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASBlockTypes.h; sourceTree = "<group>"; };
|
||||
CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIImage+ASConvenienceTests.mm"; sourceTree = "<group>"; };
|
||||
CC6AA2D81E9F03B900978E87 /* ASDisplayNode+Ancestry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "ASDisplayNode+Ancestry.h"; path = "Base/ASDisplayNode+Ancestry.h"; sourceTree = "<group>"; };
|
||||
CC6AA2D91E9F03B900978E87 /* ASDisplayNode+Ancestry.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "ASDisplayNode+Ancestry.mm"; path = "Base/ASDisplayNode+Ancestry.mm"; sourceTree = "<group>"; };
|
||||
CC7AF195200D9BD500A21BDE /* ASExperimentalFeatures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ASExperimentalFeatures.h; sourceTree = "<group>"; };
|
||||
@@ -996,6 +998,7 @@
|
||||
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
||||
D785F6611A74327E00291744 /* ASScrollNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASScrollNode.mm; sourceTree = "<group>"; };
|
||||
D933F040224AD17F00FF495E /* ASTransactionTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTransactionTests.mm; sourceTree = "<group>"; };
|
||||
D99F9157232990F30083CC8E /* ASImageNodeTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ASImageNodeTests.m; sourceTree = "<group>"; };
|
||||
DB55C25F1C6408D6004EDCF5 /* _ASTransitionContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = _ASTransitionContext.h; path = ../_ASTransitionContext.h; sourceTree = "<group>"; };
|
||||
DB55C2601C6408D6004EDCF5 /* _ASTransitionContext.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = _ASTransitionContext.mm; path = ../_ASTransitionContext.mm; sourceTree = "<group>"; };
|
||||
DB55C2651C641AE4004EDCF5 /* ASContextTransitioning.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASContextTransitioning.h; sourceTree = "<group>"; };
|
||||
@@ -1011,6 +1014,8 @@
|
||||
DEC146B41C37A16A004A0EE7 /* ASCollectionInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ASCollectionInternal.h; path = Details/ASCollectionInternal.h; sourceTree = "<group>"; };
|
||||
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = "<group>"; };
|
||||
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
|
||||
E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "ASLayout+IGListDiffKit.mm"; sourceTree = "<group>"; };
|
||||
E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASLayout+IGListDiffKit.h"; sourceTree = "<group>"; };
|
||||
E51B78BD1F01A0EE00E32604 /* ASLayoutFlatteningTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutFlatteningTests.mm; sourceTree = "<group>"; };
|
||||
E52405B21C8FEF03004DC8E7 /* ASLayoutTransition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASLayoutTransition.mm; sourceTree = "<group>"; };
|
||||
E52405B41C8FEF16004DC8E7 /* ASLayoutTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASLayoutTransition.h; sourceTree = "<group>"; };
|
||||
@@ -1049,7 +1054,6 @@
|
||||
E5E281751E71C845006B67C2 /* ASCollectionLayoutState.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASCollectionLayoutState.mm; sourceTree = "<group>"; };
|
||||
E5E2D72D1EA780C4005C24C6 /* ASCollectionGalleryLayoutDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionGalleryLayoutDelegate.h; sourceTree = "<group>"; };
|
||||
E5E2D72F1EA780DF005C24C6 /* ASCollectionGalleryLayoutDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionGalleryLayoutDelegate.mm; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F325E48B21745F9E00AC93A4 /* ASButtonNodeTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNodeTests.mm; sourceTree = "<group>"; };
|
||||
F325E48F217460B000AC93A4 /* ASTextNode2Tests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASTextNode2Tests.mm; sourceTree = "<group>"; };
|
||||
F3F698D1211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ASDisplayViewAccessibilityTests.mm; sourceTree = "<group>"; };
|
||||
@@ -1077,7 +1081,7 @@
|
||||
058D09BE195D04C000B7D73C /* XCTest.framework in Frameworks */,
|
||||
058D09C1195D04C000B7D73C /* UIKit.framework in Frameworks */,
|
||||
058D09BF195D04C000B7D73C /* Foundation.framework in Frameworks */,
|
||||
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */,
|
||||
4EE3813FF44E20C399ACB962 /* Pods_AsyncDisplayKitTests.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -1164,7 +1168,7 @@
|
||||
058D09AF195D04C000B7D73C /* Foundation.framework */,
|
||||
058D09BD195D04C000B7D73C /* XCTest.framework */,
|
||||
058D09C0195D04C000B7D73C /* UIKit.framework */,
|
||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */,
|
||||
5039B74209A895E07057081C /* Pods_AsyncDisplayKitTests.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -1248,8 +1252,6 @@
|
||||
25E327541C16819500A2170C /* ASPagerNode.h */,
|
||||
25E327551C16819500A2170C /* ASPagerNode.mm */,
|
||||
E54E00711F1D3828000B30D7 /* ASPagerNode+Beta.h */,
|
||||
A2763D771CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h */,
|
||||
A2763D781CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.mm */,
|
||||
CCBBBF5C1EB161760069AA91 /* ASRangeManagingNode.h */,
|
||||
D785F6601A74327E00291744 /* ASScrollNode.h */,
|
||||
D785F6611A74327E00291744 /* ASScrollNode.mm */,
|
||||
@@ -1333,8 +1335,10 @@
|
||||
058D0A31195D057000B7D73C /* ASDisplayNodeTestsHelper.mm */,
|
||||
F3F698D1211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm */,
|
||||
697B31591CFE4B410049936F /* ASEditableTextNodeTests.mm */,
|
||||
CC4E8DAE232C2882007C3182 /* ASGraphicsContextTests.mm */,
|
||||
471D04B0224CB98600649215 /* ASImageNodeBackingSizeTests.mm */,
|
||||
056D21541ABCEF50001107EF /* ASImageNodeSnapshotTests.mm */,
|
||||
D99F9157232990F30083CC8E /* ASImageNodeTests.m */,
|
||||
ACF6ED551B178DC700DA7C62 /* ASInsetLayoutSpecSnapshotTests.mm */,
|
||||
CCE4F9B21F0D60AC00062E4E /* ASIntegerMapTests.mm */,
|
||||
69FEE53C1D95A9AF0086F066 /* ASLayoutElementStyleTests.mm */,
|
||||
@@ -1386,6 +1390,8 @@
|
||||
83A7D95D1D446A6E00BF333E /* ASWeakMapTests.mm */,
|
||||
CC3B208D1C3F7D0A00798563 /* ASWeakSetTests.mm */,
|
||||
695BE2541DC1245C008E6EA5 /* ASWrapperSpecSnapshotTests.mm */,
|
||||
407B8BAD2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm */,
|
||||
CC698826247855F200487428 /* UIImage+ASConvenienceTests.mm */,
|
||||
057D02C01AC0A66700C7AC3C /* AsyncDisplayKitTestHost */,
|
||||
CC583ABF1EF9BAB400134156 /* Common */,
|
||||
058D09C6195D04C000B7D73C /* Supporting Files */,
|
||||
@@ -1399,7 +1405,6 @@
|
||||
children = (
|
||||
CC01EB6C23105C2000CDB61A /* TestAsset.xcassets */,
|
||||
CC0F88691E4286FA00576FED /* ReferenceImages_64 */,
|
||||
CC0F886A1E4286FA00576FED /* ReferenceImages_iOS_10 */,
|
||||
058D09C7195D04C000B7D73C /* AsyncDisplayKitTests-Info.plist */,
|
||||
058D09C8195D04C000B7D73C /* InfoPlist.strings */,
|
||||
);
|
||||
@@ -1695,8 +1700,8 @@
|
||||
ACF6ED0A1B17843500DA7C62 /* ASInsetLayoutSpec.mm */,
|
||||
ACF6ED0B1B17843500DA7C62 /* ASLayout.h */,
|
||||
ACF6ED0C1B17843500DA7C62 /* ASLayout.mm */,
|
||||
0FAFDF7320EC1C8F003A51C0 /* ASLayout+IGListKit.h */,
|
||||
0FAFDF7420EC1C90003A51C0 /* ASLayout+IGListKit.mm */,
|
||||
E517F9C723BF14BC006E40E0 /* ASLayout+IGListDiffKit.h */,
|
||||
E517F9C623BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm */,
|
||||
ACF6ED111B17843500DA7C62 /* ASLayoutElement.h */,
|
||||
E55D86311CA8A14000A0C26F /* ASLayoutElement.mm */,
|
||||
698C8B601CAB49FC0052DC3F /* ASLayoutElementExtensibility.h */,
|
||||
@@ -1891,6 +1896,7 @@
|
||||
files = (
|
||||
1A6C000D1FAB4E2100D05926 /* ASCornerLayoutSpec.h in Headers */,
|
||||
E54E00721F1D3828000B30D7 /* ASPagerNode+Beta.h in Headers */,
|
||||
E517F9C923BF14BC006E40E0 /* ASLayout+IGListDiffKit.h in Headers */,
|
||||
E5B225281F1790D6001E1431 /* ASHashing.h in Headers */,
|
||||
CC034A131E649F1300626263 /* AsyncDisplayKit+IGListKitMethods.h in Headers */,
|
||||
693A1DCA1ECC944E00D0C9D2 /* IGListAdapter+AsyncDisplayKit.h in Headers */,
|
||||
@@ -1912,7 +1918,6 @@
|
||||
69E0E8A71D356C9400627613 /* ASEqualityHelpers.h in Headers */,
|
||||
698C8B621CAB49FC0052DC3F /* ASLayoutElementExtensibility.h in Headers */,
|
||||
69F10C871C84C35D0026140C /* ASRangeControllerUpdateRangeProtocol+Beta.h in Headers */,
|
||||
0FAFDF7520EC1C90003A51C0 /* ASLayout+IGListKit.h in Headers */,
|
||||
B350623C1B010EFD0018CF92 /* _ASAsyncTransaction.h in Headers */,
|
||||
68355B411CB57A6C001D4E68 /* ASImageContainerProtocolCategories.h in Headers */,
|
||||
7630FFA81C9E267E007A7C0E /* ASVideoNode.h in Headers */,
|
||||
@@ -1934,7 +1939,6 @@
|
||||
DE84918D1C8FFF2B003D89E9 /* ASRunLoopQueue.h in Headers */,
|
||||
CC0F88621E4281E200576FED /* ASSectionController.h in Headers */,
|
||||
CCB1F95C1EFB6350009C7475 /* ASSignpost.h in Headers */,
|
||||
A2763D7A1CBDD57D00A9ADBD /* ASPINRemoteImageDownloader.h in Headers */,
|
||||
C018DF21216BF26700181FDA /* ASAbstractLayoutController+FrameworkPrivate.h in Headers */,
|
||||
34EFC7611B701C9C00AD841F /* ASBackgroundLayoutSpec.h in Headers */,
|
||||
B35062591B010F070018CF92 /* ASBaseDefines.h in Headers */,
|
||||
@@ -2013,6 +2017,7 @@
|
||||
CC87BB951DA8193C0090E380 /* ASCellNode+Internal.h in Headers */,
|
||||
E5775B021F16759300CAC9BC /* ASCollectionLayoutCache.h in Headers */,
|
||||
E5775B001F13D25400CAC9BC /* ASCollectionLayoutState+Private.h in Headers */,
|
||||
4080D66C2350384400CDC199 /* ASPINRemoteImageDownloader.h in Headers */,
|
||||
E5667E8C1F33871300FA6FC0 /* _ASCollectionGalleryLayoutInfo.h in Headers */,
|
||||
E5775AFC1F13CE9F00CAC9BC /* _ASCollectionGalleryLayoutItem.h in Headers */,
|
||||
E5855DF01EBB4D83003639AE /* ASCollectionLayoutDefines.h in Headers */,
|
||||
@@ -2148,6 +2153,7 @@
|
||||
058D09B8195D04C000B7D73C /* Sources */,
|
||||
058D09B9195D04C000B7D73C /* Frameworks */,
|
||||
058D09BA195D04C000B7D73C /* Resources */,
|
||||
572FAC967DD43A0D06367D02 /* [CP] Embed Pods Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -2184,7 +2190,7 @@
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
CLASSPREFIX = AS;
|
||||
LastUpgradeCheck = 0940;
|
||||
LastUpgradeCheck = 1140;
|
||||
ORGANIZATIONNAME = Pinterest;
|
||||
TargetAttributes = {
|
||||
057D02BE1AC0A66700C7AC3C = {
|
||||
@@ -2200,10 +2206,9 @@
|
||||
};
|
||||
buildConfigurationList = 058D09A7195D04C000B7D73C /* Build configuration list for PBXProject "AsyncDisplayKit" */;
|
||||
compatibilityVersion = "Xcode 6.3";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
@@ -2233,7 +2238,6 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
CC0F886C1E4286FA00576FED /* ReferenceImages_64 in Resources */,
|
||||
CC0F886D1E4286FA00576FED /* ReferenceImages_iOS_10 in Resources */,
|
||||
052EE06B1A15A0D8002C6279 /* TestResources in Resources */,
|
||||
CC01EB6D23105C2000CDB61A /* TestAsset.xcassets in Resources */,
|
||||
058D09CA195D04C000B7D73C /* InfoPlist.strings in Resources */,
|
||||
@@ -2269,6 +2273,26 @@
|
||||
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;
|
||||
};
|
||||
572FAC967DD43A0D06367D02 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh",
|
||||
"${BUILT_PRODUCTS_DIR}/OCMock/OCMock.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/iOSSnapshotTestCase/FBSnapshotTestCase.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/OCMock.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSnapshotTestCase.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -2297,6 +2321,7 @@
|
||||
ACF6ED5C1B178DC700DA7C62 /* ASCenterLayoutSpecSnapshotTests.mm in Sources */,
|
||||
9F06E5CD1B4CAF4200F015D8 /* ASCollectionViewTests.mm in Sources */,
|
||||
2911485C1A77147A005D0878 /* ASControlNodeTests.mm in Sources */,
|
||||
CC698827247855F200487428 /* UIImage+ASConvenienceTests.mm in Sources */,
|
||||
CC01EB6F23105C7F00CDB61A /* ASImageNodeSnapshotTests.mm in Sources */,
|
||||
CC3B208E1C3F7D0A00798563 /* ASWeakSetTests.mm in Sources */,
|
||||
F711994E1D20C21100568860 /* ASDisplayNodeExtrasTests.mm in Sources */,
|
||||
@@ -2321,6 +2346,7 @@
|
||||
4E9127691F64157600499623 /* ASRunLoopQueueTests.mm in Sources */,
|
||||
CC4981B31D1A02BE004E13CC /* ASTableViewThrashTests.mm in Sources */,
|
||||
CC54A81E1D7008B300296A24 /* ASDispatchTests.mm in Sources */,
|
||||
CC4E8DAF232C2883007C3182 /* ASGraphicsContextTests.mm in Sources */,
|
||||
F3F698D2211CAD4600800CB1 /* ASDisplayViewAccessibilityTests.mm in Sources */,
|
||||
CCE4F9B31F0D60AC00062E4E /* ASIntegerMapTests.mm in Sources */,
|
||||
058D0A3B195D057000B7D73C /* ASDisplayNodeTestsHelper.mm in Sources */,
|
||||
@@ -2330,6 +2356,7 @@
|
||||
ACF6ED601B178DC700DA7C62 /* ASLayoutSpecSnapshotTestsHelper.mm in Sources */,
|
||||
CC7FD9E11BB5F750005CCB2B /* ASPhotosFrameworkImageRequestTests.mm in Sources */,
|
||||
052EE0661A159FEF002C6279 /* ASMultiplexImageNodeTests.mm in Sources */,
|
||||
407B8BAE2310E2ED00CB979E /* ASLayoutSpecUtilitiesTests.mm in Sources */,
|
||||
058D0A3C195D057000B7D73C /* ASMutableAttributedStringBuilderTests.mm in Sources */,
|
||||
F325E48C21745F9E00AC93A4 /* ASButtonNodeTests.mm in Sources */,
|
||||
9692B4FF219E12370060C2C3 /* ASCollectionViewThrashTests.mm in Sources */,
|
||||
@@ -2352,6 +2379,7 @@
|
||||
CC35CEC620DD87280006448D /* ASCollectionsTests.mm in Sources */,
|
||||
ACF6ED631B178DC700DA7C62 /* ASStackLayoutSpecSnapshotTests.mm in Sources */,
|
||||
CCE4F9BA1F0DBB5000062E4E /* ASLayoutTestNode.mm in Sources */,
|
||||
D99F9158232990F30083CC8E /* ASImageNodeTests.m in Sources */,
|
||||
CCAA0B82206ADECB0057B336 /* ASRecursiveUnfairLockTests.mm in Sources */,
|
||||
81E95C141D62639600336598 /* ASTextNodeSnapshotTests.mm in Sources */,
|
||||
3C9C128519E616EF00E942A0 /* ASTableViewTests.mm in Sources */,
|
||||
@@ -2409,7 +2437,6 @@
|
||||
E5B078001E69F4EB00C24B5B /* ASElementMap.mm in Sources */,
|
||||
9C8898BC1C738BA800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */,
|
||||
690ED59B1E36D118000627C0 /* ASImageNode+tvOS.mm in Sources */,
|
||||
0FAFDF7620EC1C90003A51C0 /* ASLayout+IGListKit.mm in Sources */,
|
||||
CCDC9B4E200991D10063C1F8 /* ASGraphicsContext.mm in Sources */,
|
||||
CCCCCCD81EC3EF060087FE10 /* ASTextInput.mm in Sources */,
|
||||
34EFC7621B701CA400AD841F /* ASBackgroundLayoutSpec.mm in Sources */,
|
||||
@@ -2503,6 +2530,7 @@
|
||||
90FC784F1E4BFE1B00383C5A /* ASDisplayNode+Yoga.mm in Sources */,
|
||||
CCA282C91E9EB64B0037E8B7 /* ASDisplayNodeTipState.mm in Sources */,
|
||||
509E68601B3AED8E009B9150 /* ASScrollDirection.mm in Sources */,
|
||||
E517F9C823BF14BC006E40E0 /* ASLayout+IGListDiffKit.mm in Sources */,
|
||||
B35062091B010EFD0018CF92 /* ASScrollNode.mm in Sources */,
|
||||
69BCE3D91EC6513B007DCCAD /* ASDisplayNode+Layout.mm in Sources */,
|
||||
8BDA5FC81CDBDF95007D13B2 /* ASVideoPlayerNode.mm in Sources */,
|
||||
@@ -2616,6 +2644,7 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -2623,6 +2652,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -2674,6 +2704,7 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -2681,6 +2712,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
@@ -2832,6 +2864,7 @@
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
@@ -2839,6 +2872,7 @@
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES_ERROR;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0940"
|
||||
LastUpgradeVersion = "1140"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@@ -27,6 +27,15 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B35061D91B010EDF0018CF92"
|
||||
BuildableName = "AsyncDisplayKit.framework"
|
||||
BlueprintName = "AsyncDisplayKit"
|
||||
ReferencedContainer = "container:AsyncDisplayKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -38,23 +47,15 @@
|
||||
ReferencedContainer = "container:AsyncDisplayKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
<SkippedTests>
|
||||
<Test
|
||||
Identifier = "ASCALayerTests">
|
||||
</Test>
|
||||
<Test
|
||||
Identifier = "ASTextNodePerformanceTests">
|
||||
</Test>
|
||||
</SkippedTests>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B35061D91B010EDF0018CF92"
|
||||
BuildableName = "AsyncDisplayKit.framework"
|
||||
BlueprintName = "AsyncDisplayKit"
|
||||
ReferencedContainer = "container:AsyncDisplayKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@@ -82,8 +83,6 @@
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@@ -3,7 +3,8 @@ source 'https://github.com/CocoaPods/Specs.git'
|
||||
platform :ios, '9.0'
|
||||
|
||||
target :'AsyncDisplayKitTests' do
|
||||
pod 'OCMock', '=3.4.1' # 3.4.2 currently has issues.
|
||||
pod 'FBSnapshotTestCase/Core', '~> 2.1'
|
||||
pod 'JGMethodSwizzler', :git => 'https://github.com/JonasGessner/JGMethodSwizzler', :branch => 'master'
|
||||
platform :ios, '10.0'
|
||||
use_frameworks!
|
||||
pod 'OCMock', '~>3.6'
|
||||
pod 'iOSSnapshotTestCase/Core', '~> 6.2'
|
||||
end
|
||||
|
||||
+10
-45
@@ -1,55 +1,20 @@
|
||||
PODS:
|
||||
- FBSnapshotTestCase/Core (2.1.4)
|
||||
- JGMethodSwizzler (2.0.1)
|
||||
- OCMock (3.4.1)
|
||||
- PINCache (3.0.1-beta.7):
|
||||
- PINCache/Arc-exception-safe (= 3.0.1-beta.7)
|
||||
- PINCache/Core (= 3.0.1-beta.7)
|
||||
- PINCache/Arc-exception-safe (3.0.1-beta.7):
|
||||
- PINCache/Core
|
||||
- PINCache/Core (3.0.1-beta.7):
|
||||
- PINOperation (~> 1.1.1)
|
||||
- PINOperation (1.1.1)
|
||||
- PINRemoteImage (3.0.0-beta.14):
|
||||
- PINRemoteImage/PINCache (= 3.0.0-beta.14)
|
||||
- PINRemoteImage/Core (3.0.0-beta.14):
|
||||
- PINOperation
|
||||
- PINRemoteImage/PINCache (3.0.0-beta.14):
|
||||
- PINCache (= 3.0.1-beta.7)
|
||||
- PINRemoteImage/Core
|
||||
- iOSSnapshotTestCase/Core (6.2.0)
|
||||
- OCMock (3.6)
|
||||
|
||||
DEPENDENCIES:
|
||||
- FBSnapshotTestCase/Core (~> 2.1)
|
||||
- JGMethodSwizzler (from `https://github.com/JonasGessner/JGMethodSwizzler`, branch `master`)
|
||||
- OCMock (= 3.4.1)
|
||||
- PINRemoteImage (= 3.0.0-beta.14)
|
||||
- iOSSnapshotTestCase/Core (~> 6.2)
|
||||
- OCMock (~> 3.6)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- FBSnapshotTestCase
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
- iOSSnapshotTestCase
|
||||
- OCMock
|
||||
- PINCache
|
||||
- PINOperation
|
||||
- PINRemoteImage
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
JGMethodSwizzler:
|
||||
:branch: master
|
||||
:git: https://github.com/JonasGessner/JGMethodSwizzler
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
JGMethodSwizzler:
|
||||
:commit: 8791eccc5342224bd293b5867348657e3a240c7f
|
||||
:git: https://github.com/JonasGessner/JGMethodSwizzler
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
FBSnapshotTestCase: 094f9f314decbabe373b87cc339bea235a63e07a
|
||||
JGMethodSwizzler: 7328146117fffa8a4038c42eb7cd3d4c75006f97
|
||||
OCMock: 2cd0716969bab32a2283ff3a46fd26a8c8b4c5e3
|
||||
PINCache: 7cb9ae068c8f655717f7c644ef1dff9fd573e979
|
||||
PINOperation: a6219e6fc9db9c269eb7a7b871ac193bcf400aac
|
||||
PINRemoteImage: 81bbff853acc71c6de9e106e9e489a791b8bbb08
|
||||
iOSSnapshotTestCase: 9ab44cb5aa62b84d31847f40680112e15ec579a6
|
||||
OCMock: 5ea90566be239f179ba766fd9fbae5885040b992
|
||||
|
||||
PODFILE CHECKSUM: 445046ac151568c694ff286684322273f0b597d6
|
||||
PODFILE CHECKSUM: ff1a1777e31f49e6e4b7b148d0f10e504db7fa26
|
||||
|
||||
COCOAPODS: 1.6.0
|
||||
COCOAPODS: 1.9.1
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"exp_graphics_contexts",
|
||||
"exp_text_node",
|
||||
"exp_interface_state_coalesce",
|
||||
"exp_unfair_lock",
|
||||
"exp_infer_layer_defaults",
|
||||
"exp_collection_teardown",
|
||||
"exp_framesetter_cache",
|
||||
@@ -24,7 +23,7 @@
|
||||
"exp_did_enter_preload_skip_asm_layout",
|
||||
"exp_dispatch_apply",
|
||||
"exp_oom_bg_dealloc_disable",
|
||||
"exp_remove_textkit_initialising_lock"
|
||||
"exp_do_not_cache_accessibility_elements",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,9 +140,12 @@
|
||||
// UIButton documentation states that it tints the image and title of buttons when tintColor is set.
|
||||
// | "The tint color to apply to the button title and image."
|
||||
// | From: https://developer.apple.com/documentation/uikit/uibutton/1624025-tintcolor
|
||||
[self lock];
|
||||
UIColor *tintColor = self.tintColor;
|
||||
self.imageNode.tintColor = tintColor;
|
||||
self.titleNode.tintColor = tintColor;
|
||||
[self unlock];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)updateImage
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
if (ASLockedSelfCompareAssign(_selected, selected)) {
|
||||
if (!_suspendInteractionDelegate) {
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[_interactionDelegate nodeSelectedStateDidChange:self];
|
||||
[self->_interactionDelegate nodeSelectedStateDidChange:self];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -153,7 +153,7 @@
|
||||
if (ASLockedSelfCompareAssign(_highlighted, highlighted)) {
|
||||
if (!_suspendInteractionDelegate) {
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[_interactionDelegate nodeHighlightedStateDidChange:self];
|
||||
[self->_interactionDelegate nodeHighlightedStateDidChange:self];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* A Boolean value that controls whether the horizontal scroll indicator is visible.
|
||||
* The default value of this property is NO.
|
||||
* The default value of this property is YES.
|
||||
*/
|
||||
@property (nonatomic) BOOL showsHorizontalScrollIndicator;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
// ASCellLayoutMode is an NSUInteger-based NS_OPTIONS field. Be careful with BOOL handling on the
|
||||
// 32-bit Objective-C runtime, and pattern after ASInterfaceStateIncludesVisible() & friends.
|
||||
#define ASCellLayoutModeIncludes(layoutMode) ((_cellLayoutMode & layoutMode) == layoutMode)
|
||||
#define ASCellLayoutModeIncludes(layoutMode) ((self->_cellLayoutMode & layoutMode) == layoutMode)
|
||||
|
||||
/// What, if any, invalidation should we perform during the next -layoutSubviews.
|
||||
typedef NS_ENUM(NSUInteger, ASCollectionViewInvalidationStyle) {
|
||||
@@ -331,12 +331,6 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
[self setAsyncDelegate:nil];
|
||||
[self setAsyncDataSource:nil];
|
||||
}
|
||||
|
||||
// Data controller & range controller may own a ton of nodes, let's deallocate those off-main.
|
||||
if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) {
|
||||
ASPerformBackgroundDeallocation(&_dataController);
|
||||
ASPerformBackgroundDeallocation(&_rangeController);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -1875,14 +1869,14 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
if (_asyncDelegateFlags.collectionNodeWillBeginBatchFetch) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
GET_COLLECTIONNODE_OR_RETURN(collectionNode, (void)0);
|
||||
os_log_debug(ASCollectionLog(), "Beginning batch fetch for %@ with context %@", collectionNode, _batchContext);
|
||||
[_asyncDelegate collectionNode:collectionNode willBeginBatchFetchWithContext:_batchContext];
|
||||
os_log_debug(ASCollectionLog(), "Beginning batch fetch for %@ with context %@", collectionNode, self->_batchContext);
|
||||
[self->_asyncDelegate collectionNode:collectionNode willBeginBatchFetchWithContext:self->_batchContext];
|
||||
});
|
||||
} else if (_asyncDelegateFlags.collectionViewWillBeginBatchFetch) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_asyncDelegate collectionView:self willBeginBatchFetchWithContext:_batchContext];
|
||||
[self->_asyncDelegate collectionView:self willBeginBatchFetchWithContext:self->_batchContext];
|
||||
#pragma clang diagnostic pop
|
||||
});
|
||||
}
|
||||
@@ -2248,20 +2242,20 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
ASPerformBlockWithoutAnimation(!changeSet.animated, ^{
|
||||
as_activity_scope(as_activity_create("Commit collection update", changeSet.rootActivity, OS_ACTIVITY_FLAG_DEFAULT));
|
||||
if (changeSet.includesReloadData) {
|
||||
_superIsPendingDataLoad = YES;
|
||||
self->_superIsPendingDataLoad = YES;
|
||||
updates();
|
||||
[self _superReloadData:nil completion:nil];
|
||||
os_log_debug(ASCollectionLog(), "Did reloadData %@", self.collectionNode);
|
||||
[changeSet executeCompletionHandlerWithFinished:YES];
|
||||
} else {
|
||||
[_layoutFacilitator collectionViewWillPerformBatchUpdates];
|
||||
[self->_layoutFacilitator collectionViewWillPerformBatchUpdates];
|
||||
|
||||
__block NSUInteger numberOfUpdates = 0;
|
||||
const auto completion = ^(BOOL finished) {
|
||||
as_activity_scope(as_activity_create("Handle collection update completion", changeSet.rootActivity, OS_ACTIVITY_FLAG_DEFAULT));
|
||||
as_log_verbose(ASCollectionLog(), "Update animation finished %{public}@", self.collectionNode);
|
||||
// Flush any range changes that happened as part of the update animations ending.
|
||||
[_rangeController updateIfNeeded];
|
||||
[self->_rangeController updateIfNeeded];
|
||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:numberOfUpdates];
|
||||
[changeSet executeCompletionHandlerWithFinished:finished];
|
||||
};
|
||||
@@ -2317,7 +2311,7 @@ static NSString * const kReuseIdentifier = @"_ASCollectionReuseIdentifier";
|
||||
|
||||
// Flush any range changes that happened as part of submitting the update.
|
||||
as_activity_scope(changeSet.rootActivity);
|
||||
[_rangeController updateIfNeeded];
|
||||
[self->_rangeController updateIfNeeded];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+9
-10
@@ -23,7 +23,6 @@
|
||||
|
||||
// Initial capacities for dispatch tables.
|
||||
#define kASControlNodeEventDispatchTableInitialCapacity 4
|
||||
#define kASControlNodeActionDispatchTableInitialCapacity 4
|
||||
|
||||
@interface ASControlNode ()
|
||||
{
|
||||
@@ -298,10 +297,10 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// add a highlight overlay node with area of ASControlNode + UIEdgeInsets
|
||||
self.clipsToBounds = NO;
|
||||
_debugHighlightOverlay = [[ASImageNode alloc] init];
|
||||
_debugHighlightOverlay.zPosition = 1000; // ensure we're over the top of any siblings
|
||||
_debugHighlightOverlay.layerBacked = YES;
|
||||
[self addSubnode:_debugHighlightOverlay];
|
||||
self->_debugHighlightOverlay = [[ASImageNode alloc] init];
|
||||
self->_debugHighlightOverlay.zPosition = 1000; // ensure we're over the top of any siblings
|
||||
self->_debugHighlightOverlay.layerBacked = YES;
|
||||
[self addSubnode:self->_debugHighlightOverlay];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -317,7 +316,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
{
|
||||
// Do we already have an event table for this control event?
|
||||
id<NSCopying> eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent);
|
||||
NSMutableArray *eventTargetActionArray = _controlEventDispatchTable[eventKey];
|
||||
NSMutableArray *eventTargetActionArray = self->_controlEventDispatchTable[eventKey];
|
||||
|
||||
if (!eventTargetActionArray) {
|
||||
eventTargetActionArray = [[NSMutableArray alloc] init];
|
||||
@@ -330,7 +329,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
[eventTargetActionArray addObject:targetAction];
|
||||
|
||||
if (eventKey) {
|
||||
[_controlEventDispatchTable setObject:eventTargetActionArray forKey:eventKey];
|
||||
[self->_controlEventDispatchTable setObject:eventTargetActionArray forKey:eventKey];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -391,7 +390,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
{
|
||||
// Grab the dispatch table for this event (if we have it).
|
||||
id<NSCopying> eventKey = _ASControlNodeEventKeyForControlEvent(controlEvent);
|
||||
NSMutableArray *eventTargetActionArray = _controlEventDispatchTable[eventKey];
|
||||
NSMutableArray *eventTargetActionArray = self->_controlEventDispatchTable[eventKey];
|
||||
if (!eventTargetActionArray) {
|
||||
return;
|
||||
}
|
||||
@@ -411,7 +410,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
|
||||
if (eventTargetActionArray.count == 0) {
|
||||
// If there are no targets for this event anymore, remove it.
|
||||
[_controlEventDispatchTable removeObjectForKey:eventKey];
|
||||
[self->_controlEventDispatchTable removeObjectForKey:eventKey];
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -433,7 +432,7 @@ CGRect _ASControlNodeGetExpandedBounds(ASControlNode *controlNode);
|
||||
(ASControlNodeEvent controlEvent)
|
||||
{
|
||||
// Iterate on each target action pair
|
||||
for (ASControlTargetAction *targetAction in _controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)]) {
|
||||
for (ASControlTargetAction *targetAction in self->_controlEventDispatchTable[_ASControlNodeEventKeyForControlEvent(controlEvent)]) {
|
||||
ASControlTargetAction *resolvedTargetAction = [[ASControlTargetAction alloc] init];
|
||||
resolvedTargetAction.action = targetAction.action;
|
||||
resolvedTargetAction.target = targetAction.target;
|
||||
|
||||
@@ -137,12 +137,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
_primitiveTraitCollection = traitCollection;
|
||||
|
||||
l.unlock();
|
||||
if (ASActivateExperimentalFeature(ASExperimentalTraitCollectionDidChangeWithPreviousCollection)) {
|
||||
[self asyncTraitCollectionDidChangeWithPreviousTraitCollection:previousTraitCollection];
|
||||
} else {
|
||||
[self asyncTraitCollectionDidChange];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,7 +381,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
|
||||
// Figure out previous and pending layouts for layout transition
|
||||
ASDisplayNodeLayout nextLayout = _pendingDisplayNodeLayout;
|
||||
#define layoutSizeDifferentFromBounds !CGSizeEqualToSize(nextLayout.layout.size, boundsSizeForLayout)
|
||||
BOOL isLayoutSizeDifferentFromBounds = !CGSizeEqualToSize(nextLayout.layout.size, boundsSizeForLayout);
|
||||
|
||||
// nextLayout was likely created by a call to layoutThatFits:, check if it is valid and can be applied.
|
||||
// If our bounds size is different than it, or invalid, recalculate. Use #define to avoid nullptr->
|
||||
@@ -395,7 +390,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
as_log_verbose(ASLayoutLog(), "No pending layout.");
|
||||
} else if (!nextLayout.isValid(_layoutVersion)) {
|
||||
as_log_verbose(ASLayoutLog(), "Pending layout is stale.");
|
||||
} else if (layoutSizeDifferentFromBounds) {
|
||||
} else if (isLayoutSizeDifferentFromBounds) {
|
||||
as_log_verbose(ASLayoutLog(), "Pending layout size %@ doesn't match bounds size.", NSStringFromCGSize(nextLayout.layout.size));
|
||||
} else {
|
||||
as_log_verbose(ASLayoutLog(), "Using pending layout %@.", nextLayout.layout);
|
||||
@@ -656,7 +651,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
as_log_verbose(ASLayoutLog(), "Transition ID is %d", transitionID);
|
||||
// NOTE: This block captures self. It's cheaper than hitting the weak table.
|
||||
asdisplaynode_iscancelled_block_t isCancelled = ^{
|
||||
BOOL result = (_transitionID != transitionID);
|
||||
BOOL result = (self->_transitionID != transitionID);
|
||||
if (result) {
|
||||
as_log_verbose(ASLayoutLog(), "Transition %d canceled, superseded by %d", transitionID, _transitionID.load());
|
||||
}
|
||||
@@ -677,7 +672,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
}
|
||||
|
||||
// Perform a full layout creation pass with passed in constrained size to create the new layout for the transition
|
||||
NSUInteger newLayoutVersion = _layoutVersion;
|
||||
NSUInteger newLayoutVersion = self->_layoutVersion;
|
||||
ASLayout *newLayout;
|
||||
{
|
||||
ASScopedLockSelfOrToRoot();
|
||||
@@ -712,10 +707,10 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
{
|
||||
// Grab __instanceLock__ here to make sure this transition isn't invalidated
|
||||
// right after it passed the validation test and before it proceeds
|
||||
MutexLocker l(__instanceLock__);
|
||||
MutexLocker l(self->__instanceLock__);
|
||||
|
||||
// Update calculated layout
|
||||
const auto previousLayout = _calculatedDisplayNodeLayout;
|
||||
const auto previousLayout = self->_calculatedDisplayNodeLayout;
|
||||
const auto pendingLayout = ASDisplayNodeLayout(newLayout,
|
||||
constrainedSize,
|
||||
constrainedSize.max,
|
||||
@@ -723,12 +718,12 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
[self _locked_setCalculatedDisplayNodeLayout:pendingLayout];
|
||||
|
||||
// Setup pending layout transition for animation
|
||||
_pendingLayoutTransition = pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self
|
||||
self->_pendingLayoutTransition = pendingLayoutTransition = [[ASLayoutTransition alloc] initWithNode:self
|
||||
pendingLayout:pendingLayout
|
||||
previousLayout:previousLayout];
|
||||
// Setup context for pending layout transition. we need to hold a strong reference to the context
|
||||
_pendingLayoutTransitionContext = pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated
|
||||
layoutDelegate:_pendingLayoutTransition
|
||||
self->_pendingLayoutTransitionContext = pendingLayoutTransitionContext = [[_ASTransitionContext alloc] initWithAnimation:animated
|
||||
layoutDelegate:self->_pendingLayoutTransition
|
||||
completionDelegate:self];
|
||||
}
|
||||
|
||||
@@ -1043,7 +1038,7 @@ ASLayoutElementStyleExtensibilityForwarding
|
||||
if (self.isNodeLoaded) {
|
||||
ASPerformBlockOnMainThread(^{
|
||||
if (self.contents == nil) {
|
||||
_placeholderImage = [self placeholderImage];
|
||||
self->_placeholderImage = [self placeholderImage];
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -205,15 +205,6 @@ AS_CATEGORY_IMPLEMENTABLE
|
||||
* @abstract Called when the node's ASTraitCollection changes
|
||||
*
|
||||
* @discussion Subclasses can override this method to react to a trait collection change.
|
||||
*/
|
||||
AS_CATEGORY_IMPLEMENTABLE
|
||||
- (void)asyncTraitCollectionDidChange ASDISPLAYNODE_REQUIRES_SUPER;
|
||||
|
||||
|
||||
/**
|
||||
* @abstract Called when the node's ASTraitCollection changes
|
||||
*
|
||||
* @discussion Subclasses can override this method to react to a trait collection change. Use `ASExperimentalTraitCollectionDidChangeWithPreviousCollection` to have this method called instead of `asyncTraitCollectionDidChange`.
|
||||
*
|
||||
* @param previousTraitCollection The ASPrimitiveTraitCollection object before the interface environment changed.
|
||||
*/
|
||||
|
||||
@@ -734,7 +734,7 @@ AS_EXTERN NSInteger const ASDefaultDrawingPriority;
|
||||
|
||||
@property BOOL allowsGroupOpacity;
|
||||
@property BOOL allowsEdgeAntialiasing;
|
||||
@property unsigned int edgeAntialiasingMask; // default==all values from CAEdgeAntialiasingMask
|
||||
@property CAEdgeAntialiasingMask edgeAntialiasingMask; // default==all values from CAEdgeAntialiasingMask
|
||||
|
||||
@property BOOL needsDisplayOnBoundsChange; // default==NO
|
||||
@property BOOL autoresizesSubviews; // default==YES (undefined for layer-backed nodes)
|
||||
|
||||
+57
-40
@@ -241,7 +241,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
||||
class_addMethod(self, @selector(didEnterVisibleState), noArgsImp, "v@:");
|
||||
class_addMethod(self, @selector(didExitVisibleState), noArgsImp, "v@:");
|
||||
class_addMethod(self, @selector(hierarchyDisplayDidFinish), noArgsImp, "v@:");
|
||||
class_addMethod(self, @selector(asyncTraitCollectionDidChange), noArgsImp, "v@:");
|
||||
class_addMethod(self, @selector(calculatedLayoutDidChange), noArgsImp, "v@:");
|
||||
|
||||
auto type0 = "v@:" + std::string(@encode(ASSizeRange));
|
||||
@@ -438,24 +437,42 @@ ASSynthesizeLockingMethodsWithMutex(__instanceLock__);
|
||||
- (void)asyncTraitCollectionDidChangeWithPreviousTraitCollection:(ASPrimitiveTraitCollection)previousTraitCollection
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
// When changing between light and dark mode, often the entire node needs to re-render.
|
||||
// This change doesn't happen frequently so it's fairly safe to render nodes again
|
||||
__instanceLock__.lock();
|
||||
if (self.primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
|
||||
// When changing between light and dark mode, often the entire node needs to re-render.
|
||||
// This change doesn't happen frequently so it's fairly safe to render nodes again
|
||||
if (_loaded(self) && self.isLayerBacked) {
|
||||
// Background colors do not dynamically update for layer backed nodes since they utilize CGColorRef
|
||||
// instead of UIColor. We utilize the _backgroundColor instance variable to track the full dynamic color
|
||||
// and apply any changes here when trait collection updates occur.
|
||||
CGColorRef cgBackgroundColor = _backgroundColor.CGColor;
|
||||
if (!CGColorEqualToColor(_layer.backgroundColor, cgBackgroundColor)) {
|
||||
_layer.backgroundColor = cgBackgroundColor;
|
||||
}
|
||||
}
|
||||
__instanceLock__.unlock();
|
||||
[self setNeedsDisplay];
|
||||
return;
|
||||
}
|
||||
BOOL loaded = _loaded(self);
|
||||
ASPrimitiveTraitCollection primitiveTraitCollection = _primitiveTraitCollection;
|
||||
__instanceLock__.unlock();
|
||||
if (primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
|
||||
if (loaded) {
|
||||
// we need to run that on main thread, cause accessing CALayer properties.
|
||||
// It seems than in iOS 13 sometimes it causes deadlock.
|
||||
ASPerformBlockOnMainThread(^{
|
||||
self->__instanceLock__.lock();
|
||||
CGFloat cornerRadius = self->_cornerRadius;
|
||||
ASCornerRoundingType cornerRoundingType = self->_cornerRoundingType;
|
||||
UIColor *backgroundColor = self->_backgroundColor;
|
||||
self->__instanceLock__.unlock();
|
||||
// TODO: we should resolve color using node's trait collection
|
||||
// but Texture changes it from many places, so we may receive the wrong one.
|
||||
CGColorRef cgBackgroundColor = backgroundColor.CGColor;
|
||||
if (!CGColorEqualToColor(self->_layer.backgroundColor, cgBackgroundColor)) {
|
||||
// Background colors do not dynamically update for layer backed nodes since they utilize CGColorRef
|
||||
// instead of UIColor. Non layer backed node also receive color to the layer (see [_ASPendingState -applyToView:withSpecialPropertiesHandling:]).
|
||||
// We utilize the _backgroundColor instance variable to track the full dynamic color
|
||||
// and apply any changes here when trait collection updates occur.
|
||||
self->_layer.backgroundColor = cgBackgroundColor;
|
||||
}
|
||||
|
||||
// If we have clipping corners, re-render the clipping corner layer upon user interface style change
|
||||
if (cornerRoundingType == ASCornerRoundingTypeClipping && cornerRadius > 0.0f) {
|
||||
[self _updateClipCornerLayerContentsWithRadius:cornerRadius backgroundColor:backgroundColor];
|
||||
}
|
||||
|
||||
[self setNeedsDisplay];
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1331,7 +1348,7 @@ NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimestamp = @"AS
|
||||
__instanceLock__.lock();
|
||||
if (_placeholderLayer.superlayer && !placeholderShouldPersist) {
|
||||
void (^cleanupBlock)() = ^{
|
||||
[_placeholderLayer removeFromSuperlayer];
|
||||
[self->_placeholderLayer removeFromSuperlayer];
|
||||
};
|
||||
|
||||
if (_placeholderFadeDuration > 0.0 && ASInterfaceStateIncludesVisible(self.interfaceState)) {
|
||||
@@ -1477,7 +1494,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
ASPerformBlockOnMainThread(^{
|
||||
for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
|
||||
// Skip corners that aren't clipped (we have already set up & torn down layers based on maskedCorners.)
|
||||
if (_clipCornerLayers[idx] == nil) {
|
||||
if (self->_clipCornerLayers[idx] == nil) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1487,7 +1504,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
BOOL isRight = (idx == 1 || idx == 3);
|
||||
|
||||
CGSize size = CGSizeMake(radius + 1, radius + 1);
|
||||
UIImage *newContents = ASGraphicsCreateImageWithOptions(size, NO, self.contentsScaleForDisplay, nil, nil, ^{
|
||||
UIImage *newContents = ASGraphicsCreateImage(self.primitiveTraitCollection, size, NO, self.contentsScaleForDisplay, nil, nil, ^{
|
||||
CGContextRef ctx = UIGraphicsGetCurrentContext();
|
||||
if (isRight == YES) {
|
||||
CGContextTranslateCTM(ctx, -radius + 1, 0);
|
||||
@@ -1503,7 +1520,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
});
|
||||
|
||||
// No lock needed, as _clipCornerLayers is only modified on the main thread.
|
||||
unowned CALayer *clipCornerLayer = _clipCornerLayers[idx];
|
||||
unowned CALayer *clipCornerLayer = self->_clipCornerLayers[idx];
|
||||
clipCornerLayer.contents = (id)(newContents.CGImage);
|
||||
clipCornerLayer.bounds = CGRectMake(0.0, 0.0, size.width, size.height);
|
||||
clipCornerLayer.anchorPoint = CGPointMake(isRight ? 1.0 : 0.0, isTop ? 0.0 : 1.0);
|
||||
@@ -1518,7 +1535,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
ASDisplayNodeAssertMainThread();
|
||||
for (int idx = 0; idx < NUM_CLIP_CORNER_LAYERS; idx++) {
|
||||
BOOL visible = (0 != (visibleCornerLayers & (1 << idx)));
|
||||
if (visible == (_clipCornerLayers[idx] != nil)) {
|
||||
if (visible == (self->_clipCornerLayers[idx] != nil)) {
|
||||
continue;
|
||||
} else if (visible) {
|
||||
static ASDisplayNodeCornerLayerDelegate *clipCornerLayers;
|
||||
@@ -1526,15 +1543,15 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
|
||||
dispatch_once(&onceToken, ^{
|
||||
clipCornerLayers = [[ASDisplayNodeCornerLayerDelegate alloc] init];
|
||||
});
|
||||
_clipCornerLayers[idx] = [[CALayer alloc] init];
|
||||
_clipCornerLayers[idx].zPosition = 99999;
|
||||
_clipCornerLayers[idx].delegate = clipCornerLayers;
|
||||
self->_clipCornerLayers[idx] = [[CALayer alloc] init];
|
||||
self->_clipCornerLayers[idx].zPosition = 99999;
|
||||
self->_clipCornerLayers[idx].delegate = clipCornerLayers;
|
||||
} else {
|
||||
[_clipCornerLayers[idx] removeFromSuperlayer];
|
||||
_clipCornerLayers[idx] = nil;
|
||||
[self->_clipCornerLayers[idx] removeFromSuperlayer];
|
||||
self->_clipCornerLayers[idx] = nil;
|
||||
}
|
||||
}
|
||||
[self _updateClipCornerLayerContentsWithRadius:_cornerRadius backgroundColor:self.backgroundColor];
|
||||
[self _updateClipCornerLayerContentsWithRadius:self->_cornerRadius backgroundColor:self.backgroundColor];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2791,13 +2808,13 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
|
||||
if (ASInterfaceStateIncludesVisible(self.pendingInterfaceState)) {
|
||||
void(^exitVisibleInterfaceState)(void) = ^{
|
||||
// This block intentionally retains self.
|
||||
__instanceLock__.lock();
|
||||
unsigned isStillInHierarchy = _flags.isInHierarchy;
|
||||
BOOL isVisible = ASInterfaceStateIncludesVisible(_pendingInterfaceState);
|
||||
ASInterfaceState newState = (_pendingInterfaceState & ~ASInterfaceStateVisible);
|
||||
self->__instanceLock__.lock();
|
||||
unsigned isStillInHierarchy = self->_flags.isInHierarchy;
|
||||
BOOL isVisible = ASInterfaceStateIncludesVisible(self->_pendingInterfaceState);
|
||||
ASInterfaceState newState = (self->_pendingInterfaceState & ~ASInterfaceStateVisible);
|
||||
// layer may be thrashed, we need to remember the state so we can reset if it enters in same runloop later.
|
||||
_preExitingInterfaceState = _pendingInterfaceState;
|
||||
__instanceLock__.unlock();
|
||||
self->_preExitingInterfaceState = self->_pendingInterfaceState;
|
||||
self->__instanceLock__.unlock();
|
||||
if (!isStillInHierarchy && isVisible) {
|
||||
#if ENABLE_NEW_EXIT_HIERARCHY_BEHAVIOR
|
||||
if (![self supportsRangeManagedInterfaceState]) {
|
||||
@@ -2956,9 +2973,9 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
|
||||
[self setDisplaySuspended:YES];
|
||||
//schedule clear contents on next runloop
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__instanceLock__.lock();
|
||||
ASInterfaceState interfaceState = _interfaceState;
|
||||
__instanceLock__.unlock();
|
||||
self->__instanceLock__.lock();
|
||||
ASInterfaceState interfaceState = self->_interfaceState;
|
||||
self->__instanceLock__.unlock();
|
||||
if (ASInterfaceStateIncludesDisplay(interfaceState) == NO) {
|
||||
[self clearContents];
|
||||
}
|
||||
@@ -2976,9 +2993,9 @@ ASDISPLAYNODE_INLINE BOOL subtreeIsRasterized(ASDisplayNode *node) {
|
||||
[[self asyncLayer] cancelAsyncDisplay];
|
||||
//schedule clear contents on next runloop
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__instanceLock__.lock();
|
||||
ASInterfaceState interfaceState = _interfaceState;
|
||||
__instanceLock__.unlock();
|
||||
self->__instanceLock__.lock();
|
||||
ASInterfaceState interfaceState = self->_interfaceState;
|
||||
self->__instanceLock__.unlock();
|
||||
if (ASInterfaceStateIncludesDisplay(interfaceState) == NO) {
|
||||
[self clearContents];
|
||||
}
|
||||
|
||||
@@ -176,11 +176,11 @@
|
||||
[super didLoad];
|
||||
|
||||
void (^configureTextView)(UITextView *) = ^(UITextView *textView) {
|
||||
if (!_displayingPlaceholder || textView != _textKitComponents.textView) {
|
||||
if (!self->_displayingPlaceholder || textView != self->_textKitComponents.textView) {
|
||||
// If showing the placeholder, don't propagate backgroundColor/opaque to the editable textView. It is positioned over the placeholder to accept taps to begin editing, and if it's opaque/colored then it'll obscure the placeholder.
|
||||
textView.backgroundColor = self.backgroundColor;
|
||||
textView.opaque = self.opaque;
|
||||
} else if (_displayingPlaceholder && textView == _textKitComponents.textView) {
|
||||
} else if (self->_displayingPlaceholder && textView == self->_textKitComponents.textView) {
|
||||
// The default backgroundColor for a textView is white. Due to the reason described above, make sure the editable textView starts out transparent.
|
||||
textView.backgroundColor = nil;
|
||||
textView.opaque = NO;
|
||||
@@ -189,16 +189,16 @@
|
||||
|
||||
// Configure textView with UITextInputTraits
|
||||
{
|
||||
AS::MutexLocker l(_textInputTraitsLock);
|
||||
if (_textInputTraits) {
|
||||
textView.autocapitalizationType = _textInputTraits.autocapitalizationType;
|
||||
textView.autocorrectionType = _textInputTraits.autocorrectionType;
|
||||
textView.spellCheckingType = _textInputTraits.spellCheckingType;
|
||||
textView.keyboardType = _textInputTraits.keyboardType;
|
||||
textView.keyboardAppearance = _textInputTraits.keyboardAppearance;
|
||||
textView.returnKeyType = _textInputTraits.returnKeyType;
|
||||
textView.enablesReturnKeyAutomatically = _textInputTraits.enablesReturnKeyAutomatically;
|
||||
textView.secureTextEntry = _textInputTraits.isSecureTextEntry;
|
||||
AS::MutexLocker l(self->_textInputTraitsLock);
|
||||
if (self->_textInputTraits) {
|
||||
textView.autocapitalizationType = self->_textInputTraits.autocapitalizationType;
|
||||
textView.autocorrectionType = self->_textInputTraits.autocorrectionType;
|
||||
textView.spellCheckingType = self->_textInputTraits.spellCheckingType;
|
||||
textView.keyboardType = self->_textInputTraits.keyboardType;
|
||||
textView.keyboardAppearance = self->_textInputTraits.keyboardAppearance;
|
||||
textView.returnKeyType = self->_textInputTraits.returnKeyType;
|
||||
textView.enablesReturnKeyAutomatically = self->_textInputTraits.enablesReturnKeyAutomatically;
|
||||
textView.secureTextEntry = self->_textInputTraits.isSecureTextEntry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -815,8 +815,8 @@
|
||||
// 2. This delegate method (-textViewDidChangeSelection:) is called both before -textViewDidChange: and before the layout manager/etc. has necessarily generated+laid out its glyphs. Because of the former, we need to wait until -textViewDidChange: has had an opportunity to be called so can accurately determine whether this selection change is due to editing (_selectionChangedForEditedText).
|
||||
// Thus, to avoid calling out to client code in the middle of UITextView's processing, we call the delegate on the next run of the runloop, when all such internal processing is surely done.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([_delegate respondsToSelector:@selector(editableTextNodeDidChangeSelection:fromSelectedRange:toSelectedRange:dueToEditing:)])
|
||||
[_delegate editableTextNodeDidChangeSelection:self fromSelectedRange:fromSelectedRange toSelectedRange:toSelectedRange dueToEditing:_selectionChangedForEditedText];
|
||||
if ([self->_delegate respondsToSelector:@selector(editableTextNodeDidChangeSelection:fromSelectedRange:toSelectedRange:dueToEditing:)])
|
||||
[self->_delegate editableTextNodeDidChangeSelection:self fromSelectedRange:fromSelectedRange toSelectedRange:toSelectedRange dueToEditing:self->_selectionChangedForEditedText];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -831,9 +831,9 @@
|
||||
// UITextView invokes its delegate methods when it's in the middle of text-processing. For example, -textViewDidChange: is invoked before you can truly rely on the changes being propagated throughout the Text Kit hierarchy.
|
||||
// Thus, to avoid calling out to client code in the middle of UITextView's processing, we call the delegate on the next run of the runloop, when all such internal processing is surely done.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_delegateDidUpdateEnqueued = NO;
|
||||
if ([_delegate respondsToSelector:@selector(editableTextNodeDidUpdateText:)])
|
||||
[_delegate editableTextNodeDidUpdateText:self];
|
||||
self->_delegateDidUpdateEnqueued = NO;
|
||||
if ([self->_delegate respondsToSelector:@selector(editableTextNodeDidUpdateText:)])
|
||||
[self->_delegate editableTextNodeDidUpdateText:self];
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -20,18 +20,15 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
|
||||
// will be used in all cases
|
||||
ASExperimentalTextNode = 1 << 0, // exp_text_node
|
||||
ASExperimentalInterfaceStateCoalescing = 1 << 1, // exp_interface_state_coalesce
|
||||
ASExperimentalUnfairLock = 1 << 2, // exp_unfair_lock
|
||||
ASExperimentalLayerDefaults = 1 << 3, // exp_infer_layer_defaults
|
||||
ASExperimentalCollectionTeardown = 1 << 4, // exp_collection_teardown
|
||||
ASExperimentalFramesetterCache = 1 << 5, // exp_framesetter_cache
|
||||
ASExperimentalSkipClearData = 1 << 6, // exp_skip_clear_data
|
||||
ASExperimentalDidEnterPreloadSkipASMLayout = 1 << 7, // exp_did_enter_preload_skip_asm_layout
|
||||
ASExperimentalDispatchApply = 1 << 8, // exp_dispatch_apply
|
||||
ASExperimentalOOMBackgroundDeallocDisable = 1 << 9, // exp_oom_bg_dealloc_disable
|
||||
ASExperimentalRemoveTextKitInitialisingLock = 1 << 10, // exp_remove_textkit_initialising_lock
|
||||
ASExperimentalDrawingGlobal = 1 << 11, // exp_drawing_global
|
||||
ASExperimentalOptimizeDataControllerPipeline = 1 << 12, // exp_optimize_data_controller_pipeline
|
||||
ASExperimentalTraitCollectionDidChangeWithPreviousCollection = 1 << 13, // exp_trait_collection_did_change_with_previous_collection
|
||||
ASExperimentalLayerDefaults = 1 << 2, // exp_infer_layer_defaults
|
||||
ASExperimentalCollectionTeardown = 1 << 3, // exp_collection_teardown
|
||||
ASExperimentalFramesetterCache = 1 << 4, // exp_framesetter_cache
|
||||
ASExperimentalSkipClearData = 1 << 5, // exp_skip_clear_data
|
||||
ASExperimentalDidEnterPreloadSkipASMLayout = 1 << 6, // exp_did_enter_preload_skip_asm_layout
|
||||
ASExperimentalDispatchApply = 1 << 7, // exp_dispatch_apply
|
||||
ASExperimentalDrawingGlobal = 1 << 8, // exp_drawing_global
|
||||
ASExperimentalOptimizeDataControllerPipeline = 1 << 9, // exp_optimize_data_controller_pipeline
|
||||
ASExperimentalDoNotCacheAccessibilityElements = 1 << 10, // exp_do_not_cache_accessibility_elements
|
||||
ASExperimentalFeatureAll = 0xFFFFFFFF
|
||||
};
|
||||
|
||||
|
||||
@@ -14,18 +14,15 @@ NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags
|
||||
{
|
||||
NSArray *allNames = ASCreateOnce((@[@"exp_text_node",
|
||||
@"exp_interface_state_coalesce",
|
||||
@"exp_unfair_lock",
|
||||
@"exp_infer_layer_defaults",
|
||||
@"exp_collection_teardown",
|
||||
@"exp_framesetter_cache",
|
||||
@"exp_skip_clear_data",
|
||||
@"exp_did_enter_preload_skip_asm_layout",
|
||||
@"exp_dispatch_apply",
|
||||
@"exp_oom_bg_dealloc_disable",
|
||||
@"exp_remove_textkit_initialising_lock",
|
||||
@"exp_drawing_global",
|
||||
@"exp_optimize_data_controller_pipeline",
|
||||
@"exp_trait_collection_did_change_with_previous_collection"]));
|
||||
@"exp_do_not_cache_accessibility_elements"]));
|
||||
if (flags == ASExperimentalFeatureAll) {
|
||||
return allNames;
|
||||
}
|
||||
|
||||
@@ -79,11 +79,6 @@
|
||||
// not fire e.g. while scrolling down
|
||||
CFRunLoopPerformBlock(CFRunLoopGetCurrent(), kCFRunLoopCommonModes, ^(void) {
|
||||
[self animatedImageSet:animatedImage previousAnimatedImage:previousAnimatedImage];
|
||||
|
||||
// Animated image can take while to dealloc, do it off the main queue
|
||||
if (previousAnimatedImage != nil && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) {
|
||||
ASPerformBackgroundDeallocation(&previousAnimatedImage);
|
||||
}
|
||||
});
|
||||
// Don't need to wakeup the runloop as the current is already running
|
||||
// CFRunLoopWakeUp(runLoop); // Should not be necessary
|
||||
|
||||
@@ -21,8 +21,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*
|
||||
* @return A transformed image.
|
||||
*/
|
||||
typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image);
|
||||
|
||||
typedef UIImage * _Nullable (^asimagenode_modification_block_t)(UIImage *image, ASPrimitiveTraitCollection traitCollection);
|
||||
|
||||
/**
|
||||
* @abstract Draws images.
|
||||
|
||||
+123
-109
@@ -30,8 +30,6 @@
|
||||
// TODO: It would be nice to remove this dependency; it's the only subclass using more than +FrameworkSubclasses.h
|
||||
#import <AsyncDisplayKit/ASDisplayNodeInternal.h>
|
||||
|
||||
static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
|
||||
@interface ASImageNodeDrawParameters : NSObject {
|
||||
@@ -52,9 +50,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
ASDisplayNodeContextModifier _willDisplayNodeContentWithRenderingContext;
|
||||
ASDisplayNodeContextModifier _didDisplayNodeContentWithRenderingContext;
|
||||
ASImageNodeDrawParametersBlock _didDrawBlock;
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
UIUserInterfaceStyle userInterfaceStyle;
|
||||
#endif
|
||||
ASPrimitiveTraitCollection _traitCollection;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -77,9 +73,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
@property (nonatomic) ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext;
|
||||
@property (nonatomic) ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext;
|
||||
@property (nonatomic) asimagenode_modification_block_t imageModificationBlock;
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
@property UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0));
|
||||
#endif
|
||||
@end
|
||||
|
||||
@implementation ASImageNodeContentsKey
|
||||
@@ -96,7 +90,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
// overheard of our caching, so it's likely not high-impact.
|
||||
if ([object isKindOfClass:[ASImageNodeContentsKey class]]) {
|
||||
ASImageNodeContentsKey *other = (ASImageNodeContentsKey *)object;
|
||||
return [_image isEqual:other.image]
|
||||
BOOL areKeysEqual = [_image isEqual:other.image]
|
||||
&& CGSizeEqualToSize(_backingSize, other.backingSize)
|
||||
&& CGRectEqualToRect(_imageDrawRect, other.imageDrawRect)
|
||||
&& _isOpaque == other.isOpaque
|
||||
@@ -104,10 +98,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
&& [_tintColor isEqual:other.tintColor]
|
||||
&& _willDisplayNodeContentWithRenderingContext == other.willDisplayNodeContentWithRenderingContext
|
||||
&& _didDisplayNodeContentWithRenderingContext == other.didDisplayNodeContentWithRenderingContext
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
&& _userInterfaceStyle == other.userInterfaceStyle
|
||||
#endif
|
||||
&& _imageModificationBlock == other.imageModificationBlock;
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
// iOS 12, tvOS 10 and later (userInterfaceStyle only available in iOS12+)
|
||||
areKeysEqual = areKeysEqual && _userInterfaceStyle == other.userInterfaceStyle;
|
||||
}
|
||||
return areKeysEqual;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
@@ -150,13 +146,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
UIImage *_image;
|
||||
ASWeakMapEntry *_weakCacheEntry; // Holds a reference that keeps our contents in cache.
|
||||
UIColor *_placeholderColor;
|
||||
UIColor *_tintColor; // Used to cache color information for layer backed nodes. View backed will use UIViewBridge
|
||||
|
||||
void (^_displayCompletionBlock)(BOOL canceled);
|
||||
|
||||
|
||||
// Drawing
|
||||
ASTextNode *_debugLabelNode;
|
||||
|
||||
|
||||
// Cropping.
|
||||
CGSize _forcedSize; //Defaults to CGSizeZero, indicating no forced size.
|
||||
CGRect _cropRect; // Defaults to CGRectMake(0.5, 0.5, 0, 0)
|
||||
@@ -186,11 +181,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
|
||||
_imageNodeFlags.cropEnabled = YES;
|
||||
_imageNodeFlags.forceUpscaling = NO;
|
||||
_imageNodeFlags.regenerateFromImageAsset = NO;
|
||||
_cropRect = CGRectMake(0.5, 0.5, 0, 0);
|
||||
_cropDisplayBounds = CGRectNull;
|
||||
_placeholderColor = ASDisplayNodeDefaultPlaceholderColor();
|
||||
_animatedImageRunLoopMode = ASAnimatedImageDefaultRunLoopMode;
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -210,8 +206,11 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
if ((size.width * size.height) < CGFLOAT_EPSILON) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return ASGraphicsCreateImageWithOptions(size, NO, 1, nil, nil, ^{
|
||||
|
||||
__instanceLock__.lock();
|
||||
ASPrimitiveTraitCollection tc = _primitiveTraitCollection;
|
||||
__instanceLock__.unlock();
|
||||
return ASGraphicsCreateImage(tc, size, NO, 1, nil, nil, ^{
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
[_placeholderColor setFill];
|
||||
UIRectFill(CGRectMake(0, 0, size.width, size.height));
|
||||
@@ -246,37 +245,26 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
return;
|
||||
}
|
||||
|
||||
UIImage *oldImage = _image;
|
||||
_image = image;
|
||||
|
||||
|
||||
if (image != nil) {
|
||||
// We explicitly call setNeedsDisplay in this case, although we know setNeedsDisplay will be called with lock held.
|
||||
// Therefore we have to be careful in methods that are involved with setNeedsDisplay to not run into a deadlock
|
||||
[self setNeedsDisplay];
|
||||
|
||||
|
||||
// For debugging purposes we don't care about locking for now
|
||||
if ([ASImageNode shouldShowImageScalingOverlay] && _debugLabelNode == nil) {
|
||||
// do not use ASPerformBlockOnMainThread here, if it performs the block synchronously it will continue
|
||||
// holding the lock while calling addSubnode.
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
_debugLabelNode = [[ASTextNode alloc] init];
|
||||
_debugLabelNode.layerBacked = YES;
|
||||
[self addSubnode:_debugLabelNode];
|
||||
self->_debugLabelNode = [[ASTextNode alloc] init];
|
||||
self->_debugLabelNode.layerBacked = YES;
|
||||
[self addSubnode:self->_debugLabelNode];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
self.contents = nil;
|
||||
}
|
||||
|
||||
// Destruction of bigger images on the main thread can be expensive
|
||||
// and can take some time, so we dispatch onto a bg queue to
|
||||
// actually dealloc.
|
||||
CGSize oldImageSize = oldImage.size;
|
||||
BOOL shouldReleaseImageOnBackgroundThread = oldImageSize.width > kMinReleaseImageOnBackgroundSize.width
|
||||
|| oldImageSize.height > kMinReleaseImageOnBackgroundSize.height;
|
||||
if (shouldReleaseImageOnBackgroundThread && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) {
|
||||
ASPerformBackgroundDeallocation(&oldImage);
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)image
|
||||
@@ -301,35 +289,49 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
|
||||
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
|
||||
{
|
||||
ASLockScopeSelf();
|
||||
|
||||
ASImageNodeDrawParameters *drawParameters = [[ASImageNodeDrawParameters alloc] init];
|
||||
drawParameters->_image = _image;
|
||||
|
||||
{
|
||||
ASLockScopeSelf();
|
||||
UIImage *drawImage = _image;
|
||||
if (AS_AVAILABLE_IOS_TVOS(13, 10)) {
|
||||
if (_imageNodeFlags.regenerateFromImageAsset && drawImage != nil) {
|
||||
_imageNodeFlags.regenerateFromImageAsset = NO;
|
||||
UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:_primitiveTraitCollection.userInterfaceStyle];
|
||||
UIImage *generatedImage = [drawImage.imageAsset imageWithTraitCollection:tc];
|
||||
if ( generatedImage != nil ) {
|
||||
drawImage = generatedImage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
drawParameters->_image = drawImage;
|
||||
drawParameters->_contentsScale = _contentsScaleForDisplay;
|
||||
drawParameters->_cropEnabled = _imageNodeFlags.cropEnabled;
|
||||
drawParameters->_forceUpscaling = _imageNodeFlags.forceUpscaling;
|
||||
drawParameters->_forcedSize = _forcedSize;
|
||||
drawParameters->_cropRect = _cropRect;
|
||||
drawParameters->_cropDisplayBounds = _cropDisplayBounds;
|
||||
drawParameters->_imageModificationBlock = _imageModificationBlock;
|
||||
drawParameters->_willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext;
|
||||
drawParameters->_didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext;
|
||||
drawParameters->_traitCollection = _primitiveTraitCollection;
|
||||
|
||||
// Hack for now to retain the weak entry that was created while this drawing happened
|
||||
drawParameters->_didDrawBlock = ^(ASWeakMapEntry *entry){
|
||||
ASLockScopeSelf();
|
||||
self->_weakCacheEntry = entry;
|
||||
};
|
||||
}
|
||||
|
||||
// We need to unlock before we access the other accessor.
|
||||
// Especially tintColor because it needs to walk up the view hierarchy
|
||||
drawParameters->_bounds = [self threadSafeBounds];
|
||||
drawParameters->_opaque = self.opaque;
|
||||
drawParameters->_contentsScale = _contentsScaleForDisplay;
|
||||
drawParameters->_backgroundColor = self.backgroundColor;
|
||||
drawParameters->_tintColor = self.tintColor;
|
||||
drawParameters->_contentMode = self.contentMode;
|
||||
drawParameters->_cropEnabled = _imageNodeFlags.cropEnabled;
|
||||
drawParameters->_forceUpscaling = _imageNodeFlags.forceUpscaling;
|
||||
drawParameters->_forcedSize = _forcedSize;
|
||||
drawParameters->_cropRect = _cropRect;
|
||||
drawParameters->_cropDisplayBounds = _cropDisplayBounds;
|
||||
drawParameters->_imageModificationBlock = _imageModificationBlock;
|
||||
drawParameters->_willDisplayNodeContentWithRenderingContext = _willDisplayNodeContentWithRenderingContext;
|
||||
drawParameters->_didDisplayNodeContentWithRenderingContext = _didDisplayNodeContentWithRenderingContext;
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
drawParameters->userInterfaceStyle = self.primitiveTraitCollection.userInterfaceStyle;
|
||||
#endif
|
||||
drawParameters->_tintColor = self.tintColor;
|
||||
|
||||
|
||||
// Hack for now to retain the weak entry that was created while this drawing happened
|
||||
drawParameters->_didDrawBlock = ^(ASWeakMapEntry *entry){
|
||||
ASLockScopeSelf();
|
||||
_weakCacheEntry = entry;
|
||||
};
|
||||
|
||||
return drawParameters;
|
||||
}
|
||||
|
||||
@@ -341,7 +343,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
if (image == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
CGRect drawParameterBounds = drawParameter->_bounds;
|
||||
BOOL forceUpscaling = drawParameter->_forceUpscaling;
|
||||
CGSize forcedSize = drawParameter->_forcedSize;
|
||||
@@ -356,39 +358,39 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
asimagenode_modification_block_t imageModificationBlock = drawParameter->_imageModificationBlock;
|
||||
ASDisplayNodeContextModifier willDisplayNodeContentWithRenderingContext = drawParameter->_willDisplayNodeContentWithRenderingContext;
|
||||
ASDisplayNodeContextModifier didDisplayNodeContentWithRenderingContext = drawParameter->_didDisplayNodeContentWithRenderingContext;
|
||||
|
||||
|
||||
BOOL hasValidCropBounds = cropEnabled && !CGRectIsEmpty(cropDisplayBounds);
|
||||
CGRect bounds = (hasValidCropBounds ? cropDisplayBounds : drawParameterBounds);
|
||||
|
||||
|
||||
|
||||
|
||||
ASDisplayNodeAssert(contentsScale > 0, @"invalid contentsScale at display time");
|
||||
|
||||
|
||||
// if the image is resizable, bail early since the image has likely already been configured
|
||||
BOOL stretchable = !UIEdgeInsetsEqualToEdgeInsets(image.capInsets, UIEdgeInsetsZero);
|
||||
if (stretchable) {
|
||||
if (imageModificationBlock != NULL) {
|
||||
image = imageModificationBlock(image);
|
||||
image = imageModificationBlock(image, drawParameter->_traitCollection);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
|
||||
CGSize imageSize = image.size;
|
||||
CGSize imageSizeInPixels = CGSizeMake(imageSize.width * image.scale, imageSize.height * image.scale);
|
||||
CGSize boundsSizeInPixels = CGSizeMake(std::floor(bounds.size.width * contentsScale), std::floor(bounds.size.height * contentsScale));
|
||||
|
||||
|
||||
BOOL contentModeSupported = contentMode == UIViewContentModeScaleAspectFill ||
|
||||
contentMode == UIViewContentModeScaleAspectFit ||
|
||||
contentMode == UIViewContentModeCenter;
|
||||
|
||||
|
||||
CGSize backingSize = CGSizeZero;
|
||||
CGRect imageDrawRect = CGRectZero;
|
||||
|
||||
|
||||
if (boundsSizeInPixels.width * contentsScale < 1.0f || boundsSizeInPixels.height * contentsScale < 1.0f ||
|
||||
imageSizeInPixels.width < 1.0f || imageSizeInPixels.height < 1.0f) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// If we're not supposed to do any cropping, just decode image at original size
|
||||
if (!cropEnabled || !contentModeSupported) {
|
||||
backingSize = imageSizeInPixels;
|
||||
@@ -408,18 +410,12 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
&backingSize,
|
||||
&imageDrawRect);
|
||||
}
|
||||
|
||||
|
||||
if (backingSize.width <= 0.0f || backingSize.height <= 0.0f ||
|
||||
imageDrawRect.size.width <= 0.0f || imageDrawRect.size.height <= 0.0f) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
UIUserInterfaceStyle userInterfaceStyle = drawParameter->userInterfaceStyle;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
ASImageNodeContentsKey *contentsKey = [[ASImageNodeContentsKey alloc] init];
|
||||
contentsKey.image = image;
|
||||
contentsKey.backingSize = backingSize;
|
||||
@@ -430,9 +426,11 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
contentsKey.willDisplayNodeContentWithRenderingContext = willDisplayNodeContentWithRenderingContext;
|
||||
contentsKey.didDisplayNodeContentWithRenderingContext = didDisplayNodeContentWithRenderingContext;
|
||||
contentsKey.imageModificationBlock = imageModificationBlock;
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
contentsKey.userInterfaceStyle = userInterfaceStyle;
|
||||
#endif
|
||||
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
contentsKey.userInterfaceStyle = drawParameter->_traitCollection.userInterfaceStyle;
|
||||
}
|
||||
|
||||
if (isCancelled()) {
|
||||
return nil;
|
||||
}
|
||||
@@ -444,7 +442,7 @@ typedef void (^ASImageNodeDrawParametersBlock)(ASWeakMapEntry *entry);
|
||||
if (entry == nil) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
if (drawParameter->_didDrawBlock) {
|
||||
drawParameter->_didDrawBlock(entry);
|
||||
}
|
||||
@@ -461,7 +459,7 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
cacheLock = new AS::Mutex();
|
||||
});
|
||||
|
||||
|
||||
{
|
||||
AS::MutexLocker l(*cacheLock);
|
||||
if (!cache) {
|
||||
@@ -485,18 +483,20 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
}
|
||||
}
|
||||
|
||||
+ (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)drawParameters isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
|
||||
+ (UIImage *)createContentsForkey:(ASImageNodeContentsKey *)key drawParameters:(id)parameter isCancelled:(asdisplaynode_iscancelled_block_t)isCancelled
|
||||
{
|
||||
// The following `ASGraphicsCreateImageWithOptions` call will sometimes take take longer than 5ms on an
|
||||
// The following `ASGraphicsCreateImage` call will sometimes take take longer than 5ms on an
|
||||
// A5 processor for a 400x800 backingSize.
|
||||
// Check for cancellation before we call it.
|
||||
if (isCancelled()) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
ASImageNodeDrawParameters *drawParameters = (ASImageNodeDrawParameters *)parameter;
|
||||
|
||||
// Use contentsScale of 1.0 and do the contentsScale handling in boundsSizeInPixels so ASCroppedImageBackingSizeAndDrawRectInBounds
|
||||
// will do its rounding on pixel instead of point boundaries
|
||||
UIImage *result = ASGraphicsCreateImageWithOptions(key.backingSize, key.isOpaque, 1.0, key.image, isCancelled, ^{
|
||||
UIImage *result = ASGraphicsCreateImage(drawParameters->_traitCollection, key.backingSize, key.isOpaque, 1.0, key.image, isCancelled, ^{
|
||||
BOOL contextIsClean = YES;
|
||||
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
@@ -548,9 +548,9 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
}
|
||||
|
||||
if (key.imageModificationBlock) {
|
||||
result = key.imageModificationBlock(result);
|
||||
result = key.imageModificationBlock(result, drawParameters->_traitCollection);
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -587,7 +587,7 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
_debugLabelNode.attributedText = nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If we've got a block to perform after displaying, do it.
|
||||
if (shouldPerformDisplayCompletionBlock) {
|
||||
displayCompletionBlock(NO);
|
||||
@@ -613,20 +613,39 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
- (void)tintColorDidChange
|
||||
- (void)_setNeedsDisplayOnTemplatedImages
|
||||
{
|
||||
[super tintColorDidChange];
|
||||
if (_image.renderingMode == UIImageRenderingModeAlwaysTemplate) {
|
||||
BOOL isTemplateImage = NO;
|
||||
{
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
isTemplateImage = (_image.renderingMode == UIImageRenderingModeAlwaysTemplate);
|
||||
}
|
||||
|
||||
if (isTemplateImage) {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tintColorDidChange
|
||||
{
|
||||
[super tintColorDidChange];
|
||||
|
||||
[self _setNeedsDisplayOnTemplatedImages];
|
||||
}
|
||||
|
||||
#pragma mark Interface State
|
||||
|
||||
- (void)didEnterHierarchy
|
||||
{
|
||||
[super didEnterHierarchy];
|
||||
|
||||
[self _setNeedsDisplayOnTemplatedImages];
|
||||
}
|
||||
|
||||
- (void)clearContents
|
||||
{
|
||||
[super clearContents];
|
||||
|
||||
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
_weakCacheEntry = nil; // release contents from the cache.
|
||||
}
|
||||
@@ -654,7 +673,7 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
|
||||
_imageNodeFlags.cropEnabled = cropEnabled;
|
||||
_cropDisplayBounds = cropBounds;
|
||||
|
||||
|
||||
UIImage *image = _image;
|
||||
__instanceLock__.unlock();
|
||||
|
||||
@@ -740,7 +759,7 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
- (void)layout
|
||||
{
|
||||
[super layout];
|
||||
|
||||
|
||||
if (_debugLabelNode) {
|
||||
CGSize boundsSize = self.bounds.size;
|
||||
CGSize debugLabelSize = [_debugLabelNode layoutThatFits:ASSizeRangeMake(CGSizeZero, boundsSize)].size;
|
||||
@@ -758,33 +777,28 @@ static ASWeakMap<ASImageNodeContentsKey *, UIImage *> *cache = nil;
|
||||
};
|
||||
}
|
||||
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
- (void)asyncTraitCollectionDidChangeWithPreviousTraitCollection:(ASPrimitiveTraitCollection)previousTraitCollection {
|
||||
[super asyncTraitCollectionDidChangeWithPreviousTraitCollection:previousTraitCollection];
|
||||
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
|
||||
if (AS_AVAILABLE_IOS_TVOS(13, 10)) {
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
// update image if userInterfaceStyle was changed (dark mode)
|
||||
if (_image != nil && self.primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
|
||||
UITraitCollection *tc = [UITraitCollection traitCollectionWithUserInterfaceStyle:self.primitiveTraitCollection.userInterfaceStyle];
|
||||
// get an updated image from asset catalog
|
||||
UIImage *updatedImage = [self.image.imageAsset imageWithTraitCollection:tc];
|
||||
if ( updatedImage != nil ) {
|
||||
_image = updatedImage;
|
||||
}
|
||||
// trigger needs display anyway, cause image might be dynamic itself (e.g. dynamic tint color)
|
||||
[self setNeedsDisplay];
|
||||
if (_image != nil
|
||||
&& _primitiveTraitCollection.userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
|
||||
_imageNodeFlags.regenerateFromImageAsset = YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - Extras
|
||||
|
||||
asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat borderWidth, UIColor *borderColor)
|
||||
{
|
||||
return ^(UIImage *originalImage) {
|
||||
return ASGraphicsCreateImageWithOptions(originalImage.size, NO, originalImage.scale, originalImage, nil, ^{
|
||||
return ^(UIImage *originalImage, ASPrimitiveTraitCollection traitCollection) {
|
||||
return ASGraphicsCreateImage(traitCollection, originalImage.size, NO, originalImage.scale, originalImage, nil, ^{
|
||||
UIBezierPath *roundOutline = [UIBezierPath bezierPathWithOvalInRect:(CGRect){CGPointZero, originalImage.size}];
|
||||
|
||||
// Make the image round
|
||||
@@ -805,8 +819,8 @@ asimagenode_modification_block_t ASImageNodeRoundBorderModificationBlock(CGFloat
|
||||
|
||||
asimagenode_modification_block_t ASImageNodeTintColorModificationBlock(UIColor *color)
|
||||
{
|
||||
return ^(UIImage *originalImage) {
|
||||
UIImage *modifiedImage = ASGraphicsCreateImageWithOptions(originalImage.size, NO, originalImage.scale, originalImage, nil, ^{
|
||||
return ^(UIImage *originalImage, ASPrimitiveTraitCollection traitCollection) {
|
||||
UIImage *modifiedImage = ASGraphicsCreateImage(traitCollection, originalImage.size, NO, originalImage.scale, originalImage, nil, ^{
|
||||
// Set color and render template
|
||||
[color setFill];
|
||||
UIImage *templateImage = [originalImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
|
||||
+1
-1
@@ -221,7 +221,7 @@
|
||||
|
||||
CGRect finalImageRect = CGRectMake(0, 0, image.size.width, image.size.height);
|
||||
|
||||
image = ASGraphicsCreateImageWithOptions(image.size, YES, image.scale, image, nil, ^{
|
||||
image = ASGraphicsCreateImage(strongSelf.primitiveTraitCollection, image.size, YES, image.scale, image, nil, ^{
|
||||
[image drawAtPoint:CGPointZero];
|
||||
|
||||
UIImage *pinImage;
|
||||
|
||||
@@ -39,8 +39,6 @@ NSString *const ASMultiplexImageNodeErrorDomain = @"ASMultiplexImageNodeErrorDom
|
||||
static NSString *const kAssetsLibraryURLScheme = @"assets-library";
|
||||
#endif
|
||||
|
||||
static const CGSize kMinReleaseImageOnBackgroundSize = {20.0, 20.0};
|
||||
|
||||
/**
|
||||
@abstract Signature for the block to be performed after an image has loaded.
|
||||
@param image The image that was loaded, or nil if no image was loaded.
|
||||
@@ -533,17 +531,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
|
||||
- (void)_clearImage
|
||||
{
|
||||
// Destruction of bigger images on the main thread can be expensive
|
||||
// and can take some time, so we dispatch onto a bg queue to
|
||||
// actually dealloc.
|
||||
UIImage *image = self.image;
|
||||
CGSize imageSize = image.size;
|
||||
BOOL shouldReleaseImageOnBackgroundThread = imageSize.width > kMinReleaseImageOnBackgroundSize.width ||
|
||||
imageSize.height > kMinReleaseImageOnBackgroundSize.height;
|
||||
[self _setImage:nil];
|
||||
if (shouldReleaseImageOnBackgroundThread && ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) {
|
||||
ASPerformBackgroundDeallocation(&image);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -742,7 +730,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
PHAsset *imageAsset = nil;
|
||||
|
||||
// Try to get the asset immediately from the data source.
|
||||
if (_dataSourceFlags.asset) {
|
||||
if (strongSelf->_dataSourceFlags.asset) {
|
||||
imageAsset = [strongSelf.dataSource multiplexImageNode:strongSelf assetForLocalIdentifier:request.assetIdentifier];
|
||||
}
|
||||
|
||||
@@ -806,7 +794,7 @@ typedef void(^ASMultiplexImageLoadCompletionBlock)(UIImage *image, id imageIdent
|
||||
ASDisplayNodeAssertNotNil(completionBlock, @"completionBlock is required");
|
||||
|
||||
if (_cache) {
|
||||
[_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(id <ASImageContainerProtocol> imageContainer) {
|
||||
[_cache cachedImageWithURL:imageURL callbackQueue:dispatch_get_main_queue() completion:^(id <ASImageContainerProtocol> imageContainer, __unused ASImageCacheType cacheType ) {
|
||||
completionBlock([imageContainer asdk_image]);
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -867,7 +867,7 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
||||
|
||||
as_log_verbose(ASImageLoadingLog(), "Decaching image for %@ url: %@", self, URL);
|
||||
|
||||
ASImageCacherCompletion completion = ^(id <ASImageContainerProtocol> imageContainer) {
|
||||
ASImageCacherCompletion completion = ^(id <ASImageContainerProtocol> imageContainer, ASImageCacheType cacheType) {
|
||||
// If the cache sentinel changed, that means this request was cancelled.
|
||||
if (ASLockedSelf(self->_cacheSentinel != cacheSentinel)) {
|
||||
return;
|
||||
@@ -887,8 +887,8 @@ static std::atomic_bool _useMainThreadDelegateCallbacks(true);
|
||||
if (delegateDidLoadImageFromCache) {
|
||||
[delegate imageNodeDidLoadImageFromCache:self];
|
||||
}
|
||||
as_log_verbose(ASImageLoadingLog(), "Decached image for %@ img: %@ url: %@", self, [imageContainer asdk_image], URL);
|
||||
finished(imageContainer, nil, nil, ASNetworkImageSourceAsynchronousCache, nil);
|
||||
as_log_verbose(ASImageLoadingLog(), "Decached image for %@ img: %@ url: %@ cacheType: %@", self, [imageContainer asdk_image], URL, cacheType);
|
||||
finished(imageContainer, nil, nil, cacheType == ASImageCacheTypeSynchronous ? ASNetworkImageSourceSynchronousCache : ASNetworkImageSourceAsynchronousCache, nil);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#import <AsyncDisplayKit/ASPagerFlowLayout.h>
|
||||
#import <AsyncDisplayKit/ASCellNode.h>
|
||||
#import <AsyncDisplayKit/UIResponder+AsyncDisplayKit.h>
|
||||
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
|
||||
|
||||
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionDelegate, ASCollectionDelegateFlowLayout, ASDelegateProxyInterceptor, ASCollectionGalleryLayoutPropertiesProviding>
|
||||
{
|
||||
|
||||
@@ -80,7 +80,6 @@ NS_INLINE ASCATransactionQueue *ASCATransactionQueueGet(void) {
|
||||
|
||||
@interface ASDeallocQueue : NSObject
|
||||
|
||||
@property (class, readonly) ASDeallocQueue *sharedDeallocationQueue;
|
||||
+ (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED;
|
||||
|
||||
- (void)drain;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#import <AsyncDisplayKit/ASRunLoopQueue.h>
|
||||
#import <AsyncDisplayKit/ASThread.h>
|
||||
#import <AsyncDisplayKit/ASSignpost.h>
|
||||
#import <deque>
|
||||
#import <vector>
|
||||
|
||||
#define ASRunLoopQueueLoggingEnabled 0
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
|
||||
#import <AsyncDisplayKit/ASRangeController.h>
|
||||
#import <AsyncDisplayKit/ASAbstractLayoutController+FrameworkPrivate.h>
|
||||
#import <AsyncDisplayKit/ASTableView+Undeprecated.h>
|
||||
|
||||
#pragma mark - _ASTablePendingState
|
||||
|
||||
|
||||
+11
-12
@@ -20,6 +20,7 @@
|
||||
#import <AsyncDisplayKit/ASDelegateProxy.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+FrameworkPrivate.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeInternal.h>
|
||||
#import <AsyncDisplayKit/ASElementMap.h>
|
||||
#import <AsyncDisplayKit/ASInternalHelpers.h>
|
||||
#import <AsyncDisplayKit/ASLayout.h>
|
||||
@@ -27,6 +28,8 @@
|
||||
#import <AsyncDisplayKit/ASRangeController.h>
|
||||
#import <AsyncDisplayKit/ASTableLayoutController.h>
|
||||
#import <AsyncDisplayKit/ASBatchContext.h>
|
||||
#import <AsyncDisplayKit/ASTableView+Undeprecated.h>
|
||||
|
||||
|
||||
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
@@ -113,12 +116,14 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
self.selectionStyle = node.selectionStyle;
|
||||
self.focusStyle = node.focusStyle;
|
||||
self.accessoryType = node.accessoryType;
|
||||
self.tintColor = node.tintColor;
|
||||
|
||||
// the following ensures that we clip the entire cell to it's bounds if node.clipsToBounds is set (the default)
|
||||
// This is actually a workaround for a bug we are seeing in some rare cases (selected background view
|
||||
// overlaps other cells if size of ASCellNode has changed.)
|
||||
self.clipsToBounds = node.clipsToBounds;
|
||||
|
||||
// If the cell node has been explicitly configured with a tint color, we can apply that directly to the cell view to preserve the previous behavior
|
||||
self.tintColor = node->_tintColor;
|
||||
}
|
||||
|
||||
[node __setSelectedFromUIKit:self.selected];
|
||||
@@ -368,12 +373,6 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
[self setAsyncDelegate:nil];
|
||||
[self setAsyncDataSource:nil];
|
||||
}
|
||||
|
||||
// Data controller & range controller may own a ton of nodes, let's deallocate those off-main
|
||||
if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable) == NO) {
|
||||
ASPerformBackgroundDeallocation(&_dataController);
|
||||
ASPerformBackgroundDeallocation(&_rangeController);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
@@ -1497,13 +1496,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
if (_asyncDelegateFlags.tableNodeWillBeginBatchFetch) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
GET_TABLENODE_OR_RETURN(tableNode, (void)0);
|
||||
[_asyncDelegate tableNode:tableNode willBeginBatchFetchWithContext:_batchContext];
|
||||
[self->_asyncDelegate tableNode:tableNode willBeginBatchFetchWithContext:self->_batchContext];
|
||||
});
|
||||
} else if (_asyncDelegateFlags.tableViewWillBeginBatchFetch) {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[_asyncDelegate tableView:self willBeginBatchFetchWithContext:_batchContext];
|
||||
[self->_asyncDelegate tableView:self willBeginBatchFetchWithContext:self->_batchContext];
|
||||
#pragma clang diagnostic pop
|
||||
});
|
||||
}
|
||||
@@ -1561,7 +1560,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
updates();
|
||||
[super reloadData];
|
||||
// Flush any range changes that happened as part of submitting the reload.
|
||||
[_rangeController updateIfNeeded];
|
||||
[self->_rangeController updateIfNeeded];
|
||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:1];
|
||||
[changeSet executeCompletionHandlerWithFinished:YES];
|
||||
});
|
||||
@@ -1679,7 +1678,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
LOG(@"--- UITableView endUpdates");
|
||||
ASPerformBlockWithoutAnimation(!changeSet.animated, ^{
|
||||
[super endUpdates];
|
||||
[_rangeController updateIfNeeded];
|
||||
[self->_rangeController updateIfNeeded];
|
||||
[self _scheduleCheckForBatchFetchingForNumberOfChanges:numberOfUpdates];
|
||||
});
|
||||
if (shouldAdjustContentOffset) {
|
||||
@@ -1784,7 +1783,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
if (node.interactionDelegate == nil) {
|
||||
node.interactionDelegate = strongSelf;
|
||||
}
|
||||
if (_inverted) {
|
||||
if (self->_inverted) {
|
||||
node.transform = CATransform3DMakeScale(1, -1, 1) ;
|
||||
}
|
||||
return node;
|
||||
|
||||
@@ -75,7 +75,13 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
#if TARGET_OS_IOS
|
||||
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath API_DEPRECATED_WITH_REPLACEMENT("tableView:trailingSwipeActionsConfigurationForRowAtIndexPath:", ios(8.0, 13.0));
|
||||
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0));
|
||||
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0));
|
||||
- (nullable UIContextMenuConfiguration *)tableView:(UITableView *)tableView contextMenuConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath point:(CGPoint)point API_AVAILABLE(ios(13.0));
|
||||
- (nullable UITargetedPreview *)tableView:(UITableView *)tableView previewForHighlightingContextMenuWithConfiguration:(UIContextMenuConfiguration *)configuration API_AVAILABLE(ios(13.0));
|
||||
- (nullable UITargetedPreview *)tableView:(UITableView *)tableView previewForDismissingContextMenuWithConfiguration:(UIContextMenuConfiguration *)configuration API_AVAILABLE(ios(13.0));
|
||||
- (void)tableView:(UITableView *)tableView willPerformPreviewActionForMenuWithConfiguration:(UIContextMenuConfiguration *)configuration animator:(id<UIContextMenuInteractionCommitAnimating>)animator API_AVAILABLE(ios(13.0));
|
||||
#endif
|
||||
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
|
||||
+53
-4
@@ -140,6 +140,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
||||
CGFloat _contentScale;
|
||||
BOOL _opaque;
|
||||
CGRect _bounds;
|
||||
ASPrimitiveTraitCollection _traitCollection;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -151,6 +152,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
||||
contentScale:(CGFloat)contentScale
|
||||
opaque:(BOOL)opaque
|
||||
bounds:(CGRect)bounds
|
||||
traitCollection: (ASPrimitiveTraitCollection)traitCollection
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
@@ -160,6 +162,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
||||
_contentScale = contentScale;
|
||||
_opaque = opaque;
|
||||
_bounds = bounds;
|
||||
_traitCollection = traitCollection;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -183,6 +186,7 @@ static ASTextKitRenderer *rendererForAttributes(ASTextKitAttributes attributes,
|
||||
CGSize _shadowOffset;
|
||||
CGColorRef _shadowColor;
|
||||
UIColor *_cachedShadowUIColor;
|
||||
UIColor *_cachedTintColor;
|
||||
UIColor *_placeholderColor;
|
||||
CGFloat _shadowOpacity;
|
||||
CGFloat _shadowRadius;
|
||||
@@ -382,7 +386,7 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
.shadowColor = _cachedShadowUIColor,
|
||||
.shadowOpacity = _shadowOpacity,
|
||||
.shadowRadius = _shadowRadius,
|
||||
.tintColor = self.textColorFollowsTintColor ? self.tintColor : nil
|
||||
.tintColor = _cachedTintColor
|
||||
};
|
||||
}
|
||||
|
||||
@@ -542,14 +546,21 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
|
||||
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
|
||||
{
|
||||
/// have to access tintColor outside of the lock to prevent dead lock when accessing up the view hierarchy
|
||||
UIColor *tintColor = self.tintColor;
|
||||
ASLockScopeSelf();
|
||||
|
||||
if (_textColorFollowsTintColor) {
|
||||
_cachedTintColor = tintColor;
|
||||
} else {
|
||||
_cachedTintColor = nil;
|
||||
}
|
||||
return [[ASTextNodeDrawParameter alloc] initWithRendererAttributes:[self _locked_rendererAttributes]
|
||||
backgroundColor:self.backgroundColor
|
||||
textContainerInsets:_textContainerInset
|
||||
contentScale:_contentsScaleForDisplay
|
||||
opaque:self.isOpaque
|
||||
bounds:[self threadSafeBounds]];
|
||||
bounds:[self threadSafeBounds]
|
||||
traitCollection:self.primitiveTraitCollection];
|
||||
}
|
||||
|
||||
+ (UIImage *)displayWithParameters:(id<NSObject>)parameters isCancelled:(NS_NOESCAPE asdisplaynode_iscancelled_block_t)isCancelled
|
||||
@@ -564,7 +575,7 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
UIEdgeInsets textContainerInsets = drawParameter ? drawParameter->_textContainerInsets : UIEdgeInsetsZero;
|
||||
ASTextKitRenderer *renderer = [drawParameter rendererForBounds:drawParameter->_bounds];
|
||||
|
||||
UIImage *result = ASGraphicsCreateImageWithOptions(CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale, nil, nil, ^{
|
||||
UIImage *result = ASGraphicsCreateImage(drawParameter->_traitCollection, CGSizeMake(drawParameter->_bounds.size.width, drawParameter->_bounds.size.height), drawParameter->_opaque, drawParameter->_contentScale, nil, nil, ^{
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
ASDisplayNodeAssert(context, @"This is no good without a context.");
|
||||
|
||||
@@ -945,6 +956,39 @@ static CGRect ASTextNodeAdjustRenderRectForShadowPadding(CGRect rendererRect, UI
|
||||
return ASTextNodeAdjustRenderRectForShadowPadding(frame, self.shadowPadding);
|
||||
}
|
||||
|
||||
#pragma mark - Tint Colors
|
||||
|
||||
|
||||
- (void)tintColorDidChange
|
||||
{
|
||||
[super tintColorDidChange];
|
||||
|
||||
[self _setNeedsDisplayOnTintedTextColor];
|
||||
}
|
||||
|
||||
- (void)_setNeedsDisplayOnTintedTextColor
|
||||
{
|
||||
BOOL textColorFollowsTintColor = NO;
|
||||
{
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
textColorFollowsTintColor = _textColorFollowsTintColor;
|
||||
}
|
||||
|
||||
if (textColorFollowsTintColor) {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Interface State
|
||||
|
||||
- (void)didEnterHierarchy
|
||||
{
|
||||
[super didEnterHierarchy];
|
||||
|
||||
[self _setNeedsDisplayOnTintedTextColor];
|
||||
}
|
||||
|
||||
#pragma mark - Placeholders
|
||||
|
||||
- (UIColor *)placeholderColor
|
||||
@@ -1311,6 +1355,11 @@ static NSAttributedString *DefaultTruncationAttributedString()
|
||||
return ASLockedSelf([[self _locked_renderer] lineCount]);
|
||||
}
|
||||
|
||||
- (BOOL)textColorFollowsTintColor
|
||||
{
|
||||
return ASLockedSelf(_textColorFollowsTintColor);
|
||||
}
|
||||
|
||||
#pragma mark - Truncation Message
|
||||
|
||||
- (void)_invalidateTruncationText
|
||||
|
||||
+74
-25
@@ -511,40 +511,51 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
shadow.shadowBlurRadius = _shadowRadius;
|
||||
[attributedString addAttribute:NSShadowAttributeName value:shadow range:NSMakeRange(0, attributedString.length)];
|
||||
}
|
||||
|
||||
// Apply tint color if needed and foreground color is not already specified
|
||||
if (self.textColorFollowsTintColor && attributedString.length > 0) {
|
||||
// Apply tint color if specified and if foreground color is undefined for attributedString
|
||||
NSRange limit = NSMakeRange(0, attributedString.length);
|
||||
// Look for previous attributes that define foreground color
|
||||
UIColor *attributeValue = (UIColor *)[attributedString attribute:NSForegroundColorAttributeName atIndex:limit.location effectiveRange:NULL];
|
||||
UIColor *tintColor = self.tintColor;
|
||||
if (attributeValue == nil && tintColor) {
|
||||
// None are found, apply tint color if available. Fallback to "black" text color
|
||||
[attributedString addAttributes:@{ NSForegroundColorAttributeName : tintColor } range:limit];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Drawing
|
||||
|
||||
- (NSObject *)drawParametersForAsyncLayer:(_ASDisplayLayer *)layer
|
||||
{
|
||||
ASLockScopeSelf();
|
||||
[self _ensureTruncationText];
|
||||
ASTextContainer *copiedContainer;
|
||||
NSMutableAttributedString *mutableText;
|
||||
BOOL needsTintColor;
|
||||
id bgColor;
|
||||
{
|
||||
// Wrapping all the other access here, because we can't lock while accessing tintColor.
|
||||
ASLockScopeSelf();
|
||||
[self _ensureTruncationText];
|
||||
|
||||
// Unlike layout, here we must copy the container since drawing is asynchronous.
|
||||
ASTextContainer *copiedContainer = [_textContainer copy];
|
||||
copiedContainer.size = self.bounds.size;
|
||||
[copiedContainer makeImmutable];
|
||||
NSMutableAttributedString *mutableText = [_attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init];
|
||||
// Unlike layout, here we must copy the container since drawing is asynchronous.
|
||||
copiedContainer = [_textContainer copy];
|
||||
copiedContainer.size = self.bounds.size;
|
||||
[copiedContainer makeImmutable];
|
||||
mutableText = [_attributedText mutableCopy] ?: [[NSMutableAttributedString alloc] init];
|
||||
|
||||
[self prepareAttributedString:mutableText isForIntrinsicSize:NO];
|
||||
[self prepareAttributedString:mutableText isForIntrinsicSize:NO];
|
||||
needsTintColor = self.textColorFollowsTintColor && mutableText.length > 0;
|
||||
bgColor = self.backgroundColor ?: [NSNull null];
|
||||
}
|
||||
|
||||
// After all other attributes are set, apply tint color if needed and foreground color is not already specified
|
||||
if (needsTintColor) {
|
||||
// Apply tint color if specified and if foreground color is undefined for attributedString
|
||||
NSRange limit = NSMakeRange(0, mutableText.length);
|
||||
// Look for previous attributes that define foreground color
|
||||
UIColor *attributeValue = (UIColor *)[mutableText attribute:NSForegroundColorAttributeName atIndex:limit.location effectiveRange:NULL];
|
||||
|
||||
// we need to unlock before accessing tintColor
|
||||
UIColor *tintColor = self.tintColor;
|
||||
if (attributeValue == nil && tintColor) {
|
||||
// None are found, apply tint color if available. Fallback to "black" text color
|
||||
[mutableText addAttributes:@{ NSForegroundColorAttributeName : tintColor } range:limit];
|
||||
}
|
||||
}
|
||||
|
||||
return @{
|
||||
@"container": copiedContainer,
|
||||
@"text": mutableText,
|
||||
@"bgColor": self.backgroundColor ?: [NSNull null]
|
||||
@"bgColor": bgColor
|
||||
};
|
||||
}
|
||||
|
||||
@@ -577,6 +588,38 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
[layout drawInContext:context size:bounds.size point:bounds.origin view:nil layer:nil debug:[ASTextDebugOption sharedDebugOption] cancel:isCancelledBlock];
|
||||
}
|
||||
|
||||
#pragma mark - Tint Color
|
||||
|
||||
- (void)tintColorDidChange
|
||||
{
|
||||
[super tintColorDidChange];
|
||||
|
||||
[self _setNeedsDisplayOnTintedTextColor];
|
||||
}
|
||||
|
||||
- (void)_setNeedsDisplayOnTintedTextColor
|
||||
{
|
||||
BOOL textColorFollowsTintColor = NO;
|
||||
{
|
||||
AS::MutexLocker l(__instanceLock__);
|
||||
textColorFollowsTintColor = _textColorFollowsTintColor;
|
||||
}
|
||||
|
||||
if (textColorFollowsTintColor) {
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Interface State
|
||||
|
||||
- (void)didEnterHierarchy
|
||||
{
|
||||
[super didEnterHierarchy];
|
||||
|
||||
[self _setNeedsDisplayOnTintedTextColor];
|
||||
}
|
||||
|
||||
#pragma mark - Attributes
|
||||
|
||||
- (id)linkAttributeValueAtPoint:(CGPoint)point
|
||||
@@ -674,11 +717,17 @@ static NSArray *DefaultLinkAttributeNames() {
|
||||
|
||||
CTLineRef truncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_truncationAttributedText);
|
||||
CFIndex truncationTokenLineGlyphCount = truncationTokenLine ? CTLineGetGlyphCount(truncationTokenLine) : 0;
|
||||
CFRelease(truncationTokenLine);
|
||||
|
||||
if (truncationTokenLine) {
|
||||
CFRelease(truncationTokenLine);
|
||||
}
|
||||
|
||||
CTLineRef additionalTruncationTokenLine = CTLineCreateWithAttributedString((CFAttributedStringRef)_additionalTruncationMessage);
|
||||
CFIndex additionalTruncationTokenLineGlyphCount = additionalTruncationTokenLine ? CTLineGetGlyphCount(additionalTruncationTokenLine) : 0;
|
||||
CFRelease(additionalTruncationTokenLine);
|
||||
CFIndex additionalTruncationTokenLineGlyphCount = additionalTruncationTokenLine ? CTLineGetGlyphCount(additionalTruncationTokenLine) : 0;
|
||||
|
||||
if (additionalTruncationTokenLine) {
|
||||
CFRelease(additionalTruncationTokenLine);
|
||||
}
|
||||
|
||||
switch (_textContainer.truncationType) {
|
||||
case ASTextTruncationTypeStart: {
|
||||
|
||||
@@ -106,7 +106,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
- (void)videoNode:(ASVideoNode *)videoNode willChangePlayerState:(ASVideoNodePlayerState)state toState:(ASVideoNodePlayerState)toState;
|
||||
/**
|
||||
* @abstract Ssks delegate if state change is allowed
|
||||
* @abstract Asks delegate if state change is allowed
|
||||
* ASVideoNodePlayerStatePlaying or ASVideoNodePlayerStatePaused.
|
||||
* asks delegate if state change is allowed.
|
||||
* @param videoNode The video node.
|
||||
|
||||
@@ -289,7 +289,7 @@ static NSString * const kRate = @"rate";
|
||||
- (void)imageAtTime:(CMTime)imageTime completionHandler:(void(^)(UIImage *image))completionHandler
|
||||
{
|
||||
ASPerformBlockOnBackgroundThread(^{
|
||||
AVAsset *asset = self.asset;
|
||||
AVAsset *asset = self->_asset;
|
||||
|
||||
// Skip the asset image generation if we don't have any tracks available that are capable of supporting it
|
||||
NSArray<AVAssetTrack *>* visualAssetArray = [asset tracksWithMediaCharacteristic:AVMediaCharacteristicVisual];
|
||||
@@ -300,7 +300,7 @@ static NSString * const kRate = @"rate";
|
||||
|
||||
AVAssetImageGenerator *previewImageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
|
||||
previewImageGenerator.appliesPreferredTrackTransform = YES;
|
||||
previewImageGenerator.videoComposition = _videoComposition;
|
||||
previewImageGenerator.videoComposition = self->_videoComposition;
|
||||
|
||||
[previewImageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:imageTime]]
|
||||
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
|
||||
@@ -415,7 +415,7 @@ static NSString * const kRate = @"rate";
|
||||
NSArray<NSString *> *requestedKeys = @[@"playable"];
|
||||
[asset loadValuesAsynchronouslyForKeys:requestedKeys completionHandler:^{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
if (_delegateFlags.delegateVideoNodeDidFinishInitialLoading) {
|
||||
if (self->_delegateFlags.delegateVideoNodeDidFinishInitialLoading) {
|
||||
[self.delegate videoNodeDidFinishInitialLoading:self];
|
||||
}
|
||||
[self prepareToPlayAsset:asset withKeys:requestedKeys];
|
||||
|
||||
@@ -435,19 +435,19 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
slider.minimumValue = 0.0;
|
||||
slider.maximumValue = 1.0;
|
||||
|
||||
if (_delegateFlags.delegateScrubberMinimumTrackTintColor) {
|
||||
if (strongSelf->_delegateFlags.delegateScrubberMinimumTrackTintColor) {
|
||||
slider.minimumTrackTintColor = [strongSelf.delegate videoPlayerNodeScrubberMinimumTrackTint:strongSelf];
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateScrubberMaximumTrackTintColor) {
|
||||
if (strongSelf->_delegateFlags.delegateScrubberMaximumTrackTintColor) {
|
||||
slider.maximumTrackTintColor = [strongSelf.delegate videoPlayerNodeScrubberMaximumTrackTint:strongSelf];
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateScrubberThumbTintColor) {
|
||||
if (strongSelf->_delegateFlags.delegateScrubberThumbTintColor) {
|
||||
slider.thumbTintColor = [strongSelf.delegate videoPlayerNodeScrubberThumbTint:strongSelf];
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateScrubberThumbImage) {
|
||||
if (strongSelf->_delegateFlags.delegateScrubberThumbImage) {
|
||||
UIImage *thumbImage = [strongSelf.delegate videoPlayerNodeScrubberThumbImage:strongSelf];
|
||||
[slider setThumbImage:thumbImage forState:UIControlStateNormal];
|
||||
}
|
||||
@@ -645,14 +645,14 @@ static void *ASVideoPlayerNodeContext = &ASVideoPlayerNodeContext;
|
||||
UIActivityIndicatorView *spinnnerView = [[UIActivityIndicatorView alloc] init];
|
||||
spinnnerView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
if (_delegateFlags.delegateSpinnerTintColor) {
|
||||
spinnnerView.color = [_delegate videoPlayerNodeSpinnerTint:strongSelf];
|
||||
if (strongSelf->_delegateFlags.delegateSpinnerTintColor) {
|
||||
spinnnerView.color = [strongSelf->_delegate videoPlayerNodeSpinnerTint:strongSelf];
|
||||
} else {
|
||||
spinnnerView.color = _defaultControlsColor;
|
||||
spinnnerView.color = strongSelf->_defaultControlsColor;
|
||||
}
|
||||
|
||||
if (_delegateFlags.delegateSpinnerStyle) {
|
||||
spinnnerView.activityIndicatorViewStyle = [_delegate videoPlayerNodeSpinnerStyle:strongSelf];
|
||||
if (strongSelf->_delegateFlags.delegateSpinnerStyle) {
|
||||
spinnnerView.activityIndicatorViewStyle = [strongSelf->_delegate videoPlayerNodeSpinnerStyle:strongSelf];
|
||||
}
|
||||
|
||||
return spinnnerView;
|
||||
|
||||
@@ -38,6 +38,15 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C
|
||||
*/
|
||||
- (instancetype)initWithNode:(DisplayNodeType)node NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* ASViewController initializer. Useful for interoperability with normal UIViewControllers.
|
||||
*
|
||||
* @return An ASViewController instance with a nil node whose root view will be backed by a standard UIView as with a normal UIViewController.
|
||||
*
|
||||
* @see ASVisibilityDepth
|
||||
*/
|
||||
- (instancetype)init NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,6 +64,17 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self _initializeInstance];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)_initializeInstance
|
||||
{
|
||||
if (_node == nil) {
|
||||
@@ -94,14 +105,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (ASActivateExperimentalFeature(ASExperimentalOOMBackgroundDeallocDisable)) {
|
||||
return;
|
||||
}
|
||||
ASPerformBackgroundDeallocation(&_node);
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
// Apple applies a frame and autoresizing masks we need. Allocating a view is not
|
||||
|
||||
@@ -129,4 +129,5 @@
|
||||
|
||||
#import <AsyncDisplayKit/IGListAdapter+AsyncDisplayKit.h>
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit+IGListKitMethods.h>
|
||||
#import <AsyncDisplayKit/ASLayout+IGListKit.h>
|
||||
#import <AsyncDisplayKit/ASLayout+IGListDiffKit.h>
|
||||
#import <AsyncDisplayKit/ASGraphicsContext.h>
|
||||
|
||||
@@ -86,6 +86,7 @@
|
||||
|
||||
#define AS_PIN_REMOTE_IMAGE __has_include(<PINRemoteImage/PINRemoteImage.h>)
|
||||
#define AS_IG_LIST_KIT __has_include(<IGListKit/IGListKit.h>)
|
||||
#define AS_IG_LIST_DIFF_KIT __has_include(<IGListDiffKit/IGListDiffKit.h>)
|
||||
|
||||
/**
|
||||
* For IGListKit versions < 3.0, you have to use IGListCollectionView.
|
||||
|
||||
@@ -12,18 +12,6 @@
|
||||
#define AS_EXTERN FOUNDATION_EXTERN
|
||||
#define unowned __unsafe_unretained
|
||||
|
||||
/**
|
||||
* Hack to support building for iOS with Xcode 9. UIUserInterfaceStyle was previously tvOS-only,
|
||||
* and it was added to iOS 12. Xcode 9 (iOS 11 SDK) will flat-out refuse to build anything that
|
||||
* references this enum targeting iOS, even if it's guarded with the right availability macros,
|
||||
* because it thinks the entire platform isn't compatible with the enum.
|
||||
*/
|
||||
#if TARGET_OS_TV || (defined(__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0)
|
||||
#define AS_BUILD_UIUSERINTERFACESTYLE 1
|
||||
#else
|
||||
#define AS_BUILD_UIUSERINTERFACESTYLE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Decorates methods that clients can implement in categories on our base class. These methods
|
||||
* will be stubbed with an empty implementation if no implementation is provided.
|
||||
|
||||
@@ -140,7 +140,7 @@ static BOOL __enableHitTestDebug = NO;
|
||||
UIColor *clipsBorderColor = [UIColor colorWithRed:30/255.0 green:90/255.0 blue:50/255.0 alpha:0.7];
|
||||
CGRect imgRect = CGRectMake(0, 0, 2.0 * borderWidth + 1.0, 2.0 * borderWidth + 1.0);
|
||||
|
||||
UIImage *debugHighlightImage = ASGraphicsCreateImageWithOptions(imgRect.size, NO, 1, nil, nil, ^{
|
||||
UIImage *debugHighlightImage = ASGraphicsCreateImage(self.primitiveTraitCollection, imgRect.size, NO, 1, nil, nil, ^{
|
||||
[fillColor setFill];
|
||||
UIRectFill(imgRect);
|
||||
|
||||
@@ -424,10 +424,10 @@ static BOOL __shouldShowRangeDebugOverlay = NO;
|
||||
}
|
||||
|
||||
[UIView animateWithDuration:0.2 delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
|
||||
_animating = YES;
|
||||
self->_animating = YES;
|
||||
[self layoutToFitAllBarsExcept:0];
|
||||
} completion:^(BOOL finished) {
|
||||
_animating = NO;
|
||||
self->_animating = NO;
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -653,15 +653,15 @@ static BOOL __shouldShowRangeDebugOverlay = NO;
|
||||
|
||||
BOOL animate = !_firstLayoutOfRects;
|
||||
[UIView animateWithDuration:animate ? 0.3 : 0.0 delay:0.0 options:UIViewAnimationOptionLayoutSubviews animations:^{
|
||||
_visibleRect.frame = CGRectMake(HORIZONTAL_INSET + visiblePoint, rect.origin.y, visibleDimension, subCellHeight);
|
||||
_displayRect.frame = CGRectMake(HORIZONTAL_INSET + displayPoint, rect.origin.y, displayDimension, subCellHeight);
|
||||
_preloadRect.frame = CGRectMake(HORIZONTAL_INSET + preloadPoint, rect.origin.y, preloadDimension, subCellHeight);
|
||||
self->_visibleRect.frame = CGRectMake(HORIZONTAL_INSET + visiblePoint, rect.origin.y, visibleDimension, subCellHeight);
|
||||
self->_displayRect.frame = CGRectMake(HORIZONTAL_INSET + displayPoint, rect.origin.y, displayDimension, subCellHeight);
|
||||
self->_preloadRect.frame = CGRectMake(HORIZONTAL_INSET + preloadPoint, rect.origin.y, preloadDimension, subCellHeight);
|
||||
} completion:^(BOOL finished) {}];
|
||||
|
||||
if (!animate) {
|
||||
_visibleRect.alpha = _displayRect.alpha = _preloadRect.alpha = 0;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
_visibleRect.alpha = _displayRect.alpha = _preloadRect.alpha = 1;
|
||||
self->_visibleRect.alpha = self->_displayRect.alpha = self->_preloadRect.alpha = 1;
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -729,13 +729,15 @@ static BOOL __shouldShowRangeDebugOverlay = NO;
|
||||
- (ASImageNode *)createRangeNodeWithColor:(UIColor *)color
|
||||
{
|
||||
ASImageNode *rangeBarImageNode = [[ASImageNode alloc] init];
|
||||
ASPrimitiveTraitCollection primitiveTraitCollection = ASPrimitiveTraitCollectionFromUITraitCollection(self.traitCollection);
|
||||
rangeBarImageNode.image = [UIImage as_resizableRoundedImageWithCornerRadius:RANGE_BAR_CORNER_RADIUS
|
||||
cornerColor:[UIColor clearColor]
|
||||
fillColor:[color colorWithAlphaComponent:0.5]
|
||||
borderColor:[[UIColor blackColor] colorWithAlphaComponent:0.9]
|
||||
borderWidth:RANGE_BAR_BORDER_WIDTH
|
||||
roundedCorners:UIRectCornerAllCorners
|
||||
scale:[[UIScreen mainScreen] scale]];
|
||||
scale:[[UIScreen mainScreen] scale]
|
||||
traitCollection:primitiveTraitCollection];
|
||||
[self addSubnode:rangeBarImageNode];
|
||||
|
||||
return rangeBarImageNode;
|
||||
|
||||
@@ -290,7 +290,7 @@ static const void *ContextKey() {
|
||||
[context addCallbackData:[[NSDictionary alloc] initWithDictionary:callbackData]];
|
||||
|
||||
// Create new task if necessary
|
||||
NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [_session downloadTaskWithURL:URL];}];
|
||||
NSURLSessionDownloadTask *task = (NSURLSessionDownloadTask *)[context createSessionTaskIfNecessaryWithBlock:^(){return [self->_session downloadTaskWithURL:URL];}];
|
||||
|
||||
if (task) {
|
||||
task.priority = NSURLSessionTaskPriorityWithImageDownloaderPriority(priority);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#import <AsyncDisplayKit/ASCollectionView.h>
|
||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
|
||||
|
||||
#pragma mark - Helper Functions
|
||||
|
||||
|
||||
@@ -533,13 +533,13 @@ typedef void (^ASDataControllerSynchronizationBlock)();
|
||||
_synchronized = NO;
|
||||
|
||||
[changeSet addCompletionHandler:^(BOOL finished) {
|
||||
_synchronized = YES;
|
||||
self->_synchronized = YES;
|
||||
[self onDidFinishProcessingUpdates:^{
|
||||
if (_synchronized) {
|
||||
for (ASDataControllerSynchronizationBlock block in _onDidFinishSynchronizingBlocks) {
|
||||
if (self->_synchronized) {
|
||||
for (ASDataControllerSynchronizationBlock block in self->_onDidFinishSynchronizingBlocks) {
|
||||
block();
|
||||
}
|
||||
[_onDidFinishSynchronizingBlocks removeAllObjects];
|
||||
[self->_onDidFinishSynchronizingBlocks removeAllObjects];
|
||||
}
|
||||
}];
|
||||
}];
|
||||
@@ -646,9 +646,9 @@ typedef void (^ASDataControllerSynchronizationBlock)();
|
||||
}
|
||||
|
||||
// Step 4: Inform the delegate on main thread
|
||||
[_mainSerialQueue performBlockOnMainThread:^{
|
||||
[self->_mainSerialQueue performBlockOnMainThread:^{
|
||||
as_activity_scope_leave(&preparationScope);
|
||||
[_delegate dataController:self updateWithChangeSet:changeSet updates:^{
|
||||
[self->_delegate dataController:self updateWithChangeSet:changeSet updates:^{
|
||||
// Step 5: Deploy the new data as "completed"
|
||||
//
|
||||
// Note that since the backing collection view might be busy responding to user events (e.g scrolling),
|
||||
@@ -659,7 +659,7 @@ typedef void (^ASDataControllerSynchronizationBlock)();
|
||||
self.visibleMap = newMap;
|
||||
}];
|
||||
}];
|
||||
--_editingTransactionGroupCount;
|
||||
--self->_editingTransactionGroupCount;
|
||||
});
|
||||
|
||||
// We've now dispatched node allocation and layout to a concurrent background queue.
|
||||
@@ -898,7 +898,7 @@ typedef void (^ASDataControllerSynchronizationBlock)();
|
||||
- (void)environmentDidChange
|
||||
{
|
||||
ASPerformBlockOnMainThread(^{
|
||||
if (!_initialReloadDataHasBeenCalled) {
|
||||
if (!self->_initialReloadDataHasBeenCalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -906,7 +906,7 @@ typedef void (^ASDataControllerSynchronizationBlock)();
|
||||
// i.e there might be some elements that were allocated using the old trait collection but haven't been added to _visibleMap
|
||||
[self _scheduleBlockOnMainSerialQueue:^{
|
||||
ASPrimitiveTraitCollection newTraitCollection = [self.node primitiveTraitCollection];
|
||||
for (ASCollectionElement *element in _visibleMap) {
|
||||
for (ASCollectionElement *element in self->_visibleMap) {
|
||||
element.traitCollection = newTraitCollection;
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASBlockTypes.h>
|
||||
#import <AsyncDisplayKit/ASTraitCollection.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -27,6 +28,38 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*
|
||||
* @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext.
|
||||
*/
|
||||
AS_EXTERN UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE _Nullable isCancelled, void (NS_NOESCAPE ^work)());
|
||||
AS_EXTERN UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE _Nullable isCancelled, void (NS_NOESCAPE ^work)(void)) ASDISPLAYNODE_DEPRECATED_MSG("Use ASGraphicsCreateImageWithTraitCollectionAndOptions instead");
|
||||
|
||||
/**
|
||||
* A wrapper for the UIKit drawing APIs. If you are in ASExperimentalDrawingGlobal, and you have iOS >= 10, we will create
|
||||
* a UIGraphicsRenderer with an appropriate format. Otherwise, we will use UIGraphicsBeginImageContext et al.
|
||||
*
|
||||
* @param traitCollection Trait collection. The `work` block will be executed with this trait collection, so it will affect dynamic colors, etc.
|
||||
* @param size The size of the context.
|
||||
* @param opaque Whether the context should be opaque or not.
|
||||
* @param scale The scale of the context. 0 uses main screen scale.
|
||||
* @param sourceImage If you are planning to render a UIImage into this context, provide it here and we will use its
|
||||
* preferred renderer format if we are using UIGraphicsImageRenderer.
|
||||
* @param isCancelled An optional block for canceling the drawing before forming the image.
|
||||
* @param work A block, wherein the current UIGraphics context is set based on the arguments.
|
||||
*
|
||||
* @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext.
|
||||
*/
|
||||
AS_EXTERN UIImage *ASGraphicsCreateImage(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, asdisplaynode_iscancelled_block_t _Nullable NS_NOESCAPE isCancelled, void (NS_NOESCAPE ^work)(void));
|
||||
|
||||
/**
|
||||
* A wrapper for the UIKit drawing APIs.
|
||||
*
|
||||
* @param traitCollection Trait collection. The `work` block will be executed with this trait collection, so it will affect dynamic colors, etc.
|
||||
* @param size The size of the context.
|
||||
* @param opaque Whether the context should be opaque or not.
|
||||
* @param scale The scale of the context. 0 uses main screen scale.
|
||||
* @param sourceImage If you are planning to render a UIImage into this context, provide it here and we will use its
|
||||
* preferred renderer format if we are using UIGraphicsImageRenderer.
|
||||
* @param work A block, wherein the current UIGraphics context is set based on the arguments.
|
||||
*
|
||||
* @return The rendered image. You can also render intermediary images using UIGraphicsGetImageFromCurrentImageContext.
|
||||
*/
|
||||
AS_EXTERN UIImage *ASGraphicsCreateImageWithTraitCollectionAndOptions(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * _Nullable sourceImage, void (NS_NOESCAPE ^work)(void)) ASDISPLAYNODE_DEPRECATED_MSG("Use ASGraphicsCreateImage instead");
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -10,6 +10,23 @@
|
||||
#import <AsyncDisplayKit/ASAssert.h>
|
||||
#import <AsyncDisplayKit/ASConfigurationInternal.h>
|
||||
#import <AsyncDisplayKit/ASInternalHelpers.h>
|
||||
#import <AsyncDisplayKit/ASAvailability.h>
|
||||
|
||||
|
||||
#if AS_AT_LEAST_IOS13
|
||||
#define ASPerformBlockWithTraitCollection(work, traitCollection) \
|
||||
if (@available(iOS 13.0, *)) { \
|
||||
UITraitCollection *uiTraitCollection = ASPrimitiveTraitCollectionToUITraitCollection(traitCollection); \
|
||||
[uiTraitCollection performAsCurrentTraitCollection:^{ \
|
||||
work(); \
|
||||
}];\
|
||||
} else { \
|
||||
work(); \
|
||||
}
|
||||
#else
|
||||
#define ASPerformBlockWithTraitCollection(work, traitCollection) work();
|
||||
#endif
|
||||
|
||||
|
||||
NS_AVAILABLE_IOS(10)
|
||||
NS_INLINE void ASConfigureExtendedRange(UIGraphicsImageRendererFormat *format)
|
||||
@@ -26,6 +43,10 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal
|
||||
asdisplaynode_iscancelled_block_t NS_NOESCAPE isCancelled,
|
||||
void (^NS_NOESCAPE work)())
|
||||
{
|
||||
return ASGraphicsCreateImage(ASPrimitiveTraitCollectionMakeDefault(), size, opaque, scale, sourceImage, isCancelled, work);
|
||||
}
|
||||
|
||||
UIImage *ASGraphicsCreateImage(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * sourceImage, asdisplaynode_iscancelled_block_t NS_NOESCAPE isCancelled, void (NS_NOESCAPE ^work)()) {
|
||||
if (AS_AVAILABLE_IOS_TVOS(10, 10)) {
|
||||
if (ASActivateExperimentalFeature(ASExperimentalDrawingGlobal)) {
|
||||
// If they used default scale, reuse one of two preferred formats.
|
||||
@@ -76,17 +97,32 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal
|
||||
format.scale = scale;
|
||||
ASConfigureExtendedRange(format);
|
||||
}
|
||||
|
||||
return [[[UIGraphicsImageRenderer alloc] initWithSize:size format:format] imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
|
||||
ASDisplayNodeCAssert(UIGraphicsGetCurrentContext(), @"Should have a context!");
|
||||
work();
|
||||
}];
|
||||
|
||||
// Avoid using the imageWithActions: method because it does not support cancellation at the
|
||||
// last moment i.e. before actually creating the resulting image.
|
||||
__block UIImage *image;
|
||||
NSError *error;
|
||||
[[[UIGraphicsImageRenderer alloc] initWithSize:size format:format]
|
||||
runDrawingActions:^(UIGraphicsImageRendererContext *rendererContext) {
|
||||
ASDisplayNodeCAssert(UIGraphicsGetCurrentContext(), @"Should have a context!");
|
||||
ASPerformBlockWithTraitCollection(work, traitCollection);
|
||||
}
|
||||
completionActions:^(UIGraphicsImageRendererContext *rendererContext) {
|
||||
if (isCancelled == nil || !isCancelled()) {
|
||||
image = rendererContext.currentImage;
|
||||
}
|
||||
}
|
||||
error:&error];
|
||||
if (error) {
|
||||
NSCAssert(NO, @"Error drawing: %@", error);
|
||||
}
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
// Bad OS or experiment flag. Use UIGraphics* API.
|
||||
UIGraphicsBeginImageContextWithOptions(size, opaque, scale);
|
||||
work();
|
||||
ASPerformBlockWithTraitCollection(work, traitCollection)
|
||||
UIImage *image = nil;
|
||||
if (isCancelled == nil || !isCancelled()) {
|
||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
@@ -94,3 +130,7 @@ UIImage *ASGraphicsCreateImageWithOptions(CGSize size, BOOL opaque, CGFloat scal
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
UIImage *ASGraphicsCreateImageWithTraitCollectionAndOptions(ASPrimitiveTraitCollection traitCollection, CGSize size, BOOL opaque, CGFloat scale, UIImage * sourceImage, void (NS_NOESCAPE ^work)()) {
|
||||
return ASGraphicsCreateImage(traitCollection, size, opaque, scale, sourceImage, nil, work);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,12 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@end
|
||||
|
||||
typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable imageFromCache);
|
||||
typedef NS_ENUM(NSInteger, ASImageCacheType) {
|
||||
ASImageCacheTypeAsynchronous = 0,
|
||||
ASImageCacheTypeSynchronous,
|
||||
};
|
||||
|
||||
typedef void(^ASImageCacherCompletion)(id <ASImageContainerProtocol> _Nullable imageFromCache, ASImageCacheType cacheType);
|
||||
|
||||
@protocol ASImageCacheProtocol <NSObject>
|
||||
|
||||
|
||||
@@ -11,38 +11,29 @@
|
||||
|
||||
#import <AsyncDisplayKit/ASThread.h>
|
||||
#import <AsyncDisplayKit/ASInternalHelpers.h>
|
||||
#import <queue>
|
||||
|
||||
@interface ASMainSerialQueue ()
|
||||
{
|
||||
AS::Mutex _serialQueueLock;
|
||||
NSMutableArray *_blocks;
|
||||
std::queue<dispatch_block_t> _blocks;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASMainSerialQueue
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_blocks = [[NSMutableArray alloc] init];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSUInteger)numberOfScheduledBlocks
|
||||
{
|
||||
AS::MutexLocker l(_serialQueueLock);
|
||||
return _blocks.count;
|
||||
return _blocks.size();
|
||||
}
|
||||
|
||||
- (void)performBlockOnMainThread:(dispatch_block_t)block
|
||||
{
|
||||
{
|
||||
AS::MutexLocker l(_serialQueueLock);
|
||||
[_blocks addObject:block];
|
||||
_blocks.push(block);
|
||||
}
|
||||
|
||||
[self runBlocks];
|
||||
@@ -53,13 +44,11 @@
|
||||
dispatch_block_t mainThread = ^{
|
||||
AS::UniqueLock l(self->_serialQueueLock);
|
||||
do {
|
||||
dispatch_block_t block;
|
||||
if (self->_blocks.count > 0) {
|
||||
block = _blocks[0];
|
||||
[self->_blocks removeObjectAtIndex:0];
|
||||
} else {
|
||||
if (self->_blocks.empty()) {
|
||||
break;
|
||||
}
|
||||
dispatch_block_t block = self->_blocks.front();
|
||||
self->_blocks.pop();
|
||||
{
|
||||
l.unlock();
|
||||
block();
|
||||
@@ -73,7 +62,15 @@
|
||||
|
||||
- (NSString *)description
|
||||
{
|
||||
return [[super description] stringByAppendingFormat:@" Blocks: %@", _blocks];
|
||||
NSString *desc = [super description];
|
||||
std::queue<dispatch_block_t> blocks = _blocks;
|
||||
[desc stringByAppendingString:@" Blocks: "];
|
||||
while (!blocks.empty()) {
|
||||
dispatch_block_t block = blocks.front();
|
||||
[desc stringByAppendingFormat:@"%@", block];
|
||||
blocks.pop();
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -231,14 +231,15 @@ static dispatch_once_t shared_init_predicate;
|
||||
{
|
||||
[[self sharedPINRemoteImageManager] imageFromCacheWithURL:URL processorKey:nil options:PINRemoteImageManagerDownloadOptionsSkipDecode completion:^(PINRemoteImageManagerResult * _Nonnull result) {
|
||||
[ASPINRemoteImageDownloader _performWithCallbackQueue:callbackQueue work:^{
|
||||
ASImageCacheType cacheType = (result.resultType == PINRemoteImageResultTypeMemoryCache ? ASImageCacheTypeSynchronous : ASImageCacheTypeAsynchronous);
|
||||
#if PIN_ANIMATED_AVAILABLE
|
||||
if (result.alternativeRepresentation) {
|
||||
completion(result.alternativeRepresentation);
|
||||
completion(result.alternativeRepresentation, cacheType);
|
||||
} else {
|
||||
completion(result.image);
|
||||
completion(result.image, cacheType);
|
||||
}
|
||||
#else
|
||||
completion(result.image);
|
||||
completion(result.image, cacheType);
|
||||
#endif
|
||||
}];
|
||||
}];
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#import <AsyncDisplayKit/ASCellNode+Internal.h>
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit+Debug.h>
|
||||
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
|
||||
|
||||
#define AS_RANGECONTROLLER_LOG_UPDATE_FREQ 0
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
OS_UNFAIR_LOCK_AVAILABILITY
|
||||
typedef struct {
|
||||
os_unfair_lock _lock OS_UNFAIR_LOCK_AVAILABILITY;
|
||||
_Atomic(pthread_t) _thread; // Write-protected by lock
|
||||
_Atomic(pthread_t) _thread;
|
||||
int _count; // Protected by lock
|
||||
} ASRecursiveUnfairLock;
|
||||
|
||||
|
||||
@@ -11,57 +11,58 @@
|
||||
#import <stdatomic.h>
|
||||
|
||||
/**
|
||||
* For our atomic _thread, we use acquire/release memory order so that we can have
|
||||
* the minimum possible constraint on the hardware. The default, `memory_order_seq_cst`
|
||||
* demands that there be a total order of all such modifications as seen by all threads.
|
||||
* Acquire/release only requires that modifications to this specific atomic are
|
||||
* synchronized across acquire/release pairs.
|
||||
* http://en.cppreference.com/w/cpp/atomic/memory_order
|
||||
*
|
||||
* Note also that the unfair_lock involves a thread fence as well, so we don't need to
|
||||
* take care of synchronizing other values. Just the thread value.
|
||||
* Since the lock itself is a memory barrier, we only need memory_order_relaxed for our
|
||||
* thread atomic. That guarantees we won't have torn writes, but otherwise no ordering
|
||||
* is required.
|
||||
*/
|
||||
#define rul_set_thread(l, t) atomic_store_explicit(&l->_thread, t, memory_order_release)
|
||||
#define rul_get_thread(l) atomic_load_explicit(&l->_thread, memory_order_acquire)
|
||||
#define rul_set_thread(l, t) atomic_store_explicit(&l->_thread, t, memory_order_relaxed)
|
||||
#define rul_get_thread(l) atomic_load_explicit(&l->_thread, memory_order_relaxed)
|
||||
|
||||
NS_INLINE void ASRecursiveUnfairLockDidAcquire(ASRecursiveUnfairLock *l, pthread_t tid) {
|
||||
NSCAssert(pthread_equal(rul_get_thread(l), NULL) && l->_count == 0, @"Unfair lock error");
|
||||
rul_set_thread(l, tid);
|
||||
}
|
||||
|
||||
NS_INLINE void ASRecursiveUnfairLockWillRelease(ASRecursiveUnfairLock *l) {
|
||||
NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()) && l->_count == 0, @"Unfair lock error");
|
||||
rul_set_thread(l, NULL);
|
||||
}
|
||||
|
||||
NS_INLINE void ASRecursiveUnfairLockAssertHeld(ASRecursiveUnfairLock *l) {
|
||||
NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()) && l->_count > 0, @"Unfair lock error");
|
||||
}
|
||||
|
||||
void ASRecursiveUnfairLockLock(ASRecursiveUnfairLock *l)
|
||||
{
|
||||
// Try to lock without blocking. If we fail, check what thread owns it.
|
||||
// Note that the owning thread CAN CHANGE freely, but it can't become `self`
|
||||
// because only we are `self`. And if it's already `self` then we already have
|
||||
// the lock, because we reset it to NULL before we unlock. So (thread == self) is
|
||||
// invariant.
|
||||
|
||||
// Note that the owning thread CAN CHANGE freely, but if the thread is specifically `self` then we know
|
||||
// it is a recursive call, because we clear it before unlocking, and only `self` can set it
|
||||
// to `self`.
|
||||
|
||||
const pthread_t s = pthread_self();
|
||||
if (os_unfair_lock_trylock(&l->_lock)) {
|
||||
// Owned by nobody. We now have the lock. Assign self.
|
||||
rul_set_thread(l, s);
|
||||
} else if (rul_get_thread(l) == s) {
|
||||
// Owned by self (recursive lock). nop.
|
||||
if (pthread_equal(rul_get_thread(l), s)) {
|
||||
// Owned by self (recursive lock.) nop.
|
||||
ASRecursiveUnfairLockAssertHeld(l);
|
||||
} else {
|
||||
// Owned by other thread. Block and then set thread to self.
|
||||
os_unfair_lock_lock(&l->_lock);
|
||||
rul_set_thread(l, s);
|
||||
ASRecursiveUnfairLockDidAcquire(l, s);
|
||||
}
|
||||
|
||||
|
||||
l->_count++;
|
||||
}
|
||||
|
||||
BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l)
|
||||
{
|
||||
BOOL ASRecursiveUnfairLockTryLock(ASRecursiveUnfairLock *l) {
|
||||
// Same as Lock above. See comments there.
|
||||
|
||||
const pthread_t s = pthread_self();
|
||||
if (os_unfair_lock_trylock(&l->_lock)) {
|
||||
// Owned by nobody. We now have the lock. Assign self.
|
||||
rul_set_thread(l, s);
|
||||
} else if (rul_get_thread(l) == s) {
|
||||
// Owned by self (recursive lock). nop.
|
||||
if (pthread_equal(rul_get_thread(l), s)) {
|
||||
ASRecursiveUnfairLockAssertHeld(l);
|
||||
} else if (os_unfair_lock_trylock(&l->_lock)) {
|
||||
ASRecursiveUnfairLockDidAcquire(l, s);
|
||||
} else {
|
||||
// Owned by other thread. Fail.
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
l->_count++;
|
||||
return YES;
|
||||
}
|
||||
@@ -70,14 +71,14 @@ void ASRecursiveUnfairLockUnlock(ASRecursiveUnfairLock *l)
|
||||
{
|
||||
// Ensure we have the lock. This check may miss some pathological cases,
|
||||
// but it'll catch 99.999999% of this serious programmer error.
|
||||
NSCAssert(rul_get_thread(l) == pthread_self(), @"Unlocking from a different thread than locked.");
|
||||
NSCAssert(pthread_equal(rul_get_thread(l), pthread_self()), @"Unlocking from a different thread than locked.");
|
||||
|
||||
if (0 == --l->_count) {
|
||||
// Note that we have to clear this before unlocking because, if another thread
|
||||
// succeeds in locking above, but hasn't managed to update _thread, and we
|
||||
// try to re-lock, and fail the -tryLock, and read _thread, then we'll mistakenly
|
||||
// think that we still own the lock and proceed without blocking.
|
||||
rul_set_thread(l, NULL);
|
||||
ASRecursiveUnfairLockWillRelease(l);
|
||||
os_unfair_lock_unlock(&l->_lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace AS {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
if (AS_AVAILABLE_IOS_TVOS(10, 10)) {
|
||||
gMutex_unfair = ASActivateExperimentalFeature(ASExperimentalUnfairLock);
|
||||
gMutex_unfair = YES;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -40,14 +40,19 @@ typedef struct {
|
||||
UIUserInterfaceIdiom userInterfaceIdiom;
|
||||
UIForceTouchCapability forceTouchCapability;
|
||||
UITraitEnvironmentLayoutDirection layoutDirection API_AVAILABLE(ios(10.0));
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0));
|
||||
#endif
|
||||
|
||||
|
||||
// NOTE: This must be a constant. We will assert.
|
||||
unowned UIContentSizeCategory preferredContentSizeCategory API_AVAILABLE(ios(10.0));
|
||||
|
||||
CGSize containerSize;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
UIUserInterfaceLevel userInterfaceLevel API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos);
|
||||
#endif
|
||||
UIAccessibilityContrast accessibilityContrast API_AVAILABLE(ios(13.0));
|
||||
UILegibilityWeight legibilityWeight API_AVAILABLE(ios(13.0));
|
||||
} ASPrimitiveTraitCollection;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@@ -61,6 +66,11 @@ AS_EXTERN ASPrimitiveTraitCollection ASPrimitiveTraitCollectionMakeDefault(void)
|
||||
*/
|
||||
AS_EXTERN ASPrimitiveTraitCollection ASPrimitiveTraitCollectionFromUITraitCollection(UITraitCollection *traitCollection);
|
||||
|
||||
/**
|
||||
* Creates a UITraitCollection from a given ASPrimitiveTraitCollection.
|
||||
*/
|
||||
AS_EXTERN UITraitCollection * ASPrimitiveTraitCollectionToUITraitCollection(ASPrimitiveTraitCollection traitCollection);
|
||||
|
||||
|
||||
/**
|
||||
* Compares two ASPrimitiveTraitCollection to determine if they are the same.
|
||||
@@ -139,13 +149,18 @@ AS_SUBCLASSING_RESTRICTED
|
||||
@property (readonly) UIUserInterfaceIdiom userInterfaceIdiom;
|
||||
@property (readonly) UIForceTouchCapability forceTouchCapability;
|
||||
@property (readonly) UITraitEnvironmentLayoutDirection layoutDirection API_AVAILABLE(ios(10.0));
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
@property (readonly) UIUserInterfaceStyle userInterfaceStyle API_AVAILABLE(tvos(10.0), ios(12.0));
|
||||
#endif
|
||||
@property (readonly) UIContentSizeCategory preferredContentSizeCategory API_AVAILABLE(ios(10.0));
|
||||
|
||||
@property (readonly) CGSize containerSize;
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
@property (readonly) UIUserInterfaceLevel userInterfaceLevel API_AVAILABLE(ios(13.0)) API_UNAVAILABLE(tvos);
|
||||
#endif
|
||||
|
||||
@property (readonly) UIAccessibilityContrast accessibilityContrast API_AVAILABLE(ios(13.0));
|
||||
@property (readonly) UILegibilityWeight legibilityWeight API_AVAILABLE(ios(13.0));
|
||||
|
||||
- (BOOL)isEqualToTraitCollection:(ASTraitCollection *)traitCollection;
|
||||
|
||||
@end
|
||||
|
||||
@@ -38,11 +38,20 @@ ASPrimitiveTraitCollection ASPrimitiveTraitCollectionMakeDefault() {
|
||||
tc.preferredContentSizeCategory = UIContentSizeCategoryUnspecified;
|
||||
tc.layoutDirection = UITraitEnvironmentLayoutDirectionUnspecified;
|
||||
}
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
tc.userInterfaceStyle = UIUserInterfaceStyleUnspecified;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
if(AS_AVAILABLE_IOS(13)){
|
||||
tc.userInterfaceLevel = UIUserInterfaceLevelUnspecified;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (AS_AVAILABLE_IOS(13)) {
|
||||
tc.accessibilityContrast = UIAccessibilityContrastUnspecified;
|
||||
tc.legibilityWeight = UILegibilityWeightUnspecified;
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
|
||||
@@ -60,14 +69,45 @@ ASPrimitiveTraitCollection ASPrimitiveTraitCollectionFromUITraitCollection(UITra
|
||||
ASDisplayNodeCAssertPermanent(traitCollection.preferredContentSizeCategory);
|
||||
environmentTraitCollection.preferredContentSizeCategory = traitCollection.preferredContentSizeCategory;
|
||||
}
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
environmentTraitCollection.userInterfaceStyle = traitCollection.userInterfaceStyle;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
if(AS_AVAILABLE_IOS(13)){
|
||||
environmentTraitCollection.userInterfaceLevel = traitCollection.userInterfaceLevel;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (AS_AVAILABLE_IOS(13)) {
|
||||
environmentTraitCollection.accessibilityContrast = traitCollection.accessibilityContrast;
|
||||
environmentTraitCollection.legibilityWeight = traitCollection.legibilityWeight;
|
||||
}
|
||||
return environmentTraitCollection;
|
||||
}
|
||||
|
||||
AS_EXTERN UITraitCollection * ASPrimitiveTraitCollectionToUITraitCollection(ASPrimitiveTraitCollection traitCollection) {
|
||||
NSMutableArray *collections = [[NSMutableArray alloc] initWithArray:@[
|
||||
[UITraitCollection traitCollectionWithHorizontalSizeClass:traitCollection.horizontalSizeClass],
|
||||
[UITraitCollection traitCollectionWithVerticalSizeClass:traitCollection.verticalSizeClass],
|
||||
[UITraitCollection traitCollectionWithDisplayScale:traitCollection.displayScale],
|
||||
[UITraitCollection traitCollectionWithUserInterfaceIdiom:traitCollection.userInterfaceIdiom],
|
||||
[UITraitCollection traitCollectionWithForceTouchCapability:traitCollection.forceTouchCapability],
|
||||
]];
|
||||
|
||||
if (AS_AVAILABLE_IOS(10)) {
|
||||
[collections addObject:[UITraitCollection traitCollectionWithDisplayGamut:traitCollection.displayGamut]];
|
||||
[collections addObject:[UITraitCollection traitCollectionWithLayoutDirection:traitCollection.layoutDirection]];
|
||||
[collections addObject:[UITraitCollection traitCollectionWithPreferredContentSizeCategory:traitCollection.preferredContentSizeCategory]];
|
||||
}
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
[collections addObject:[UITraitCollection traitCollectionWithUserInterfaceStyle:traitCollection.userInterfaceStyle]];
|
||||
}
|
||||
|
||||
UITraitCollection *result = [UITraitCollection traitCollectionWithTraitsFromCollections:collections];
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(ASPrimitiveTraitCollection lhs, ASPrimitiveTraitCollection rhs) {
|
||||
return !memcmp(&lhs, &rhs, sizeof(ASPrimitiveTraitCollection));
|
||||
}
|
||||
@@ -139,7 +179,6 @@ ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentLayoutDirection(
|
||||
}
|
||||
|
||||
// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
API_AVAILABLE(tvos(10.0), ios(12.0))
|
||||
ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUIUserInterfaceStyle(UIUserInterfaceStyle userInterfaceStyle) {
|
||||
switch (userInterfaceStyle) {
|
||||
@@ -151,7 +190,47 @@ ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUIUserInterfaceStyle(UIUserInterfa
|
||||
return @"Unspecified";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline
|
||||
API_AVAILABLE(ios(13)) API_UNAVAILABLE(tvos)
|
||||
ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentUserInterfaceLevel(UIUserInterfaceLevel userInterfaceLevel) {
|
||||
switch (userInterfaceLevel) {
|
||||
case UIUserInterfaceLevelBase:
|
||||
return @"Base";
|
||||
case UIUserInterfaceLevelElevated:
|
||||
return @"Elevated";
|
||||
default:
|
||||
return @"Unspecified";
|
||||
}
|
||||
}
|
||||
|
||||
// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline
|
||||
API_AVAILABLE(ios(13))
|
||||
ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentAccessibilityContrast(UIAccessibilityContrast accessibilityContrast) {
|
||||
switch (accessibilityContrast) {
|
||||
case UIAccessibilityContrastNormal:
|
||||
return @"Normal";
|
||||
case UIAccessibilityContrastHigh:
|
||||
return @"High";
|
||||
default:
|
||||
return @"Unspecified";
|
||||
}
|
||||
}
|
||||
|
||||
// Named so as not to conflict with a hidden Apple function, in case compiler decides not to inline
|
||||
API_AVAILABLE(ios(13))
|
||||
ASDISPLAYNODE_INLINE NSString *AS_NSStringFromUITraitEnvironmentLegibilityWeight(UILegibilityWeight legibilityWeight) {
|
||||
switch (legibilityWeight) {
|
||||
case UILegibilityWeightRegular:
|
||||
return @"Regular";
|
||||
case UILegibilityWeightBold:
|
||||
return @"Bold";
|
||||
default:
|
||||
return @"Unspecified";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection traits) {
|
||||
NSMutableArray<NSDictionary *> *props = [NSMutableArray array];
|
||||
@@ -160,16 +239,27 @@ NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection trai
|
||||
[props addObject:@{ @"displayScale": [NSString stringWithFormat: @"%.0lf", (double)traits.displayScale] }];
|
||||
[props addObject:@{ @"userInterfaceIdiom": AS_NSStringFromUIUserInterfaceIdiom(traits.userInterfaceIdiom) }];
|
||||
[props addObject:@{ @"forceTouchCapability": AS_NSStringFromUIForceTouchCapability(traits.forceTouchCapability) }];
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
if (AS_AVAILABLE_IOS_TVOS(12, 10)) {
|
||||
[props addObject:@{ @"userInterfaceStyle": AS_NSStringFromUIUserInterfaceStyle(traits.userInterfaceStyle) }];
|
||||
}
|
||||
#endif
|
||||
if (AS_AVAILABLE_IOS(10)) {
|
||||
[props addObject:@{ @"layoutDirection": AS_NSStringFromUITraitEnvironmentLayoutDirection(traits.layoutDirection) }];
|
||||
[props addObject:@{ @"preferredContentSizeCategory": traits.preferredContentSizeCategory }];
|
||||
if (traits.preferredContentSizeCategory != nil) {
|
||||
[props addObject:@{ @"preferredContentSizeCategory": traits.preferredContentSizeCategory }];
|
||||
}
|
||||
[props addObject:@{ @"displayGamut": AS_NSStringFromUIDisplayGamut(traits.displayGamut) }];
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
if (AS_AVAILABLE_IOS(13)){
|
||||
[props addObject:@{ @"userInterfaceLevel": AS_NSStringFromUITraitEnvironmentUserInterfaceLevel(traits.userInterfaceLevel) }];
|
||||
}
|
||||
#endif
|
||||
|
||||
if (AS_AVAILABLE_IOS(13)) {
|
||||
[props addObject:@{ @"accessibilityContrast": AS_NSStringFromUITraitEnvironmentAccessibilityContrast(traits.accessibilityContrast) }];
|
||||
[props addObject:@{ @"legibilityWeight": AS_NSStringFromUITraitEnvironmentLegibilityWeight(traits.legibilityWeight) }];
|
||||
}
|
||||
[props addObject:@{ @"containerSize": NSStringFromCGSize(traits.containerSize) }];
|
||||
return ASObjectDescriptionMakeWithoutObject(props);
|
||||
}
|
||||
@@ -220,16 +310,34 @@ NSString *NSStringFromASPrimitiveTraitCollection(ASPrimitiveTraitCollection trai
|
||||
{
|
||||
return _prim.containerSize;
|
||||
}
|
||||
#if AS_BUILD_UIUSERINTERFACESTYLE
|
||||
|
||||
- (UIUserInterfaceStyle)userInterfaceStyle
|
||||
{
|
||||
return _prim.userInterfaceStyle;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (UIContentSizeCategory)preferredContentSizeCategory
|
||||
{
|
||||
return _prim.preferredContentSizeCategory;
|
||||
}
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
- (UIUserInterfaceLevel)userInterfaceLevel
|
||||
{
|
||||
return _prim.userInterfaceLevel;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (UIAccessibilityContrast)accessibilityContrast
|
||||
{
|
||||
return _prim.accessibilityContrast;
|
||||
}
|
||||
|
||||
- (UILegibilityWeight)legibilityWeight
|
||||
{
|
||||
return _prim.legibilityWeight;
|
||||
}
|
||||
|
||||
- (NSUInteger)hash {
|
||||
return ASHashBytes(&_prim, sizeof(ASPrimitiveTraitCollection));
|
||||
}
|
||||
|
||||
@@ -268,10 +268,7 @@ void ASAsyncTransactionQueue::GroupImpl::notify(dispatch_queue_t queue, dispatch
|
||||
if (_pendingOperations == 0) {
|
||||
dispatch_async(queue, block);
|
||||
} else {
|
||||
GroupNotify notify;
|
||||
notify._block = block;
|
||||
notify._queue = queue;
|
||||
_notifyList.push_back(notify);
|
||||
_notifyList.push_back({block, queue});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,7 +330,7 @@ ASAsyncTransactionQueue & ASAsyncTransactionQueue::instance()
|
||||
|
||||
- (instancetype)initWithCompletionBlock:(void(^)(_ASAsyncTransaction *, BOOL))completionBlock
|
||||
{
|
||||
if ((self = [self init])) {
|
||||
if ((self = [super init])) {
|
||||
_completionBlock = completionBlock;
|
||||
self.state = ASAsyncTransactionStateOpen;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@property (nonatomic) UIColor *backgroundColor;
|
||||
@property (nonatomic) BOOL allowsGroupOpacity;
|
||||
@property (nonatomic) BOOL allowsEdgeAntialiasing;
|
||||
@property (nonatomic) unsigned int edgeAntialiasingMask;
|
||||
@property (nonatomic) CAEdgeAntialiasingMask edgeAntialiasingMask;
|
||||
@property (nonatomic, nullable, copy) NSDictionary<NSString *, id<CAAction>> *actions;
|
||||
|
||||
- (void)setNeedsDisplay;
|
||||
|
||||
@@ -14,3 +14,17 @@
|
||||
// should still work as long as accessibility is enabled, this framework provides no guarantees on
|
||||
// their correctness. For details, see
|
||||
// https://developer.apple.com/documentation/objectivec/nsobject/1615147-accessibilityelements
|
||||
|
||||
// After recusively collecting all of the accessibility elements of a node, they get sorted. This sort determines
|
||||
// the order that a screen reader will traverse the elements. By default, we sort these elements based on their
|
||||
// origin: lower y origin comes first, then lower x origin. If 2 nodes have an equal origin, the node with the smaller
|
||||
// height is placed before the node with the smaller width. If two nodes have the exact same rect, we throw up our hands
|
||||
// and return NSOrderedSame.
|
||||
//
|
||||
// In general this seems to work fairly well. However, if you want to provide a custom sort you can do so via
|
||||
// setUserDefinedAccessibilitySortComparator(). The two elements you are comparing are NSObjects, which conforms to the
|
||||
// informal UIAccessibility protocol, so you can safely compare properties like accessibilityFrame.
|
||||
typedef NSComparisonResult (^ASSortAccessibilityElementsComparator)(NSObject *, NSObject *);
|
||||
|
||||
// Use this method to supply your own custom sort comparator used to determine the order of the accessibility elements
|
||||
void setUserDefinedAccessibilitySortComparator(ASSortAccessibilityElementsComparator userDefinedComparator);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#ifndef ASDK_ACCESSIBILITY_DISABLE
|
||||
|
||||
#import <AsyncDisplayKit/_ASDisplayView.h>
|
||||
#import <AsyncDisplayKit/_ASDisplayViewAccessiblity.h>
|
||||
#import <AsyncDisplayKit/ASAvailability.h>
|
||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNodeExtras.h>
|
||||
@@ -21,35 +22,47 @@
|
||||
|
||||
#pragma mark - UIAccessibilityElement
|
||||
|
||||
@protocol ASAccessibilityElementPositioning
|
||||
static ASSortAccessibilityElementsComparator currentAccessibilityComparator = nil;
|
||||
static ASSortAccessibilityElementsComparator defaultAccessibilityComparator = nil;
|
||||
|
||||
@property (nonatomic, readonly) CGRect accessibilityFrame;
|
||||
|
||||
@end
|
||||
|
||||
typedef NSComparisonResult (^SortAccessibilityElementsComparator)(id<ASAccessibilityElementPositioning>, id<ASAccessibilityElementPositioning>);
|
||||
void setUserDefinedAccessibilitySortComparator(ASSortAccessibilityElementsComparator userDefinedComparator) {
|
||||
currentAccessibilityComparator = userDefinedComparator ?: defaultAccessibilityComparator;
|
||||
}
|
||||
|
||||
/// Sort accessiblity elements first by y and than by x origin.
|
||||
static void SortAccessibilityElements(NSMutableArray *elements)
|
||||
void SortAccessibilityElements(NSMutableArray *elements)
|
||||
{
|
||||
ASDisplayNodeCAssertNotNil(elements, @"Should pass in a NSMutableArray");
|
||||
|
||||
static SortAccessibilityElementsComparator comparator = nil;
|
||||
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
comparator = ^NSComparisonResult(id<ASAccessibilityElementPositioning> a, id<ASAccessibilityElementPositioning> b) {
|
||||
CGPoint originA = a.accessibilityFrame.origin;
|
||||
CGPoint originB = b.accessibilityFrame.origin;
|
||||
if (originA.y == originB.y) {
|
||||
if (originA.x == originB.x) {
|
||||
return NSOrderedSame;
|
||||
defaultAccessibilityComparator = ^NSComparisonResult(NSObject *a, NSObject *b) {
|
||||
CGPoint originA = a.accessibilityFrame.origin;
|
||||
CGPoint originB = b.accessibilityFrame.origin;
|
||||
if (originA.y == originB.y) {
|
||||
if (originA.x == originB.x) {
|
||||
// if we have the same origin, favor shorter items. If heights are the same, favor thinner items. If size is the same ¯\_(ツ)_/¯
|
||||
CGSize sizeA = a.accessibilityFrame.size;
|
||||
CGSize sizeB = b.accessibilityFrame.size;
|
||||
if (sizeA.height == sizeB.height) {
|
||||
if (sizeA.width == sizeB.width) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
return (sizeA.width < sizeB.width) ? NSOrderedAscending : NSOrderedDescending;
|
||||
}
|
||||
return (originA.x < originB.x) ? NSOrderedAscending : NSOrderedDescending;
|
||||
return (sizeA.height < sizeB.height) ? NSOrderedAscending : NSOrderedDescending;
|
||||
}
|
||||
return (originA.y < originB.y) ? NSOrderedAscending : NSOrderedDescending;
|
||||
};
|
||||
return (originA.x < originB.x) ? NSOrderedAscending : NSOrderedDescending;
|
||||
}
|
||||
return (originA.y < originB.y) ? NSOrderedAscending : NSOrderedDescending;
|
||||
};
|
||||
|
||||
if (!currentAccessibilityComparator) {
|
||||
currentAccessibilityComparator = defaultAccessibilityComparator;
|
||||
}
|
||||
});
|
||||
[elements sortUsingComparator:comparator];
|
||||
|
||||
[elements sortUsingComparator:currentAccessibilityComparator];
|
||||
}
|
||||
|
||||
static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) {
|
||||
@@ -57,7 +70,7 @@ static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) {
|
||||
return [layer convertRect:node.bounds toLayer:ASFindWindowOfLayer(layer).layer];
|
||||
}
|
||||
|
||||
@interface ASAccessibilityElement : UIAccessibilityElement<ASAccessibilityElementPositioning>
|
||||
@interface ASAccessibilityElement : UIAccessibilityElement
|
||||
|
||||
@property (nonatomic) ASDisplayNode *node;
|
||||
|
||||
@@ -93,7 +106,7 @@ static CGRect ASAccessibilityFrameForNode(ASDisplayNode *node) {
|
||||
|
||||
#pragma mark - _ASDisplayView / UIAccessibilityContainer
|
||||
|
||||
@interface ASAccessibilityCustomAction : UIAccessibilityCustomAction<ASAccessibilityElementPositioning>
|
||||
@interface ASAccessibilityCustomAction : UIAccessibilityCustomAction
|
||||
|
||||
@property (nonatomic) ASDisplayNode *node;
|
||||
|
||||
@@ -197,6 +210,17 @@ static void CollectAccessibilityElementsForContainer(ASDisplayNode *container, U
|
||||
[elements addObject:accessiblityElement];
|
||||
}
|
||||
|
||||
/// Check if a view is a subviews of an UIScrollView. This is used to determine whether to enforce that
|
||||
/// accessibility elements must be on screen
|
||||
static BOOL recusivelyCheckSuperviewsForScrollView(UIView *view) {
|
||||
if (!view) {
|
||||
return NO;
|
||||
} else if ([view isKindOfClass:[UIScrollView class]]) {
|
||||
return YES;
|
||||
}
|
||||
return recusivelyCheckSuperviewsForScrollView(view.superview);
|
||||
}
|
||||
|
||||
/// Collect all accessibliity elements for a given view and view node
|
||||
static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *elements)
|
||||
{
|
||||
@@ -213,6 +237,11 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el
|
||||
}));
|
||||
|
||||
UIView *view = node.view;
|
||||
|
||||
// If we don't have a window, let's just bail out
|
||||
if (!view.window) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (node.isAccessibilityContainer && !anySubNodeIsCollection) {
|
||||
CollectAccessibilityElementsForContainer(node, view, elements);
|
||||
@@ -224,8 +253,20 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el
|
||||
CollectUIAccessibilityElementsForNode(node, node, view, elements);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (ASDisplayNode *subnode in node.subnodes) {
|
||||
// If a node is hidden or has an alpha of 0.0 we should not include it
|
||||
if (subnode.hidden || subnode.alpha == 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If a subnode is outside of the view's window, exclude it UNLESS it is a subview of an UIScrollView.
|
||||
// In this case UIKit will return the element even if it is outside of the window or the scrollView's visible rect (contentOffset + contentSize)
|
||||
CGRect nodeInWindowCoords = [node convertRect:subnode.frame toNode:nil];
|
||||
if (!CGRectIntersectsRect(view.window.frame, nodeInWindowCoords) && !recusivelyCheckSuperviewsForScrollView(view)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (subnode.isAccessibilityElement) {
|
||||
// An accessiblityElement can either be a UIView or a UIAccessibilityElement
|
||||
if (subnode.isLayerBacked) {
|
||||
@@ -259,6 +300,10 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el
|
||||
- (void)setAccessibilityElements:(NSArray *)accessibilityElements
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
// While it looks very strange to ignore the accessibilyElements param and set _accessibilityElements to nil, it is actually on purpose.
|
||||
// _ASDisplayView's accessibilityElements method will always defer to the node for accessibilityElements when _accessibilityElements is
|
||||
// nil. Calling setAccessibilityElements on _ASDisplayView is basically clearing the cache and forcing _ASDisplayView to ask the node
|
||||
// for its accessibilityElements the next time they are requested.
|
||||
_accessibilityElements = nil;
|
||||
}
|
||||
|
||||
@@ -271,7 +316,9 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el
|
||||
return @[];
|
||||
}
|
||||
|
||||
if (_accessibilityElements == nil) {
|
||||
// when items become hidden/visible we have to manually clear the _accessibilityElements in order to get an updated version
|
||||
// Instead, let's try computing the elements every time and see how badly it affects performance.
|
||||
if (_accessibilityElements == nil || ASActivateExperimentalFeature(ASExperimentalDoNotCacheAccessibilityElements)) {
|
||||
_accessibilityElements = [viewNode accessibilityElements];
|
||||
}
|
||||
return _accessibilityElements;
|
||||
@@ -283,6 +330,14 @@ static void CollectAccessibilityElements(ASDisplayNode *node, NSMutableArray *el
|
||||
|
||||
- (NSArray *)accessibilityElements
|
||||
{
|
||||
// NSObject implements the informal accessibility protocol. This means that all ASDisplayNodes already have an accessibilityElements
|
||||
// property. If an ASDisplayNode subclass has explicitly set the property, let's use that instead of traversing the node tree to try
|
||||
// to create the elements automatically
|
||||
NSArray *elements = [super accessibilityElements];
|
||||
if (elements.count) {
|
||||
return elements;
|
||||
}
|
||||
|
||||
if (!self.isNodeLoaded) {
|
||||
ASDisplayNodeFailAssert(@"Cannot access accessibilityElements since node is not loaded");
|
||||
return @[];
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
//
|
||||
// ASLayout+IGListKit.h
|
||||
// ASLayout+IGListDiffKit.h
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#if AS_IG_LIST_KIT
|
||||
#if AS_IG_LIST_DIFF_KIT
|
||||
#import <AsyncDisplayKit/ASLayout.h>
|
||||
#import <IGListKit/IGListKit.h>
|
||||
@interface ASLayout(IGListKit) <IGListDiffable>
|
||||
@end
|
||||
#import <IGListDiffKit/IGListDiffKit.h>
|
||||
|
||||
#endif // AS_IG_LIST_KIT
|
||||
@interface ASLayout(IGListDiffKit) <IGListDiffable>
|
||||
@end
|
||||
#endif // AS_IG_LIST_DIFF_KIT
|
||||
@@ -1,13 +1,13 @@
|
||||
//
|
||||
// ASLayout+IGListKit.mm
|
||||
// ASLayout+IGListDiffKit.mm
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
#import <AsyncDisplayKit/ASAvailability.h>
|
||||
#if AS_IG_LIST_KIT
|
||||
#import "ASLayout+IGListKit.h"
|
||||
#if AS_IG_LIST_DIFF_KIT
|
||||
#import "ASLayout+IGListDiffKit.h"
|
||||
|
||||
@interface ASLayout() {
|
||||
@public
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ASLayout(IGListKit)
|
||||
@implementation ASLayout(IGListDiffKit)
|
||||
|
||||
- (id <NSObject>)diffIdentifier
|
||||
{
|
||||
@@ -27,4 +27,4 @@
|
||||
return [self isEqual:other];
|
||||
}
|
||||
@end
|
||||
#endif // AS_IG_LIST_KIT
|
||||
#endif // AS_IG_LIST_DIFF_KIT
|
||||
@@ -338,7 +338,12 @@ static const ASScrollDirection kASStaticScrollDirection = (ASScrollDirectionRigh
|
||||
if (NSUInteger count = blockingAttrs.count) {
|
||||
ASDispatchApply(count, queue, 0, ^(size_t i) {
|
||||
UICollectionViewLayoutAttributes *attrs = blockingAttrs[i];
|
||||
ASCellNode *node = [elements elementForItemAtIndexPath:attrs.indexPath].node;
|
||||
ASCellNode *node;
|
||||
if (attrs.representedElementKind == nil) {
|
||||
node = [elements elementForItemAtIndexPath:attrs.indexPath].node;
|
||||
} else {
|
||||
node = [elements supplementaryElementOfKind:attrs.representedElementKind atIndexPath:attrs.indexPath].node;
|
||||
}
|
||||
CGSize expectedSize = attrs.frame.size;
|
||||
if (! CGSizeEqualToSize(expectedSize, node.calculatedSize)) {
|
||||
[node layoutThatFits:ASCollectionLayoutElementSizeRangeFromSize(expectedSize)];
|
||||
@@ -353,7 +358,12 @@ static const ASScrollDirection kASStaticScrollDirection = (ASScrollDirectionRigh
|
||||
__strong ASElementMap *strongElements = weakElements;
|
||||
if (strongElements) {
|
||||
UICollectionViewLayoutAttributes *attrs = nonBlockingAttrs[i];
|
||||
ASCellNode *node = [elements elementForItemAtIndexPath:attrs.indexPath].node;
|
||||
ASCellNode *node;
|
||||
if (attrs.representedElementKind == nil) {
|
||||
node = [elements elementForItemAtIndexPath:attrs.indexPath].node;
|
||||
} else {
|
||||
node = [elements supplementaryElementOfKind:attrs.representedElementKind atIndexPath:attrs.indexPath].node;
|
||||
}
|
||||
CGSize expectedSize = attrs.frame.size;
|
||||
if (! CGSizeEqualToSize(expectedSize, node.calculatedSize)) {
|
||||
[node layoutThatFits:ASCollectionLayoutElementSizeRangeFromSize(expectedSize)];
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#import <AsyncDisplayKit/ASCollectionView.h>
|
||||
#import <AsyncDisplayKit/ASEqualityHelpers.h>
|
||||
#import <AsyncDisplayKit/ASCollectionNode.h>
|
||||
#import <AsyncDisplayKit/ASCollectionView+Undeprecated.h>
|
||||
|
||||
#define kDefaultItemSize CGSizeMake(50, 50)
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ using AS::MutexLocker;
|
||||
displayBlock = ^id{
|
||||
CHECK_CANCELLED_AND_RETURN_NIL();
|
||||
|
||||
UIImage *image = ASGraphicsCreateImageWithOptions(bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, ^{
|
||||
UIImage *image = ASGraphicsCreateImage(self.primitiveTraitCollection, bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, ^{
|
||||
for (dispatch_block_t block in displayBlocks) {
|
||||
if (isCancelledBlock()) return;
|
||||
block();
|
||||
@@ -247,7 +247,7 @@ using AS::MutexLocker;
|
||||
};
|
||||
|
||||
if (shouldCreateGraphicsContext) {
|
||||
return ASGraphicsCreateImageWithOptions(bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, workWithContext);
|
||||
return ASGraphicsCreateImage(self.primitiveTraitCollection, bounds.size, opaque, contentsScaleForDisplay, nil, isCancelledBlock, workWithContext);
|
||||
} else {
|
||||
workWithContext();
|
||||
return image;
|
||||
|
||||
@@ -823,6 +823,7 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_tintColor = color;
|
||||
_setToViewOnly(tintColor, color);
|
||||
}
|
||||
__instanceLock__.unlock();
|
||||
@@ -929,13 +930,13 @@ if (shouldApply) { _layer.layerProperty = (layerValueExpr); } else { ASDisplayNo
|
||||
_setToLayer(allowsEdgeAntialiasing, allowsEdgeAntialiasing);
|
||||
}
|
||||
|
||||
- (unsigned int)edgeAntialiasingMask
|
||||
- (CAEdgeAntialiasingMask)edgeAntialiasingMask
|
||||
{
|
||||
_bridge_prologue_read;
|
||||
return _getFromLayer(edgeAntialiasingMask);
|
||||
}
|
||||
|
||||
- (void)setEdgeAntialiasingMask:(unsigned int)edgeAntialiasingMask
|
||||
- (void)setEdgeAntialiasingMask:(CAEdgeAntialiasingMask)edgeAntialiasingMask
|
||||
{
|
||||
_bridge_prologue_write;
|
||||
_setToLayer(edgeAntialiasingMask, edgeAntialiasingMask);
|
||||
|
||||
@@ -86,6 +86,21 @@ typedef struct {
|
||||
[self.delegate collectionView:collectionNode.view didSelectItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode didDeselectItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[self.delegate collectionView:collectionNode.view didDeselectItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode didHighlightItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[self.delegate collectionView:collectionNode.view didHighlightItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode didUnhighlightItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[self.delegate collectionView:collectionNode.view didUnhighlightItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
|
||||
{
|
||||
[self.delegate scrollViewDidScroll:scrollView];
|
||||
@@ -147,6 +162,32 @@ typedef struct {
|
||||
[ctrl beginBatchFetchWithContext:context];
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode willDisplayItemWithNode:(ASCellNode *)node
|
||||
{
|
||||
NSIndexPath *indexPath = [collectionNode.view indexPathForNode:node];
|
||||
UIView *contentView = node.view.superview;
|
||||
UICollectionViewCell *cell = contentView.superview;
|
||||
|
||||
if (cell == nil || indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:collectionNode.view willDisplayCell:cell forItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)collectionNode:(ASCollectionNode *)collectionNode didEndDisplayingItemWithNode:(ASCellNode *)node
|
||||
{
|
||||
NSIndexPath *indexPath = [collectionNode.view indexPathForNode:node];
|
||||
UIView *contentView = node.view.superview;
|
||||
UICollectionViewCell *cell = contentView.superview;
|
||||
|
||||
if (cell == nil || indexPath == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.delegate collectionView:collectionNode.view didEndDisplayingCell:cell forItemAtIndexPath:indexPath];
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: It is not documented that ASCollectionNode will forward these UIKit delegate calls if they are implemented.
|
||||
* It is not considered harmful to do so, and adding them to documentation will confuse most users, who should
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
unsigned int animatedImagePaused:1;
|
||||
unsigned int cropEnabled:1; // Defaults to YES.
|
||||
unsigned int forceUpscaling:1; //Defaults to NO.
|
||||
unsigned int regenerateFromImageAsset:1; //Defaults to NO.
|
||||
} _imageNodeFlags;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
|
||||
#import <queue>
|
||||
|
||||
#if AS_IG_LIST_KIT
|
||||
#import <IGListKit/IGListKit.h>
|
||||
#import <AsyncDisplayKit/ASLayout+IGListKit.h>
|
||||
#if AS_IG_LIST_DIFF_KIT
|
||||
#import <AsyncDisplayKit/ASLayout+IGListDiffKit.h>
|
||||
#endif
|
||||
|
||||
using AS::MutexLocker;
|
||||
@@ -160,13 +159,13 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
||||
ASLayout *pendingLayout = _pendingLayout.layout;
|
||||
|
||||
if (previousLayout) {
|
||||
#if AS_IG_LIST_KIT
|
||||
#if AS_IG_LIST_DIFF_KIT
|
||||
// IGListDiff completes in linear time O(m+n), so use it if we have it:
|
||||
IGListIndexSetResult *result = IGListDiff(previousLayout.sublayouts, pendingLayout.sublayouts, IGListDiffEquality);
|
||||
_insertedSubnodePositions = findNodesInLayoutAtIndexes(pendingLayout, result.inserts, &_insertedSubnodes);
|
||||
findNodesInLayoutAtIndexes(previousLayout, result.deletes, &_removedSubnodes);
|
||||
for (IGListMoveIndex *move in result.moves) {
|
||||
_subnodeMoves.push_back(std::make_pair(previousLayout.sublayouts[move.from].layoutElement, move.to));
|
||||
_subnodeMoves.emplace_back(previousLayout.sublayouts[move.from].layoutElement, move.to);
|
||||
}
|
||||
|
||||
// Sort by ascending order of move destinations, this will allow easy loop of `insertSubnode:AtIndex` later.
|
||||
@@ -188,8 +187,8 @@ static inline BOOL ASLayoutCanTransitionAsynchronous(ASLayout *layout) {
|
||||
_removedSubnodes = [previousNodes objectsAtIndexes:deletions];
|
||||
// These should arrive sorted in ascending order of move destinations.
|
||||
for (NSIndexPath *move in moves) {
|
||||
_subnodeMoves.push_back(std::make_pair(previousLayout.sublayouts[([move indexAtPosition:0])].layoutElement,
|
||||
[move indexAtPosition:1]));
|
||||
_subnodeMoves.emplace_back(previousLayout.sublayouts[([move indexAtPosition:0])].layoutElement,
|
||||
[move indexAtPosition:1]);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
||||
@@ -24,17 +24,15 @@ namespace AS {
|
||||
{
|
||||
// Some convenience type definitions
|
||||
typedef decltype(func(std::declval<typename T::value_type>())) value_type;
|
||||
typedef std::vector<value_type> result_type;
|
||||
|
||||
// Prepares an output vector of the appropriate size
|
||||
result_type res(iterable.size());
|
||||
std::vector<value_type> res;
|
||||
res.reserve(iterable.size());
|
||||
|
||||
// Let std::transform apply `func` to all elements
|
||||
// (use perfect forwarding for the function object)
|
||||
std::transform(
|
||||
begin(iterable), end(iterable), res.begin(),
|
||||
std::forward<Func>(func)
|
||||
);
|
||||
std::transform(std::begin(iterable), std::end(iterable), std::back_inserter(res),
|
||||
std::forward<Func>(func));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
Additional information about the the run delegate.
|
||||
*/
|
||||
@property (nullable, nonatomic) NSDictionary *userInfo;
|
||||
@property (nullable, nonatomic, copy) NSDictionary *userInfo;
|
||||
|
||||
/**
|
||||
The typographic ascent of glyphs in the run.
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
#define __shouldSetNeedsDisplayForView(view) (flags.needsDisplay \
|
||||
|| (flags.setOpaque && _flags.opaque != (view).opaque)\
|
||||
|| (flags.setBackgroundColor && ![backgroundColor isEqual:(view).backgroundColor]))
|
||||
|| (flags.setBackgroundColor && ![backgroundColor isEqual:(view).backgroundColor])\
|
||||
|| (flags.setTintColor && ![tintColor isEqual:(view).tintColor]))
|
||||
|
||||
#define __shouldSetNeedsDisplayForLayer(layer) (flags.needsDisplay \
|
||||
|| (flags.setOpaque && _flags.opaque != (layer).opaque)\
|
||||
@@ -104,6 +105,7 @@ static constexpr ASPendingStateFlags kZeroFlags = {0};
|
||||
CGRect frame; // Frame is only to be used for synchronous views wrapped by nodes (see setFrame:)
|
||||
CGRect bounds;
|
||||
UIColor *backgroundColor;
|
||||
UIColor *tintColor;
|
||||
CGFloat alpha;
|
||||
CGFloat cornerRadius;
|
||||
UIViewContentMode contentMode;
|
||||
@@ -374,7 +376,7 @@ static CGColorRef blackColorRef = NULL;
|
||||
return _flags.allowsEdgeAntialiasing;
|
||||
}
|
||||
|
||||
- (void)setEdgeAntialiasingMask:(unsigned int)mask
|
||||
- (void)setEdgeAntialiasingMask:(CAEdgeAntialiasingMask)mask
|
||||
{
|
||||
edgeAntialiasingMask = mask;
|
||||
_stateToApplyFlags.setEdgeAntialiasingMask = YES;
|
||||
@@ -428,8 +430,16 @@ static CGColorRef blackColorRef = NULL;
|
||||
_stateToApplyFlags.setBackgroundColor = YES;
|
||||
}
|
||||
|
||||
- (UIColor *)tintColor
|
||||
{
|
||||
return tintColor;
|
||||
}
|
||||
|
||||
- (void)setTintColor:(UIColor *)newTintColor
|
||||
{
|
||||
if ([newTintColor isEqual:tintColor]) {
|
||||
return;
|
||||
}
|
||||
tintColor = newTintColor;
|
||||
_stateToApplyFlags.setTintColor = YES;
|
||||
}
|
||||
@@ -1097,7 +1107,7 @@ static CGColorRef blackColorRef = NULL;
|
||||
}
|
||||
|
||||
if (flags.setTintColor)
|
||||
view.tintColor = self.tintColor;
|
||||
view.tintColor = tintColor;
|
||||
|
||||
if (flags.setOpaque) {
|
||||
view.opaque = _flags.opaque;
|
||||
@@ -1324,7 +1334,7 @@ static CGColorRef blackColorRef = NULL;
|
||||
pendingState.contentsScale = layer.contentsScale;
|
||||
pendingState.rasterizationScale = layer.rasterizationScale;
|
||||
pendingState.clipsToBounds = view.clipsToBounds;
|
||||
pendingState.backgroundColor = [UIColor colorWithCGColor:layer.backgroundColor];
|
||||
pendingState.backgroundColor = view.backgroundColor;
|
||||
pendingState.tintColor = view.tintColor;
|
||||
pendingState.opaque = layer.opaque;
|
||||
pendingState.hidden = view.hidden;
|
||||
|
||||
@@ -37,9 +37,7 @@
|
||||
static dispatch_once_t onceToken;
|
||||
// Concurrently initialising TextKit components crashes (rdar://18448377) so we use a global lock.
|
||||
dispatch_once(&onceToken, ^{
|
||||
if (!ASActivateExperimentalFeature(ASExperimentalRemoveTextKitInitialisingLock)) {
|
||||
mutex = new AS::Mutex();
|
||||
}
|
||||
});
|
||||
if (mutex != NULL) {
|
||||
mutex->lock();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASTraitCollection.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -68,7 +69,20 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(nullable UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
fillColor:(UIColor *)fillColor NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:traitCollection: instead");
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
* @param traitCollection The trait collection.
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(nullable UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
@@ -83,7 +97,23 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(nullable UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
borderWidth:(CGFloat)borderWidth NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:borderColor:borderWidth:traitCollection: instead");
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
* @param borderColor The border color. Set to nil for no border.
|
||||
* @param borderWidth The border width. Dummy value if borderColor = nil.
|
||||
* @param traitCollection The trait collection.
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(nullable UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
@@ -102,7 +132,30 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
borderColor:(nullable UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
scale:(CGFloat)scale NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT ASDISPLAYNODE_DEPRECATED_MSG("Use as_resizableRoundedImageWithCornerRadius:cornerColor:fillColor:borderColor:borderWidth:roundedCorners:traitCollection: instead");
|
||||
;
|
||||
|
||||
/**
|
||||
* This generates a flat-color, rounded-corner resizeable image with a border
|
||||
*
|
||||
* @param cornerRadius The radius of the rounded-corner
|
||||
* @param cornerColor The fill color of the corners (For Alpha corners use clearColor)
|
||||
* @param fillColor The fill color of the rounded-corner image
|
||||
* @param borderColor The border color. Set to nil for no border.
|
||||
* @param borderWidth The border width. Dummy value if borderColor = nil.
|
||||
* @param roundedCorners Select individual or multiple corners to round. Set to UIRectCornerAllCorners to round all 4 corners.
|
||||
* @param scale The number of pixels per point. Provide 0.0 to use the screen scale.
|
||||
* @param traitCollection The trait collection.
|
||||
*/
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(nullable UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(nullable UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale
|
||||
traitCollection:(ASPrimitiveTraitCollection) traitCollection
|
||||
NS_RETURNS_RETAINED AS_WARN_UNUSED_RESULT;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -30,7 +30,12 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio
|
||||
NSString *imageKey = imageName;
|
||||
if (traitCollection) {
|
||||
char imageKeyBuffer[256];
|
||||
snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass, (long)traitCollection.userInterfaceStyle);
|
||||
if (@available(iOS 12.0, *)) {
|
||||
snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass, (long)traitCollection.userInterfaceStyle);
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
snprintf(imageKeyBuffer, sizeof(imageKeyBuffer), "%s|%ld|%ld", imageName.UTF8String, (long)traitCollection.horizontalSizeClass, (long)traitCollection.verticalSizeClass);
|
||||
}
|
||||
imageKey = [NSString stringWithUTF8String:imageKeyBuffer];
|
||||
}
|
||||
|
||||
@@ -74,6 +79,38 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio
|
||||
scale:0.0];
|
||||
}
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED
|
||||
{
|
||||
return [self as_resizableRoundedImageWithCornerRadius:cornerRadius
|
||||
cornerColor:cornerColor
|
||||
fillColor:fillColor
|
||||
borderColor:nil
|
||||
borderWidth:1.0
|
||||
roundedCorners:UIRectCornerAllCorners
|
||||
scale:0.0
|
||||
traitCollection:traitCollection];
|
||||
}
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED {
|
||||
return [self as_resizableRoundedImageWithCornerRadius:cornerRadius
|
||||
cornerColor:cornerColor
|
||||
fillColor:fillColor
|
||||
borderColor:borderColor
|
||||
borderWidth:borderWidth
|
||||
roundedCorners:UIRectCornerAllCorners
|
||||
scale:0.0
|
||||
traitCollection:traitCollection];
|
||||
}
|
||||
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
@@ -95,7 +132,27 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale NS_RETURNS_RETAINED
|
||||
scale:(CGFloat)scale NS_RETURNS_RETAINED {
|
||||
|
||||
return [self as_resizableRoundedImageWithCornerRadius:cornerRadius
|
||||
cornerColor:cornerColor
|
||||
fillColor:fillColor
|
||||
borderColor:borderColor
|
||||
borderWidth:borderWidth
|
||||
roundedCorners:roundedCorners
|
||||
scale:scale
|
||||
traitCollection:ASPrimitiveTraitCollectionMakeDefault()];
|
||||
}
|
||||
|
||||
|
||||
+ (UIImage *)as_resizableRoundedImageWithCornerRadius:(CGFloat)cornerRadius
|
||||
cornerColor:(UIColor *)cornerColor
|
||||
fillColor:(UIColor *)fillColor
|
||||
borderColor:(UIColor *)borderColor
|
||||
borderWidth:(CGFloat)borderWidth
|
||||
roundedCorners:(UIRectCorner)roundedCorners
|
||||
scale:(CGFloat)scale
|
||||
traitCollection:(ASPrimitiveTraitCollection) traitCollection NS_RETURNS_RETAINED
|
||||
{
|
||||
static NSCache *__pathCache = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -129,7 +186,7 @@ UIImage *cachedImageNamed(NSString *imageName, UITraitCollection *traitCollectio
|
||||
|
||||
// We should probably check if the background color has any alpha component but that
|
||||
// might be expensive due to needing to check mulitple color spaces.
|
||||
UIImage *result = ASGraphicsCreateImageWithOptions(bounds.size, cornerColor != nil, scale, nil, nil, ^{
|
||||
UIImage *result = ASGraphicsCreateImage(traitCollection, bounds.size, cornerColor != nil, scale, nil, nil, ^{
|
||||
BOOL contextIsClean = YES;
|
||||
if (cornerColor) {
|
||||
contextIsClean = NO;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
@interface ASBridgedPropertiesTestView : UIView
|
||||
@property (nonatomic, readonly) BOOL receivedSetNeedsLayout;
|
||||
@property (nonatomic, readonly) NSUInteger setNeedsDisplayCount;
|
||||
@end
|
||||
|
||||
@implementation ASBridgedPropertiesTestView
|
||||
@@ -31,6 +32,12 @@
|
||||
[super setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
_setNeedsDisplayCount += 1;
|
||||
[super setNeedsDisplay];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ASBridgedPropertiesTestNode : ASDisplayNode
|
||||
@@ -138,6 +145,32 @@ static inline void ASDispatchSyncOnOtherThread(dispatch_block_t block) {
|
||||
});
|
||||
}
|
||||
|
||||
- (void)testThatSettingTintColorSetNeedsDisplayOnView
|
||||
{
|
||||
ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
|
||||
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] initWithViewClass:ASBridgedPropertiesTestView.class];
|
||||
ASBridgedPropertiesTestView *view = (ASBridgedPropertiesTestView *)node.view;
|
||||
NSUInteger initialSetNeedsDisplayCount = view.setNeedsDisplayCount;
|
||||
#if AS_AT_LEAST_IOS13
|
||||
// This is called an extra time on iOS13 for unknown reasons. Need to Investigate.
|
||||
if (@available(iOS 13.0, *)) {
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 2);
|
||||
} else {
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
ASDispatchSyncOnOtherThread(^{
|
||||
node.tintColor = UIColor.orangeColor;
|
||||
});
|
||||
XCTAssertNotEqualObjects(view.tintColor, UIColor.orangeColor);
|
||||
XCTAssertEqual(view.setNeedsDisplayCount, initialSetNeedsDisplayCount);
|
||||
[ctrl flush];
|
||||
XCTAssertEqualObjects(view.tintColor, UIColor.orangeColor);
|
||||
XCTAssertEqual(view.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1);
|
||||
}
|
||||
|
||||
- (void)testThatManuallyFlushingTheSyncControllerImmediatelyAppliesChanges
|
||||
{
|
||||
ASPendingStateController *ctrl = [ASPendingStateController sharedInstance];
|
||||
|
||||
@@ -80,4 +80,36 @@
|
||||
ASSnapshotVerifyNode(node, nil);
|
||||
}
|
||||
|
||||
- (void)testTintColorWithInheritedTintColor
|
||||
{
|
||||
ASDisplayNode *container = [[ASDisplayNode alloc] init];
|
||||
container.tintColor = UIColor.redColor;
|
||||
|
||||
// Add to hierarchy, assert new tint is picked up
|
||||
ASButtonNode *node = [[ASButtonNode alloc] init];
|
||||
[container addSubnode:node];
|
||||
[node setImage:[[self testImage] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
|
||||
[node setTitle:@"Press Me"
|
||||
withFont:[UIFont systemFontOfSize:48]
|
||||
withColor:nil
|
||||
forState:UIControlStateNormal];
|
||||
node.imageNode.style.width = ASDimensionMake(200);
|
||||
node.imageNode.style.height = ASDimensionMake(200);
|
||||
container.style.preferredSize = CGSizeMake(1000,1000);
|
||||
ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000));
|
||||
// Force load so the superview is set for the button _ASDisplayView
|
||||
__unused UIView *v = container.view;
|
||||
ASSnapshotVerifyNode(node, @"red_inherited_tint");
|
||||
|
||||
// Change hierarchy, assert new tint is picked up
|
||||
ASDisplayNode *container2 = [[ASDisplayNode alloc] init];
|
||||
container2.tintColor = UIColor.greenColor;
|
||||
container2.style.preferredSize = CGSizeMake(1000,1000);
|
||||
[container2 addSubnode:node];
|
||||
ASDisplayNodeSizeToFitSize(node, CGSizeMake(1000, 1000));
|
||||
// Force load so the superview is set for the button _ASDisplayView
|
||||
__unused UIView *v2 = container2.view; // Force load
|
||||
ASSnapshotVerifyNode(node, @"green_inherited_tint");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -32,22 +32,22 @@
|
||||
|
||||
@implementation InspectorTestDataSource
|
||||
|
||||
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return [[ASCellNode alloc] init];
|
||||
}
|
||||
|
||||
- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return ^{ return [[ASCellNode alloc] init]; };
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
|
||||
- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
@@ -63,12 +63,12 @@
|
||||
|
||||
@implementation InspectorTestDataSourceDelegateWithoutNodeConstrainedSize
|
||||
|
||||
- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
return ^{ return [[ASCellNode alloc] init]; };
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
|
||||
- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -88,9 +88,9 @@
|
||||
|
||||
@implementation HeaderReferenceSizeTestDelegate
|
||||
|
||||
- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section
|
||||
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return CGSizeMake(125.0, 125.0);
|
||||
return ASSizeRangeMake(CGSizeMake(125.0, 125.0));
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -104,9 +104,9 @@
|
||||
|
||||
@implementation FooterReferenceSizeTestDelegate
|
||||
|
||||
- (CGSize)collectionView:(ASCollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section
|
||||
- (ASSizeRange)collectionNode:(ASCollectionNode *)collectionNode sizeRangeForFooterInSection:(NSInteger)section
|
||||
{
|
||||
return CGSizeMake(125.0, 125.0);
|
||||
return ASSizeRangeMake(CGSizeMake(125.0, 125.0));
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new];
|
||||
textCellNode.text = indexPath.description;
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
}
|
||||
|
||||
|
||||
- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return ^{
|
||||
ASTextCellNodeWithSetSelectedCounter *textCellNode = [ASTextCellNodeWithSetSelectedCounter new];
|
||||
textCellNode.text = indexPath.description;
|
||||
@@ -94,11 +94,11 @@
|
||||
};
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
- (NSInteger)numberOfSectionsInCollectionNode:(ASCollectionNode *)collectionNode {
|
||||
return _itemCounts.size();
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
- (NSInteger)collectionNode:(ASCollectionNode *)collectionNode numberOfItemsInSection:(NSInteger)section {
|
||||
return _itemCounts[section];
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
return CGSizeMake(100, 100);
|
||||
}
|
||||
|
||||
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
|
||||
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForSupplementaryElementOfKind:(nonnull NSString *)kind atIndexPath:(nonnull NSIndexPath *)indexPath
|
||||
{
|
||||
return [[ASTextCellNodeWithSetSelectedCounter alloc] init];
|
||||
}
|
||||
@@ -147,8 +147,7 @@
|
||||
// Populate these immediately so that they're not unexpectedly nil during tests.
|
||||
self.asyncDelegate = [[ASCollectionViewTestDelegate alloc] initWithNumberOfSections:10 numberOfItemsInSection:10];
|
||||
id realLayout = [UICollectionViewFlowLayout new];
|
||||
id mockLayout = [OCMockObject partialMockForObject:realLayout];
|
||||
self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:mockLayout];
|
||||
self.collectionNode = [[ASCollectionNode alloc] initWithFrame:self.view.bounds collectionViewLayout:realLayout];
|
||||
self.collectionView = self.collectionNode.view;
|
||||
self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.collectionNode.dataSource = self.asyncDelegate;
|
||||
@@ -182,18 +181,6 @@
|
||||
[ASConfigurationManager test_resetWithConfiguration:config];
|
||||
}
|
||||
|
||||
- (void)tearDown
|
||||
{
|
||||
// We can't prevent the system from retaining windows, but we can at least clear them out to avoid
|
||||
// pollution between test cases.
|
||||
for (UIWindow *window in [UIApplication sharedApplication].windows) {
|
||||
for (UIView *subview in window.subviews) {
|
||||
[subview removeFromSuperview];
|
||||
}
|
||||
}
|
||||
[super tearDown];
|
||||
}
|
||||
|
||||
- (void)testDataSourceImplementsNecessaryMethods
|
||||
{
|
||||
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
|
||||
@@ -648,14 +635,14 @@
|
||||
- (void)testThatNodeCalculatedSizesAreUpdatedBeforeFirstPrepareLayoutAfterRotation
|
||||
{
|
||||
updateValidationTestPrologue
|
||||
id layout = cv.collectionViewLayout;
|
||||
id collectionViewLayoutMock = OCMPartialMock(cv.collectionViewLayout);
|
||||
CGSize initialItemSize = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize;
|
||||
CGSize initialCVSize = cv.bounds.size;
|
||||
|
||||
// Capture the node size before first call to prepareLayout after frame change.
|
||||
__block CGSize itemSizeAtFirstLayout = CGSizeZero;
|
||||
__block CGSize boundsSizeAtFirstLayout = CGSizeZero;
|
||||
[[[[layout expect] andDo:^(NSInvocation *) {
|
||||
[[[[collectionViewLayoutMock expect] andDo:^(NSInvocation *) {
|
||||
itemSizeAtFirstLayout = [cv nodeForItemAtIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]].calculatedSize;
|
||||
boundsSizeAtFirstLayout = [cv bounds].size;
|
||||
}] andForwardToRealObject] prepareLayout];
|
||||
@@ -670,10 +657,12 @@
|
||||
XCTAssertNotEqualObjects(NSStringFromCGSize(initialCVSize), NSStringFromCGSize(boundsSizeAtFirstLayout));
|
||||
XCTAssertEqualObjects(NSStringFromCGSize(itemSizeAtFirstLayout), NSStringFromCGSize(finalItemSize));
|
||||
XCTAssertEqualObjects(NSStringFromCGSize(boundsSizeAtFirstLayout), NSStringFromCGSize(finalCVSize));
|
||||
[layout verify];
|
||||
[collectionViewLayoutMock verify];
|
||||
|
||||
// Teardown
|
||||
[[UIDevice currentDevice] setValue:@(oldDeviceOrientation) forKey:@"orientation"];
|
||||
|
||||
[collectionViewLayoutMock stopMocking];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1152,6 +1141,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testASPrimitiveTraitCollectionToUITraitCollection {
|
||||
ASPrimitiveTraitCollection collection = ASPrimitiveTraitCollectionMakeDefault();
|
||||
collection.displayGamut = UIDisplayGamutSRGB;
|
||||
collection.displayScale = 11;
|
||||
collection.forceTouchCapability = UIForceTouchCapabilityAvailable;
|
||||
collection.horizontalSizeClass = UIUserInterfaceSizeClassRegular;
|
||||
collection.layoutDirection = UITraitEnvironmentLayoutDirectionRightToLeft;
|
||||
collection.preferredContentSizeCategory = UIContentSizeCategoryMedium;
|
||||
collection.userInterfaceIdiom = UIUserInterfaceIdiomTV;
|
||||
if (@available(iOS 12.0, *)) {
|
||||
collection.userInterfaceStyle = UIUserInterfaceStyleDark;
|
||||
}
|
||||
collection.verticalSizeClass = UIUserInterfaceSizeClassRegular;
|
||||
|
||||
// create `UITraitCollection` from `ASPrimitiveTraitCollection`
|
||||
UITraitCollection *uiCollection = ASPrimitiveTraitCollectionToUITraitCollection(collection);
|
||||
|
||||
// now convert it back to `ASPrimitiveTraitCollection`
|
||||
ASPrimitiveTraitCollection newCollection = ASPrimitiveTraitCollectionFromUITraitCollection(uiCollection);
|
||||
|
||||
// compare
|
||||
XCTAssert(ASPrimitiveTraitCollectionIsEqualToASPrimitiveTraitCollection(collection, newCollection));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This tests an issue where, since subnode insertions aren't applied until the UIKit layout pass,
|
||||
* which we trigger during the display phase, subnodes like network image nodes are not preloading
|
||||
|
||||
@@ -151,10 +151,10 @@
|
||||
@autoreleasepool {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSArray *sections = [ASThrashTestSection sectionsWithCount:kInitialSectionCount];
|
||||
_update = [[ASThrashUpdate alloc] initWithData:sections];
|
||||
self->_update = [[ASThrashUpdate alloc] initWithData:sections];
|
||||
ASThrashDataSource *ds = [[ASThrashDataSource alloc] initCollectionViewDataSourceWithData:sections];
|
||||
|
||||
[self applyUpdateUsingBatchUpdates:_update
|
||||
[self applyUpdateUsingBatchUpdates:self->_update
|
||||
toDataSource:ds
|
||||
animated:NO
|
||||
useXCTestWait:NO];
|
||||
|
||||
@@ -20,17 +20,15 @@ static ASExperimentalFeatures features[] = {
|
||||
ASExperimentalTextNode,
|
||||
#endif
|
||||
ASExperimentalInterfaceStateCoalescing,
|
||||
ASExperimentalUnfairLock,
|
||||
ASExperimentalLayerDefaults,
|
||||
ASExperimentalCollectionTeardown,
|
||||
ASExperimentalFramesetterCache,
|
||||
ASExperimentalSkipClearData,
|
||||
ASExperimentalDidEnterPreloadSkipASMLayout,
|
||||
ASExperimentalDispatchApply,
|
||||
ASExperimentalOOMBackgroundDeallocDisable,
|
||||
ASExperimentalRemoveTextKitInitialisingLock,
|
||||
ASExperimentalDrawingGlobal,
|
||||
ASExperimentalOptimizeDataControllerPipeline
|
||||
ASExperimentalOptimizeDataControllerPipeline,
|
||||
ASExperimentalDoNotCacheAccessibilityElements,
|
||||
};
|
||||
|
||||
@interface ASConfigurationTests : ASTestCase <ASConfigurationDelegate>
|
||||
@@ -45,17 +43,15 @@ static ASExperimentalFeatures features[] = {
|
||||
return @[
|
||||
@"exp_text_node",
|
||||
@"exp_interface_state_coalesce",
|
||||
@"exp_unfair_lock",
|
||||
@"exp_infer_layer_defaults",
|
||||
@"exp_collection_teardown",
|
||||
@"exp_framesetter_cache",
|
||||
@"exp_skip_clear_data",
|
||||
@"exp_did_enter_preload_skip_asm_layout",
|
||||
@"exp_dispatch_apply",
|
||||
@"exp_oom_bg_dealloc_disable",
|
||||
@"exp_remove_textkit_initialising_lock",
|
||||
@"exp_drawing_global",
|
||||
@"exp_optimize_data_controller_pipeline"
|
||||
@"exp_optimize_data_controller_pipeline",
|
||||
@"exp_do_not_cache_accessibility_elements",
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,11 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
_didExitHierarchyCounts = [[NSCountedSet alloc] init];
|
||||
|
||||
dispatch_block_t cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(willEnterHierarchy), ^(id blockSelf){
|
||||
[_willEnterHierarchyCounts addObject:blockSelf];
|
||||
[self->_willEnterHierarchyCounts addObject:blockSelf];
|
||||
});
|
||||
[_swizzleCleanupBlocks addObject:cleanupBlock];
|
||||
cleanupBlock = modifyMethodByAddingPrologueBlockAndReturnCleanupBlock([ASDisplayNode class], @selector(didExitHierarchy), ^(id blockSelf){
|
||||
[_didExitHierarchyCounts addObject:blockSelf];
|
||||
[self->_didExitHierarchyCounts addObject:blockSelf];
|
||||
});
|
||||
[_swizzleCleanupBlocks addObject:cleanupBlock];
|
||||
}
|
||||
@@ -117,6 +117,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
{
|
||||
// ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it.
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
DeclareNodeNamed(n);
|
||||
DeclareViewNamed(superview);
|
||||
@@ -154,6 +155,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
{
|
||||
// ASDisplayNode visibility does not change if modifying a hierarchy that is not in a window. So create one and add the superview to it.
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
DeclareNodeNamed(parent);
|
||||
DeclareNodeNamed(a);
|
||||
@@ -253,6 +255,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
layerBackedNode.layerBacked = YES;
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
|
||||
[window makeKeyAndVisible];
|
||||
[parentSynchronousNode addSubnode:layerBackedNode];
|
||||
[parentSynchronousNode addSubnode:viewBackedNode];
|
||||
|
||||
@@ -291,6 +294,7 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
- (void)checkMoveAcrossHierarchyLayerBacked:(BOOL)isLayerBacked useManualCalls:(BOOL)useManualDisable useNodeAPI:(BOOL)useNodeAPI
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
DeclareNodeNamed(parentA);
|
||||
DeclareNodeNamed(parentB);
|
||||
@@ -374,6 +378,8 @@ static dispatch_block_t modifyMethodByAddingPrologueBlockAndReturnCleanupBlock(C
|
||||
// Make sure that we don't leave these unbalanced
|
||||
XCTAssertFalse([child __visibilityNotificationsDisabled], @"Unbalanced visibility notifications calls");
|
||||
XCTAssertFalse([child __selfOrParentHasVisibilityNotificationsDisabled], @"Should not have re-enabled yet");
|
||||
[parentA removeFromSupernode];
|
||||
[parentB removeFromSupernode];
|
||||
}
|
||||
|
||||
- (void)testMoveAcrossHierarchyLayer
|
||||
|
||||
@@ -67,12 +67,35 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds)
|
||||
node.image = BlueImageMake(bounds);
|
||||
node.frame = bounds;
|
||||
node.cornerRoundingType = ASCornerRoundingTypeClipping;
|
||||
#if AS_AT_LEAST_IOS13
|
||||
if (@available(iOS 13.0, *)) {
|
||||
node.backgroundColor = UIColor.systemBackgroundColor;
|
||||
} else {
|
||||
node.backgroundColor = UIColor.greenColor;
|
||||
}
|
||||
#else
|
||||
node.backgroundColor = UIColor.greenColor;
|
||||
#endif
|
||||
node.maskedCorners = c;
|
||||
node.cornerRadius = 15;
|
||||
// A layout pass is required, because that's where we lay out the clip layers.
|
||||
[node.layer layoutIfNeeded];
|
||||
|
||||
#if AS_AT_LEAST_IOS13
|
||||
if (@available(iOS 13.0, *)) {
|
||||
[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight] performAsCurrentTraitCollection:^{
|
||||
ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d_light", (int)c]));
|
||||
}];
|
||||
|
||||
[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{
|
||||
ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d_dark", (int)c]));
|
||||
}];
|
||||
} else {
|
||||
ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c]));
|
||||
}
|
||||
#else
|
||||
ASSnapshotVerifyNode(node, ([NSString stringWithFormat:@"%d", (int)c]));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,10 +104,6 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds)
|
||||
- (void)testUserInterfaceStyleSnapshotTesting
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
ASConfiguration *config = [ASConfiguration new];
|
||||
config.experimentalFeatures = ASExperimentalTraitCollectionDidChangeWithPreviousCollection;
|
||||
[ASConfigurationManager test_resetWithConfiguration:config];
|
||||
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
[node setLayerBacked:YES];
|
||||
|
||||
@@ -103,6 +122,45 @@ NS_INLINE UIImage *BlueImageMake(CGRect bounds)
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testBackgroundDynamicColor {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
ASDisplayNode *node = [[ASImageNode alloc] init];
|
||||
node.backgroundColor = [UIColor systemGray6Color];
|
||||
auto bounds = CGRectMake(0, 0, 100, 100);
|
||||
node.frame = bounds;
|
||||
|
||||
UITraitCollection *tcLight = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight];
|
||||
[tcLight performAsCurrentTraitCollection: ^{
|
||||
ASSnapshotVerifyNode(node, @"light");
|
||||
}];
|
||||
|
||||
UITraitCollection *tcDark = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
[tcDark performAsCurrentTraitCollection: ^{
|
||||
ASSnapshotVerifyNode(node, @"dark");
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testBackgroundDynamicColorLayerBacked {
|
||||
if (@available(iOS 13.0, *)) {
|
||||
ASDisplayNode *node = [[ASImageNode alloc] init];
|
||||
node.backgroundColor = [UIColor systemGray6Color];
|
||||
node.layerBacked = YES;
|
||||
auto bounds = CGRectMake(0, 0, 100, 100);
|
||||
node.frame = bounds;
|
||||
|
||||
UITraitCollection *tcLight = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight];
|
||||
[tcLight performAsCurrentTraitCollection: ^{
|
||||
ASSnapshotVerifyNode(node, @"light");
|
||||
}];
|
||||
|
||||
UITraitCollection *tcDark = [UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark];
|
||||
[tcDark performAsCurrentTraitCollection: ^{
|
||||
ASSnapshotVerifyNode(node, @"dark");
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if AS_AT_LEAST_IOS13
|
||||
|
||||
@end
|
||||
|
||||
@@ -465,14 +465,14 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
XCTAssertEqual(NO, node.needsDisplayOnBoundsChange, @"default needsDisplayOnBoundsChange broken %@", hasLoadedView);
|
||||
XCTAssertEqual(YES, node.allowsGroupOpacity, @"default allowsGroupOpacity broken %@", hasLoadedView);
|
||||
XCTAssertEqual(NO, node.allowsEdgeAntialiasing, @"default allowsEdgeAntialiasing broken %@", hasLoadedView);
|
||||
XCTAssertEqual((unsigned int)(kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge), node.edgeAntialiasingMask, @"default edgeAntialisingMask broken %@", hasLoadedView);
|
||||
XCTAssertEqual((kCALayerLeftEdge | kCALayerRightEdge | kCALayerBottomEdge | kCALayerTopEdge), node.edgeAntialiasingMask, @"default edgeAntialisingMask broken %@", hasLoadedView);
|
||||
XCTAssertEqual(NO, node.hidden, @"default hidden broken %@", hasLoadedView);
|
||||
XCTAssertEqual(1.0f, node.alpha, @"default alpha broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.bounds), @"default bounds broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectZero, node.frame), @"default frame broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CGPointEqualToPoint(CGPointZero, node.position), @"default position broken %@", hasLoadedView);
|
||||
XCTAssertEqual((CGFloat)0.0, node.zPosition, @"default zPosition broken %@", hasLoadedView);
|
||||
XCTAssertEqual(1.0f, node.contentsScale, @"default contentsScale broken %@", hasLoadedView);
|
||||
XCTAssertEqual(node.isNodeLoaded && !isLayerBacked ? 2.0f : 1.0f, node.contentsScale, @"default contentsScale broken %@", hasLoadedView);
|
||||
XCTAssertEqual([UIScreen mainScreen].scale, node.contentsScaleForDisplay, @"default contentsScaleForDisplay broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.transform), @"default transform broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DIdentity, node.subnodeTransform), @"default subnodeTransform broken %@", hasLoadedView);
|
||||
@@ -515,9 +515,15 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
XCTAssertEqual(NO, node.preservesSuperviewLayoutMargins, @"default preservesSuperviewLayoutMargins broken %@", hasLoadedView);
|
||||
XCTAssertTrue(UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, node.safeAreaInsets), @"default safeAreaInsets broken %@", hasLoadedView);
|
||||
XCTAssertEqual(YES, node.insetsLayoutMarginsFromSafeArea, @"default insetsLayoutMarginsFromSafeArea broken %@", hasLoadedView);
|
||||
if (node.nodeLoaded) {
|
||||
XCTAssertNotNil(node.tintColor, @"default tintColor broken %@", hasLoadedView); // It has been populated by the UIView.
|
||||
} else {
|
||||
XCTAssertNil(node.tintColor, @"default tintColor broken %@", hasLoadedView);
|
||||
}
|
||||
} else {
|
||||
XCTAssertEqual(NO, node.userInteractionEnabled, @"layer-backed nodes do not support userInteractionEnabled %@", hasLoadedView);
|
||||
XCTAssertEqual(NO, node.exclusiveTouch, @"layer-backed nodes do not support exclusiveTouch %@", hasLoadedView);
|
||||
XCTAssertNil(node.tintColor, @"default tintColor broken %@", hasLoadedView);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,7 +585,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
XCTAssertEqual(YES, node.needsDisplayOnBoundsChange, @"needsDisplayOnBoundsChange broken %@", hasLoadedView);
|
||||
XCTAssertEqual(NO, node.allowsGroupOpacity, @"allowsGroupOpacity broken %@", hasLoadedView);
|
||||
XCTAssertEqual(YES, node.allowsEdgeAntialiasing, @"allowsEdgeAntialiasing broken %@", hasLoadedView);
|
||||
XCTAssertTrue((unsigned int)(kCALayerLeftEdge | kCALayerTopEdge) == node.edgeAntialiasingMask, @"edgeAntialiasingMask broken: %@", hasLoadedView);
|
||||
XCTAssertTrue((kCALayerLeftEdge | kCALayerTopEdge) == node.edgeAntialiasingMask, @"edgeAntialiasingMask broken: %@", hasLoadedView);
|
||||
XCTAssertEqual(YES, node.hidden, @"hidden broken %@", hasLoadedView);
|
||||
XCTAssertEqual(.5f, node.alpha, @"alpha broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 15, 42, 115.2), node.bounds), @"bounds broken %@", hasLoadedView);
|
||||
@@ -589,6 +595,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeScale(0.5, 0.5, 1.0), node.transform), @"transform broken %@", hasLoadedView);
|
||||
XCTAssertTrue(CATransform3DEqualToTransform(CATransform3DMakeTranslation(1337, 7357, 7007), node.subnodeTransform), @"subnodeTransform broken %@", hasLoadedView);
|
||||
XCTAssertEqualObjects([UIColor clearColor], node.backgroundColor, @"backgroundColor broken %@", hasLoadedView);
|
||||
XCTAssertEqualObjects([UIColor orangeColor], node.tintColor, @"tintColor broken %@", hasLoadedView);
|
||||
XCTAssertEqual(UIViewContentModeBottom, node.contentMode, @"contentMode broken %@", hasLoadedView);
|
||||
XCTAssertEqual([[UIColor cyanColor] CGColor], node.shadowColor, @"shadowColor broken %@", hasLoadedView);
|
||||
XCTAssertEqual(.5f, node.shadowOpacity, @"shadowOpacity broken %@", hasLoadedView);
|
||||
@@ -663,6 +670,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
node.transform = CATransform3DMakeScale(0.5, 0.5, 1.0);
|
||||
node.subnodeTransform = CATransform3DMakeTranslation(1337, 7357, 7007);
|
||||
node.backgroundColor = [UIColor clearColor];
|
||||
node.tintColor = [UIColor orangeColor];
|
||||
node.contentMode = UIViewContentModeBottom;
|
||||
node.shadowColor = [[UIColor cyanColor] CGColor];
|
||||
node.shadowOpacity = .5f;
|
||||
@@ -753,6 +761,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
return view;
|
||||
}];
|
||||
node.backgroundColor = [UIColor blueColor];
|
||||
node.tintColor = [UIColor orangeColor];
|
||||
node.frame = CGRectMake(10, 20, 30, 40);
|
||||
node.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
node.userInteractionEnabled = YES;
|
||||
@@ -772,6 +781,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
[node view];
|
||||
|
||||
node.backgroundColor = [UIColor blueColor];
|
||||
node.tintColor = [UIColor orangeColor];
|
||||
node.frame = CGRectMake(10, 20, 30, 40);
|
||||
node.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
node.userInteractionEnabled = YES;
|
||||
@@ -784,6 +794,7 @@ for (ASDisplayNode *n in @[ nodes ]) {\
|
||||
UIView *view = node.view;
|
||||
|
||||
XCTAssertEqualObjects([UIColor blueColor], view.backgroundColor, @"backgroundColor not propagated to view");
|
||||
XCTAssertEqualObjects([UIColor orangeColor], view.tintColor, @"tintColor not propagated to view");
|
||||
XCTAssertTrue(CGRectEqualToRect(CGRectMake(10, 20, 30, 40), view.frame), @"frame not propagated to view");
|
||||
XCTAssertEqual(UIViewAutoresizingFlexibleWidth, view.autoresizingMask, @"autoresizingMask not propagated to view");
|
||||
XCTAssertEqual(YES, view.userInteractionEnabled, @"userInteractionEnabled not propagated to view");
|
||||
@@ -2643,7 +2654,9 @@ static bool stringContainsPointer(NSString *description, id p) {
|
||||
ASXCTAssertEqualPoints([node convertPoint:node.bounds.origin toNode:nil], expectedOrigin);
|
||||
}
|
||||
|
||||
- (void)testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread
|
||||
// this test fails with assertion cause some data should be accessed from the main thread
|
||||
// so it doesn't really work
|
||||
- (void)DISABLED_testThatItIsAllowedToRetrieveDebugDescriptionIncludingVCOffMainThread
|
||||
{
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
UIViewController *vc = [[UIViewController alloc] init];
|
||||
@@ -2677,7 +2690,9 @@ static bool stringContainsPointer(NSString *description, id p) {
|
||||
UIWindow *window = [[UIWindow alloc] init];
|
||||
window.rootViewController = viewController;
|
||||
[window setHidden:NO];
|
||||
[window layoutIfNeeded];
|
||||
|
||||
[window.rootViewController.view setNeedsLayout];
|
||||
[window.rootViewController.view layoutIfNeeded];
|
||||
|
||||
UIEdgeInsets expectedRootNodeSafeArea = UIEdgeInsetsMake(10, 10, 10, 10);
|
||||
UIEdgeInsets expectedSubnodeSafeArea = UIEdgeInsetsMake(9, 8, 7, 6);
|
||||
@@ -2736,6 +2751,7 @@ static bool stringContainsPointer(NSString *description, id p) {
|
||||
- (void)testLayerActionForKeyIsCalled
|
||||
{
|
||||
UIWindow *window = [[UIWindow alloc] init];
|
||||
[window makeKeyAndVisible];
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
|
||||
id mockNode = OCMPartialMock(node);
|
||||
|
||||
@@ -12,14 +12,21 @@
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import <AsyncDisplayKit/_ASDisplayView.h>
|
||||
#import <AsyncDisplayKit/_ASDisplayViewAccessiblity.h>
|
||||
#import <AsyncDisplayKit/ASButtonNode.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Beta.h>
|
||||
#import <AsyncDisplayKit/ASTextNode.h>
|
||||
#import <AsyncDisplayKit/ASConfiguration.h>
|
||||
#import <AsyncDisplayKit/ASConfigurationInternal.h>
|
||||
#import <AsyncDisplayKit/ASScrollNode.h>
|
||||
#import <AsyncDisplayKit/ASViewController.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import "ASDisplayNodeTestsHelper.h"
|
||||
|
||||
extern void SortAccessibilityElements(NSMutableArray *elements);
|
||||
|
||||
@interface ASDisplayViewAccessibilityTests : XCTestCase
|
||||
@end
|
||||
|
||||
@@ -32,6 +39,11 @@
|
||||
ASDisplayNode *subnode = nil;
|
||||
node = [[ASDisplayNode alloc] init];
|
||||
subnode = [[ASDisplayNode alloc] init];
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:node];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
NSString *label = @"foo";
|
||||
subnode.isAccessibilityElement = YES;
|
||||
subnode.accessibilityLabel = label;
|
||||
@@ -54,6 +66,10 @@
|
||||
innerNode1 = [[ASDisplayNode alloc] init];
|
||||
innerNode2 = [[ASDisplayNode alloc] init];
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:node];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
// Initialize nodes with relevant accessibility data
|
||||
node.isAccessibilityContainer = YES;
|
||||
innerNode1.accessibilityLabel = @"hello";
|
||||
@@ -76,6 +92,10 @@
|
||||
node = [[ASDisplayNode alloc] init];
|
||||
innerNode = [[ASDisplayNode alloc] init];
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:node];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
// Initialize nodes with relevant accessibility data
|
||||
node.isAccessibilityContainer = YES;
|
||||
node.accessibilityLabel = @"hello";
|
||||
@@ -92,6 +112,10 @@
|
||||
- (void)testAccessibilityLayerBackedContainerWithinAccessibilityContainer
|
||||
{
|
||||
ASDisplayNode *container = [[ASDisplayNode alloc] init];
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:container];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
container.frame = CGRectMake(50, 50, 200, 600);
|
||||
container.isAccessibilityContainer = YES;
|
||||
|
||||
@@ -193,4 +217,276 @@
|
||||
OCMVerifyAll(mockNode);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark AccessibilityElements
|
||||
|
||||
// dummy action for a button
|
||||
- (void)fakeSelector:(id)sender { }
|
||||
|
||||
- (void)testThatAccessibilityElementsWorks {
|
||||
|
||||
ASDisplayNode *containerNode = [[ASDisplayNode alloc] init];
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:containerNode];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
containerNode.frame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASButtonNode *button = [[ASButtonNode alloc] init];
|
||||
[button setTitle:@"tap me" withFont:[UIFont systemFontOfSize:17] withColor:nil forState:UIControlStateNormal];
|
||||
[button addTarget:self action:@selector(fakeSelector:) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||
button.frame = CGRectMake(0, 25, 100, 20);
|
||||
|
||||
[containerNode addSubnode:label];
|
||||
[containerNode addSubnode:button];
|
||||
|
||||
// force load
|
||||
__unused UIView *view = containerNode.view;
|
||||
|
||||
NSArray *elements = [containerNode accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 2);
|
||||
XCTAssertEqual([elements.firstObject asyncdisplaykit_node], label);
|
||||
XCTAssertEqual([elements.lastObject asyncdisplaykit_node], button);
|
||||
}
|
||||
|
||||
- (void)testThatAccessibilityElementsOverrideWorks {
|
||||
ASDisplayNode *containerNode = [[ASDisplayNode alloc] init];
|
||||
containerNode.frame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASButtonNode *button = [[ASButtonNode alloc] init];
|
||||
[button setTitle:@"tap me" withFont:[UIFont systemFontOfSize:17] withColor:nil forState:UIControlStateNormal];
|
||||
[button addTarget:self action:@selector(fakeSelector:) forControlEvents:ASControlNodeEventTouchUpInside];
|
||||
button.frame = CGRectMake(0, 25, 100, 20);
|
||||
|
||||
[containerNode addSubnode:label];
|
||||
[containerNode addSubnode:button];
|
||||
containerNode.accessibilityElements = @[ label ];
|
||||
|
||||
// force load
|
||||
__unused UIView *view = containerNode.view;
|
||||
|
||||
NSArray *elements = [containerNode accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 1);
|
||||
XCTAssertEqual(elements.firstObject, label);
|
||||
}
|
||||
|
||||
- (void)testHiddenAccessibilityElements {
|
||||
ASDisplayNode *containerNode = [[ASDisplayNode alloc] init];
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:containerNode];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
containerNode.frame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASTextNode *hiddenLabel = [[ASTextNode alloc] init];
|
||||
hiddenLabel.attributedText = [[NSAttributedString alloc] initWithString:@"hidden label"];
|
||||
hiddenLabel.frame = CGRectMake(0, 24, 100, 20);
|
||||
hiddenLabel.hidden = YES;
|
||||
|
||||
[containerNode addSubnode:label];
|
||||
[containerNode addSubnode:hiddenLabel];
|
||||
|
||||
// force load
|
||||
__unused UIView *view = containerNode.view;
|
||||
|
||||
NSArray *elements = [containerNode accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 1);
|
||||
XCTAssertEqual(elements.firstObject, label.view);
|
||||
}
|
||||
|
||||
- (void)testTransparentAccessibilityElements {
|
||||
ASDisplayNode *containerNode = [[ASDisplayNode alloc] init];
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:containerNode];
|
||||
[window makeKeyAndVisible];
|
||||
containerNode.frame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"test label"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASTextNode *hiddenLabel = [[ASTextNode alloc] init];
|
||||
hiddenLabel.attributedText = [[NSAttributedString alloc] initWithString:@"hidden label"];
|
||||
hiddenLabel.frame = CGRectMake(0, 24, 100, 20);
|
||||
hiddenLabel.alpha = 0.0;
|
||||
|
||||
[containerNode addSubnode:label];
|
||||
[containerNode addSubnode:hiddenLabel];
|
||||
|
||||
// force load
|
||||
__unused UIView *view = containerNode.view;
|
||||
|
||||
NSArray *elements = [containerNode accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 1);
|
||||
XCTAssertEqual(elements.firstObject, label.view);
|
||||
}
|
||||
|
||||
- (void)testAccessibilityElementsNotInAppWindow {
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 568)];
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
node.automaticallyManagesSubnodes = YES;
|
||||
|
||||
ASViewController *vc = [[ASViewController alloc] initWithNode:node];
|
||||
window.rootViewController = vc;
|
||||
[window makeKeyAndVisible];
|
||||
[window layoutIfNeeded];
|
||||
|
||||
CGSize windowSize = window.frame.size;
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"on screen"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASTextNode *partiallyOnScreenNodeY = [[ASTextNode alloc] init];
|
||||
partiallyOnScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen y"];
|
||||
partiallyOnScreenNodeY.frame = CGRectMake(0, windowSize.height - 10, 100, 20);
|
||||
|
||||
ASTextNode *partiallyOnScreenNodeX = [[ASTextNode alloc] init];
|
||||
partiallyOnScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen x"];
|
||||
partiallyOnScreenNodeX.frame = CGRectMake(windowSize.width - 10, 100, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNodeY = [[ASTextNode alloc] init];
|
||||
offScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"off screen y"];
|
||||
offScreenNodeY.frame = CGRectMake(0, windowSize.height + 10, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNodeX = [[ASTextNode alloc] init];
|
||||
offScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"off screen x"];
|
||||
offScreenNodeX.frame = CGRectMake(windowSize.width + 1, 200, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNode = [[ASTextNode alloc] init];
|
||||
offScreenNode.attributedText = [[NSAttributedString alloc] initWithString:@"off screen"];
|
||||
offScreenNode.frame = CGRectMake(windowSize.width + 1, windowSize.height + 1, 100, 20);
|
||||
|
||||
[node addSubnode:label];
|
||||
[node addSubnode:partiallyOnScreenNodeY];
|
||||
[node addSubnode:partiallyOnScreenNodeX];
|
||||
[node addSubnode:offScreenNodeY];
|
||||
[node addSubnode:offScreenNodeX];
|
||||
[node addSubnode:offScreenNode];
|
||||
|
||||
NSArray *elements = [node accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 3);
|
||||
XCTAssertTrue([elements containsObject:label.view]);
|
||||
XCTAssertTrue([elements containsObject:partiallyOnScreenNodeX.view]);
|
||||
XCTAssertTrue([elements containsObject:partiallyOnScreenNodeY.view]);
|
||||
}
|
||||
|
||||
- (void)testAccessibilityElementsNotInAppWindowButInScrollView {
|
||||
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 568)];
|
||||
ASScrollNode *node = [[ASScrollNode alloc] init];
|
||||
node.automaticallyManagesSubnodes = YES;
|
||||
|
||||
ASViewController *vc = [[ASViewController alloc] initWithNode:node];
|
||||
window.rootViewController = vc;
|
||||
[window makeKeyAndVisible];
|
||||
[window layoutIfNeeded];
|
||||
|
||||
CGSize windowSize = window.frame.size;
|
||||
node.view.contentSize = CGSizeMake(window.frame.size.width, window.frame.size.height * 2.0);
|
||||
ASTextNode *label = [[ASTextNode alloc] init];
|
||||
label.attributedText = [[NSAttributedString alloc] initWithString:@"on screen"];
|
||||
label.frame = CGRectMake(0, 0, 100, 20);
|
||||
|
||||
ASTextNode *partiallyOnScreenNodeY = [[ASTextNode alloc] init];
|
||||
partiallyOnScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen y"];
|
||||
partiallyOnScreenNodeY.frame = CGRectMake(0, windowSize.height - 10, 100, 20);
|
||||
|
||||
ASTextNode *partiallyOnScreenNodeX = [[ASTextNode alloc] init];
|
||||
partiallyOnScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"partially on screen x"];
|
||||
partiallyOnScreenNodeX.frame = CGRectMake(windowSize.width - 10, 100, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNodeY = [[ASTextNode alloc] init];
|
||||
offScreenNodeY.attributedText = [[NSAttributedString alloc] initWithString:@"off screen y"];
|
||||
offScreenNodeY.frame = CGRectMake(0, windowSize.height + 10, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNodeX = [[ASTextNode alloc] init];
|
||||
offScreenNodeX.attributedText = [[NSAttributedString alloc] initWithString:@"off screen x"];
|
||||
offScreenNodeX.frame = CGRectMake(windowSize.width + 1, 200, 100, 20);
|
||||
|
||||
ASTextNode *offScreenNode = [[ASTextNode alloc] init];
|
||||
offScreenNode.attributedText = [[NSAttributedString alloc] initWithString:@"off screen"];
|
||||
offScreenNode.frame = CGRectMake(windowSize.width + 1, windowSize.height + 1, 100, 20);
|
||||
|
||||
[node addSubnode:label];
|
||||
[node addSubnode:partiallyOnScreenNodeY];
|
||||
[node addSubnode:partiallyOnScreenNodeX];
|
||||
[node addSubnode:offScreenNodeY];
|
||||
[node addSubnode:offScreenNodeX];
|
||||
[node addSubnode:offScreenNode];
|
||||
|
||||
NSArray *elements = [node accessibilityElements];
|
||||
XCTAssertTrue(elements.count == 6);
|
||||
XCTAssertTrue([elements containsObject:label.view]);
|
||||
XCTAssertTrue([elements containsObject:partiallyOnScreenNodeX.view]);
|
||||
XCTAssertTrue([elements containsObject:partiallyOnScreenNodeY.view]);
|
||||
XCTAssertTrue([elements containsObject:offScreenNodeY.view]);
|
||||
XCTAssertTrue([elements containsObject:offScreenNodeX.view]);
|
||||
XCTAssertTrue([elements containsObject:offScreenNode.view]);
|
||||
}
|
||||
|
||||
- (void)testAccessibilitySort {
|
||||
ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
|
||||
node1.accessibilityFrame = CGRectMake(0, 0, 50, 200);
|
||||
|
||||
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
||||
node2.accessibilityFrame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
|
||||
node3.accessibilityFrame = CGRectMake(0, 1, 100, 200);
|
||||
|
||||
ASDisplayNode *node4 = [[ASDisplayNode alloc] init];
|
||||
node4.accessibilityFrame = CGRectMake(1, 1, 100, 200);
|
||||
|
||||
NSMutableArray *elements = [@[node2, node4, node3, node1] mutableCopy];
|
||||
SortAccessibilityElements(elements);
|
||||
XCTAssertEqual(elements[0], node1);
|
||||
XCTAssertEqual(elements[1], node2);
|
||||
XCTAssertEqual(elements[2], node3);
|
||||
XCTAssertEqual(elements[3], node4);
|
||||
}
|
||||
|
||||
- (void)testCustomAccessibilitySort {
|
||||
|
||||
// silly custom sorter that puts items with the largest height first.
|
||||
setUserDefinedAccessibilitySortComparator(^NSComparisonResult(NSObject *a, NSObject *b) {
|
||||
if (a.accessibilityFrame.size.height == b.accessibilityFrame.size.height) {
|
||||
return NSOrderedSame;
|
||||
}
|
||||
return a.accessibilityFrame.size.height > b.accessibilityFrame.size.height ? NSOrderedAscending : NSOrderedDescending;
|
||||
});
|
||||
|
||||
ASDisplayNode *node1 = [[ASDisplayNode alloc] init];
|
||||
node1.accessibilityFrame = CGRectMake(0, 0, 50, 300);
|
||||
|
||||
ASDisplayNode *node2 = [[ASDisplayNode alloc] init];
|
||||
node2.accessibilityFrame = CGRectMake(0, 0, 100, 250);
|
||||
|
||||
ASDisplayNode *node3 = [[ASDisplayNode alloc] init];
|
||||
node3.accessibilityFrame = CGRectMake(0, 0, 100, 200);
|
||||
|
||||
ASDisplayNode *node4 = [[ASDisplayNode alloc] init];
|
||||
node4.accessibilityFrame = CGRectMake(0, 0, 100, 150);
|
||||
|
||||
NSMutableArray *elements = [@[node2, node4, node3, node1] mutableCopy];
|
||||
SortAccessibilityElements(elements);
|
||||
XCTAssertEqual(elements[0], node1);
|
||||
XCTAssertEqual(elements[1], node2);
|
||||
XCTAssertEqual(elements[2], node3);
|
||||
XCTAssertEqual(elements[3], node4);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
//
|
||||
// ASGraphicsContextTests.mm
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <AsyncDisplayKit/ASGraphicsContext.h>
|
||||
#import <AsyncDisplayKit/ASBaseDefines.h>
|
||||
#import <AsyncDisplayKit/ASAvailability.h>
|
||||
#import <AsyncDisplayKit/ASConfigurationInternal.h>
|
||||
|
||||
@interface ASGraphicsContextTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation ASGraphicsContextTests
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
ASConfiguration *config = [ASConfiguration new];
|
||||
config.experimentalFeatures = ASExperimentalDrawingGlobal;
|
||||
[ASConfigurationManager test_resetWithConfiguration:config];
|
||||
}
|
||||
|
||||
|
||||
#if AS_AT_LEAST_IOS13
|
||||
- (void)testCanceled
|
||||
{
|
||||
if (AS_AVAILABLE_IOS_TVOS(13, 13)) {
|
||||
CGSize size = CGSize{.width=100, .height=100};
|
||||
|
||||
XCTestExpectation *expectationCancelled = [self expectationWithDescription:@"canceled"];
|
||||
|
||||
asdisplaynode_iscancelled_block_t isCancelledBlock =^BOOL{
|
||||
[expectationCancelled fulfill];
|
||||
return true;
|
||||
};
|
||||
|
||||
ASPrimitiveTraitCollection traitCollection = ASPrimitiveTraitCollectionMakeDefault();
|
||||
UIImage *canceledImage = ASGraphicsCreateImage(traitCollection, size, false, 0, nil, isCancelledBlock, ^{});
|
||||
|
||||
XCTAssertNil(canceledImage);
|
||||
|
||||
[self waitForExpectations:@[expectationCancelled] timeout:1];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testCanceledNil
|
||||
{
|
||||
if (AS_AVAILABLE_IOS_TVOS(13, 13)) {
|
||||
CGSize size = CGSize{.width=100, .height=100};
|
||||
ASPrimitiveTraitCollection traitCollection = ASPrimitiveTraitCollectionMakeDefault();
|
||||
|
||||
XCTestExpectation *expectation = [self expectationWithDescription:@"normal"];
|
||||
UIImage *image = ASGraphicsCreateImage(traitCollection, size, false, 0, nil, nil, ^{
|
||||
[expectation fulfill];
|
||||
});
|
||||
|
||||
XCTAssert(image);
|
||||
|
||||
[self waitForExpectations:@[expectation] timeout:1];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testTraitCollectionPassedToWork
|
||||
{
|
||||
if (AS_AVAILABLE_IOS_TVOS(13, 13)) {
|
||||
CGSize size = CGSize{.width=100, .height=100};
|
||||
|
||||
XCTestExpectation *expectationDark = [self expectationWithDescription:@"trait collection dark"];
|
||||
ASPrimitiveTraitCollection traitCollectionDark = ASPrimitiveTraitCollectionMakeDefault();
|
||||
traitCollectionDark.userInterfaceStyle = UIUserInterfaceStyleDark;
|
||||
ASGraphicsCreateImage(traitCollectionDark, size, false, 0, nil, nil, ^{
|
||||
UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
XCTAssertEqual(currentTraitCollection.userInterfaceStyle, UIUserInterfaceStyleDark);
|
||||
[expectationDark fulfill];
|
||||
});
|
||||
|
||||
XCTestExpectation *expectationLight = [self expectationWithDescription:@"trait collection light"];
|
||||
ASPrimitiveTraitCollection traitCollectionLight = ASPrimitiveTraitCollectionMakeDefault();
|
||||
traitCollectionLight.userInterfaceStyle = UIUserInterfaceStyleLight;
|
||||
ASGraphicsCreateImage(traitCollectionLight, size, false, 0, nil, nil, ^{
|
||||
UITraitCollection *currentTraitCollection = [UITraitCollection currentTraitCollection];
|
||||
XCTAssertEqual(currentTraitCollection.userInterfaceStyle, UIUserInterfaceStyleLight);
|
||||
[expectationLight fulfill];
|
||||
});
|
||||
|
||||
[self waitForExpectations:@[expectationDark, expectationLight] timeout:1];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@end
|
||||
@@ -11,6 +11,18 @@
|
||||
|
||||
#import <AsyncDisplayKit/AsyncDisplayKit.h>
|
||||
|
||||
#if AS_AT_LEAST_IOS13
|
||||
static UIImage* makeImageWithColor(UIColor *color, CGSize size) {
|
||||
CGRect rect = CGRect{.origin = CGPointZero, .size = size};
|
||||
UIGraphicsBeginImageContextWithOptions(size, false, 0);
|
||||
[color setFill];
|
||||
UIRectFill(rect);
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
#endif
|
||||
|
||||
@interface ASImageNodeSnapshotTests : ASSnapshotTestCase
|
||||
@end
|
||||
|
||||
@@ -182,7 +194,31 @@
|
||||
UIRectFill(CGRectMake(0, 0, 100, 100));
|
||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
UIImage *rounded = ASImageNodeRoundBorderModificationBlock(2, [UIColor redColor])(result);
|
||||
|
||||
ASPrimitiveTraitCollection traitCollection;
|
||||
|
||||
if (@available(iOS 13.0, *)) {
|
||||
traitCollection = ASPrimitiveTraitCollectionFromUITraitCollection(UITraitCollection.currentTraitCollection);
|
||||
} else {
|
||||
traitCollection = ASPrimitiveTraitCollectionMakeDefault();
|
||||
}
|
||||
|
||||
UIImage *rounded = ASImageNodeRoundBorderModificationBlock(2, [UIColor redColor])(result, traitCollection);
|
||||
ASImageNode *node = [[ASImageNode alloc] init];
|
||||
node.image = rounded;
|
||||
ASDisplayNodeSizeToFitSize(node, rounded.size);
|
||||
ASSnapshotVerifyNode(node, nil);
|
||||
}
|
||||
|
||||
- (void)testTintColorBlock
|
||||
{
|
||||
UIGraphicsBeginImageContext(CGSizeMake(100, 100));
|
||||
[[UIColor blueColor] setFill];
|
||||
UIRectFill(CGRectMake(0, 0, 100, 100));
|
||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
UIImage *rounded = ASImageNodeTintColorModificationBlock([UIColor redColor])(result, ASPrimitiveTraitCollectionMakeDefault());
|
||||
ASImageNode *node = [[ASImageNode alloc] init];
|
||||
node.image = rounded;
|
||||
ASDisplayNodeSizeToFitSize(node, rounded.size);
|
||||
@@ -206,10 +242,6 @@
|
||||
- (void)testDynamicAssetImage
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
ASConfiguration *config = [ASConfiguration new];
|
||||
config.experimentalFeatures = ASExperimentalTraitCollectionDidChangeWithPreviousCollection;
|
||||
[ASConfigurationManager test_resetWithConfiguration:config];
|
||||
|
||||
UIImage *image = [UIImage imageNamed:@"light-dark" inBundle:[NSBundle bundleForClass:[self class]] compatibleWithTraitCollection:nil];
|
||||
ASImageNode *node = [[ASImageNode alloc] init];
|
||||
node.image = image;
|
||||
@@ -222,8 +254,29 @@
|
||||
[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{
|
||||
ASSnapshotVerifyNode(node, @"user_interface_style_dark");
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testDynamicTintColor
|
||||
{
|
||||
if (@available(iOS 13.0, *)) {
|
||||
UIImage *image = makeImageWithColor(UIColor.redColor, CGSize{.width = 100, .height = 100});
|
||||
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
|
||||
UIColor* tintColor = UIColor.systemBackgroundColor;
|
||||
ASImageNode *node = [[ASImageNode alloc] init];
|
||||
|
||||
NSLog(@"%@", image);
|
||||
node.image = image;
|
||||
node.tintColor = tintColor;
|
||||
|
||||
ASDisplayNodeSizeToFitSize(node, image.size);
|
||||
|
||||
[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight] performAsCurrentTraitCollection:^{
|
||||
ASSnapshotVerifyNode(node, @"user_interface_style_light");
|
||||
}];
|
||||
|
||||
[[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark] performAsCurrentTraitCollection:^{
|
||||
ASSnapshotVerifyNode(node, @"user_interface_style_dark");
|
||||
}];
|
||||
}
|
||||
}
|
||||
#endif // #if AS_AT_LEAST_IOS13
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
//
|
||||
// ASImageNodeTests.m
|
||||
// Texture
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import <OCMock/OCMock.h>
|
||||
#import <AsyncDisplayKit/ASImageNode.h>
|
||||
#import <AsyncDisplayKit/ASDisplayNode+Subclasses.h>
|
||||
|
||||
@interface ASImageTestNode : ASImageNode
|
||||
@property (nonatomic, readonly) NSUInteger setNeedsDisplayCount;
|
||||
@end
|
||||
|
||||
@implementation ASImageTestNode
|
||||
|
||||
- (void)setNeedsDisplay
|
||||
{
|
||||
// Do not call super so that the background mechanics do not fire up.
|
||||
_setNeedsDisplayCount += 1;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ASImageNodeTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASImageNodeTests
|
||||
|
||||
- (void)testImage_didEnterHierarchy
|
||||
{
|
||||
id imageMock = OCMClassMock(UIImage.class);
|
||||
|
||||
ASImageTestNode *imageNode = [[ASImageTestNode alloc] init];
|
||||
imageNode.layerBacked = YES;
|
||||
imageNode.image = imageMock;
|
||||
|
||||
CALayer *layer = imageNode.layer;
|
||||
XCTAssertNotNil(layer);
|
||||
id<CALayerDelegate> layerDelegate = layer.delegate;
|
||||
|
||||
NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount;
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 1);
|
||||
|
||||
[layerDelegate actionForLayer:layer forKey:kCAOnOrderIn];
|
||||
|
||||
XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount);
|
||||
|
||||
[layerDelegate actionForLayer:layer forKey:kCAOnOrderOut];
|
||||
|
||||
[imageMock stopMocking];
|
||||
}
|
||||
|
||||
- (void)testTemplateImage_didEnterHierarchy
|
||||
{
|
||||
id imageMock = OCMClassMock(UIImage.class);
|
||||
OCMStub([imageMock renderingMode]).andReturn(UIImageRenderingModeAlwaysTemplate);
|
||||
|
||||
ASImageTestNode *imageNode = [[ASImageTestNode alloc] init];
|
||||
imageNode.layerBacked = YES;
|
||||
imageNode.image = imageMock;
|
||||
|
||||
CALayer *layer = imageNode.layer;
|
||||
XCTAssertNotNil(layer);
|
||||
id<CALayerDelegate> layerDelegate = layer.delegate;
|
||||
|
||||
NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount;
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 1);
|
||||
|
||||
[layerDelegate actionForLayer:layer forKey:kCAOnOrderIn];
|
||||
|
||||
XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1);
|
||||
|
||||
[layerDelegate actionForLayer:layer forKey:kCAOnOrderOut];
|
||||
|
||||
[imageMock stopMocking];
|
||||
}
|
||||
|
||||
- (void)testImage_tintColorDidChange
|
||||
{
|
||||
id imageMock = OCMClassMock(UIImage.class);
|
||||
|
||||
ASImageTestNode *imageNode = [[ASImageTestNode alloc] init];
|
||||
imageNode.image = imageMock;
|
||||
|
||||
NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount;
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 1);
|
||||
|
||||
[imageNode tintColorDidChange];
|
||||
XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount);
|
||||
|
||||
[imageMock stopMocking];
|
||||
}
|
||||
|
||||
- (void)testTemplateImage_tintColorDidChange
|
||||
{
|
||||
id imageMock = OCMClassMock(UIImage.class);
|
||||
OCMStub([imageMock renderingMode]).andReturn(UIImageRenderingModeAlwaysTemplate);
|
||||
|
||||
ASImageTestNode *imageNode = [[ASImageTestNode alloc] init];
|
||||
imageNode.image = imageMock;
|
||||
|
||||
NSUInteger initialSetNeedsDisplayCount = imageNode.setNeedsDisplayCount;
|
||||
XCTAssertEqual(initialSetNeedsDisplayCount, 1);
|
||||
|
||||
[imageNode tintColorDidChange];
|
||||
XCTAssertEqual(imageNode.setNeedsDisplayCount, initialSetNeedsDisplayCount + 1);
|
||||
|
||||
[imageMock stopMocking];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -36,7 +36,7 @@ static UIEdgeInsets insetsForCombination(NSUInteger combination, CGFloat insetVa
|
||||
|
||||
static NSString *nameForInsets(UIEdgeInsets insets)
|
||||
{
|
||||
return [NSString stringWithFormat:@"%.f-%.f-%.f-%.f", insets.top, insets.left, insets.bottom, insets.right];
|
||||
return [NSString stringWithFormat:@"%.f_%.f_%.f_%.f", insets.top, insets.left, insets.bottom, insets.right];
|
||||
}
|
||||
|
||||
@interface ASInsetLayoutSpecSnapshotTests : ASLayoutSpecSnapshotTestCase
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
allNodes = @[ nodeA, nodeB, nodeC, nodeD, nodeE ];
|
||||
ASSetDebugNames(nodeA, nodeB, nodeC, nodeD, nodeE);
|
||||
ASLayoutSpecBlock b = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeD ]];
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeC, self->nodeD ]];
|
||||
};
|
||||
fixture1and3and5NodeALayoutSpecBlock = b;
|
||||
fixture1 = [self createFixture1];
|
||||
@@ -162,10 +162,10 @@
|
||||
injectedMainThreadWork = ^{
|
||||
injectedMainThreadWorkDone = YES;
|
||||
|
||||
[window layoutIfNeeded];
|
||||
[self->window layoutIfNeeded];
|
||||
|
||||
// Ensure we're still on the old layout. We should stay on this until the transition completes.
|
||||
[self verifyFixture:fixture1];
|
||||
[self verifyFixture:self->fixture1];
|
||||
};
|
||||
|
||||
measurementCompletionBlock = ^{
|
||||
@@ -286,7 +286,7 @@
|
||||
as_log_verbose(OS_LOG_DEFAULT, "Begin injectedMainThreadWork");
|
||||
injectedMainThreadWorkDone = YES;
|
||||
|
||||
[fixture4 apply];
|
||||
[self->fixture4 apply];
|
||||
as_log_verbose(OS_LOG_DEFAULT, "Did apply new fixture");
|
||||
|
||||
if (enforceCorrectBehavior) {
|
||||
@@ -294,10 +294,10 @@
|
||||
// are common to both fixture2 and fixture4 are available from the cache.
|
||||
} else {
|
||||
// Incorrect behavior: nodeC will get measured against its new bounds on main.
|
||||
const auto cPendingSize = [fixture2 layoutForNode:nodeC].size;
|
||||
OCMExpect([nodeC.mock calculateLayoutThatFits:ASSizeRangeMake(cPendingSize)]).onMainThread();
|
||||
const auto cPendingSize = [self->fixture2 layoutForNode:self->nodeC].size;
|
||||
OCMExpect([self->nodeC.mock calculateLayoutThatFits:ASSizeRangeMake(cPendingSize)]).onMainThread();
|
||||
}
|
||||
[window layoutIfNeeded];
|
||||
[self->window layoutIfNeeded];
|
||||
as_log_verbose(OS_LOG_DEFAULT, "End injectedMainThreadWork");
|
||||
};
|
||||
|
||||
@@ -342,7 +342,7 @@
|
||||
OCMExpect([nodeB.mock calculateLayoutThatFits:[fixture3 firstSizeRangeForNode:nodeB]]);
|
||||
|
||||
[fixture1 withSizeRangesForNode:nodeA block:^(ASSizeRange sizeRange) {
|
||||
OCMExpect([nodeA.mock calculateLayoutThatFits:sizeRange]);
|
||||
OCMExpect([self->nodeA.mock calculateLayoutThatFits:sizeRange]);
|
||||
}];
|
||||
|
||||
[window layoutIfNeeded];
|
||||
@@ -456,7 +456,7 @@
|
||||
fixture.layout = layoutA;
|
||||
|
||||
ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeC, nodeE ]];
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeC, self->nodeE ]];
|
||||
};
|
||||
[fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA];
|
||||
return fixture;
|
||||
@@ -535,7 +535,7 @@
|
||||
fixture.layout = layoutA;
|
||||
|
||||
ASLayoutSpecBlock specBlockA = ^ASLayoutSpec * _Nonnull(__kindof ASDisplayNode * _Nonnull node, ASSizeRange constrainedSize) {
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ nodeB, nodeD, nodeE ]];
|
||||
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:0 justifyContent:ASStackLayoutJustifyContentSpaceBetween alignItems:ASStackLayoutAlignItemsStart children:@[ self->nodeB, self->nodeD, self->nodeE ]];
|
||||
};
|
||||
[fixture.layoutSpecBlocks setObject:specBlockA forKey:nodeA];
|
||||
return fixture;
|
||||
@@ -576,7 +576,7 @@
|
||||
[fixture withSizeRangesForAllNodesUsingBlock:^(ASLayoutTestNode * _Nonnull node, ASSizeRange sizeRange) {
|
||||
OCMExpect([node.mock calculateLayoutThatFits:sizeRange]).onMainThread();
|
||||
|
||||
if (!stubbedCalculatedLayoutDidChange) {
|
||||
if (!self->stubbedCalculatedLayoutDidChange) {
|
||||
OCMExpect([node.mock calculatedLayoutDidChange]).onMainThread();
|
||||
}
|
||||
}];
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// ASLayoutSpecUtilitiesTests.m
|
||||
// AsyncDisplayKitTests
|
||||
//
|
||||
// Copyright (c) Pinterest, Inc. All rights reserved.
|
||||
// Licensed under Apache 2.0: http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
#import "ASLayoutSpecUtilities.h"
|
||||
|
||||
@interface ASLayoutSpecUtilitiesTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASLayoutSpecUtilitiesTests
|
||||
|
||||
- (void)testMapVectorPrimitive
|
||||
{
|
||||
std::vector<int> a = {3, 1, 4};
|
||||
std::vector<int> b = AS::map(a, ^int(int i) {
|
||||
return i * 2;
|
||||
});
|
||||
std::vector<int> c = {6, 2, 8};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapVectorNSObject
|
||||
{
|
||||
std::vector<NSString *> a = {@"2.16", @"3.14"};
|
||||
std::vector<float> b = AS::map(a, ^float(NSString *str) {
|
||||
return str.floatValue;
|
||||
});
|
||||
std::vector<float> c = {2.16, 3.14};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapVectorStruct
|
||||
{
|
||||
struct TestStruct
|
||||
{
|
||||
NSString *value;
|
||||
|
||||
bool operator==(const TestStruct& rhs) const
|
||||
{
|
||||
return [value isEqualToString:rhs.value];
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<TestStruct> a = {
|
||||
{.value = @"2"},
|
||||
{.value = @"1"},
|
||||
{.value = @"6"}
|
||||
};
|
||||
std::vector<NSInteger> b = AS::map(a, ^NSInteger(TestStruct s) {
|
||||
return s.value.integerValue;
|
||||
});
|
||||
std::vector<NSInteger> c = {2, 1, 6};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapVectorClass
|
||||
{
|
||||
class TestClass {
|
||||
private:
|
||||
NSString *_value;
|
||||
|
||||
public:
|
||||
TestClass (NSString *value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
NSString *getValue() const noexcept
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
void setValue(NSString *value) noexcept
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
bool operator==(const TestClass& rhs) const noexcept
|
||||
{
|
||||
return [getValue() isEqualToString:rhs.getValue()];
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<TestClass> a = {
|
||||
TestClass(@"2"),
|
||||
TestClass(@"1"),
|
||||
TestClass(@"6")
|
||||
};
|
||||
std::vector<NSInteger> b = AS::map(a, ^NSInteger(TestClass c) {
|
||||
return c.getValue().integerValue;
|
||||
});
|
||||
std::vector<NSInteger> c = {2, 1, 6};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapVectorEmpty
|
||||
{
|
||||
std::vector<NSString *> a = {};
|
||||
std::vector<int> b = AS::map(a, ^int(NSString *str) {
|
||||
return str.intValue;
|
||||
});
|
||||
std::vector<int> c = {};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapNSFastEnumeration
|
||||
{
|
||||
struct TestStruct {
|
||||
NSString *value;
|
||||
|
||||
bool operator==(const TestStruct& rhs) const
|
||||
{
|
||||
return [value isEqualToString:rhs.value];
|
||||
}
|
||||
};
|
||||
|
||||
NSArray<NSNumber *> *a = @[@1, @2, @3];
|
||||
std::vector<TestStruct> b = AS::map(a, ^TestStruct(NSNumber *num) {
|
||||
return {.value = num.stringValue};
|
||||
});
|
||||
std::vector<TestStruct> c = {
|
||||
{.value = @"1"},
|
||||
{.value = @"2"},
|
||||
{.value = @"3"}
|
||||
};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testMapNSFastEnumerationEmpty
|
||||
{
|
||||
NSArray<NSNumber *> *a = @[];
|
||||
std::vector<int> b = AS::map(a, ^int(NSNumber *num) {
|
||||
return num.intValue;
|
||||
});
|
||||
std::vector<int> c = {};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testFilterVectorPrimitive
|
||||
{
|
||||
std::vector<int> a = {1, 2, 3, 4};
|
||||
std::vector<int> b = AS::filter(a, ^BOOL(int num) {
|
||||
return num < 3;
|
||||
});
|
||||
std::vector<int> c = {1, 2};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testFilterVectorNSObject
|
||||
{
|
||||
std::vector<NSString *> a = {@"9", @"2", @"6"};
|
||||
std::vector<NSString *> b = AS::filter(a, ^BOOL(NSString *str) {
|
||||
return str.integerValue % 2 == 0;
|
||||
});
|
||||
std::vector<NSString *> c = {@"2", @"6"};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testFilterVectorStruct
|
||||
{
|
||||
struct TestStruct {
|
||||
NSString *value;
|
||||
|
||||
bool operator==(const TestStruct& rhs) const
|
||||
{
|
||||
return [value isEqualToString:rhs.value];
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<TestStruct> a = {
|
||||
{.value = @"6"},
|
||||
{.value = @"8"},
|
||||
{.value = @"3"},
|
||||
{.value = @"9"}
|
||||
};
|
||||
std::vector<TestStruct> b = AS::filter(a, ^BOOL(TestStruct s) {
|
||||
return s.value.integerValue == 3;
|
||||
});
|
||||
std::vector<TestStruct> c = {
|
||||
{.value = @"3"}
|
||||
};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testFilterVectorClass
|
||||
{
|
||||
class TestClass {
|
||||
private:
|
||||
NSString *_value;
|
||||
|
||||
public:
|
||||
TestClass (NSString *value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
NSString *getValue() const noexcept
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
void setValue(NSString *value) noexcept
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
bool operator==(const TestClass& rhs) const noexcept
|
||||
{
|
||||
return [getValue() isEqualToString:rhs.getValue()];
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<TestClass> a = {
|
||||
TestClass(@"2"),
|
||||
TestClass(@"1"),
|
||||
TestClass(@"6")
|
||||
};
|
||||
std::vector<TestClass> b = AS::filter(a, ^BOOL(TestClass c) {
|
||||
return c.getValue().integerValue > 1;
|
||||
});
|
||||
std::vector<TestClass> c = {
|
||||
TestClass(@"2"),
|
||||
TestClass(@"6")
|
||||
};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
- (void)testFilterVectorEmpty
|
||||
{
|
||||
std::vector<int> a = {};
|
||||
std::vector<int> b = AS::filter(a, ^BOOL(int num) {
|
||||
return num < 2;
|
||||
});
|
||||
std::vector<int> c = {};
|
||||
XCTAssertEqual(b, c);
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -112,7 +112,7 @@
|
||||
OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]])
|
||||
.andDo(^(NSInvocation *inv) {
|
||||
ASImageCacherCompletion completionBlock = [inv as_argumentAtIndexAsObject:4];
|
||||
completionBlock([self _testImage]);
|
||||
completionBlock([self _testImage], ASImageCacheTypeAsynchronous);
|
||||
});
|
||||
|
||||
imageNode.imageIdentifiers = @[imageIdentifier];
|
||||
@@ -217,7 +217,7 @@
|
||||
OCMExpect([mockCache cachedImageWithURL:[self _testImageURL] callbackQueue:OCMOCK_ANY completion:[OCMArg isNotNil]])
|
||||
.andDo(^(NSInvocation *inv){
|
||||
ASImageCacherCompletion completion = [inv as_argumentAtIndexAsObject:4];
|
||||
completion(nil);
|
||||
completion(nil, ASImageCacheTypeAsynchronous);
|
||||
});
|
||||
|
||||
// Mock a 50%-progress URL download.
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
- (void)cachedImageWithURL:(NSURL *)URL callbackQueue:(dispatch_queue_t)callbackQueue completion:(ASImageCacherCompletion)completion
|
||||
{
|
||||
completion(nil);
|
||||
completion(nil, ASImageCacheTypeAsynchronous);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
ASRecursiveUnfairLockLock(&lock);
|
||||
XCTestExpectation *e1 = [self expectationWithDescription:@"Other thread tried lock."];
|
||||
[NSThread detachNewThreadWithBlock:^{
|
||||
XCTAssertThrows(ASRecursiveUnfairLockUnlock(&lock));
|
||||
XCTAssertThrows(ASRecursiveUnfairLockUnlock(&self->lock));
|
||||
[e1 fulfill];
|
||||
}];
|
||||
[self waitForExpectationsWithTimeout:10 handler:nil];
|
||||
@@ -93,7 +93,7 @@ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
|
||||
{
|
||||
__block int value = 0;
|
||||
[self measureBlock:^{
|
||||
CHAOS_TEST_BODY(YES, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock));
|
||||
CHAOS_TEST_BODY(YES, ASRecursiveUnfairLockLock(&self->lock), {}, ASRecursiveUnfairLockUnlock(&self->lock));
|
||||
}];
|
||||
XCTAssertEqual(value, 0);
|
||||
}
|
||||
@@ -102,7 +102,7 @@ dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
|
||||
{
|
||||
__block int value = 0;
|
||||
[self measureBlock:^{
|
||||
CHAOS_TEST_BODY(NO, ASRecursiveUnfairLockLock(&lock), {}, ASRecursiveUnfairLockUnlock(&lock));
|
||||
CHAOS_TEST_BODY(NO, ASRecursiveUnfairLockLock(&self->lock), {}, ASRecursiveUnfairLockUnlock(&self->lock));
|
||||
}];
|
||||
XCTAssertEqual(value, 0);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#import "ASDisplayNodeTestsHelper.h"
|
||||
|
||||
static NSTimeInterval const kRunLoopRunTime = 0.001; // Allow the RunLoop to run for one millisecond each time.
|
||||
static NSTimeInterval const kRunLoopRunTime = 0.01; // Allow the RunLoop to run for 1/100 second each time.
|
||||
|
||||
@interface QueueObject : NSObject <ASCATransactionQueueObserving>
|
||||
@property (nonatomic) BOOL queueObjectProcessed;
|
||||
|
||||
@@ -170,6 +170,10 @@
|
||||
|
||||
- (void)testASScrollNodeAccessibility {
|
||||
ASDisplayNode *scrollNode = [[ASDisplayNode alloc] init];
|
||||
UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 320, 560)];
|
||||
[window addSubnode:scrollNode];
|
||||
[window makeKeyAndVisible];
|
||||
|
||||
ASDisplayNode *node = [[ASDisplayNode alloc] init];
|
||||
node.isAccessibilityContainer = YES;
|
||||
node.accessibilityLabel = @"node";
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user