mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-08 17:53:38 +00:00
Refactor ItemListUI
This commit is contained in:
parent
49777d8834
commit
17223c9cfb
22
submodules/ItemListUI/Info.plist
Normal file
22
submodules/ItemListUI/Info.plist
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
675
submodules/ItemListUI/ItemListUI_Xcode.xcodeproj/project.pbxproj
Normal file
675
submodules/ItemListUI/ItemListUI_Xcode.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,675 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 50;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
D060182122F35C2300796784 /* ProgressNavigationButtonNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */; };
|
||||||
|
D060185322F35E1F00796784 /* ItemListMultilineInputItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */; };
|
||||||
|
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */; };
|
||||||
|
D060185522F35E1F00796784 /* ItemListActivityTextItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184B22F35E1E00796784 /* ItemListActivityTextItem.swift */; };
|
||||||
|
D060185622F35E1F00796784 /* ItemListActionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184C22F35E1E00796784 /* ItemListActionItem.swift */; };
|
||||||
|
D060185722F35E1F00796784 /* ItemListSwitchItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184D22F35E1E00796784 /* ItemListSwitchItem.swift */; };
|
||||||
|
D060185822F35E1F00796784 /* ItemListLoadingIndicatorEmptyStateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184E22F35E1E00796784 /* ItemListLoadingIndicatorEmptyStateItem.swift */; };
|
||||||
|
D060185922F35E1F00796784 /* ItemListEditableItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060184F22F35E1E00796784 /* ItemListEditableItem.swift */; };
|
||||||
|
D060185A22F35E1F00796784 /* ItemListDisclosureItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060185022F35E1E00796784 /* ItemListDisclosureItem.swift */; };
|
||||||
|
D060185B22F35E1F00796784 /* ItemListMultilineTextItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060185122F35E1E00796784 /* ItemListMultilineTextItem.swift */; };
|
||||||
|
D060185C22F35E1F00796784 /* ItemListCheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060185222F35E1F00796784 /* ItemListCheckboxItem.swift */; };
|
||||||
|
D060186122F35F6C00796784 /* ItemListRevealOptionsNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */; };
|
||||||
|
D06018A022F3618B00796784 /* SwitchNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189F22F3618B00796784 /* SwitchNode.framework */; };
|
||||||
|
D06018A222F3619000796784 /* AnimationUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06018A122F3619000796784 /* AnimationUI.framework */; };
|
||||||
|
D06018BB22F3663900796784 /* ItemListEditableReorderControlNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */; };
|
||||||
|
D06018BC22F3663900796784 /* ItemListSelectableControlNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06018B922F3663800796784 /* ItemListSelectableControlNode.swift */; };
|
||||||
|
D06018BD22F3663900796784 /* ItemListEditableDeleteControlNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */; };
|
||||||
|
D06018E322F366F200796784 /* CheckNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D06018E222F366F200796784 /* CheckNode.framework */; };
|
||||||
|
D0D3282422F3205E00D07EE2 /* ItemListUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D3282222F3205E00D07EE2 /* ItemListUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
D0D3286522F3366600D07EE2 /* ItemListControllerEmptyStateItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3286022F3366500D07EE2 /* ItemListControllerEmptyStateItem.swift */; };
|
||||||
|
D0D3286622F3366600D07EE2 /* ItemListControllerSegmentedTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */; };
|
||||||
|
D0D3286722F3366600D07EE2 /* ItemListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3286222F3366500D07EE2 /* ItemListController.swift */; };
|
||||||
|
D0D3286822F3366600D07EE2 /* ItemListControllerSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */; };
|
||||||
|
D0D3286922F3366600D07EE2 /* ItemListControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3286422F3366500D07EE2 /* ItemListControllerNode.swift */; };
|
||||||
|
D0D3286C22F3367300D07EE2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3286B22F3367300D07EE2 /* UIKit.framework */; };
|
||||||
|
D0D3286E22F3367700D07EE2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3286D22F3367700D07EE2 /* Foundation.framework */; };
|
||||||
|
D0D3287022F3367D00D07EE2 /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3286F22F3367D00D07EE2 /* AsyncDisplayKit.framework */; };
|
||||||
|
D0D3287222F3368300D07EE2 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3287122F3368300D07EE2 /* Display.framework */; };
|
||||||
|
D0D3287422F3368C00D07EE2 /* AccountContext.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3287322F3368C00D07EE2 /* AccountContext.framework */; };
|
||||||
|
D0D3287622F3369200D07EE2 /* TelegramPresentationData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3287522F3369200D07EE2 /* TelegramPresentationData.framework */; };
|
||||||
|
D0D3289822F3449800D07EE2 /* MergeLists.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D3289722F3449800D07EE2 /* MergeLists.framework */; };
|
||||||
|
D0D3289A22F345C500D07EE2 /* ItemListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D3289922F345C500D07EE2 /* ItemListItem.swift */; };
|
||||||
|
D0D328A522F346C200D07EE2 /* ItemListTextItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D328A422F346C200D07EE2 /* ItemListTextItem.swift */; };
|
||||||
|
D0D328DE22F34A0D00D07EE2 /* TextFormat.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0D328DD22F34A0D00D07EE2 /* TextFormat.framework */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ProgressNavigationButtonNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListMultilineInputItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListTextWithLabelItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184B22F35E1E00796784 /* ItemListActivityTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListActivityTextItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184C22F35E1E00796784 /* ItemListActionItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListActionItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184D22F35E1E00796784 /* ItemListSwitchItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListSwitchItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184E22F35E1E00796784 /* ItemListLoadingIndicatorEmptyStateItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListLoadingIndicatorEmptyStateItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060184F22F35E1E00796784 /* ItemListEditableItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListEditableItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060185022F35E1E00796784 /* ItemListDisclosureItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListDisclosureItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060185122F35E1E00796784 /* ItemListMultilineTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListMultilineTextItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060185222F35E1F00796784 /* ItemListCheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListCheckboxItem.swift; sourceTree = "<group>"; };
|
||||||
|
D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListRevealOptionsNode.swift; sourceTree = "<group>"; };
|
||||||
|
D060189F22F3618B00796784 /* SwitchNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwitchNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D06018A122F3619000796784 /* AnimationUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AnimationUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListEditableReorderControlNode.swift; sourceTree = "<group>"; };
|
||||||
|
D06018B922F3663800796784 /* ItemListSelectableControlNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListSelectableControlNode.swift; sourceTree = "<group>"; };
|
||||||
|
D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListEditableDeleteControlNode.swift; sourceTree = "<group>"; };
|
||||||
|
D06018E222F366F200796784 /* CheckNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CheckNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3281F22F3205E00D07EE2 /* ItemListUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ItemListUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3282222F3205E00D07EE2 /* ItemListUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ItemListUI.h; sourceTree = "<group>"; };
|
||||||
|
D0D3282322F3205E00D07EE2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
D0D3286022F3366500D07EE2 /* ItemListControllerEmptyStateItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListControllerEmptyStateItem.swift; sourceTree = "<group>"; };
|
||||||
|
D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListControllerSegmentedTitleView.swift; sourceTree = "<group>"; };
|
||||||
|
D0D3286222F3366500D07EE2 /* ItemListController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListController.swift; sourceTree = "<group>"; };
|
||||||
|
D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListControllerSearch.swift; sourceTree = "<group>"; };
|
||||||
|
D0D3286422F3366500D07EE2 /* ItemListControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListControllerNode.swift; sourceTree = "<group>"; };
|
||||||
|
D0D3286B22F3367300D07EE2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
|
D0D3286D22F3367700D07EE2 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
D0D3286F22F3367D00D07EE2 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3287122F3368300D07EE2 /* Display.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3287322F3368C00D07EE2 /* AccountContext.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AccountContext.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3287522F3369200D07EE2 /* TelegramPresentationData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramPresentationData.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3289722F3449800D07EE2 /* MergeLists.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MergeLists.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
D0D3289922F345C500D07EE2 /* ItemListItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListItem.swift; sourceTree = "<group>"; };
|
||||||
|
D0D328A422F346C200D07EE2 /* ItemListTextItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ItemListTextItem.swift; sourceTree = "<group>"; };
|
||||||
|
D0D328DD22F34A0D00D07EE2 /* TextFormat.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TextFormat.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
D0D3281C22F3205E00D07EE2 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D06018E322F366F200796784 /* CheckNode.framework in Frameworks */,
|
||||||
|
D06018A222F3619000796784 /* AnimationUI.framework in Frameworks */,
|
||||||
|
D06018A022F3618B00796784 /* SwitchNode.framework in Frameworks */,
|
||||||
|
D060182122F35C2300796784 /* ProgressNavigationButtonNode.framework in Frameworks */,
|
||||||
|
D0D328DE22F34A0D00D07EE2 /* TextFormat.framework in Frameworks */,
|
||||||
|
D0D3289822F3449800D07EE2 /* MergeLists.framework in Frameworks */,
|
||||||
|
D0D3287622F3369200D07EE2 /* TelegramPresentationData.framework in Frameworks */,
|
||||||
|
D0D3287422F3368C00D07EE2 /* AccountContext.framework in Frameworks */,
|
||||||
|
D0D3287222F3368300D07EE2 /* Display.framework in Frameworks */,
|
||||||
|
D0D3287022F3367D00D07EE2 /* AsyncDisplayKit.framework in Frameworks */,
|
||||||
|
D0D3286E22F3367700D07EE2 /* Foundation.framework in Frameworks */,
|
||||||
|
D0D3286C22F3367300D07EE2 /* UIKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
D060185D22F35E2200796784 /* Items */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D060184C22F35E1E00796784 /* ItemListActionItem.swift */,
|
||||||
|
D060184B22F35E1E00796784 /* ItemListActivityTextItem.swift */,
|
||||||
|
D060185222F35E1F00796784 /* ItemListCheckboxItem.swift */,
|
||||||
|
D060185022F35E1E00796784 /* ItemListDisclosureItem.swift */,
|
||||||
|
D060184F22F35E1E00796784 /* ItemListEditableItem.swift */,
|
||||||
|
D060184922F35E1E00796784 /* ItemListMultilineInputItem.swift */,
|
||||||
|
D060185122F35E1E00796784 /* ItemListMultilineTextItem.swift */,
|
||||||
|
D060184D22F35E1E00796784 /* ItemListSwitchItem.swift */,
|
||||||
|
D060184A22F35E1E00796784 /* ItemListTextWithLabelItem.swift */,
|
||||||
|
D0D328A422F346C200D07EE2 /* ItemListTextItem.swift */,
|
||||||
|
);
|
||||||
|
path = Items;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D0D3281522F3205E00D07EE2 = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D0D3282322F3205E00D07EE2 /* Info.plist */,
|
||||||
|
D0D3282122F3205E00D07EE2 /* Sources */,
|
||||||
|
D0D3282022F3205E00D07EE2 /* Products */,
|
||||||
|
D0D3286A22F3367300D07EE2 /* Frameworks */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D0D3282022F3205E00D07EE2 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D0D3281F22F3205E00D07EE2 /* ItemListUI.framework */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D0D3282122F3205E00D07EE2 /* Sources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D060185D22F35E2200796784 /* Items */,
|
||||||
|
D060184E22F35E1E00796784 /* ItemListLoadingIndicatorEmptyStateItem.swift */,
|
||||||
|
D0D3286222F3366500D07EE2 /* ItemListController.swift */,
|
||||||
|
D0D3286022F3366500D07EE2 /* ItemListControllerEmptyStateItem.swift */,
|
||||||
|
D0D3286422F3366500D07EE2 /* ItemListControllerNode.swift */,
|
||||||
|
D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */,
|
||||||
|
D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */,
|
||||||
|
D0D3289922F345C500D07EE2 /* ItemListItem.swift */,
|
||||||
|
D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */,
|
||||||
|
D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */,
|
||||||
|
D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */,
|
||||||
|
D06018B922F3663800796784 /* ItemListSelectableControlNode.swift */,
|
||||||
|
D0D3282222F3205E00D07EE2 /* ItemListUI.h */,
|
||||||
|
);
|
||||||
|
path = Sources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
D0D3286A22F3367300D07EE2 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
D06018E222F366F200796784 /* CheckNode.framework */,
|
||||||
|
D06018A122F3619000796784 /* AnimationUI.framework */,
|
||||||
|
D060189F22F3618B00796784 /* SwitchNode.framework */,
|
||||||
|
D060182022F35C2300796784 /* ProgressNavigationButtonNode.framework */,
|
||||||
|
D0D328DD22F34A0D00D07EE2 /* TextFormat.framework */,
|
||||||
|
D0D3289722F3449800D07EE2 /* MergeLists.framework */,
|
||||||
|
D0D3287522F3369200D07EE2 /* TelegramPresentationData.framework */,
|
||||||
|
D0D3287322F3368C00D07EE2 /* AccountContext.framework */,
|
||||||
|
D0D3287122F3368300D07EE2 /* Display.framework */,
|
||||||
|
D0D3286F22F3367D00D07EE2 /* AsyncDisplayKit.framework */,
|
||||||
|
D0D3286D22F3367700D07EE2 /* Foundation.framework */,
|
||||||
|
D0D3286B22F3367300D07EE2 /* UIKit.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXHeadersBuildPhase section */
|
||||||
|
D0D3281A22F3205E00D07EE2 /* Headers */ = {
|
||||||
|
isa = PBXHeadersBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D0D3282422F3205E00D07EE2 /* ItemListUI.h in Headers */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXHeadersBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
D0D3281E22F3205E00D07EE2 /* ItemListUI */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = D0D3282722F3205E00D07EE2 /* Build configuration list for PBXNativeTarget "ItemListUI" */;
|
||||||
|
buildPhases = (
|
||||||
|
D0D3281A22F3205E00D07EE2 /* Headers */,
|
||||||
|
D0D3281B22F3205E00D07EE2 /* Sources */,
|
||||||
|
D0D3281C22F3205E00D07EE2 /* Frameworks */,
|
||||||
|
D0D3281D22F3205E00D07EE2 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = ItemListUI;
|
||||||
|
productName = ItemListUI;
|
||||||
|
productReference = D0D3281F22F3205E00D07EE2 /* ItemListUI.framework */;
|
||||||
|
productType = "com.apple.product-type.framework";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
D0D3281622F3205E00D07EE2 /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
DefaultBuildSystemTypeForWorkspace = Latest;
|
||||||
|
LastUpgradeCheck = 1010;
|
||||||
|
ORGANIZATIONNAME = "Telegram Messenger LLP";
|
||||||
|
TargetAttributes = {
|
||||||
|
D0D3281E22F3205E00D07EE2 = {
|
||||||
|
CreatedOnToolsVersion = 10.1;
|
||||||
|
LastSwiftMigration = 1010;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = D0D3281922F3205E00D07EE2 /* Build configuration list for PBXProject "ItemListUI_Xcode" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
);
|
||||||
|
mainGroup = D0D3281522F3205E00D07EE2;
|
||||||
|
productRefGroup = D0D3282022F3205E00D07EE2 /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
D0D3281E22F3205E00D07EE2 /* ItemListUI */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
D0D3281D22F3205E00D07EE2 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
D0D3281B22F3205E00D07EE2 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
D060185322F35E1F00796784 /* ItemListMultilineInputItem.swift in Sources */,
|
||||||
|
D06018BB22F3663900796784 /* ItemListEditableReorderControlNode.swift in Sources */,
|
||||||
|
D060185522F35E1F00796784 /* ItemListActivityTextItem.swift in Sources */,
|
||||||
|
D060186122F35F6C00796784 /* ItemListRevealOptionsNode.swift in Sources */,
|
||||||
|
D06018BC22F3663900796784 /* ItemListSelectableControlNode.swift in Sources */,
|
||||||
|
D060185822F35E1F00796784 /* ItemListLoadingIndicatorEmptyStateItem.swift in Sources */,
|
||||||
|
D0D3286522F3366600D07EE2 /* ItemListControllerEmptyStateItem.swift in Sources */,
|
||||||
|
D060185622F35E1F00796784 /* ItemListActionItem.swift in Sources */,
|
||||||
|
D060185922F35E1F00796784 /* ItemListEditableItem.swift in Sources */,
|
||||||
|
D060185A22F35E1F00796784 /* ItemListDisclosureItem.swift in Sources */,
|
||||||
|
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */,
|
||||||
|
D0D3286722F3366600D07EE2 /* ItemListController.swift in Sources */,
|
||||||
|
D0D3286822F3366600D07EE2 /* ItemListControllerSearch.swift in Sources */,
|
||||||
|
D060185722F35E1F00796784 /* ItemListSwitchItem.swift in Sources */,
|
||||||
|
D0D3286622F3366600D07EE2 /* ItemListControllerSegmentedTitleView.swift in Sources */,
|
||||||
|
D060185B22F35E1F00796784 /* ItemListMultilineTextItem.swift in Sources */,
|
||||||
|
D0D3286922F3366600D07EE2 /* ItemListControllerNode.swift in Sources */,
|
||||||
|
D0D328A522F346C200D07EE2 /* ItemListTextItem.swift in Sources */,
|
||||||
|
D06018BD22F3663900796784 /* ItemListEditableDeleteControlNode.swift in Sources */,
|
||||||
|
D0D3289A22F345C500D07EE2 /* ItemListItem.swift in Sources */,
|
||||||
|
D060185C22F35E1F00796784 /* ItemListCheckboxItem.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
D0D3282522F3205E00D07EE2 /* DebugAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
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;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = DebugAppStoreLLC;
|
||||||
|
};
|
||||||
|
D0D3282622F3205E00D07EE2 /* ReleaseAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
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;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D0D3282822F3205E00D07EE2 /* DebugAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ItemListUI;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 4.2;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = DebugAppStoreLLC;
|
||||||
|
};
|
||||||
|
D0D3282922F3205E00D07EE2 /* ReleaseAppStoreLLC */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ItemListUI;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 4.2;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D0D3282A22F3208400D07EE2 /* DebugHockeyapp */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
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;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = DebugHockeyapp;
|
||||||
|
};
|
||||||
|
D0D3282B22F3208400D07EE2 /* DebugHockeyapp */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ItemListUI;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 4.2;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = DebugHockeyapp;
|
||||||
|
};
|
||||||
|
D0D3282C22F3209200D07EE2 /* ReleaseHockeyappInternal */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
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;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu11;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
VERSION_INFO_PREFIX = "";
|
||||||
|
};
|
||||||
|
name = ReleaseHockeyappInternal;
|
||||||
|
};
|
||||||
|
D0D3282D22F3209200D07EE2 /* ReleaseHockeyappInternal */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "";
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
DEFINES_MODULE = YES;
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
DYLIB_COMPATIBILITY_VERSION = 1;
|
||||||
|
DYLIB_CURRENT_VERSION = 1;
|
||||||
|
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||||
|
INFOPLIST_FILE = Info.plist;
|
||||||
|
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@loader_path/Frameworks",
|
||||||
|
);
|
||||||
|
MACH_O_TYPE = staticlib;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = org.telegram.ItemListUI;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SWIFT_VERSION = 4.2;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = ReleaseHockeyappInternal;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
D0D3281922F3205E00D07EE2 /* Build configuration list for PBXProject "ItemListUI_Xcode" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D0D3282522F3205E00D07EE2 /* DebugAppStoreLLC */,
|
||||||
|
D0D3282A22F3208400D07EE2 /* DebugHockeyapp */,
|
||||||
|
D0D3282622F3205E00D07EE2 /* ReleaseAppStoreLLC */,
|
||||||
|
D0D3282C22F3209200D07EE2 /* ReleaseHockeyappInternal */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
D0D3282722F3205E00D07EE2 /* Build configuration list for PBXNativeTarget "ItemListUI" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
D0D3282822F3205E00D07EE2 /* DebugAppStoreLLC */,
|
||||||
|
D0D3282B22F3208400D07EE2 /* DebugHockeyapp */,
|
||||||
|
D0D3282922F3205E00D07EE2 /* ReleaseAppStoreLLC */,
|
||||||
|
D0D3282D22F3209200D07EE2 /* ReleaseHockeyappInternal */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
};
|
||||||
|
rootObject = D0D3281622F3205E00D07EE2 /* Project object */;
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1010"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D0D3281E22F3205E00D07EE2"
|
||||||
|
BuildableName = "ItemListUI.framework"
|
||||||
|
BlueprintName = "ItemListUI"
|
||||||
|
ReferencedContainer = "container:ItemListUI_Xcode.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "DebugAppStoreLLC"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<Testables>
|
||||||
|
</Testables>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "DebugHockeyapp"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D0D3281E22F3205E00D07EE2"
|
||||||
|
BuildableName = "ItemListUI.framework"
|
||||||
|
BlueprintName = "ItemListUI"
|
||||||
|
ReferencedContainer = "container:ItemListUI_Xcode.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<AdditionalOptions>
|
||||||
|
</AdditionalOptions>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "ReleaseAppStoreLLC"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "D0D3281E22F3205E00D07EE2"
|
||||||
|
BuildableName = "ItemListUI.framework"
|
||||||
|
BlueprintName = "ItemListUI"
|
||||||
|
ReferencedContainer = "container:ItemListUI_Xcode.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "DebugAppStoreLLC">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "ReleaseAppStoreLLC"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@ -4,101 +4,70 @@ import Display
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import AccountContext
|
||||||
|
import ProgressNavigationButtonNode
|
||||||
|
|
||||||
enum ItemListNavigationButtonStyle {
|
public enum ItemListNavigationButtonStyle {
|
||||||
case regular
|
case regular
|
||||||
case bold
|
case bold
|
||||||
case activity
|
case activity
|
||||||
|
|
||||||
var barButtonItemStyle: UIBarButtonItemStyle {
|
public var barButtonItemStyle: UIBarButtonItem.Style {
|
||||||
switch self {
|
switch self {
|
||||||
case .regular, .activity:
|
case .regular, .activity:
|
||||||
return .plain
|
return .plain
|
||||||
case .bold:
|
case .bold:
|
||||||
return .done
|
return .done
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListNavigationButtonContentIcon {
|
public enum ItemListNavigationButtonContentIcon {
|
||||||
case search
|
case search
|
||||||
case add
|
case add
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListNavigationButtonContent: Equatable {
|
public enum ItemListNavigationButtonContent: Equatable {
|
||||||
case none
|
case none
|
||||||
case text(String)
|
case text(String)
|
||||||
case icon(ItemListNavigationButtonContentIcon)
|
case icon(ItemListNavigationButtonContentIcon)
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct ItemListNavigationButton {
|
||||||
|
public let content: ItemListNavigationButtonContent
|
||||||
|
public let style: ItemListNavigationButtonStyle
|
||||||
|
public let enabled: Bool
|
||||||
|
public let action: () -> Void
|
||||||
|
|
||||||
static func ==(lhs: ItemListNavigationButtonContent, rhs: ItemListNavigationButtonContent) -> Bool {
|
public init(content: ItemListNavigationButtonContent, style: ItemListNavigationButtonStyle, enabled: Bool, action: @escaping () -> Void) {
|
||||||
switch lhs {
|
self.content = content
|
||||||
case .none:
|
self.style = style
|
||||||
if case .none = rhs {
|
self.enabled = enabled
|
||||||
return true
|
self.action = action
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .text(value):
|
|
||||||
if case .text(value) = rhs {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .icon(value):
|
|
||||||
if case .icon(value) = rhs {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemListNavigationButton {
|
public struct ItemListBackButton: Equatable {
|
||||||
let content: ItemListNavigationButtonContent
|
public let title: String
|
||||||
let style: ItemListNavigationButtonStyle
|
|
||||||
let enabled: Bool
|
|
||||||
let action: () -> Void
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ItemListBackButton: Equatable {
|
|
||||||
let title: String
|
|
||||||
|
|
||||||
static func ==(lhs: ItemListBackButton, rhs: ItemListBackButton) -> Bool {
|
public init(title: String) {
|
||||||
return lhs.title == rhs.title
|
self.title = title
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListControllerTitle: Equatable {
|
public enum ItemListControllerTitle: Equatable {
|
||||||
case text(String)
|
case text(String)
|
||||||
case sectionControl([String], Int)
|
case sectionControl([String], Int)
|
||||||
|
|
||||||
static func ==(lhs: ItemListControllerTitle, rhs: ItemListControllerTitle) -> Bool {
|
|
||||||
switch lhs {
|
|
||||||
case let .text(text):
|
|
||||||
if case .text(text) = rhs {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case let .sectionControl(lhsSection, lhsIndex):
|
|
||||||
if case let .sectionControl(rhsSection, rhsIndex) = rhs, lhsSection == rhsSection, lhsIndex == rhsIndex {
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListControllerTabBarItem: Equatable {
|
public final class ItemListControllerTabBarItem: Equatable {
|
||||||
let title: String
|
let title: String
|
||||||
let image: UIImage?
|
let image: UIImage?
|
||||||
let selectedImage: UIImage?
|
let selectedImage: UIImage?
|
||||||
let tintImages: Bool
|
let tintImages: Bool
|
||||||
let badgeValue: String?
|
let badgeValue: String?
|
||||||
|
|
||||||
init(title: String, image: UIImage?, selectedImage: UIImage?, tintImages: Bool = true, badgeValue: String? = nil) {
|
public init(title: String, image: UIImage?, selectedImage: UIImage?, tintImages: Bool = true, badgeValue: String? = nil) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.image = image
|
self.image = image
|
||||||
self.selectedImage = selectedImage
|
self.selectedImage = selectedImage
|
||||||
@ -106,12 +75,12 @@ final class ItemListControllerTabBarItem: Equatable {
|
|||||||
self.badgeValue = badgeValue
|
self.badgeValue = badgeValue
|
||||||
}
|
}
|
||||||
|
|
||||||
static func ==(lhs: ItemListControllerTabBarItem, rhs: ItemListControllerTabBarItem) -> Bool {
|
public static func ==(lhs: ItemListControllerTabBarItem, rhs: ItemListControllerTabBarItem) -> Bool {
|
||||||
return lhs.title == rhs.title && lhs.image === rhs.image && lhs.selectedImage === rhs.selectedImage && lhs.tintImages == rhs.tintImages && lhs.badgeValue == rhs.badgeValue
|
return lhs.title == rhs.title && lhs.image === rhs.image && lhs.selectedImage === rhs.selectedImage && lhs.tintImages == rhs.tintImages && lhs.badgeValue == rhs.badgeValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemListControllerState {
|
public struct ItemListControllerState {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let title: ItemListControllerTitle
|
let title: ItemListControllerTitle
|
||||||
let leftNavigationButton: ItemListNavigationButton?
|
let leftNavigationButton: ItemListNavigationButton?
|
||||||
@ -121,7 +90,7 @@ struct ItemListControllerState {
|
|||||||
let tabBarItem: ItemListControllerTabBarItem?
|
let tabBarItem: ItemListControllerTabBarItem?
|
||||||
let animateChanges: Bool
|
let animateChanges: Bool
|
||||||
|
|
||||||
init(theme: PresentationTheme, title: ItemListControllerTitle, leftNavigationButton: ItemListNavigationButton?, rightNavigationButton: ItemListNavigationButton?, secondaryRightNavigationButton: ItemListNavigationButton? = nil, backNavigationButton: ItemListBackButton?, tabBarItem: ItemListControllerTabBarItem? = nil, animateChanges: Bool = true) {
|
public init(theme: PresentationTheme, title: ItemListControllerTitle, leftNavigationButton: ItemListNavigationButton?, rightNavigationButton: ItemListNavigationButton?, secondaryRightNavigationButton: ItemListNavigationButton? = nil, backNavigationButton: ItemListBackButton?, tabBarItem: ItemListControllerTabBarItem? = nil, animateChanges: Bool = true) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.title = title
|
self.title = title
|
||||||
self.leftNavigationButton = leftNavigationButton
|
self.leftNavigationButton = leftNavigationButton
|
||||||
@ -133,7 +102,7 @@ struct ItemListControllerState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutResponder, PresentableController {
|
open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutResponder, PresentableController {
|
||||||
private let state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>
|
private let state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>
|
||||||
|
|
||||||
private var leftNavigationButtonTitleAndStyle: (ItemListNavigationButtonContent, ItemListNavigationButtonStyle)?
|
private var leftNavigationButtonTitleAndStyle: (ItemListNavigationButtonContent, ItemListNavigationButtonStyle)?
|
||||||
@ -149,20 +118,20 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
private var didPlayPresentationAnimation = false
|
private var didPlayPresentationAnimation = false
|
||||||
private(set) var didAppearOnce = false
|
public private(set) var didAppearOnce = false
|
||||||
var didAppear: ((Bool) -> Void)?
|
public var didAppear: ((Bool) -> Void)?
|
||||||
private var isDismissed = false
|
private var isDismissed = false
|
||||||
|
|
||||||
var titleControlValueChanged: ((Int) -> Void)?
|
public var titleControlValueChanged: ((Int) -> Void)?
|
||||||
|
|
||||||
private var tabBarItemDisposable: Disposable?
|
private var tabBarItemDisposable: Disposable?
|
||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
override var ready: Promise<Bool> {
|
override open var ready: Promise<Bool> {
|
||||||
return self._ready
|
return self._ready
|
||||||
}
|
}
|
||||||
|
|
||||||
var experimentalSnapScrollToItem: Bool = false {
|
public var experimentalSnapScrollToItem: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.experimentalSnapScrollToItem = self.experimentalSnapScrollToItem
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.experimentalSnapScrollToItem = self.experimentalSnapScrollToItem
|
||||||
@ -170,7 +139,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableInteractiveDismiss = false {
|
public var enableInteractiveDismiss = false {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).enableInteractiveDismiss = self.enableInteractiveDismiss
|
(self.displayNode as! ItemListControllerNode<Entry>).enableInteractiveDismiss = self.enableInteractiveDismiss
|
||||||
@ -178,7 +147,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibleEntriesUpdated: ((ItemListNodeVisibleEntries<Entry>) -> Void)? {
|
public var visibleEntriesUpdated: ((ItemListNodeVisibleEntries<Entry>) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).visibleEntriesUpdated = self.visibleEntriesUpdated
|
(self.displayNode as! ItemListControllerNode<Entry>).visibleEntriesUpdated = self.visibleEntriesUpdated
|
||||||
@ -186,7 +155,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? {
|
public var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).visibleBottomContentOffsetChanged = self.visibleBottomContentOffsetChanged
|
(self.displayNode as! ItemListControllerNode<Entry>).visibleBottomContentOffsetChanged = self.visibleBottomContentOffsetChanged
|
||||||
@ -194,14 +163,15 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentOffsetChanged: ((ListViewVisibleContentOffset, Bool) -> Void)? {
|
public var contentOffsetChanged: ((ListViewVisibleContentOffset, Bool) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).contentOffsetChanged = self.contentOffsetChanged
|
(self.displayNode as! ItemListControllerNode<Entry>).contentOffsetChanged = self.contentOffsetChanged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var contentScrollingEnded: ((ListView) -> Bool)? {
|
|
||||||
|
public var contentScrollingEnded: ((ListView) -> Bool)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).contentScrollingEnded = self.contentScrollingEnded
|
(self.displayNode as! ItemListControllerNode<Entry>).contentScrollingEnded = self.contentScrollingEnded
|
||||||
@ -209,7 +179,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var searchActivated: ((Bool) -> Void)? {
|
public var searchActivated: ((Bool) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).searchActivated = self.searchActivated
|
(self.displayNode as! ItemListControllerNode<Entry>).searchActivated = self.searchActivated
|
||||||
@ -217,9 +187,9 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var willScrollToTop: (() -> Void)?
|
public var willScrollToTop: (() -> Void)?
|
||||||
|
|
||||||
var reorderEntry: ((Int, Int, [Entry]) -> Void)? {
|
public var reorderEntry: ((Int, Int, [Entry]) -> Void)? {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).reorderEntry = self.reorderEntry
|
(self.displayNode as! ItemListControllerNode<Entry>).reorderEntry = self.reorderEntry
|
||||||
@ -227,22 +197,22 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var previewItemWithTag: ((ItemListItemTag) -> UIViewController?)?
|
public var previewItemWithTag: ((ItemListItemTag) -> UIViewController?)?
|
||||||
var commitPreview: ((UIViewController) -> Void)?
|
public var commitPreview: ((UIViewController) -> Void)?
|
||||||
|
|
||||||
var willDisappear: ((Bool) -> Void)?
|
public var willDisappear: ((Bool) -> Void)?
|
||||||
var didDisappear: ((Bool) -> Void)?
|
public var didDisappear: ((Bool) -> Void)?
|
||||||
|
|
||||||
convenience init(context: AccountContext, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
convenience public init(context: AccountContext, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
||||||
self.init(sharedContext: context.sharedContext, state: state, tabBarItem: tabBarItem)
|
self.init(sharedContext: context.genericSharedContext, state: state, tabBarItem: tabBarItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
convenience init(sharedContext: SharedAccountContext, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
convenience public init(sharedContext: SharedAccountContext, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>? = nil) {
|
||||||
let presentationData = sharedContext.currentPresentationData.with { $0 }
|
let presentationData = sharedContext.currentPresentationData.with { $0 }
|
||||||
self.init(theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: sharedContext.presentationData |> map { ($0.theme, $0.strings) }, state: state, tabBarItem: tabBarItem)
|
self.init(theme: presentationData.theme, strings: presentationData.strings, updatedPresentationData: sharedContext.presentationData |> map { ($0.theme, $0.strings) }, state: state, tabBarItem: tabBarItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
init(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>?) {
|
public init(theme: PresentationTheme, strings: PresentationStrings, updatedPresentationData: Signal<(theme: PresentationTheme, strings: PresentationStrings), NoError>, state: Signal<(ItemListControllerState, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>, tabBarItem: Signal<ItemListControllerTabBarItem, NoError>?) {
|
||||||
self.state = state
|
self.state = state
|
||||||
|
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
@ -276,7 +246,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
required public init(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +254,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
self.tabBarItemDisposable?.dispose()
|
self.tabBarItemDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func loadDisplayNode() {
|
override open func loadDisplayNode() {
|
||||||
let previousControllerState = Atomic<ItemListControllerState?>(value: nil)
|
let previousControllerState = Atomic<ItemListControllerState?>(value: nil)
|
||||||
let nodeState = self.state
|
let nodeState = self.state
|
||||||
|> deliverOnMainQueue
|
|> deliverOnMainQueue
|
||||||
@ -458,7 +428,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
self._ready.set((self.displayNode as! ItemListControllerNode<Entry>).ready)
|
self._ready.set((self.displayNode as! ItemListControllerNode<Entry>).ready)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override open func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
self.validLayout = layout
|
self.validLayout = layout
|
||||||
@ -478,13 +448,13 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
self.navigationButtonActions.secondaryRight?()
|
self.navigationButtonActions.secondaryRight?()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool) {
|
override open func viewDidAppear(_ animated: Bool) {
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
|
|
||||||
self.viewDidAppear(completion: {})
|
self.viewDidAppear(completion: {})
|
||||||
}
|
}
|
||||||
|
|
||||||
func viewDidAppear(completion: @escaping () -> Void) {
|
public func viewDidAppear(completion: @escaping () -> Void) {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.preloadPages = true
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.preloadPages = true
|
||||||
|
|
||||||
if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments, !self.didPlayPresentationAnimation {
|
if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments, !self.didPlayPresentationAnimation {
|
||||||
@ -506,26 +476,26 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
self.didAppear?(firstTime)
|
self.didAppear?(firstTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillDisappear(_ animated: Bool) {
|
override open func viewWillDisappear(_ animated: Bool) {
|
||||||
super.viewWillDisappear(animated)
|
super.viewWillDisappear(animated)
|
||||||
|
|
||||||
self.willDisappear?(animated)
|
self.willDisappear?(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewDidDisappear(_ animated: Bool) {
|
override open func viewDidDisappear(_ animated: Bool) {
|
||||||
super.viewDidDisappear(animated)
|
super.viewDidDisappear(animated)
|
||||||
|
|
||||||
self.didDisappear?(animated)
|
self.didDisappear?(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func dismiss(completion: (() -> Void)? = nil) {
|
override open func dismiss(completion: (() -> Void)? = nil) {
|
||||||
if !self.isDismissed {
|
if !self.isDismissed {
|
||||||
self.isDismissed = true
|
self.isDismissed = true
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).animateOut(completion: completion)
|
(self.displayNode as! ItemListControllerNode<Entry>).animateOut(completion: completion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func frameForItemNode(_ predicate: (ListViewItemNode) -> Bool) -> CGRect? {
|
public func frameForItemNode(_ predicate: (ListViewItemNode) -> Bool) -> CGRect? {
|
||||||
var result: CGRect?
|
var result: CGRect?
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? ListViewItemNode {
|
if let itemNode = itemNode as? ListViewItemNode {
|
||||||
@ -537,7 +507,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func forEachItemNode(_ f: (ListViewItemNode) -> Void) {
|
public func forEachItemNode(_ f: (ListViewItemNode) -> Void) {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.forEachItemNode { itemNode in
|
||||||
if let itemNode = itemNode as? ListViewItemNode {
|
if let itemNode = itemNode as? ListViewItemNode {
|
||||||
f(itemNode)
|
f(itemNode)
|
||||||
@ -545,15 +515,15 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureItemNodeVisible(_ itemNode: ListViewItemNode) {
|
public func ensureItemNodeVisible(_ itemNode: ListViewItemNode) {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.ensureItemNodeVisible(itemNode)
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.ensureItemNodeVisible(itemNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func afterLayout(_ f: @escaping () -> Void) {
|
public func afterLayout(_ f: @escaping () -> Void) {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).afterLayout(f)
|
(self.displayNode as! ItemListControllerNode<Entry>).afterLayout(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? {
|
public func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? {
|
||||||
guard let layout = self.validLayout else {
|
guard let layout = self.validLayout else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -590,16 +560,16 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShortcutR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func clearItemNodesHighlight(animated: Bool = false) {
|
public func clearItemNodesHighlight(animated: Bool = false) {
|
||||||
(self.displayNode as! ItemListControllerNode<Entry>).listNode.clearHighlightAnimated(animated)
|
(self.displayNode as! ItemListControllerNode<Entry>).listNode.clearHighlightAnimated(animated)
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewingCommit(_ viewControllerToCommit: UIViewController) {
|
public func previewingCommit(_ viewControllerToCommit: UIViewController) {
|
||||||
self.commitPreview?(viewControllerToCommit)
|
self.commitPreview?(viewControllerToCommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var keyShortcuts: [KeyShortcut] {
|
public var keyShortcuts: [KeyShortcut] {
|
||||||
return [KeyShortcut(input: UIKeyInputEscape, action: { [weak self] in
|
return [KeyShortcut(input: UIKeyCommand.inputEscape, action: { [weak self] in
|
||||||
if !(self?.navigationController?.topViewController is TabBarController) {
|
if !(self?.navigationController?.topViewController is TabBarController) {
|
||||||
_ = self?.navigationBar?.executeBack()
|
_ = self?.navigationBar?.executeBack()
|
||||||
}
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import Display
|
||||||
|
|
||||||
|
public protocol ItemListControllerEmptyStateItem {
|
||||||
|
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool
|
||||||
|
func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode
|
||||||
|
}
|
||||||
|
|
||||||
|
open class ItemListControllerEmptyStateItemNode: ASDisplayNode {
|
||||||
|
open func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,10 +5,11 @@ import Display
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramCore
|
import TelegramCore
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import MergeLists
|
||||||
|
|
||||||
typealias ItemListSectionId = Int32
|
public typealias ItemListSectionId = Int32
|
||||||
|
|
||||||
protocol ItemListNodeEntry: Comparable, Identifiable {
|
public protocol ItemListNodeEntry: Comparable, Identifiable {
|
||||||
associatedtype ItemGenerationArguments
|
associatedtype ItemGenerationArguments
|
||||||
|
|
||||||
var section: ItemListSectionId { get }
|
var section: ItemListSectionId { get }
|
||||||
@ -17,7 +18,7 @@ protocol ItemListNodeEntry: Comparable, Identifiable {
|
|||||||
func item(_ arguments: ItemGenerationArguments) -> ListViewItem
|
func item(_ arguments: ItemGenerationArguments) -> ListViewItem
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ItemListNodeEntry {
|
public extension ItemListNodeEntry {
|
||||||
var tag: ItemListItemTag? { return nil }
|
var tag: ItemListItemTag? { return nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ private func preparedItemListNodeEntryTransition<Entry: ItemListNodeEntry>(from
|
|||||||
return ItemListNodeEntryTransition(deletions: deletions, insertions: insertions, updates: updates)
|
return ItemListNodeEntryTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListStyle {
|
public enum ItemListStyle {
|
||||||
case plain
|
case plain
|
||||||
case blocks
|
case blocks
|
||||||
}
|
}
|
||||||
@ -59,7 +60,7 @@ private struct ItemListNodeTransition<Entry: ItemListNodeEntry> {
|
|||||||
let scrollEnabled: Bool
|
let scrollEnabled: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemListNodeState<Entry: ItemListNodeEntry> {
|
public struct ItemListNodeState<Entry: ItemListNodeEntry> {
|
||||||
let entries: [Entry]
|
let entries: [Entry]
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let emptyStateItem: ItemListControllerEmptyStateItem?
|
let emptyStateItem: ItemListControllerEmptyStateItem?
|
||||||
@ -71,7 +72,7 @@ struct ItemListNodeState<Entry: ItemListNodeEntry> {
|
|||||||
let ensureVisibleItemTag: ItemListItemTag?
|
let ensureVisibleItemTag: ItemListItemTag?
|
||||||
let initialScrollToItem: ListViewScrollToItem?
|
let initialScrollToItem: ListViewScrollToItem?
|
||||||
|
|
||||||
init(entries: [Entry], style: ItemListStyle, focusItemTag: ItemListItemTag? = nil, ensureVisibleItemTag: ItemListItemTag? = nil, emptyStateItem: ItemListControllerEmptyStateItem? = nil, searchItem: ItemListControllerSearch? = nil, initialScrollToItem: ListViewScrollToItem? = nil, crossfadeState: Bool = false, animateChanges: Bool = true, scrollEnabled: Bool = true) {
|
public init(entries: [Entry], style: ItemListStyle, focusItemTag: ItemListItemTag? = nil, ensureVisibleItemTag: ItemListItemTag? = nil, emptyStateItem: ItemListControllerEmptyStateItem? = nil, searchItem: ItemListControllerSearch? = nil, initialScrollToItem: ListViewScrollToItem? = nil, crossfadeState: Bool = false, animateChanges: Bool = true, scrollEnabled: Bool = true) {
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
self.style = style
|
self.style = style
|
||||||
self.emptyStateItem = emptyStateItem
|
self.emptyStateItem = emptyStateItem
|
||||||
@ -93,21 +94,21 @@ private final class ItemListNodeOpaqueState<Entry: ItemListNodeEntry> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListNodeVisibleEntries<Entry: ItemListNodeEntry>: Sequence {
|
public final class ItemListNodeVisibleEntries<Entry: ItemListNodeEntry>: Sequence {
|
||||||
let iterate: () -> Entry?
|
let iterate: () -> Entry?
|
||||||
|
|
||||||
init(iterate: @escaping () -> Entry?) {
|
init(iterate: @escaping () -> Entry?) {
|
||||||
self.iterate = iterate
|
self.iterate = iterate
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeIterator() -> AnyIterator<Entry> {
|
public func makeIterator() -> AnyIterator<Entry> {
|
||||||
return AnyIterator { () -> Entry? in
|
return AnyIterator { () -> Entry? in
|
||||||
return self.iterate()
|
return self.iterate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayerView, PreviewingHostView {
|
public final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayerView, PreviewingHostView {
|
||||||
var onLayout: (() -> Void)?
|
var onLayout: (() -> Void)?
|
||||||
|
|
||||||
init(controller: ItemListController<Entry>?) {
|
init(controller: ItemListController<Entry>?) {
|
||||||
@ -120,7 +121,7 @@ final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayer
|
|||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
override public func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
self.onLayout?()
|
self.onLayout?()
|
||||||
@ -129,7 +130,7 @@ final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayer
|
|||||||
private var inHitTest = false
|
private var inHitTest = false
|
||||||
var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)?
|
var hitTestImpl: ((CGPoint, UIEvent?) -> UIView?)?
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
if self.inHitTest {
|
if self.inHitTest {
|
||||||
return super.hitTest(point, with: event)
|
return super.hitTest(point, with: event)
|
||||||
} else {
|
} else {
|
||||||
@ -140,7 +141,7 @@ final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var previewingDelegate: PreviewingHostViewDelegate? {
|
public var previewingDelegate: PreviewingHostViewDelegate? {
|
||||||
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
|
return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in
|
||||||
return self?.controller?.previewingController(from: sourceView, for: point)
|
return self?.controller?.previewingController(from: sourceView, for: point)
|
||||||
}, commitController: { [weak self] controller in
|
}, commitController: { [weak self] controller in
|
||||||
@ -151,16 +152,16 @@ final class ItemListControllerNodeView<Entry: ItemListNodeEntry>: UITracingLayer
|
|||||||
weak var controller: ItemListController<Entry>?
|
weak var controller: ItemListController<Entry>?
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollViewDelegate {
|
open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollViewDelegate {
|
||||||
private var _ready = ValuePromise<Bool>()
|
private var _ready = ValuePromise<Bool>()
|
||||||
public var ready: Signal<Bool, NoError> {
|
open var ready: Signal<Bool, NoError> {
|
||||||
return self._ready.get()
|
return self._ready.get()
|
||||||
}
|
}
|
||||||
private var didSetReady = false
|
private var didSetReady = false
|
||||||
|
|
||||||
private let navigationBar: NavigationBar
|
private let navigationBar: NavigationBar
|
||||||
|
|
||||||
let listNode: ListView
|
public let listNode: ListView
|
||||||
private var emptyStateItem: ItemListControllerEmptyStateItem?
|
private var emptyStateItem: ItemListControllerEmptyStateItem?
|
||||||
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
|
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
|
||||||
|
|
||||||
@ -180,23 +181,23 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
|
|
||||||
private var afterLayoutActions: [() -> Void] = []
|
private var afterLayoutActions: [() -> Void] = []
|
||||||
|
|
||||||
let updateNavigationOffset: (CGFloat) -> Void
|
public let updateNavigationOffset: (CGFloat) -> Void
|
||||||
var dismiss: (() -> Void)?
|
public var dismiss: (() -> Void)?
|
||||||
|
|
||||||
var visibleEntriesUpdated: ((ItemListNodeVisibleEntries<Entry>) -> Void)?
|
public var visibleEntriesUpdated: ((ItemListNodeVisibleEntries<Entry>) -> Void)?
|
||||||
var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
public var visibleBottomContentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
||||||
var contentOffsetChanged: ((ListViewVisibleContentOffset, Bool) -> Void)?
|
public var contentOffsetChanged: ((ListViewVisibleContentOffset, Bool) -> Void)?
|
||||||
var contentScrollingEnded: ((ListView) -> Bool)?
|
public var contentScrollingEnded: ((ListView) -> Bool)?
|
||||||
var searchActivated: ((Bool) -> Void)?
|
public var searchActivated: ((Bool) -> Void)?
|
||||||
var reorderEntry: ((Int, Int, [Entry]) -> Void)?
|
public var reorderEntry: ((Int, Int, [Entry]) -> Void)?
|
||||||
var requestLayout: ((ContainedViewLayoutTransition) -> Void)?
|
public var requestLayout: ((ContainedViewLayoutTransition) -> Void)?
|
||||||
|
|
||||||
var enableInteractiveDismiss = false {
|
public var enableInteractiveDismiss = false {
|
||||||
didSet {
|
didSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(controller: ItemListController<Entry>?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, state: Signal<(PresentationTheme, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>) {
|
public init(controller: ItemListController<Entry>?, navigationBar: NavigationBar, updateNavigationOffset: @escaping (CGFloat) -> Void, state: Signal<(PresentationTheme, (ItemListNodeState<Entry>, Entry.ItemGenerationArguments)), NoError>) {
|
||||||
self.navigationBar = navigationBar
|
self.navigationBar = navigationBar
|
||||||
self.updateNavigationOffset = updateNavigationOffset
|
self.updateNavigationOffset = updateNavigationOffset
|
||||||
|
|
||||||
@ -287,7 +288,7 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
self.transitionDisposable.dispose()
|
self.transitionDisposable.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override open func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
(self.view as? ItemListControllerNodeView<Entry>)?.onLayout = { [weak self] in
|
(self.view as? ItemListControllerNodeView<Entry>)?.onLayout = { [weak self] in
|
||||||
@ -308,14 +309,14 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateIn(completion: (() -> Void)? = nil) {
|
open func animateIn(completion: (() -> Void)? = nil) {
|
||||||
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, completion: { _ in
|
||||||
completion?()
|
completion?()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateOut(completion: (() -> Void)? = nil) {
|
open func animateOut(completion: (() -> Void)? = nil) {
|
||||||
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { [weak self] _ in
|
self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.dismiss?()
|
strongSelf.dismiss?()
|
||||||
}
|
}
|
||||||
@ -323,7 +324,7 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
open func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
var duration: Double = 0.0
|
var duration: Double = 0.0
|
||||||
var curve: UInt = 0
|
var curve: UInt = 0
|
||||||
switch transition {
|
switch transition {
|
||||||
@ -601,15 +602,15 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollToTop() {
|
open func scrollToTop() {
|
||||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: ListViewScrollToItem(index: 0, position: .top(0.0), animated: true, curve: .Default(duration: nil), directionHint: .Up), updateSizeAndInsets: nil, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||||
self.searchNode?.scrollToTop()
|
self.searchNode?.scrollToTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
|
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
|
||||||
|
|
||||||
let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 50.0))
|
//let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 50.0))
|
||||||
|
|
||||||
self.updateNavigationOffset(-distanceFromEquilibrium)
|
self.updateNavigationOffset(-distanceFromEquilibrium)
|
||||||
|
|
||||||
@ -618,7 +619,7 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||||
targetContentOffset.pointee = scrollView.contentOffset
|
targetContentOffset.pointee = scrollView.contentOffset
|
||||||
|
|
||||||
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
|
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
|
||||||
@ -628,7 +629,7 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
if let searchNode = self.searchNode {
|
if let searchNode = self.searchNode {
|
||||||
if let result = searchNode.hitTest(point, with: event) {
|
if let result = searchNode.hitTest(point, with: event) {
|
||||||
return result
|
return result
|
||||||
@ -638,7 +639,7 @@ class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UIScrollV
|
|||||||
return super.hitTest(point, with: event)
|
return super.hitTest(point, with: event)
|
||||||
}
|
}
|
||||||
|
|
||||||
func afterLayout(_ f: @escaping () -> Void) {
|
open func afterLayout(_ f: @escaping () -> Void) {
|
||||||
self.afterLayoutActions.append(f)
|
self.afterLayoutActions.append(f)
|
||||||
self.view.setNeedsLayout()
|
self.view.setNeedsLayout()
|
||||||
}
|
}
|
||||||
@ -3,40 +3,37 @@ import UIKit
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
|
||||||
protocol ItemListControllerSearchNavigationContentNode {
|
public protocol ItemListControllerSearchNavigationContentNode {
|
||||||
func activate()
|
func activate()
|
||||||
func deactivate()
|
func deactivate()
|
||||||
|
|
||||||
func setQueryUpdated(_ f: @escaping (String) -> Void)
|
func setQueryUpdated(_ f: @escaping (String) -> Void)
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol ItemListControllerSearch {
|
public protocol ItemListControllerSearch {
|
||||||
func isEqual(to: ItemListControllerSearch) -> Bool
|
func isEqual(to: ItemListControllerSearch) -> Bool
|
||||||
func titleContentNode(current: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> NavigationBarContentNode & ItemListControllerSearchNavigationContentNode
|
func titleContentNode(current: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> NavigationBarContentNode & ItemListControllerSearchNavigationContentNode
|
||||||
func node(current: ItemListControllerSearchNode?, titleContentNode: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> ItemListControllerSearchNode
|
func node(current: ItemListControllerSearchNode?, titleContentNode: (NavigationBarContentNode & ItemListControllerSearchNavigationContentNode)?) -> ItemListControllerSearchNode
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListControllerSearchNode: ASDisplayNode {
|
open class ItemListControllerSearchNode: ASDisplayNode {
|
||||||
func activate() {
|
open func activate() {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivate() {
|
open func deactivate() {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { [weak self] _ in
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, completion: { [weak self] _ in
|
||||||
self?.removeFromSupernode()
|
self?.removeFromSupernode()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollToTop() {
|
open func scrollToTop() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryUpdated(_ query: String) {
|
open func queryUpdated(_ query: String) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
open func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
final class ItemListControllerSegmentedTitleView: UIView {
|
public final class ItemListControllerSegmentedTitleView: UIView {
|
||||||
var segments: [String] {
|
public var segments: [String] {
|
||||||
didSet {
|
didSet {
|
||||||
if self.segments != oldValue {
|
if self.segments != oldValue {
|
||||||
self.control.removeAllSegments()
|
self.control.removeAllSegments()
|
||||||
@ -16,7 +16,7 @@ final class ItemListControllerSegmentedTitleView: UIView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var index: Int {
|
public var index: Int {
|
||||||
didSet {
|
didSet {
|
||||||
self.control.selectedSegmentIndex = self.index
|
self.control.selectedSegmentIndex = self.index
|
||||||
}
|
}
|
||||||
@ -24,15 +24,15 @@ final class ItemListControllerSegmentedTitleView: UIView {
|
|||||||
|
|
||||||
private let control: UISegmentedControl
|
private let control: UISegmentedControl
|
||||||
|
|
||||||
var indexUpdated: ((Int) -> Void)?
|
public var indexUpdated: ((Int) -> Void)?
|
||||||
|
|
||||||
var color: UIColor {
|
public var color: UIColor {
|
||||||
didSet {
|
didSet {
|
||||||
self.control.tintColor = self.color
|
self.control.tintColor = self.color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(segments: [String], index: Int, color: UIColor) {
|
public init(segments: [String], index: Int, color: UIColor) {
|
||||||
self.segments = segments
|
self.segments = segments
|
||||||
self.index = index
|
self.index = index
|
||||||
self.color = color
|
self.color = color
|
||||||
@ -47,11 +47,11 @@ final class ItemListControllerSegmentedTitleView: UIView {
|
|||||||
self.control.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
self.control.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
required init?(coder aDecoder: NSCoder) {
|
required public init?(coder aDecoder: NSCoder) {
|
||||||
fatalError("init(coder:) has not been implemented")
|
fatalError("init(coder:) has not been implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
override public func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
@ -61,7 +61,7 @@ final class ItemListControllerSegmentedTitleView: UIView {
|
|||||||
self.control.frame = CGRect(origin: CGPoint(x: floor((size.width - controlSize.width) / 2.0), y: floor((size.height - controlSize.height) / 2.0)), size: controlSize)
|
self.control.frame = CGRect(origin: CGPoint(x: floor((size.width - controlSize.width) / 2.0), y: floor((size.height - controlSize.height) / 2.0)), size: controlSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func indexChanged() {
|
@objc private func indexChanged() {
|
||||||
self.indexUpdated?(self.control.selectedSegmentIndex)
|
self.indexUpdated?(self.control.selectedSegmentIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,11 +4,11 @@ import AsyncDisplayKit
|
|||||||
import Display
|
import Display
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
final class ItemListEditableControlNode: ASDisplayNode {
|
public final class ItemListEditableControlNode: ASDisplayNode {
|
||||||
var tapped: (() -> Void)?
|
public var tapped: (() -> Void)?
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
|
|
||||||
override init() {
|
override public init() {
|
||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
self.iconNode.isLayerBacked = true
|
self.iconNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -17,13 +17,13 @@ final class ItemListEditableControlNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.iconNode)
|
self.addSubnode(self.iconNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||||
}
|
}
|
||||||
|
|
||||||
static func asyncLayout(_ node: ItemListEditableControlNode?) -> (_ height: CGFloat, _ theme: PresentationTheme, _ hidden: Bool) -> (CGSize, () -> ItemListEditableControlNode) {
|
public static func asyncLayout(_ node: ItemListEditableControlNode?) -> (_ height: CGFloat, _ theme: PresentationTheme, _ hidden: Bool) -> (CGSize, () -> ItemListEditableControlNode) {
|
||||||
return { height, theme, hidden in
|
return { height, theme, hidden in
|
||||||
let image = PresentationResourcesItemList.itemListDeleteIndicatorIcon(theme)
|
let image = PresentationResourcesItemList.itemListDeleteIndicatorIcon(theme)
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ final class ItemListEditableControlNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
self.tapped?()
|
self.tapped?()
|
||||||
}
|
}
|
||||||
@ -4,11 +4,11 @@ import AsyncDisplayKit
|
|||||||
import Display
|
import Display
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
final class ItemListEditableReorderControlNode: ASDisplayNode {
|
public final class ItemListEditableReorderControlNode: ASDisplayNode {
|
||||||
var tapped: (() -> Void)?
|
public var tapped: (() -> Void)?
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
|
|
||||||
override init() {
|
override public init() {
|
||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
self.iconNode.displayWithoutProcessing = true
|
self.iconNode.displayWithoutProcessing = true
|
||||||
self.iconNode.displaysAsynchronously = false
|
self.iconNode.displaysAsynchronously = false
|
||||||
@ -19,7 +19,7 @@ final class ItemListEditableReorderControlNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.iconNode)
|
self.addSubnode(self.iconNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func asyncLayout(_ node: ItemListEditableReorderControlNode?) -> (_ height: CGFloat, _ theme: PresentationTheme) -> (CGSize, (Bool) -> ItemListEditableReorderControlNode) {
|
public static func asyncLayout(_ node: ItemListEditableReorderControlNode?) -> (_ height: CGFloat, _ theme: PresentationTheme) -> (CGSize, (Bool) -> ItemListEditableReorderControlNode) {
|
||||||
return { height, theme in
|
return { height, theme in
|
||||||
let image = PresentationResourcesItemList.itemListReorderIndicatorIcon(theme)
|
let image = PresentationResourcesItemList.itemListReorderIndicatorIcon(theme)
|
||||||
|
|
||||||
@ -2,57 +2,62 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
|
|
||||||
protocol ItemListItemTag {
|
public protocol ItemListItemTag {
|
||||||
func isEqual(to other: ItemListItemTag) -> Bool
|
func isEqual(to other: ItemListItemTag) -> Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol ItemListItem {
|
public protocol ItemListItem {
|
||||||
var sectionId: ItemListSectionId { get }
|
var sectionId: ItemListSectionId { get }
|
||||||
var tag: ItemListItemTag? { get }
|
var tag: ItemListItemTag? { get }
|
||||||
var isAlwaysPlain: Bool { get }
|
var isAlwaysPlain: Bool { get }
|
||||||
var requestsNoInset: Bool { get }
|
var requestsNoInset: Bool { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension ItemListItem {
|
public extension ItemListItem {
|
||||||
var isAlwaysPlain: Bool {
|
public var isAlwaysPlain: Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
public var tag: ItemListItemTag? {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var requestsNoInset: Bool {
|
public var requestsNoInset: Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol ItemListItemNode {
|
public protocol ItemListItemNode {
|
||||||
var tag: ItemListItemTag? { get }
|
var tag: ItemListItemTag? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
protocol ItemListItemFocusableNode {
|
public protocol ItemListItemFocusableNode {
|
||||||
func focus()
|
func focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListInsetWithOtherSection {
|
public enum ItemListInsetWithOtherSection {
|
||||||
case none
|
case none
|
||||||
case full
|
case full
|
||||||
case reduced
|
case reduced
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListNeighbor {
|
public enum ItemListNeighbor {
|
||||||
case none
|
case none
|
||||||
case otherSection(ItemListInsetWithOtherSection)
|
case otherSection(ItemListInsetWithOtherSection)
|
||||||
case sameSection(alwaysPlain: Bool)
|
case sameSection(alwaysPlain: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemListNeighbors {
|
public struct ItemListNeighbors {
|
||||||
var top: ItemListNeighbor
|
public var top: ItemListNeighbor
|
||||||
var bottom: ItemListNeighbor
|
public var bottom: ItemListNeighbor
|
||||||
|
|
||||||
|
public init(top: ItemListNeighbor, bottom: ItemListNeighbor) {
|
||||||
|
self.top = top
|
||||||
|
self.bottom = bottom
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemListNeighbors(item: ItemListItem, topItem: ItemListItem?, bottomItem: ItemListItem?) -> ItemListNeighbors {
|
public func itemListNeighbors(item: ItemListItem, topItem: ItemListItem?, bottomItem: ItemListItem?) -> ItemListNeighbors {
|
||||||
let topNeighbor: ItemListNeighbor
|
let topNeighbor: ItemListNeighbor
|
||||||
if let topItem = topItem {
|
if let topItem = topItem {
|
||||||
if topItem.sectionId != item.sectionId {
|
if topItem.sectionId != item.sectionId {
|
||||||
@ -90,50 +95,50 @@ func itemListNeighbors(item: ItemListItem, topItem: ItemListItem?, bottomItem: I
|
|||||||
} else {
|
} else {
|
||||||
bottomNeighbor = .none
|
bottomNeighbor = .none
|
||||||
}
|
}
|
||||||
|
|
||||||
return ItemListNeighbors(top: topNeighbor, bottom: bottomNeighbor)
|
return ItemListNeighbors(top: topNeighbor, bottom: bottomNeighbor)
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemListNeighborsPlainInsets(_ neighbors: ItemListNeighbors) -> UIEdgeInsets {
|
public func itemListNeighborsPlainInsets(_ neighbors: ItemListNeighbors) -> UIEdgeInsets {
|
||||||
var insets = UIEdgeInsets()
|
var insets = UIEdgeInsets()
|
||||||
switch neighbors.top {
|
switch neighbors.top {
|
||||||
case .otherSection:
|
case .otherSection:
|
||||||
insets.top += 22.0
|
insets.top += 22.0
|
||||||
case .none, .sameSection:
|
case .none, .sameSection:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
switch neighbors.bottom {
|
switch neighbors.bottom {
|
||||||
case .none:
|
case .none:
|
||||||
insets.bottom += 22.0
|
insets.bottom += 22.0
|
||||||
case .otherSection, .sameSection:
|
case .otherSection, .sameSection:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
return insets
|
return insets
|
||||||
}
|
}
|
||||||
|
|
||||||
func itemListNeighborsGroupedInsets(_ neighbors: ItemListNeighbors) -> UIEdgeInsets {
|
public func itemListNeighborsGroupedInsets(_ neighbors: ItemListNeighbors) -> UIEdgeInsets {
|
||||||
let topInset: CGFloat
|
let topInset: CGFloat
|
||||||
switch neighbors.top {
|
switch neighbors.top {
|
||||||
|
case .none:
|
||||||
|
topInset = UIScreenPixel + 35.0
|
||||||
|
case .sameSection:
|
||||||
|
topInset = 0.0
|
||||||
|
case let .otherSection(otherInset):
|
||||||
|
switch otherInset {
|
||||||
case .none:
|
case .none:
|
||||||
topInset = UIScreenPixel + 35.0
|
|
||||||
case .sameSection:
|
|
||||||
topInset = 0.0
|
topInset = 0.0
|
||||||
case let .otherSection(otherInset):
|
case .full:
|
||||||
switch otherInset {
|
topInset = UIScreenPixel + 35.0
|
||||||
case .none:
|
case .reduced:
|
||||||
topInset = 0.0
|
topInset = UIScreenPixel + 16.0
|
||||||
case .full:
|
}
|
||||||
topInset = UIScreenPixel + 35.0
|
|
||||||
case .reduced:
|
|
||||||
topInset = UIScreenPixel + 16.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let bottomInset: CGFloat
|
let bottomInset: CGFloat
|
||||||
switch neighbors.bottom {
|
switch neighbors.bottom {
|
||||||
case .sameSection, .otherSection:
|
case .sameSection, .otherSection:
|
||||||
bottomInset = 0.0
|
bottomInset = 0.0
|
||||||
case .none:
|
case .none:
|
||||||
bottomInset = UIScreenPixel + 35.0
|
bottomInset = UIScreenPixel + 35.0
|
||||||
}
|
}
|
||||||
return UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0)
|
return UIEdgeInsets(top: topInset, left: 0.0, bottom: bottomInset, right: 0.0)
|
||||||
}
|
}
|
||||||
@ -3,19 +3,20 @@ import UIKit
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import ActivityIndicator
|
||||||
|
|
||||||
final class ItemListLoadingIndicatorEmptyStateItem: ItemListControllerEmptyStateItem {
|
public final class ItemListLoadingIndicatorEmptyStateItem: ItemListControllerEmptyStateItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
|
|
||||||
init(theme: PresentationTheme) {
|
public init(theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool {
|
public func isEqual(to: ItemListControllerEmptyStateItem) -> Bool {
|
||||||
return to is ItemListLoadingIndicatorEmptyStateItem
|
return to is ItemListLoadingIndicatorEmptyStateItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode {
|
public func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode {
|
||||||
if let current = current as? ItemListLoadingIndicatorEmptyStateItemNode {
|
if let current = current as? ItemListLoadingIndicatorEmptyStateItemNode {
|
||||||
current.theme = self.theme
|
current.theme = self.theme
|
||||||
return current
|
return current
|
||||||
@ -25,8 +26,8 @@ final class ItemListLoadingIndicatorEmptyStateItem: ItemListControllerEmptyState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyStateItemNode {
|
public final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyStateItemNode {
|
||||||
var theme: PresentationTheme {
|
public var theme: PresentationTheme {
|
||||||
didSet {
|
didSet {
|
||||||
self.indicator.type = .custom(self.theme.list.itemAccentColor, 40.0, 2.0, false)
|
self.indicator.type = .custom(self.theme.list.itemAccentColor, 40.0, 2.0, false)
|
||||||
}
|
}
|
||||||
@ -35,7 +36,7 @@ final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyS
|
|||||||
|
|
||||||
private var validLayout: (ContainerViewLayout, CGFloat)?
|
private var validLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
init(theme: PresentationTheme) {
|
public init(theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.indicator = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 22.0, 2.0, false))
|
self.indicator = ActivityIndicator(type: .custom(theme.list.itemAccentColor, 22.0, 2.0, false))
|
||||||
|
|
||||||
@ -44,7 +45,7 @@ final class ItemListLoadingIndicatorEmptyStateItemNode: ItemListControllerEmptyS
|
|||||||
self.addSubnode(self.indicator)
|
self.addSubnode(self.indicator)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
override public func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.validLayout = (layout, navigationBarHeight)
|
self.validLayout = (layout, navigationBarHeight)
|
||||||
|
|
||||||
var insets = layout.insets(options: [.statusBar])
|
var insets = layout.insets(options: [.statusBar])
|
||||||
@ -2,44 +2,53 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
import AnimationUI
|
||||||
|
|
||||||
enum ItemListRevealOptionIcon: Equatable {
|
public enum ItemListRevealOptionIcon: Equatable {
|
||||||
case none
|
case none
|
||||||
case image(image: UIImage)
|
case image(image: UIImage)
|
||||||
case animation(animation: String, scale: CGFloat, offset: CGFloat, keysToColor: [String]?, flip: Bool)
|
case animation(animation: String, scale: CGFloat, offset: CGFloat, keysToColor: [String]?, flip: Bool)
|
||||||
|
|
||||||
public static func ==(lhs: ItemListRevealOptionIcon, rhs: ItemListRevealOptionIcon) -> Bool {
|
public static func ==(lhs: ItemListRevealOptionIcon, rhs: ItemListRevealOptionIcon) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
case .none:
|
case .none:
|
||||||
if case .none = rhs {
|
if case .none = rhs {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .image(lhsImage):
|
case let .image(lhsImage):
|
||||||
if case let .image(rhsImage) = rhs, lhsImage == rhsImage {
|
if case let .image(rhsImage) = rhs, lhsImage == rhsImage {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
case let .animation(lhsAnimation, lhsScale, lhsOffset, lhsKeysToColor, lhsFlip):
|
case let .animation(lhsAnimation, lhsScale, lhsOffset, lhsKeysToColor, lhsFlip):
|
||||||
if case let .animation(rhsAnimation, rhsScale, rhsOffset, rhsKeysToColor, rhsFlip) = rhs, lhsAnimation == rhsAnimation, lhsScale == rhsScale, lhsOffset == rhsOffset, lhsKeysToColor == rhsKeysToColor, lhsFlip == rhsFlip {
|
if case let .animation(rhsAnimation, rhsScale, rhsOffset, rhsKeysToColor, rhsFlip) = rhs, lhsAnimation == rhsAnimation, lhsScale == rhsScale, lhsOffset == rhsOffset, lhsKeysToColor == rhsKeysToColor, lhsFlip == rhsFlip {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemListRevealOption: Equatable {
|
public struct ItemListRevealOption: Equatable {
|
||||||
let key: Int32
|
public let key: Int32
|
||||||
let title: String
|
public let title: String
|
||||||
let icon: ItemListRevealOptionIcon
|
public let icon: ItemListRevealOptionIcon
|
||||||
let color: UIColor
|
public let color: UIColor
|
||||||
let textColor: UIColor
|
public let textColor: UIColor
|
||||||
|
|
||||||
static func ==(lhs: ItemListRevealOption, rhs: ItemListRevealOption) -> Bool {
|
public init(key: Int32, title: String, icon: ItemListRevealOptionIcon, color: UIColor, textColor: UIColor) {
|
||||||
|
self.key = key
|
||||||
|
self.title = title
|
||||||
|
self.icon = icon
|
||||||
|
self.color = color
|
||||||
|
self.textColor = textColor
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: ItemListRevealOption, rhs: ItemListRevealOption) -> Bool {
|
||||||
if lhs.key != rhs.key {
|
if lhs.key != rhs.key {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -86,33 +95,33 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
|||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: icon == .none ? titleFontWithoutIcon : titleFontWithIcon, textColor: textColor)
|
self.titleNode.attributedText = NSAttributedString(string: title, font: icon == .none ? titleFontWithoutIcon : titleFontWithIcon, textColor: textColor)
|
||||||
|
|
||||||
switch icon {
|
switch icon {
|
||||||
case let .image(image):
|
case let .image(image):
|
||||||
let iconNode = ASImageNode()
|
let iconNode = ASImageNode()
|
||||||
iconNode.image = generateTintedImage(image: image, color: textColor)
|
iconNode.image = generateTintedImage(image: image, color: textColor)
|
||||||
self.iconNode = iconNode
|
self.iconNode = iconNode
|
||||||
self.animationNode = nil
|
self.animationNode = nil
|
||||||
|
|
||||||
case let .animation(animation, scale, offset, keysToColor, flip):
|
case let .animation(animation, scale, offset, keysToColor, flip):
|
||||||
self.iconNode = nil
|
self.iconNode = nil
|
||||||
var colors: [String: UIColor] = [:]
|
var colors: [String: UIColor] = [:]
|
||||||
if let keysToColor = keysToColor {
|
if let keysToColor = keysToColor {
|
||||||
for key in keysToColor {
|
for key in keysToColor {
|
||||||
colors[key] = color
|
colors[key] = color
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.animationNode = AnimationNode(animation: animation, colors: colors, scale: scale)
|
}
|
||||||
if flip {
|
self.animationNode = AnimationNode(animation: animation, colors: colors, scale: scale)
|
||||||
self.animationNode!.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
if flip {
|
||||||
}
|
self.animationNode!.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
|
||||||
self.animationNodeOffset = offset
|
}
|
||||||
self.animationNodeFlip = flip
|
self.animationNodeOffset = offset
|
||||||
break
|
self.animationNodeFlip = flip
|
||||||
|
break
|
||||||
|
|
||||||
case .none:
|
case .none:
|
||||||
self.iconNode = nil
|
self.iconNode = nil
|
||||||
self.animationNode = nil
|
self.animationNode = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
self.addSubnode(self.backgroundNode)
|
||||||
@ -129,7 +138,7 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
|||||||
func setHighlighted(_ highlighted: Bool) {
|
func setHighlighted(_ highlighted: Bool) {
|
||||||
if highlighted {
|
if highlighted {
|
||||||
self.insertSubnode(self.highlightNode, aboveSubnode: self.backgroundNode)
|
self.insertSubnode(self.highlightNode, aboveSubnode: self.backgroundNode)
|
||||||
self.highlightNode.layer.animate(from: 0.0 as NSNumber, to: 1.0 as NSNumber, keyPath: "opacity", timingFunction: kCAMediaTimingFunctionEaseInEaseOut, duration: 0.3)
|
self.highlightNode.layer.animate(from: 0.0 as NSNumber, to: 1.0 as NSNumber, keyPath: "opacity", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.3)
|
||||||
self.highlightNode.alpha = 1.0
|
self.highlightNode.alpha = 1.0
|
||||||
} else {
|
} else {
|
||||||
self.highlightNode.removeFromSupernode()
|
self.highlightNode.removeFromSupernode()
|
||||||
@ -177,10 +186,10 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
|||||||
let titleSize = self.titleNode.calculatedSize
|
let titleSize = self.titleNode.calculatedSize
|
||||||
var contentRect = CGRect(origin: CGPoint(), size: baseSize)
|
var contentRect = CGRect(origin: CGPoint(), size: baseSize)
|
||||||
switch alignment {
|
switch alignment {
|
||||||
case .left:
|
case .left:
|
||||||
contentRect.origin.x = 0.0
|
contentRect.origin.x = 0.0
|
||||||
case .right:
|
case .right:
|
||||||
contentRect.origin.x = extendedWidth - contentRect.width
|
contentRect.origin.x = extendedWidth - contentRect.width
|
||||||
}
|
}
|
||||||
|
|
||||||
if let animationNode = self.animationNode, let imageSize = animationNode.preferredSize() {
|
if let animationNode = self.animationNode, let imageSize = animationNode.preferredSize() {
|
||||||
@ -251,7 +260,7 @@ private final class ItemListRevealOptionNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListRevealOptionsNode: ASDisplayNode {
|
public final class ItemListRevealOptionsNode: ASDisplayNode {
|
||||||
private let optionSelected: (ItemListRevealOption) -> Void
|
private let optionSelected: (ItemListRevealOption) -> Void
|
||||||
private let tapticAction: () -> Void
|
private let tapticAction: () -> Void
|
||||||
|
|
||||||
@ -262,14 +271,14 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
private var revealOffset: CGFloat = 0.0
|
private var revealOffset: CGFloat = 0.0
|
||||||
private var sideInset: CGFloat = 0.0
|
private var sideInset: CGFloat = 0.0
|
||||||
|
|
||||||
init(optionSelected: @escaping (ItemListRevealOption) -> Void, tapticAction: @escaping () -> Void) {
|
public init(optionSelected: @escaping (ItemListRevealOption) -> Void, tapticAction: @escaping () -> Void) {
|
||||||
self.optionSelected = optionSelected
|
self.optionSelected = optionSelected
|
||||||
self.tapticAction = tapticAction
|
self.tapticAction = tapticAction
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let gestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
let gestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))
|
||||||
@ -290,7 +299,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
self.view.addGestureRecognizer(gestureRecognizer)
|
self.view.addGestureRecognizer(gestureRecognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setOptions(_ options: [ItemListRevealOption], isLeft: Bool) {
|
public func setOptions(_ options: [ItemListRevealOption], isLeft: Bool) {
|
||||||
if self.options != options || self.isLeft != isLeft {
|
if self.options != options || self.isLeft != isLeft {
|
||||||
self.options = options
|
self.options = options
|
||||||
self.isLeft = isLeft
|
self.isLeft = isLeft
|
||||||
@ -313,7 +322,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
override public func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
|
||||||
var maxWidth: CGFloat = 0.0
|
var maxWidth: CGFloat = 0.0
|
||||||
for node in self.optionNodes {
|
for node in self.optionNodes {
|
||||||
let nodeSize = node.measure(constrainedSize)
|
let nodeSize = node.measure(constrainedSize)
|
||||||
@ -322,7 +331,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
return CGSize(width: maxWidth * CGFloat(self.optionNodes.count), height: constrainedSize.height)
|
return CGSize(width: maxWidth * CGFloat(self.optionNodes.count), height: constrainedSize.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRevealOffset(offset: CGFloat, sideInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
public func updateRevealOffset(offset: CGFloat, sideInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
self.revealOffset = offset
|
self.revealOffset = offset
|
||||||
self.sideInset = sideInset
|
self.sideInset = sideInset
|
||||||
self.updateNodesLayout(transition: transition)
|
self.updateNodesLayout(transition: transition)
|
||||||
@ -363,7 +372,6 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
while i >= 0 && i < self.optionNodes.count {
|
while i >= 0 && i < self.optionNodes.count {
|
||||||
let node = self.optionNodes[i]
|
let node = self.optionNodes[i]
|
||||||
let nodeWidth = i == (self.optionNodes.count - 1) ? lastNodeWidth : basicNodeWidth
|
let nodeWidth = i == (self.optionNodes.count - 1) ? lastNodeWidth : basicNodeWidth
|
||||||
let defaultAlignment: ItemListRevealOptionAlignment = self.isLeft ? .right : .left
|
|
||||||
var nodeTransition = transition
|
var nodeTransition = transition
|
||||||
var isExpanded = false
|
var isExpanded = false
|
||||||
if (self.isLeft && i == 0) || (!self.isLeft && i == self.optionNodes.count - 1) {
|
if (self.isLeft && i == 0) || (!self.isLeft && i == self.optionNodes.count - 1) {
|
||||||
@ -401,7 +409,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: nodeLeftOffset, y: 0.0), size: CGSize(width: extendedWidth, height: size.height)), completion: { _ in
|
transition.updateFrame(node: node, frame: CGRect(origin: CGPoint(x: nodeLeftOffset, y: 0.0), size: CGSize(width: extendedWidth, height: size.height)), completion: { _ in
|
||||||
completionCount -= 1
|
completionCount -= 1
|
||||||
intermediateCompletion()
|
intermediateCompletion()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
var nodeAlignment: ItemListRevealOptionAlignment
|
var nodeAlignment: ItemListRevealOptionAlignment
|
||||||
@ -425,7 +433,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc private func tapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state, let gesture = recognizer.lastRecognizedGestureAndLocation?.0, case .tap = gesture {
|
if case .ended = recognizer.state, let gesture = recognizer.lastRecognizedGestureAndLocation?.0, case .tap = gesture {
|
||||||
let location = recognizer.location(in: self.view)
|
let location = recognizer.location(in: self.view)
|
||||||
var selectedOption: Int?
|
var selectedOption: Int?
|
||||||
@ -449,7 +457,7 @@ final class ItemListRevealOptionsNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func isDisplayingExtendedAction() -> Bool {
|
public func isDisplayingExtendedAction() -> Bool {
|
||||||
return self.optionNodes.contains(where: { $0.isExpanded })
|
return self.optionNodes.contains(where: { $0.isExpanded })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,11 +2,12 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import Display
|
import Display
|
||||||
|
import CheckNode
|
||||||
|
|
||||||
final class ItemListSelectableControlNode: ASDisplayNode {
|
public final class ItemListSelectableControlNode: ASDisplayNode {
|
||||||
private let checkNode: CheckNode
|
private let checkNode: CheckNode
|
||||||
|
|
||||||
init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor) {
|
public init(strokeColor: UIColor, fillColor: UIColor, foregroundColor: UIColor) {
|
||||||
self.checkNode = CheckNode(strokeColor: strokeColor, fillColor: fillColor, foregroundColor: foregroundColor, style: .plain)
|
self.checkNode = CheckNode(strokeColor: strokeColor, fillColor: fillColor, foregroundColor: foregroundColor, style: .plain)
|
||||||
self.checkNode.isUserInteractionEnabled = false
|
self.checkNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ final class ItemListSelectableControlNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.checkNode)
|
self.addSubnode(self.checkNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ compact: Bool) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) {
|
public static func asyncLayout(_ node: ItemListSelectableControlNode?) -> (_ strokeColor: UIColor, _ fillColor: UIColor, _ foregroundColor: UIColor, _ selected: Bool, _ compact: Bool) -> (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode) {
|
||||||
return { strokeColor, fillColor, foregroundColor, selected, compact in
|
return { strokeColor, fillColor, foregroundColor, selected, compact in
|
||||||
let resultNode: ItemListSelectableControlNode
|
let resultNode: ItemListSelectableControlNode
|
||||||
if let node = node {
|
if let node = node {
|
||||||
19
submodules/ItemListUI/Sources/ItemListUI.h
Normal file
19
submodules/ItemListUI/Sources/ItemListUI.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//
|
||||||
|
// ItemListUI.h
|
||||||
|
// ItemListUI
|
||||||
|
//
|
||||||
|
// Created by Peter on 8/1/19.
|
||||||
|
// Copyright © 2019 Telegram Messenger LLP. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
//! Project version number for ItemListUI.
|
||||||
|
FOUNDATION_EXPORT double ItemListUIVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for ItemListUI.
|
||||||
|
FOUNDATION_EXPORT const unsigned char ItemListUIVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <ItemListUI/PublicHeader.h>
|
||||||
|
|
||||||
|
|
||||||
@ -5,31 +5,31 @@ import AsyncDisplayKit
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
enum ItemListActionKind {
|
public enum ItemListActionKind {
|
||||||
case generic
|
case generic
|
||||||
case destructive
|
case destructive
|
||||||
case neutral
|
case neutral
|
||||||
case disabled
|
case disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListActionAlignment {
|
public enum ItemListActionAlignment {
|
||||||
case natural
|
case natural
|
||||||
case center
|
case center
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListActionItem: ListViewItem, ItemListItem {
|
public class ItemListActionItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let title: String
|
let title: String
|
||||||
let kind: ItemListActionKind
|
let kind: ItemListActionKind
|
||||||
let alignment: ItemListActionAlignment
|
let alignment: ItemListActionAlignment
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let action: () -> Void
|
public let action: () -> Void
|
||||||
let longTapAction: (() -> Void)?
|
let longTapAction: (() -> Void)?
|
||||||
let clearHighlightAutomatically: Bool
|
let clearHighlightAutomatically: Bool
|
||||||
let tag: Any?
|
public let tag: Any?
|
||||||
|
|
||||||
init(theme: PresentationTheme, title: String, kind: ItemListActionKind, alignment: ItemListActionAlignment, sectionId: ItemListSectionId, style: ItemListStyle, action: @escaping () -> Void, longTapAction: (() -> Void)? = nil, clearHighlightAutomatically: Bool = true, tag: Any? = nil) {
|
public init(theme: PresentationTheme, title: String, kind: ItemListActionKind, alignment: ItemListActionAlignment, sectionId: ItemListSectionId, style: ItemListStyle, action: @escaping () -> Void, longTapAction: (() -> Void)? = nil, clearHighlightAutomatically: Bool = true, tag: Any? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.title = title
|
self.title = title
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
@ -42,7 +42,7 @@ class ItemListActionItem: ListViewItem, ItemListItem {
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListActionItemNode()
|
let node = ItemListActionItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -58,7 +58,7 @@ class ItemListActionItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListActionItemNode {
|
if let nodeValue = node() as? ItemListActionItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -75,9 +75,9 @@ class ItemListActionItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectable: Bool = true
|
public var selectable: Bool = true
|
||||||
|
|
||||||
func selected(listView: ListView){
|
public func selected(listView: ListView){
|
||||||
if self.clearHighlightAutomatically {
|
if self.clearHighlightAutomatically {
|
||||||
listView.clearHighlightAnimated(true)
|
listView.clearHighlightAnimated(true)
|
||||||
}
|
}
|
||||||
@ -87,7 +87,7 @@ class ItemListActionItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
private let titleFont = Font.regular(17.0)
|
private let titleFont = Font.regular(17.0)
|
||||||
|
|
||||||
class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -99,11 +99,11 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
private var item: ItemListActionItem?
|
private var item: ItemListActionItem?
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
public var tag: ItemListItemTag? {
|
||||||
return self.item?.tag as? ItemListItemTag
|
return self.item?.tag as? ItemListItemTag
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
@ -131,7 +131,7 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListActionItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListActionItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
|
||||||
let currentItem = self.item
|
let currentItem = self.item
|
||||||
@ -185,10 +185,10 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
|
||||||
strongSelf.activateArea.accessibilityLabel = item.title
|
strongSelf.activateArea.accessibilityLabel = item.title
|
||||||
|
|
||||||
var accessibilityTraits: UIAccessibilityTraits = UIAccessibilityTraitButton
|
var accessibilityTraits: UIAccessibilityTraits = .button
|
||||||
switch item.kind {
|
switch item.kind {
|
||||||
case .disabled:
|
case .disabled:
|
||||||
accessibilityTraits |= UIAccessibilityTraitNotEnabled
|
accessibilityTraits.insert(.notEnabled)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -262,7 +262,7 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted && self.item?.kind != ItemListActionKind.disabled {
|
if highlighted && self.item?.kind != ItemListActionKind.disabled {
|
||||||
@ -300,19 +300,19 @@ class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func longTapped() {
|
override public func longTapped() {
|
||||||
self.item?.longTapAction?()
|
self.item?.longTapAction?()
|
||||||
}
|
}
|
||||||
|
|
||||||
override var canBeLongTapped: Bool {
|
override public var canBeLongTapped: Bool {
|
||||||
return self.item?.longTapAction != nil
|
return self.item?.longTapAction != nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,23 +4,24 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import ActivityIndicator
|
||||||
|
|
||||||
class ItemListActivityTextItem: ListViewItem, ItemListItem {
|
public class ItemListActivityTextItem: ListViewItem, ItemListItem {
|
||||||
let displayActivity: Bool
|
let displayActivity: Bool
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let text: NSAttributedString
|
let text: NSAttributedString
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
|
|
||||||
let isAlwaysPlain: Bool = true
|
public let isAlwaysPlain: Bool = true
|
||||||
|
|
||||||
init(displayActivity: Bool, theme: PresentationTheme, text: NSAttributedString, sectionId: ItemListSectionId) {
|
public init(displayActivity: Bool, theme: PresentationTheme, text: NSAttributedString, sectionId: ItemListSectionId) {
|
||||||
self.displayActivity = displayActivity
|
self.displayActivity = displayActivity
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.text = text
|
self.text = text
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListActivityTextItemNode()
|
let node = ItemListActivityTextItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -36,7 +37,7 @@ class ItemListActivityTextItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
guard let nodeValue = node() as? ItemListActivityTextItemNode else {
|
guard let nodeValue = node() as? ItemListActivityTextItemNode else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
@ -59,13 +60,13 @@ class ItemListActivityTextItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
private let titleFont = Font.regular(14.0)
|
private let titleFont = Font.regular(14.0)
|
||||||
|
|
||||||
class ItemListActivityTextItemNode: ListViewItemNode {
|
public class ItemListActivityTextItemNode: ListViewItemNode {
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let activityIndicator: ActivityIndicator
|
private let activityIndicator: ActivityIndicator
|
||||||
|
|
||||||
private var item: ItemListActivityTextItem?
|
private var item: ItemListActivityTextItem?
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.titleNode = TextNode()
|
self.titleNode = TextNode()
|
||||||
self.titleNode.isUserInteractionEnabled = false
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
self.titleNode.contentMode = .left
|
self.titleNode.contentMode = .left
|
||||||
@ -79,7 +80,7 @@ class ItemListActivityTextItemNode: ListViewItemNode {
|
|||||||
self.addSubnode(self.activityIndicator)
|
self.addSubnode(self.activityIndicator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListActivityTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListActivityTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
|
||||||
return { item, params, neighbors in
|
return { item, params, neighbors in
|
||||||
@ -94,8 +95,8 @@ class ItemListActivityTextItemNode: ListViewItemNode {
|
|||||||
let titleString = NSMutableAttributedString(attributedString: item.text)
|
let titleString = NSMutableAttributedString(attributedString: item.text)
|
||||||
let hasFont = titleString.attribute(.font, at: 0, effectiveRange: nil) != nil
|
let hasFont = titleString.attribute(.font, at: 0, effectiveRange: nil) != nil
|
||||||
if !hasFont {
|
if !hasFont {
|
||||||
titleString.removeAttribute(NSAttributedStringKey.font, range: NSMakeRange(0, titleString.length))
|
titleString.removeAttribute(NSAttributedString.Key.font, range: NSMakeRange(0, titleString.length))
|
||||||
titleString.addAttributes([NSAttributedStringKey.font: titleFont], range: NSMakeRange(0, titleString.length))
|
titleString.addAttributes([NSAttributedString.Key.font: titleFont], range: NSMakeRange(0, titleString.length))
|
||||||
}
|
}
|
||||||
|
|
||||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - 22.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: TextNodeCutout(topLeft: CGSize(width: activityWidth, height: 4.0)), insets: UIEdgeInsets()))
|
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - 20.0 - 22.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: TextNodeCutout(topLeft: CGSize(width: activityWidth, height: 4.0)), insets: UIEdgeInsets()))
|
||||||
@ -129,11 +130,11 @@ class ItemListActivityTextItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,27 +5,27 @@ import AsyncDisplayKit
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
enum ItemListCheckboxItemStyle {
|
public enum ItemListCheckboxItemStyle {
|
||||||
case left
|
case left
|
||||||
case right
|
case right
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListCheckboxItemColor {
|
public enum ItemListCheckboxItemColor {
|
||||||
case accent
|
case accent
|
||||||
case secondary
|
case secondary
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
public class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let title: String
|
let title: String
|
||||||
let style: ItemListCheckboxItemStyle
|
let style: ItemListCheckboxItemStyle
|
||||||
let color: ItemListCheckboxItemColor
|
let color: ItemListCheckboxItemColor
|
||||||
let checked: Bool
|
let checked: Bool
|
||||||
let zeroSeparatorInsets: Bool
|
let zeroSeparatorInsets: Bool
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
|
|
||||||
init(theme: PresentationTheme, title: String, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void) {
|
public init(theme: PresentationTheme, title: String, style: ItemListCheckboxItemStyle, color: ItemListCheckboxItemColor = .accent, checked: Bool, zeroSeparatorInsets: Bool, sectionId: ItemListSectionId, action: @escaping () -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.title = title
|
self.title = title
|
||||||
self.style = style
|
self.style = style
|
||||||
@ -36,7 +36,7 @@ class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
|||||||
self.action = action
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListCheckboxItemNode()
|
let node = ItemListCheckboxItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -52,7 +52,7 @@ class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListCheckboxItemNode {
|
if let nodeValue = node() as? ItemListCheckboxItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -69,9 +69,9 @@ class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectable: Bool = true
|
public var selectable: Bool = true
|
||||||
|
|
||||||
func selected(listView: ListView){
|
public func selected(listView: ListView){
|
||||||
listView.clearHighlightAnimated(true)
|
listView.clearHighlightAnimated(true)
|
||||||
self.action()
|
self.action()
|
||||||
}
|
}
|
||||||
@ -79,7 +79,7 @@ class ItemListCheckboxItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
private let titleFont = Font.regular(17.0)
|
private let titleFont = Font.regular(17.0)
|
||||||
|
|
||||||
class ItemListCheckboxItemNode: ListViewItemNode {
|
public class ItemListCheckboxItemNode: ListViewItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -92,7 +92,7 @@ class ItemListCheckboxItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
private var item: ItemListCheckboxItem?
|
private var item: ItemListCheckboxItem?
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -129,7 +129,7 @@ class ItemListCheckboxItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListCheckboxItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListCheckboxItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
|
||||||
let currentItem = self.item
|
let currentItem = self.item
|
||||||
@ -243,7 +243,7 @@ class ItemListCheckboxItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted {
|
if highlighted {
|
||||||
@ -281,11 +281,11 @@ class ItemListCheckboxItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5,17 +5,17 @@ import AsyncDisplayKit
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
enum ItemListDisclosureItemTitleColor {
|
public enum ItemListDisclosureItemTitleColor {
|
||||||
case primary
|
case primary
|
||||||
case accent
|
case accent
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListDisclosureStyle {
|
public enum ItemListDisclosureStyle {
|
||||||
case arrow
|
case arrow
|
||||||
case none
|
case none
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListDisclosureLabelStyle {
|
public enum ItemListDisclosureLabelStyle {
|
||||||
case text
|
case text
|
||||||
case detailText
|
case detailText
|
||||||
case multilineDetailText
|
case multilineDetailText
|
||||||
@ -23,7 +23,7 @@ enum ItemListDisclosureLabelStyle {
|
|||||||
case color(UIColor)
|
case color(UIColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
public class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let icon: UIImage?
|
let icon: UIImage?
|
||||||
let title: String
|
let title: String
|
||||||
@ -31,14 +31,14 @@ class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
|||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
let label: String
|
let label: String
|
||||||
let labelStyle: ItemListDisclosureLabelStyle
|
let labelStyle: ItemListDisclosureLabelStyle
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let disclosureStyle: ItemListDisclosureStyle
|
let disclosureStyle: ItemListDisclosureStyle
|
||||||
let action: (() -> Void)?
|
let action: (() -> Void)?
|
||||||
let clearHighlightAutomatically: Bool
|
let clearHighlightAutomatically: Bool
|
||||||
let tag: ItemListItemTag?
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
init(theme: PresentationTheme, icon: UIImage? = nil, title: String, enabled: Bool = true, titleColor: ItemListDisclosureItemTitleColor = .primary, label: String, labelStyle: ItemListDisclosureLabelStyle = .text, sectionId: ItemListSectionId, style: ItemListStyle, disclosureStyle: ItemListDisclosureStyle = .arrow, action: (() -> Void)?, clearHighlightAutomatically: Bool = true, tag: ItemListItemTag? = nil) {
|
public init(theme: PresentationTheme, icon: UIImage? = nil, title: String, enabled: Bool = true, titleColor: ItemListDisclosureItemTitleColor = .primary, label: String, labelStyle: ItemListDisclosureLabelStyle = .text, sectionId: ItemListSectionId, style: ItemListStyle, disclosureStyle: ItemListDisclosureStyle = .arrow, action: (() -> Void)?, clearHighlightAutomatically: Bool = true, tag: ItemListItemTag? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.title = title
|
self.title = title
|
||||||
@ -54,7 +54,7 @@ class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListDisclosureItemNode()
|
let node = ItemListDisclosureItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -70,7 +70,7 @@ class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListDisclosureItemNode {
|
if let nodeValue = node() as? ItemListDisclosureItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -87,9 +87,9 @@ class ItemListDisclosureItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectable: Bool = true
|
public var selectable: Bool = true
|
||||||
|
|
||||||
func selected(listView: ListView){
|
public func selected(listView: ListView){
|
||||||
if self.clearHighlightAutomatically {
|
if self.clearHighlightAutomatically {
|
||||||
listView.clearHighlightAnimated(true)
|
listView.clearHighlightAnimated(true)
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ private let titleFont = Font.regular(17.0)
|
|||||||
private let badgeFont = Font.regular(15.0)
|
private let badgeFont = Font.regular(15.0)
|
||||||
private let detailFont = Font.regular(13.0)
|
private let detailFont = Font.regular(13.0)
|
||||||
|
|
||||||
class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -120,7 +120,7 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
private var item: ItemListDisclosureItem?
|
private var item: ItemListDisclosureItem?
|
||||||
|
|
||||||
override var canBeSelected: Bool {
|
override public var canBeSelected: Bool {
|
||||||
if let item = self.item, let _ = item.action {
|
if let item = self.item, let _ = item.action {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -128,11 +128,11 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
public var tag: ItemListItemTag? {
|
||||||
return self.item?.tag
|
return self.item?.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
@ -178,7 +178,7 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListDisclosureItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListDisclosureItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
||||||
|
|
||||||
@ -308,9 +308,9 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
strongSelf.activateArea.accessibilityLabel = item.title
|
strongSelf.activateArea.accessibilityLabel = item.title
|
||||||
strongSelf.activateArea.accessibilityValue = item.label
|
strongSelf.activateArea.accessibilityValue = item.label
|
||||||
if item.enabled {
|
if item.enabled {
|
||||||
strongSelf.activateArea.accessibilityTraits = 0
|
strongSelf.activateArea.accessibilityTraits = []
|
||||||
} else {
|
} else {
|
||||||
strongSelf.activateArea.accessibilityTraits = UIAccessibilityTraitNotEnabled
|
strongSelf.activateArea.accessibilityTraits = .notEnabled
|
||||||
}
|
}
|
||||||
|
|
||||||
if let icon = item.icon {
|
if let icon = item.icon {
|
||||||
@ -447,7 +447,7 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted && (self.item?.enabled ?? false) {
|
if highlighted && (self.item?.enabled ?? false) {
|
||||||
@ -485,15 +485,15 @@ class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,37 +3,37 @@ import UIKit
|
|||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
|
|
||||||
final class ItemListRevealOptionsGestureRecognizer: UIPanGestureRecognizer {
|
public final class ItemListRevealOptionsGestureRecognizer: UIPanGestureRecognizer {
|
||||||
var validatedGesture = false
|
public var validatedGesture = false
|
||||||
var firstLocation: CGPoint = CGPoint()
|
public var firstLocation: CGPoint = CGPoint()
|
||||||
|
|
||||||
var allowAnyDirection = false
|
public var allowAnyDirection = false
|
||||||
var lastVelocity: CGPoint = CGPoint()
|
public var lastVelocity: CGPoint = CGPoint()
|
||||||
|
|
||||||
override init(target: Any?, action: Selector?) {
|
override public init(target: Any?, action: Selector?) {
|
||||||
super.init(target: target, action: action)
|
super.init(target: target, action: action)
|
||||||
|
|
||||||
self.maximumNumberOfTouches = 1
|
self.maximumNumberOfTouches = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override func reset() {
|
override public func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
|
|
||||||
self.validatedGesture = false
|
self.validatedGesture = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func becomeCancelled() {
|
public func becomeCancelled() {
|
||||||
self.state = .cancelled
|
self.state = .cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
super.touchesBegan(touches, with: event)
|
super.touchesBegan(touches, with: event)
|
||||||
|
|
||||||
let touch = touches.first!
|
let touch = touches.first!
|
||||||
self.firstLocation = touch.location(in: self.view)
|
self.firstLocation = touch.location(in: self.view)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||||
let location = touches.first!.location(in: self.view)
|
let location = touches.first!.location(in: self.view)
|
||||||
let translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y)
|
let translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y)
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ final class ItemListRevealOptionsGestureRecognizer: UIPanGestureRecognizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelegate {
|
open class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelegate {
|
||||||
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
||||||
|
|
||||||
private var leftRevealNode: ItemListRevealOptionsNode?
|
private var leftRevealNode: ItemListRevealOptionsNode?
|
||||||
@ -62,7 +62,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
private var revealOptions: (left: [ItemListRevealOption], right: [ItemListRevealOption]) = ([], [])
|
private var revealOptions: (left: [ItemListRevealOption], right: [ItemListRevealOption]) = ([], [])
|
||||||
|
|
||||||
private var initialRevealOffset: CGFloat = 0.0
|
private var initialRevealOffset: CGFloat = 0.0
|
||||||
private(set) var revealOffset: CGFloat = 0.0
|
public private(set) var revealOffset: CGFloat = 0.0
|
||||||
|
|
||||||
private var recognizer: ItemListRevealOptionsGestureRecognizer?
|
private var recognizer: ItemListRevealOptionsGestureRecognizer?
|
||||||
private var tapRecognizer: UITapGestureRecognizer?
|
private var tapRecognizer: UITapGestureRecognizer?
|
||||||
@ -70,19 +70,19 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
|
|
||||||
private var allowAnyDirection = false
|
private var allowAnyDirection = false
|
||||||
|
|
||||||
var isDisplayingRevealedOptions: Bool {
|
public var isDisplayingRevealedOptions: Bool {
|
||||||
return !self.revealOffset.isZero
|
return !self.revealOffset.isZero
|
||||||
}
|
}
|
||||||
|
|
||||||
override var canBeSelected: Bool {
|
override open var canBeSelected: Bool {
|
||||||
return !self.isDisplayingRevealedOptions
|
return !self.isDisplayingRevealedOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
override init(layerBacked: Bool, dynamicBounce: Bool, rotated: Bool, seeThrough: Bool) {
|
override public init(layerBacked: Bool, dynamicBounce: Bool, rotated: Bool, seeThrough: Bool) {
|
||||||
super.init(layerBacked: layerBacked, dynamicBounce: dynamicBounce, rotated: rotated, seeThrough: seeThrough)
|
super.init(layerBacked: layerBacked, dynamicBounce: dynamicBounce, rotated: rotated, seeThrough: seeThrough)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override open func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let recognizer = ItemListRevealOptionsGestureRecognizer(target: self, action: #selector(self.revealGesture(_:)))
|
let recognizer = ItemListRevealOptionsGestureRecognizer(target: self, action: #selector(self.revealGesture(_:)))
|
||||||
@ -98,7 +98,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
self.view.disablesInteractiveTransitionGestureRecognizer = self.allowAnyDirection
|
self.view.disablesInteractiveTransitionGestureRecognizer = self.allowAnyDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRevealOptions(_ options: (left: [ItemListRevealOption], right: [ItemListRevealOption])) {
|
open func setRevealOptions(_ options: (left: [ItemListRevealOption], right: [ItemListRevealOption])) {
|
||||||
if self.revealOptions == options {
|
if self.revealOptions == options {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -143,7 +143,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
override open func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
if let recognizer = self.recognizer, gestureRecognizer == self.tapRecognizer {
|
if let recognizer = self.recognizer, gestureRecognizer == self.tapRecognizer {
|
||||||
return abs(self.revealOffset) > 0.0 && !recognizer.validatedGesture
|
return abs(self.revealOffset) > 0.0 && !recognizer.validatedGesture
|
||||||
} else {
|
} else {
|
||||||
@ -151,7 +151,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
open func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
if let recognizer = self.recognizer, otherGestureRecognizer == recognizer {
|
if let recognizer = self.recognizer, otherGestureRecognizer == recognizer {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
@ -159,14 +159,14 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc private func revealTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if case .ended = recognizer.state {
|
if case .ended = recognizer.state {
|
||||||
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
|
self.updateRevealOffsetInternal(offset: 0.0, transition: .animated(duration: 0.3, curve: .spring))
|
||||||
self.revealOptionsInteractivelyClosed()
|
self.revealOptionsInteractivelyClosed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func revealGesture(_ recognizer: ItemListRevealOptionsGestureRecognizer) {
|
@objc private func revealGesture(_ recognizer: ItemListRevealOptionsGestureRecognizer) {
|
||||||
guard let (size, _, _) = self.validLayout else {
|
guard let (size, _, _) = self.validLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -336,7 +336,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
||||||
self.validLayout = (size, leftInset, rightInset)
|
self.validLayout = (size, leftInset, rightInset)
|
||||||
|
|
||||||
if let leftRevealNode = self.leftRevealNode {
|
if let leftRevealNode = self.leftRevealNode {
|
||||||
@ -352,7 +352,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRevealOffsetInternal(offset: CGFloat, transition: ContainedViewLayoutTransition, completion: (() -> Void)? = nil) {
|
open func updateRevealOffsetInternal(offset: CGFloat, transition: ContainedViewLayoutTransition, completion: (() -> Void)? = nil) {
|
||||||
self.revealOffset = offset
|
self.revealOffset = offset
|
||||||
guard let (size, leftInset, rightInset) = self.validLayout else {
|
guard let (size, leftInset, rightInset) = self.validLayout else {
|
||||||
return
|
return
|
||||||
@ -425,19 +425,19 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
self.updateRevealOffset(offset: offset, transition: transition)
|
self.updateRevealOffset(offset: offset, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
|
open func updateRevealOffset(offset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func revealOptionsInteractivelyOpened() {
|
open func revealOptionsInteractivelyOpened() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func revealOptionsInteractivelyClosed() {
|
open func revealOptionsInteractivelyClosed() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setRevealOptionsOpened(_ value: Bool, animated: Bool) {
|
open func setRevealOptionsOpened(_ value: Bool, animated: Bool) {
|
||||||
if value != !self.revealOffset.isZero {
|
if value != !self.revealOffset.isZero {
|
||||||
if !self.revealOffset.isZero {
|
if !self.revealOffset.isZero {
|
||||||
self.recognizer?.becomeCancelled()
|
self.recognizer?.becomeCancelled()
|
||||||
@ -463,7 +463,7 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateRevealOptionsFill(completion: (() -> Void)? = nil) {
|
open func animateRevealOptionsFill(completion: (() -> Void)? = nil) {
|
||||||
if let validLayout = self.validLayout {
|
if let validLayout = self.validLayout {
|
||||||
self.layer.allowsGroupOpacity = true
|
self.layer.allowsGroupOpacity = true
|
||||||
self.updateRevealOffsetInternal(offset: -validLayout.0.width - 74.0, transition: .animated(duration: 0.2, curve: .spring), completion: {
|
self.updateRevealOffsetInternal(offset: -validLayout.0.width - 74.0, transition: .animated(duration: 0.2, curve: .spring), completion: {
|
||||||
@ -473,14 +473,14 @@ class ItemListRevealOptionsItemNode: ListViewItemNode, UIGestureRecognizerDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
|
open func revealOptionSelected(_ option: ItemListRevealOption, animated: Bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
override var preventsTouchesToOtherItems: Bool {
|
override open var preventsTouchesToOtherItems: Bool {
|
||||||
return self.isDisplayingRevealedOptions
|
return self.isDisplayingRevealedOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
override func touchesToOtherItemsPrevented() {
|
override open func touchesToOtherItemsPrevented() {
|
||||||
if self.isDisplayingRevealedOptions {
|
if self.isDisplayingRevealedOptions {
|
||||||
self.setRevealOptionsOpened(false, animated: true)
|
self.setRevealOptionsOpened(false, animated: true)
|
||||||
}
|
}
|
||||||
@ -5,23 +5,28 @@ import AsyncDisplayKit
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
|
||||||
struct ItemListMultilineInputItemTextLimit {
|
public struct ItemListMultilineInputItemTextLimit {
|
||||||
let value: Int
|
public let value: Int
|
||||||
let display: Bool
|
public let display: Bool
|
||||||
|
|
||||||
|
public init(value: Int, display: Bool) {
|
||||||
|
self.value = value
|
||||||
|
self.display = display
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListMultilineInputItem: ListViewItem, ItemListItem {
|
public class ItemListMultilineInputItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let text: String
|
let text: String
|
||||||
let placeholder: String
|
let placeholder: String
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let action: () -> Void
|
let action: () -> Void
|
||||||
let textUpdated: (String) -> Void
|
let textUpdated: (String) -> Void
|
||||||
let tag: ItemListItemTag?
|
public let tag: ItemListItemTag?
|
||||||
let maxLength: ItemListMultilineInputItemTextLimit?
|
let maxLength: ItemListMultilineInputItemTextLimit?
|
||||||
|
|
||||||
init(theme: PresentationTheme, text: String, placeholder: String, maxLength: ItemListMultilineInputItemTextLimit?, sectionId: ItemListSectionId, style: ItemListStyle, textUpdated: @escaping (String) -> Void, tag: ItemListItemTag? = nil, action: @escaping () -> Void) {
|
public init(theme: PresentationTheme, text: String, placeholder: String, maxLength: ItemListMultilineInputItemTextLimit?, sectionId: ItemListSectionId, style: ItemListStyle, textUpdated: @escaping (String) -> Void, tag: ItemListItemTag? = nil, action: @escaping () -> Void) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.text = text
|
self.text = text
|
||||||
self.placeholder = placeholder
|
self.placeholder = placeholder
|
||||||
@ -33,7 +38,7 @@ class ItemListMultilineInputItem: ListViewItem, ItemListItem {
|
|||||||
self.action = action
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListMultilineInputItemNode()
|
let node = ItemListMultilineInputItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -49,7 +54,7 @@ class ItemListMultilineInputItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListMultilineInputItemNode {
|
if let nodeValue = node() as? ItemListMultilineInputItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -69,7 +74,7 @@ class ItemListMultilineInputItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
private let titleFont = Font.regular(17.0)
|
private let titleFont = Font.regular(17.0)
|
||||||
|
|
||||||
class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelegate, ItemListItemNode, ItemListItemFocusableNode {
|
public class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelegate, ItemListItemNode, ItemListItemFocusableNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -83,11 +88,11 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
private var item: ItemListMultilineInputItem?
|
private var item: ItemListMultilineInputItem?
|
||||||
private var layoutParams: ListViewItemLayoutParams?
|
private var layoutParams: ListViewItemLayoutParams?
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
public var tag: ItemListItemTag? {
|
||||||
return self.item?.tag
|
return self.item?.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -112,20 +117,20 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
var textColor: UIColor = .black
|
var textColor: UIColor = .black
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
textColor = item.theme.list.itemPrimaryTextColor
|
textColor = item.theme.list.itemPrimaryTextColor
|
||||||
}
|
}
|
||||||
self.textNode.typingAttributes = [NSAttributedStringKey.font.rawValue: Font.regular(17.0), NSAttributedStringKey.foregroundColor.rawValue: textColor]
|
self.textNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: textColor]
|
||||||
self.textNode.clipsToBounds = true
|
self.textNode.clipsToBounds = true
|
||||||
self.textNode.delegate = self
|
self.textNode.delegate = self
|
||||||
self.textNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
|
self.textNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListMultilineInputItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListMultilineInputItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTextLayout = TextNode.asyncLayout(self.measureTextNode)
|
let makeTextLayout = TextNode.asyncLayout(self.measureTextNode)
|
||||||
let makeLimitTextLayout = TextNode.asyncLayout(self.limitTextNode)
|
let makeLimitTextLayout = TextNode.asyncLayout(self.limitTextNode)
|
||||||
|
|
||||||
@ -202,7 +207,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
strongSelf.backgroundNode.backgroundColor = itemBackgroundColor
|
||||||
|
|
||||||
if strongSelf.isNodeLoaded {
|
if strongSelf.isNodeLoaded {
|
||||||
strongSelf.textNode.typingAttributes = [NSAttributedStringKey.font.rawValue: Font.regular(17.0), NSAttributedStringKey.foregroundColor.rawValue: item.theme.list.itemPrimaryTextColor]
|
strongSelf.textNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: item.theme.list.itemPrimaryTextColor]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,15 +269,15 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateFrameTransition(_ progress: CGFloat, _ currentValue: CGFloat) {
|
override public func animateFrameTransition(_ progress: CGFloat, _ currentValue: CGFloat) {
|
||||||
super.animateFrameTransition(progress, currentValue)
|
super.animateFrameTransition(progress, currentValue)
|
||||||
|
|
||||||
guard let params = self.layoutParams else {
|
guard let params = self.layoutParams else {
|
||||||
@ -293,7 +298,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
self.textClippingNode.frame = CGRect(origin: CGPoint(x: leftInset, y: textTopInset), size: CGSize(width: max(0.0, params.width - leftInset - params.rightInset), height: max(0.0, contentSize.height - textTopInset - textBottomInset)))
|
self.textClippingNode.frame = CGRect(origin: CGPoint(x: leftInset, y: textTopInset), size: CGSize(width: max(0.0, params.width - leftInset - params.rightInset), height: max(0.0, contentSize.height - textTopInset - textBottomInset)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
|
public func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
if let text = self.textNode.attributedText {
|
if let text = self.textNode.attributedText {
|
||||||
let updatedText = text.string
|
let updatedText = text.string
|
||||||
@ -308,7 +313,7 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
public func editableTextNodeShouldPaste(_ editableTextNode: ASEditableTextNode) -> Bool {
|
||||||
if let _ = self.item {
|
if let _ = self.item {
|
||||||
let text: String? = UIPasteboard.general.string
|
let text: String? = UIPasteboard.general.string
|
||||||
if let _ = text {
|
if let _ = text {
|
||||||
@ -318,13 +323,13 @@ class ItemListMultilineInputItemNode: ListViewItemNode, ASEditableTextNodeDelega
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func focus() {
|
public func focus() {
|
||||||
if !self.textNode.textView.isFirstResponder {
|
if !self.textNode.textView.isFirstResponder {
|
||||||
self.textNode.textView.becomeFirstResponder()
|
self.textNode.textView.becomeFirstResponder()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateError() {
|
public func animateError() {
|
||||||
self.textNode.layer.addShakeAnimation()
|
self.textNode.layer.addShakeAnimation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,23 +4,14 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import TextFormat
|
||||||
|
import AccountContext
|
||||||
|
|
||||||
enum TextLinkItemActionType {
|
public class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
||||||
case tap
|
|
||||||
case longTap
|
|
||||||
}
|
|
||||||
|
|
||||||
enum TextLinkItem {
|
|
||||||
case url(String)
|
|
||||||
case mention(String)
|
|
||||||
case hashtag(String?, String)
|
|
||||||
}
|
|
||||||
|
|
||||||
class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let text: String
|
let text: String
|
||||||
let enabledEntityTypes: EnabledEntityTypes
|
let enabledEntityTypes: EnabledEntityTypes
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let action: (() -> Void)?
|
let action: (() -> Void)?
|
||||||
let longTapAction: (() -> Void)?
|
let longTapAction: (() -> Void)?
|
||||||
@ -28,9 +19,9 @@ class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
|||||||
|
|
||||||
let tag: Any?
|
let tag: Any?
|
||||||
|
|
||||||
let selectable: Bool
|
public let selectable: Bool
|
||||||
|
|
||||||
init(theme: PresentationTheme, text: String, enabledEntityTypes: EnabledEntityTypes, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) {
|
public init(theme: PresentationTheme, text: String, enabledEntityTypes: EnabledEntityTypes, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)? = nil, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.text = text
|
self.text = text
|
||||||
self.enabledEntityTypes = enabledEntityTypes
|
self.enabledEntityTypes = enabledEntityTypes
|
||||||
@ -44,7 +35,7 @@ class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
|||||||
self.selectable = action != nil
|
self.selectable = action != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListMultilineTextItemNode()
|
let node = ItemListMultilineTextItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -60,7 +51,7 @@ class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListMultilineTextItemNode {
|
if let nodeValue = node() as? ItemListMultilineTextItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -77,7 +68,7 @@ class ItemListMultilineTextItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func selected(listView: ListView){
|
public func selected(listView: ListView){
|
||||||
listView.clearHighlightAnimated(true)
|
listView.clearHighlightAnimated(true)
|
||||||
self.action?()
|
self.action?()
|
||||||
}
|
}
|
||||||
@ -89,7 +80,7 @@ private let titleItalicFont = Font.italic(17.0)
|
|||||||
private let titleBoldItalicFont = Font.semiboldItalic(17.0)
|
private let titleBoldItalicFont = Font.semiboldItalic(17.0)
|
||||||
private let titleFixedFont = Font.regular(17.0)
|
private let titleFixedFont = Font.regular(17.0)
|
||||||
|
|
||||||
class ItemListMultilineTextItemNode: ListViewItemNode {
|
public class ItemListMultilineTextItemNode: ListViewItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -102,15 +93,15 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
private var item: ItemListMultilineTextItem?
|
private var item: ItemListMultilineTextItem?
|
||||||
|
|
||||||
var tag: Any? {
|
public var tag: Any? {
|
||||||
return self.item?.tag
|
return self.item?.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
override var canBeLongTapped: Bool {
|
override public var canBeLongTapped: Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
self.backgroundNode.backgroundColor = .white
|
self.backgroundNode.backgroundColor = .white
|
||||||
@ -137,7 +128,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||||
@ -155,7 +146,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
self.view.addGestureRecognizer(recognizer)
|
self.view.addGestureRecognizer(recognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListMultilineTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListMultilineTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
||||||
|
|
||||||
let currentItem = self.item
|
let currentItem = self.item
|
||||||
@ -273,7 +264,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted && self.linkItemAtPoint(point) == nil {
|
if highlighted && self.linkItemAtPoint(point) == nil {
|
||||||
@ -311,15 +302,15 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
case .ended:
|
case .ended:
|
||||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||||
@ -340,11 +331,11 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
private func linkItemAtPoint(_ point: CGPoint) -> TextLinkItem? {
|
private func linkItemAtPoint(_ point: CGPoint) -> TextLinkItem? {
|
||||||
let textNodeFrame = self.textNode.frame
|
let textNodeFrame = self.textNode.frame
|
||||||
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||||
if let url = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] as? String {
|
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||||
return .url(url)
|
return .url(url)
|
||||||
} else if let peerName = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
|
} else if let peerName = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
|
||||||
return .mention(peerName)
|
return .mention(peerName)
|
||||||
} else if let hashtag = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
|
} else if let hashtag = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
|
||||||
return .hashtag(hashtag.peerName, hashtag.hashtag)
|
return .hashtag(hashtag.peerName, hashtag.hashtag)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@ -353,7 +344,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
override func longTapped() {
|
override public func longTapped() {
|
||||||
self.item?.longTapAction?()
|
self.item?.longTapAction?()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +362,7 @@ class ItemListMultilineTextItemNode: ListViewItemNode {
|
|||||||
TelegramTextAttributes.Hashtag
|
TelegramTextAttributes.Hashtag
|
||||||
]
|
]
|
||||||
for name in possibleNames {
|
for name in possibleNames {
|
||||||
if let _ = attributes[NSAttributedStringKey(rawValue: name)] {
|
if let _ = attributes[NSAttributedString.Key(rawValue: name)] {
|
||||||
rects = self.textNode.attributeRects(name: name, at: index)
|
rects = self.textNode.attributeRects(name: name, at: index)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -4,13 +4,14 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import SwitchNode
|
||||||
|
|
||||||
enum ItemListSwitchItemNodeType {
|
public enum ItemListSwitchItemNodeType {
|
||||||
case regular
|
case regular
|
||||||
case icon
|
case icon
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListSwitchItem: ListViewItem, ItemListItem {
|
public class ItemListSwitchItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let title: String
|
let title: String
|
||||||
let value: Bool
|
let value: Bool
|
||||||
@ -18,12 +19,12 @@ class ItemListSwitchItem: ListViewItem, ItemListItem {
|
|||||||
let enableInteractiveChanges: Bool
|
let enableInteractiveChanges: Bool
|
||||||
let enabled: Bool
|
let enabled: Bool
|
||||||
let maximumNumberOfLines: Int
|
let maximumNumberOfLines: Int
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let updated: (Bool) -> Void
|
let updated: (Bool) -> Void
|
||||||
let tag: ItemListItemTag?
|
public let tag: ItemListItemTag?
|
||||||
|
|
||||||
init(theme: PresentationTheme, title: String, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, maximumNumberOfLines: Int = 1, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, tag: ItemListItemTag? = nil) {
|
public init(theme: PresentationTheme, title: String, value: Bool, type: ItemListSwitchItemNodeType = .regular, enableInteractiveChanges: Bool = true, enabled: Bool = true, maximumNumberOfLines: Int = 1, sectionId: ItemListSectionId, style: ItemListStyle, updated: @escaping (Bool) -> Void, tag: ItemListItemTag? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.title = title
|
self.title = title
|
||||||
self.value = value
|
self.value = value
|
||||||
@ -37,7 +38,7 @@ class ItemListSwitchItem: ListViewItem, ItemListItem {
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListSwitchItemNode(type: self.type)
|
let node = ItemListSwitchItemNode(type: self.type)
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -53,7 +54,7 @@ class ItemListSwitchItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListSwitchItemNode {
|
if let nodeValue = node() as? ItemListSwitchItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -108,7 +109,7 @@ extension SwitchNode: ItemListSwitchNodeImpl {
|
|||||||
extension IconSwitchNode: ItemListSwitchNodeImpl {
|
extension IconSwitchNode: ItemListSwitchNodeImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||||
private let backgroundNode: ASDisplayNode
|
private let backgroundNode: ASDisplayNode
|
||||||
private let topStripeNode: ASDisplayNode
|
private let topStripeNode: ASDisplayNode
|
||||||
private let bottomStripeNode: ASDisplayNode
|
private let bottomStripeNode: ASDisplayNode
|
||||||
@ -123,7 +124,7 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
|
|
||||||
private var item: ItemListSwitchItem?
|
private var item: ItemListSwitchItem?
|
||||||
|
|
||||||
var tag: ItemListItemTag? {
|
public var tag: ItemListItemTag? {
|
||||||
return self.item?.tag
|
return self.item?.tag
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +175,7 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
(self.switchNode.view as? UISwitch)?.addTarget(self, action: #selector(self.switchValueChanged(_:)), for: .valueChanged)
|
(self.switchNode.view as? UISwitch)?.addTarget(self, action: #selector(self.switchValueChanged(_:)), for: .valueChanged)
|
||||||
@ -241,7 +242,7 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
var accessibilityTraits = UIAccessibilityTraits()
|
var accessibilityTraits = UIAccessibilityTraits()
|
||||||
if item.enabled {
|
if item.enabled {
|
||||||
} else {
|
} else {
|
||||||
accessibilityTraits |= UIAccessibilityTraitNotEnabled
|
accessibilityTraits.insert(.notEnabled)
|
||||||
}
|
}
|
||||||
strongSelf.activateArea.accessibilityTraits = accessibilityTraits
|
strongSelf.activateArea.accessibilityTraits = accessibilityTraits
|
||||||
|
|
||||||
@ -351,7 +352,7 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func accessibilityActivate() -> Bool {
|
override public func accessibilityActivate() -> Bool {
|
||||||
guard let item = self.item else {
|
guard let item = self.item else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -368,7 +369,7 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted {
|
if highlighted {
|
||||||
@ -406,22 +407,22 @@ class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func switchValueChanged(_ switchView: UISwitch) {
|
@objc private func switchValueChanged(_ switchView: UISwitch) {
|
||||||
if let item = self.item {
|
if let item = self.item {
|
||||||
let value = switchView.isOn
|
let value = switchView.isOn
|
||||||
item.updated(value)
|
item.updated(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
if let item = self.item, let switchView = self.switchNode.view as? UISwitch, case .ended = recognizer.state {
|
if let item = self.item, let switchView = self.switchNode.view as? UISwitch, case .ended = recognizer.state {
|
||||||
let value = switchView.isOn
|
let value = switchView.isOn
|
||||||
item.updated(!value)
|
item.updated(!value)
|
||||||
@ -4,25 +4,26 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import TextFormat
|
||||||
|
|
||||||
enum ItemListTextItemText {
|
public enum ItemListTextItemText {
|
||||||
case plain(String)
|
case plain(String)
|
||||||
case markdown(String)
|
case markdown(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ItemListTextItemLinkAction {
|
public enum ItemListTextItemLinkAction {
|
||||||
case tap(String)
|
case tap(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ItemListTextItem: ListViewItem, ItemListItem {
|
public class ItemListTextItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let text: ItemListTextItemText
|
let text: ItemListTextItemText
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let linkAction: ((ItemListTextItemLinkAction) -> Void)?
|
let linkAction: ((ItemListTextItemLinkAction) -> Void)?
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let isAlwaysPlain: Bool = true
|
public let isAlwaysPlain: Bool = true
|
||||||
|
|
||||||
init(theme: PresentationTheme, text: ItemListTextItemText, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil, style: ItemListStyle = .blocks) {
|
public init(theme: PresentationTheme, text: ItemListTextItemText, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil, style: ItemListStyle = .blocks) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.text = text
|
self.text = text
|
||||||
self.sectionId = sectionId
|
self.sectionId = sectionId
|
||||||
@ -30,7 +31,7 @@ class ItemListTextItem: ListViewItem, ItemListItem {
|
|||||||
self.style = style
|
self.style = style
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListTextItemNode()
|
let node = ItemListTextItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -46,7 +47,7 @@ class ItemListTextItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
guard let nodeValue = node() as? ItemListTextItemNode else {
|
guard let nodeValue = node() as? ItemListTextItemNode else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
@ -70,20 +71,20 @@ class ItemListTextItem: ListViewItem, ItemListItem {
|
|||||||
private let titleFont = Font.regular(14.0)
|
private let titleFont = Font.regular(14.0)
|
||||||
private let titleBoldFont = Font.semibold(14.0)
|
private let titleBoldFont = Font.semibold(14.0)
|
||||||
|
|
||||||
class ItemListTextItemNode: ListViewItemNode {
|
public class ItemListTextItemNode: ListViewItemNode {
|
||||||
private let titleNode: TextNode
|
private let titleNode: TextNode
|
||||||
private let activateArea: AccessibilityAreaNode
|
private let activateArea: AccessibilityAreaNode
|
||||||
|
|
||||||
private var item: ItemListTextItem?
|
private var item: ItemListTextItem?
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.titleNode = TextNode()
|
self.titleNode = TextNode()
|
||||||
self.titleNode.isUserInteractionEnabled = false
|
self.titleNode.isUserInteractionEnabled = false
|
||||||
self.titleNode.contentMode = .left
|
self.titleNode.contentMode = .left
|
||||||
self.titleNode.contentsScale = UIScreen.main.scale
|
self.titleNode.contentsScale = UIScreen.main.scale
|
||||||
|
|
||||||
self.activateArea = AccessibilityAreaNode()
|
self.activateArea = AccessibilityAreaNode()
|
||||||
self.activateArea.accessibilityTraits = UIAccessibilityTraitStaticText
|
self.activateArea.accessibilityTraits = .staticText
|
||||||
|
|
||||||
super.init(layerBacked: false, dynamicBounce: false)
|
super.init(layerBacked: false, dynamicBounce: false)
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ class ItemListTextItemNode: ListViewItemNode {
|
|||||||
self.addSubnode(self.activateArea)
|
self.addSubnode(self.activateArea)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||||
@ -101,7 +102,7 @@ class ItemListTextItemNode: ListViewItemNode {
|
|||||||
self.view.addGestureRecognizer(recognizer)
|
self.view.addGestureRecognizer(recognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
public func asyncLayout() -> (_ item: ItemListTextItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
|
||||||
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
let makeTitleLayout = TextNode.asyncLayout(self.titleNode)
|
||||||
|
|
||||||
return { item, params, neighbors in
|
return { item, params, neighbors in
|
||||||
@ -143,15 +144,15 @@ class ItemListTextItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
case .ended:
|
case .ended:
|
||||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||||
@ -160,7 +161,7 @@ class ItemListTextItemNode: ListViewItemNode {
|
|||||||
let titleFrame = self.titleNode.frame
|
let titleFrame = self.titleNode.frame
|
||||||
if let item = self.item, titleFrame.contains(location) {
|
if let item = self.item, titleFrame.contains(location) {
|
||||||
if let (_, attributes) = self.titleNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
if let (_, attributes) = self.titleNode.attributesAtPoint(CGPoint(x: location.x - titleFrame.minX, y: location.y - titleFrame.minY)) {
|
||||||
if let url = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] as? String {
|
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||||
item.linkAction?(.tap(url))
|
item.linkAction?(.tap(url))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,31 +4,33 @@ import Display
|
|||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
|
import TextFormat
|
||||||
|
import AccountContext
|
||||||
|
|
||||||
enum ItemListTextWithLabelItemTextColor {
|
public enum ItemListTextWithLabelItemTextColor {
|
||||||
case primary
|
case primary
|
||||||
case accent
|
case accent
|
||||||
case highlighted
|
case highlighted
|
||||||
}
|
}
|
||||||
|
|
||||||
final class ItemListTextWithLabelItem: ListViewItem, ItemListItem {
|
public final class ItemListTextWithLabelItem: ListViewItem, ItemListItem {
|
||||||
let theme: PresentationTheme
|
let theme: PresentationTheme
|
||||||
let label: String
|
public let label: String
|
||||||
let text: String
|
public let text: String
|
||||||
let style: ItemListStyle
|
let style: ItemListStyle
|
||||||
let labelColor: ItemListTextWithLabelItemTextColor
|
let labelColor: ItemListTextWithLabelItemTextColor
|
||||||
let textColor: ItemListTextWithLabelItemTextColor
|
let textColor: ItemListTextWithLabelItemTextColor
|
||||||
let enabledEntityTypes: EnabledEntityTypes
|
let enabledEntityTypes: EnabledEntityTypes
|
||||||
let multiline: Bool
|
let multiline: Bool
|
||||||
let selected: Bool?
|
let selected: Bool?
|
||||||
let sectionId: ItemListSectionId
|
public let sectionId: ItemListSectionId
|
||||||
let action: (() -> Void)?
|
let action: (() -> Void)?
|
||||||
let longTapAction: (() -> Void)?
|
let longTapAction: (() -> Void)?
|
||||||
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)?
|
||||||
|
|
||||||
let tag: Any?
|
public let tag: Any?
|
||||||
|
|
||||||
init(theme: PresentationTheme, label: String, text: String, style: ItemListStyle = .plain, labelColor: ItemListTextWithLabelItemTextColor = .primary, textColor: ItemListTextWithLabelItemTextColor = .primary, enabledEntityTypes: EnabledEntityTypes, multiline: Bool, selected: Bool? = nil, sectionId: ItemListSectionId, action: (() -> Void)?, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) {
|
public init(theme: PresentationTheme, label: String, text: String, style: ItemListStyle = .plain, labelColor: ItemListTextWithLabelItemTextColor = .primary, textColor: ItemListTextWithLabelItemTextColor = .primary, enabledEntityTypes: EnabledEntityTypes, multiline: Bool, selected: Bool? = nil, sectionId: ItemListSectionId, action: (() -> Void)?, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.label = label
|
self.label = label
|
||||||
self.text = text
|
self.text = text
|
||||||
@ -45,7 +47,7 @@ final class ItemListTextWithLabelItem: ListViewItem, ItemListItem {
|
|||||||
self.tag = tag
|
self.tag = tag
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||||
async {
|
async {
|
||||||
let node = ItemListTextWithLabelItemNode()
|
let node = ItemListTextWithLabelItemNode()
|
||||||
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem))
|
||||||
@ -61,7 +63,7 @@ final class ItemListTextWithLabelItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
if let nodeValue = node() as? ItemListTextWithLabelItemNode {
|
if let nodeValue = node() as? ItemListTextWithLabelItemNode {
|
||||||
let makeLayout = nodeValue.asyncLayout()
|
let makeLayout = nodeValue.asyncLayout()
|
||||||
@ -78,11 +80,11 @@ final class ItemListTextWithLabelItem: ListViewItem, ItemListItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectable: Bool {
|
public var selectable: Bool {
|
||||||
return self.action != nil
|
return self.action != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func selected(listView: ListView) {
|
public func selected(listView: ListView) {
|
||||||
listView.clearHighlightAnimated(true)
|
listView.clearHighlightAnimated(true)
|
||||||
self.action?()
|
self.action?()
|
||||||
}
|
}
|
||||||
@ -95,7 +97,7 @@ private let textItalicFont = Font.italic(17.0)
|
|||||||
private let textBoldItalicFont = Font.semiboldItalic(17.0)
|
private let textBoldItalicFont = Font.semiboldItalic(17.0)
|
||||||
private let textFixedFont = Font.regular(17.0)
|
private let textFixedFont = Font.regular(17.0)
|
||||||
|
|
||||||
class ItemListTextWithLabelItemNode: ListViewItemNode {
|
public class ItemListTextWithLabelItemNode: ListViewItemNode {
|
||||||
let labelNode: TextNode
|
let labelNode: TextNode
|
||||||
let textNode: TextNode
|
let textNode: TextNode
|
||||||
|
|
||||||
@ -106,13 +108,13 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
private var linkHighlightingNode: LinkHighlightingNode?
|
private var linkHighlightingNode: LinkHighlightingNode?
|
||||||
private var selectionNode: ItemListSelectableControlNode?
|
private var selectionNode: ItemListSelectableControlNode?
|
||||||
|
|
||||||
var item: ItemListTextWithLabelItem?
|
public var item: ItemListTextWithLabelItem?
|
||||||
|
|
||||||
override var canBeLongTapped: Bool {
|
override public var canBeLongTapped: Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
self.backgroundNode = ASDisplayNode()
|
self.backgroundNode = ASDisplayNode()
|
||||||
self.backgroundNode.isLayerBacked = true
|
self.backgroundNode.isLayerBacked = true
|
||||||
|
|
||||||
@ -143,7 +145,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
self.addSubnode(self.textNode)
|
self.addSubnode(self.textNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override public func didLoad() {
|
||||||
super.didLoad()
|
super.didLoad()
|
||||||
|
|
||||||
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:)))
|
||||||
@ -161,7 +163,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
self.view.addGestureRecognizer(recognizer)
|
self.view.addGestureRecognizer(recognizer)
|
||||||
}
|
}
|
||||||
|
|
||||||
func asyncLayout() -> (_ item: ItemListTextWithLabelItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
|
public func asyncLayout() -> (_ item: ItemListTextWithLabelItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) {
|
||||||
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
|
||||||
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
let makeTextLayout = TextNode.asyncLayout(self.textNode)
|
||||||
|
|
||||||
@ -323,7 +325,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
override public func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) {
|
||||||
super.setHighlighted(highlighted, at: point, animated: animated)
|
super.setHighlighted(highlighted, at: point, animated: animated)
|
||||||
|
|
||||||
if highlighted && self.linkItemAtPoint(point) == nil && self.selectionNode == nil {
|
if highlighted && self.linkItemAtPoint(point) == nil && self.selectionNode == nil {
|
||||||
@ -361,7 +363,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
@objc private func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||||
switch recognizer.state {
|
switch recognizer.state {
|
||||||
case .ended:
|
case .ended:
|
||||||
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
if let (gesture, location) = recognizer.lastRecognizedGestureAndLocation {
|
||||||
@ -382,11 +384,11 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
private func linkItemAtPoint(_ point: CGPoint) -> TextLinkItem? {
|
private func linkItemAtPoint(_ point: CGPoint) -> TextLinkItem? {
|
||||||
let textNodeFrame = self.textNode.frame
|
let textNodeFrame = self.textNode.frame
|
||||||
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
if let (_, attributes) = self.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||||
if let url = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.URL)] as? String {
|
if let url = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||||
return .url(url)
|
return .url(url)
|
||||||
} else if let peerName = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
|
} else if let peerName = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerTextMention)] as? String {
|
||||||
return .mention(peerName)
|
return .mention(peerName)
|
||||||
} else if let hashtag = attributes[NSAttributedStringKey(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
|
} else if let hashtag = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Hashtag)] as? TelegramHashtag {
|
||||||
return .hashtag(hashtag.peerName, hashtag.hashtag)
|
return .hashtag(hashtag.peerName, hashtag.hashtag)
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
@ -395,15 +397,15 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
override public func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
|
||||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func longTapped() {
|
override public func longTapped() {
|
||||||
self.item?.longTapAction?()
|
self.item?.longTapAction?()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -421,7 +423,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
TelegramTextAttributes.Hashtag
|
TelegramTextAttributes.Hashtag
|
||||||
]
|
]
|
||||||
for name in possibleNames {
|
for name in possibleNames {
|
||||||
if let _ = attributes[NSAttributedStringKey(rawValue: name)] {
|
if let _ = attributes[NSAttributedString.Key(rawValue: name)] {
|
||||||
rects = self.textNode.attributeRects(name: name, at: index)
|
rects = self.textNode.attributeRects(name: name, at: index)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -449,7 +451,7 @@ class ItemListTextWithLabelItemNode: ListViewItemNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tag: Any? {
|
public var tag: Any? {
|
||||||
return self.item?.tag
|
return self.item?.tag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,15 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import AsyncDisplayKit
|
|
||||||
import Display
|
|
||||||
|
|
||||||
protocol ItemListControllerEmptyStateItem {
|
|
||||||
func isEqual(to: ItemListControllerEmptyStateItem) -> Bool
|
|
||||||
func node(current: ItemListControllerEmptyStateItemNode?) -> ItemListControllerEmptyStateItemNode
|
|
||||||
}
|
|
||||||
|
|
||||||
class ItemListControllerEmptyStateItemNode: ASDisplayNode {
|
|
||||||
func updateLayout(layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user