mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-06-20 18:24:43 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
@@ -247,7 +247,6 @@ build_verbose: check_env
|
||||
|
||||
kill_xcode:
|
||||
killall Xcode || true
|
||||
killall Simulator || true
|
||||
|
||||
clean: kill_xcode
|
||||
sh clean.sh
|
||||
|
||||
@@ -63,9 +63,20 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)completeWithContent:(UNNotificationContent * _Nonnull)content {
|
||||
/*NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"org.telegram.Telegram-iOS.background"];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
|
||||
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"https://telegram.org"]];
|
||||
[task resume];*/
|
||||
|
||||
if (_contentHandler) {
|
||||
_contentHandler(content);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
|
||||
if (_rootPath == nil) {
|
||||
contentHandler(request.content);
|
||||
[self completeWithContent:request.content];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -289,8 +300,8 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
_bestAttemptContent.attachments = @[attachment];
|
||||
}
|
||||
}
|
||||
if (_contentHandler && _bestAttemptContent != nil) {
|
||||
_contentHandler(_bestAttemptContent);
|
||||
if (_bestAttemptContent != nil) {
|
||||
[self completeWithContent:_bestAttemptContent];
|
||||
}
|
||||
} else {
|
||||
BuildConfig *buildConfig = [[BuildConfig alloc] initWithBaseAppBundleId:_baseAppBundleId];
|
||||
@@ -322,21 +333,21 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
if (strongSelf->_contentHandler && strongSelf->_bestAttemptContent != nil) {
|
||||
strongSelf->_contentHandler(strongSelf->_bestAttemptContent);
|
||||
if (strongSelf->_bestAttemptContent != nil) {
|
||||
[strongSelf completeWithContent:strongSelf->_bestAttemptContent];
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (_contentHandler && _bestAttemptContent != nil) {
|
||||
_contentHandler(_bestAttemptContent);
|
||||
if (_bestAttemptContent != nil) {
|
||||
[self completeWithContent:_bestAttemptContent];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_contentHandler && _bestAttemptContent != nil) {
|
||||
_contentHandler(_bestAttemptContent);
|
||||
if (_bestAttemptContent != nil) {
|
||||
[self completeWithContent:_bestAttemptContent];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -349,7 +360,7 @@ static int64_t makePeerId(int32_t namespace, int32_t value) {
|
||||
|
||||
if (_contentHandler) {
|
||||
if(_bestAttemptContent) {
|
||||
_contentHandler(_bestAttemptContent);
|
||||
[self completeWithContent:_bestAttemptContent];
|
||||
_bestAttemptContent = nil;
|
||||
}
|
||||
_contentHandler = nil;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
@implementation Serialization
|
||||
|
||||
- (NSUInteger)currentLayer {
|
||||
return 105;
|
||||
return 106;
|
||||
}
|
||||
|
||||
- (id _Nullable)parseMessage:(NSData * _Nullable)data {
|
||||
|
||||
@@ -277,6 +277,9 @@
|
||||
<FileRef
|
||||
location = "group:submodules/RadialStatusNode/RadialStatusNode_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/SegmentedControlNode/SegmentedControlNode_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:submodules/LiveLocationTimerNode/LiveLocationTimerNode_Xcode.xcodeproj">
|
||||
</FileRef>
|
||||
|
||||
+14
-10
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0900"
|
||||
version = "1.3">
|
||||
version = "1.8">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -41,15 +41,6 @@
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D008599B1B28189D00EAF753"
|
||||
BuildableName = "Telegram.app"
|
||||
BlueprintName = "Telegram-iOS"
|
||||
ReferencedContainer = "container:Telegram-iOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO">
|
||||
@@ -72,6 +63,17 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D008599B1B28189D00EAF753"
|
||||
BuildableName = "Telegram.app"
|
||||
BlueprintName = "Telegram-iOS"
|
||||
ReferencedContainer = "container:Telegram-iOS.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "DebugHockeyapp"
|
||||
@@ -104,6 +106,8 @@
|
||||
isEnabled = "YES">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "DebugHockeyapp"
|
||||
|
||||
@@ -4725,3 +4725,27 @@ Any member of this group will be able to see messages in the channel.";
|
||||
"Theme.UsersCount_0" = "%@ people are using this theme";
|
||||
|
||||
"Conversation.SendMessageErrorTooMuchScheduled" = "Sorry, you can not schedule more than 100 messages.";
|
||||
|
||||
"ChatList.Context.MarkAllAsRead" = "Mark All as Read";
|
||||
"ChatList.Context.HideArchive" = "Hide Above the List";
|
||||
"ChatList.Context.UnhideArchive" = "Pin in the list";
|
||||
"ChatList.Context.RemoveFromRecents" = "Clear from Recents";
|
||||
"ChatList.Context.AddToContacts" = "Add to Contacts";
|
||||
"ChatList.Context.MarkAsRead" = "Mark as Read";
|
||||
"ChatList.Context.MarkAsUnread" = "Mark as Unread";
|
||||
"ChatList.Context.Archive" = "Archive";
|
||||
"ChatList.Context.Unarchive" = "Unarchive";
|
||||
"ChatList.Context.Pin" = "Pin";
|
||||
"ChatList.Context.Unpin" = "Unpin";
|
||||
"ChatList.Context.Mute" = "Mute";
|
||||
"ChatList.Context.Unmute" = "Unmute";
|
||||
"ChatList.Context.JoinChannel" = "Join Channel";
|
||||
"ChatList.Context.Delete" = "Delete";
|
||||
|
||||
"ContactList.Context.SendMessage" = "Send Message";
|
||||
"ContactList.Context.StartSecretChat" = "Start Secret Chat";
|
||||
"ContactList.Context.Call" = "Cal";
|
||||
|
||||
"Theme.Context.Apply" = "Apply";
|
||||
|
||||
"Settings.Context.Logout" = "Logout";
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -706,6 +706,20 @@
|
||||
ReferencedContainer = "container:submodules/ProgressNavigationButtonNode/ProgressNavigationButtonNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04EB84A82AD00000000"
|
||||
BuildableName = "libSegmentedControlNode.a"
|
||||
BlueprintName = "SegmentedControlNode"
|
||||
ReferencedContainer = "container:submodules/SegmentedControlNode/SegmentedControlNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
@@ -1014,6 +1028,48 @@
|
||||
ReferencedContainer = "container:submodules/ChatTitleActivityNode/ChatTitleActivityNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04EE09F1DE500000000"
|
||||
BuildableName = "libReactionSelectionNode.a"
|
||||
BlueprintName = "ReactionSelectionNode"
|
||||
ReferencedContainer = "container:submodules/ReactionSelectionNode/ReactionSelectionNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04E5B33A96100000000"
|
||||
BuildableName = "libTextSelectionNode.a"
|
||||
BlueprintName = "TextSelectionNode"
|
||||
ReferencedContainer = "container:submodules/TextSelectionNode/TextSelectionNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04E5F32B06300000000"
|
||||
BuildableName = "libContextUI.a"
|
||||
BlueprintName = "ContextUI"
|
||||
ReferencedContainer = "container:submodules/ContextUI/ContextUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
@@ -1056,6 +1112,20 @@
|
||||
ReferencedContainer = "container:submodules/ContactsPeerItem/ContactsPeerItem.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04EEAAB097E00000000"
|
||||
BuildableName = "libOverlayStatusController.a"
|
||||
BlueprintName = "OverlayStatusController"
|
||||
ReferencedContainer = "container:submodules/OverlayStatusController/OverlayStatusController.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
@@ -1210,20 +1280,6 @@
|
||||
ReferencedContainer = "container:submodules/LanguageSuggestionUI/LanguageSuggestionUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04EEAAB097E00000000"
|
||||
BuildableName = "libOverlayStatusController.a"
|
||||
BlueprintName = "OverlayStatusController"
|
||||
ReferencedContainer = "container:submodules/OverlayStatusController/OverlayStatusController.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
@@ -1294,48 +1350,6 @@
|
||||
ReferencedContainer = "container:submodules/ComposePollUI/ComposePollUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04EE09F1DE500000000"
|
||||
BuildableName = "libReactionSelectionNode.a"
|
||||
BlueprintName = "ReactionSelectionNode"
|
||||
ReferencedContainer = "container:submodules/ReactionSelectionNode/ReactionSelectionNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04E5B33A96100000000"
|
||||
BuildableName = "libTextSelectionNode.a"
|
||||
BlueprintName = "TextSelectionNode"
|
||||
ReferencedContainer = "container:submodules/TextSelectionNode/TextSelectionNode.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "E66DC04E5F32B06300000000"
|
||||
BuildableName = "libContextUI.a"
|
||||
BlueprintName = "ContextUI"
|
||||
ReferencedContainer = "container:submodules/ContextUI/ContextUI.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
|
||||
@@ -432,6 +432,7 @@ public protocol SharedAccountContext: class {
|
||||
func resolveUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError>
|
||||
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void)
|
||||
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
|
||||
func openAddPersonContact(context: AccountContext, peerId: PeerId, present: @escaping (ViewController, Any?) -> Void)
|
||||
func presentContactsWarningSuppression(context: AccountContext, present: (ViewController, Any?) -> Void)
|
||||
|
||||
func navigateToCurrentCall()
|
||||
|
||||
@@ -703,6 +703,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -930,6 +943,7 @@
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -1379,6 +1393,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1488,6 +1509,7 @@
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04A889192100000000</string>
|
||||
|
||||
@@ -422,6 +422,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -631,6 +644,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -935,6 +949,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1002,6 +1023,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F042417E0B200000000</string>
|
||||
|
||||
@@ -46,7 +46,7 @@ public final class CallListController: ViewController {
|
||||
self.mode = mode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.segmentedTitleView = ItemListControllerSegmentedTitleView(segments: [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed], index: 0, color: self.presentationData.theme.rootController.navigationBar.accentTextColor)
|
||||
self.segmentedTitleView = ItemListControllerSegmentedTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed], selectedIndex: 0)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
|
||||
@@ -102,7 +102,7 @@ public final class CallListController: ViewController {
|
||||
private func updateThemeAndStrings() {
|
||||
let index = self.segmentedTitleView.index
|
||||
self.segmentedTitleView.segments = [self.presentationData.strings.Calls_All, self.presentationData.strings.Calls_Missed]
|
||||
self.segmentedTitleView.color = self.presentationData.theme.rootController.navigationBar.accentTextColor
|
||||
self.segmentedTitleView.theme = self.presentationData.theme
|
||||
self.segmentedTitleView.index = index
|
||||
|
||||
self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle
|
||||
|
||||
@@ -37,6 +37,7 @@ static_library(
|
||||
"//submodules/ContactListUI:ContactListUI",
|
||||
"//submodules/PhotoResources:PhotoResources",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -182,6 +182,17 @@
|
||||
<string>1DD70E29BE4AC65500000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>1DD70E29308FEF0200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>ChatContextMenus.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/ChatContextMenus.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E29577C319700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -292,6 +303,7 @@
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>B401C9790025222200000000</string>
|
||||
<string>1DD70E29308FEF0200000000</string>
|
||||
<string>1DD70E29577C319700000000</string>
|
||||
<string>1DD70E2943B2E93900000000</string>
|
||||
<string>1DD70E2906CA893E00000000</string>
|
||||
@@ -553,6 +565,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CED1620500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -865,6 +890,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E291D58331200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -904,6 +942,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1125,6 +1176,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29B4B05B7A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1213,6 +1277,7 @@
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E292F91702000000000</string>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E29CED1620500000000</string>
|
||||
<string>1DD70E292417E0B200000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
@@ -1237,9 +1302,11 @@
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E293E4DE92B00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E291D58331200000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E291328E99400000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E29524F478E00000000</string>
|
||||
@@ -1257,6 +1324,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29B4B05B7A00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E29AE67341000000000</string>
|
||||
@@ -1390,6 +1458,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BE4AC65500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04308FEF0200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29308FEF0200000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04577C319700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1471,6 +1546,7 @@
|
||||
<string>E7A30F0428E77D0F00000000</string>
|
||||
<string>E7A30F04978C105400000000</string>
|
||||
<string>E7A30F04BE4AC65500000000</string>
|
||||
<string>E7A30F04308FEF0200000000</string>
|
||||
<string>E7A30F04577C319700000000</string>
|
||||
<string>E7A30F0443B2E93900000000</string>
|
||||
<string>E7A30F0406CA893E00000000</string>
|
||||
@@ -1720,6 +1796,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04CBE117ED00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1727,6 +1824,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1762,6 +1866,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F041328E99400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1867,13 +1978,6 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29E220F5E800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04247D9AC100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1956,12 +2060,17 @@
|
||||
<string>E7A30F047AB043C800000000</string>
|
||||
<string>E7A30F04B6F47D1F00000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F0431752C6000000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F041328E99400000000</string>
|
||||
<string>E7A30F041E16CC6C00000000</string>
|
||||
<string>E7A30F043E4DE92B00000000</string>
|
||||
@@ -1977,7 +2086,6 @@
|
||||
<string>E7A30F042F91702000000000</string>
|
||||
<string>E7A30F04CED1620500000000</string>
|
||||
<string>E7A30F04E220F5E800000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F04247D9AC100000000</string>
|
||||
<string>E7A30F04B4B05B7A00000000</string>
|
||||
<string>E7A30F04490601EB00000000</string>
|
||||
|
||||
@@ -0,0 +1,229 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import ContextUI
|
||||
import AccountContext
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import Display
|
||||
import TelegramUIPreferences
|
||||
import OverlayStatusController
|
||||
import AlertUI
|
||||
|
||||
func archiveContextMenuItems(context: AccountContext, groupId: PeerGroupId, chatListController: ChatListControllerImpl?) -> Signal<[ContextMenuItem], NoError> {
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if !transaction.getUnreadChatListPeerIds(groupId: groupId).isEmpty {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAllAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { [weak chatListController] _, f in
|
||||
let _ = (context.account.postbox.transaction { transaction in
|
||||
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: groupId)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
let settings = transaction.getPreferencesEntry(key: ApplicationSpecificPreferencesKeys.chatArchiveSettings) as? ChatArchiveSettings ?? ChatArchiveSettings.default
|
||||
let isPinned = !settings.isHiddenByDefault
|
||||
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_HideArchive : strings.ChatList_Context_UnhideArchive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin": "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak chatListController] _, f in
|
||||
chatListController?.toggleArchivedFolderHiddenByDefault()
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatContextMenuSource {
|
||||
case chatList
|
||||
case search(ChatListSearchContextActionSource)
|
||||
}
|
||||
|
||||
func chatContextMenuItems(context: AccountContext, peerId: PeerId, source: ChatContextMenuSource, chatListController: ChatListControllerImpl?) -> Signal<[ContextMenuItem], NoError> {
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if case let .search(search) = source {
|
||||
switch search {
|
||||
case .recentPeers:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (removeRecentPeer(account: context.account, peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .recentSearch:
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_RemoveFromRecents, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
let _ = (removeRecentlySearchedPeer(postbox: context.account.postbox, peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
items.append(.separator)
|
||||
case .search:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
let isSavedMessages = peerId == context.account.peerId
|
||||
|
||||
let chatPeer = transaction.getPeer(peerId)
|
||||
var peer: Peer?
|
||||
if let chatPeer = chatPeer {
|
||||
if let chatPeer = chatPeer as? TelegramSecretChat {
|
||||
peer = transaction.getPeer(chatPeer.regularPeerId)
|
||||
} else {
|
||||
peer = chatPeer
|
||||
}
|
||||
}
|
||||
if !isSavedMessages, let peer = peer as? TelegramUser {
|
||||
if !transaction.isPeerContact(peerId: peer.id) {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_AddToContacts, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AddUser"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
context.sharedContext.openAddPersonContact(context: context, peerId: peerId, present: { controller, arguments in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.present(controller, in: .window(.root), with: arguments)
|
||||
}
|
||||
})
|
||||
f(.default)
|
||||
})))
|
||||
items.append(.separator)
|
||||
}
|
||||
}
|
||||
|
||||
if case .chatList = source, !isSavedMessages {
|
||||
if let readState = transaction.getCombinedPeerReadState(peerId), readState.isUnread {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
} else {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
let groupAndIndex = transaction.getPeerChatListIndex(peerId)
|
||||
|
||||
if let (group, index) = groupAndIndex {
|
||||
if !isSavedMessages {
|
||||
let isArchived = group == Namespaces.PeerGroup.archive
|
||||
items.append(.action(ContextMenuActionItem(text: isArchived ? strings.ChatList_Context_Archive : strings.ChatList_Context_Unarchive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isArchived ? "Chat/Context Menu/Unarchive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
if isArchived {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: .root)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
} else {
|
||||
if let chatListController = chatListController {
|
||||
chatListController.archiveChats(peerIds: [peerId])
|
||||
f(.default)
|
||||
} else {
|
||||
let _ = (context.account.postbox.transaction { transaction -> Void in
|
||||
updatePeerGroupIdInteractively(transaction: transaction, peerId: peerId, groupId: Namespaces.PeerGroup.archive)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
}
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
let isPinned = index.pinningIndex != nil
|
||||
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (toggleItemPinned(postbox: context.account.postbox, groupId: group, itemId: .peer(peerId))
|
||||
|> deliverOnMainQueue).start(next: { result in
|
||||
switch result {
|
||||
case .done:
|
||||
break
|
||||
case let .limitExceeded(maxCount):
|
||||
break
|
||||
//strongSelf.presentAlert?(strongSelf.currentState.presentationData.strings.DialogList_PinLimitError("\(maxCount)").0)
|
||||
}
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
|
||||
if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
|
||||
var isMuted = false
|
||||
if case .muted = notificationSettings.muteState {
|
||||
isMuted = true
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: isMuted ? strings.ChatList_Context_Unmute : strings.ChatList_Context_Mute, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (togglePeerMuted(account: context.account, peerId: peerId)
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
} else {
|
||||
if case .search = source {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_JoinChannel, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Add"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
var createSignal = joinChannel(account: context.account, peerId: peerId)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
chatListController?.present(controller, in: .window(.root))
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let joinChannelDisposable = MetaDisposable()
|
||||
cancelImpl = {
|
||||
joinChannelDisposable.set(nil)
|
||||
}
|
||||
|
||||
joinChannelDisposable.set((createSignal
|
||||
|> deliverOnMainQueue).start(next: { _ in
|
||||
if let navigationController = (chatListController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { _ in
|
||||
if let chatListController = chatListController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
chatListController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if case .chatList = source, groupAndIndex != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.deletePeerChat(peerId: peerId)
|
||||
}
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import TelegramNotices
|
||||
import SearchUI
|
||||
import DeleteChatPeerActionSheetItem
|
||||
import LanguageSuggestionUI
|
||||
import ContextUI
|
||||
import AppBundle
|
||||
|
||||
public func useSpecialTabBarIcons() -> Bool {
|
||||
@@ -65,6 +66,27 @@ private func fixListNodeScrolling(_ listNode: ListView, searchNode: NavigationBa
|
||||
return false
|
||||
}
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
weak var sourceNode: ASDisplayNode?
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||
let sourceNode = self.sourceNode
|
||||
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||
if let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatListControllerImpl: TelegramBaseController, ChatListController, UIViewControllerPreviewingDelegate {
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
@@ -442,240 +464,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Bool in
|
||||
var updatedValue = false
|
||||
updateChatArchiveSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.isHiddenByDefault = !settings.isHiddenByDefault
|
||||
updatedValue = settings.isHiddenByDefault
|
||||
return settings
|
||||
})
|
||||
return updatedValue
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState { state in
|
||||
var state = state
|
||||
if value {
|
||||
state.archiveShouldBeTemporaryRevealed = false
|
||||
}
|
||||
state.peerIdWithRevealedOptions = nil
|
||||
return state
|
||||
}
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitActionAndReplacementAnimation()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if value {
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenText, undo: false), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !shouldCommit {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Bool in
|
||||
var updatedValue = false
|
||||
updateChatArchiveSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.isHiddenByDefault = false
|
||||
updatedValue = settings.isHiddenByDefault
|
||||
return settings
|
||||
})
|
||||
return updatedValue
|
||||
}).start()
|
||||
}
|
||||
}), in: .current)
|
||||
} else {
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .revealedArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedText, undo: false), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
}), in: .current)
|
||||
}
|
||||
})
|
||||
strongSelf.toggleArchivedFolderHiddenByDefault()
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.chatListNode.deletePeerChat = { [weak self] peerId in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> RenderedPeer? in
|
||||
guard let peer = transaction.getPeer(peerId) else {
|
||||
return nil
|
||||
}
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
if let associatedPeer = transaction.getPeer(associatedPeerId) {
|
||||
return RenderedPeer(peerId: peerId, peers: SimpleDictionary([peer.id: peer, associatedPeer.id: associatedPeer]))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return RenderedPeer(peer: peer)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { peer in
|
||||
guard let strongSelf = self, let peer = peer, let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
var canRemoveGlobally = false
|
||||
let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 }
|
||||
if peer.peerId.namespace == Namespaces.Peer.CloudUser && peer.peerId != strongSelf.context.account.peerId {
|
||||
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
|
||||
if let user = chatPeer as? TelegramUser, user.botInfo == nil, canRemoveGlobally {
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in }, removed: {})
|
||||
} else {
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
var canClear = true
|
||||
var canStop = false
|
||||
|
||||
var deleteTitle = strongSelf.presentationData.strings.Common_Delete
|
||||
if let channel = chatPeer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
canClear = false
|
||||
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
|
||||
} else {
|
||||
deleteTitle = strongSelf.presentationData.strings.Group_LeaveGroup
|
||||
}
|
||||
if let addressName = channel.addressName, !addressName.isEmpty {
|
||||
canClear = false
|
||||
}
|
||||
} else if let user = chatPeer as? TelegramUser, user.botInfo != nil {
|
||||
canStop = !user.flags.contains(.isSupport)
|
||||
canClear = user.botInfo == nil
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
} else if let _ = chatPeer as? TelegramSecretChat {
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
}
|
||||
|
||||
var canRemoveGlobally = false
|
||||
let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 }
|
||||
if chatPeer is TelegramUser && chatPeer.id != strongSelf.context.account.peerId {
|
||||
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: strongSelf.presentationData.strings))
|
||||
if canClear {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.DialogList_ClearHistoryConfirmation, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { type in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.insert(peer.peerId)
|
||||
return state
|
||||
})
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitActionAndReplacementAnimation()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .removedChat(text: strongSelf.presentationData.strings.Undo_ChatCleared), elevatedLayout: false, animateInAsReplacement: true, action: { shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if shouldCommit {
|
||||
let _ = clearHistoryInteractively(postbox: strongSelf.context.account.postbox, peerId: peerId, type: type).start(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
})
|
||||
} else {
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
}
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
if canRemoveGlobally {
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: strongSelf.presentationData.strings))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forLocalPeer)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
} else {
|
||||
beginClear(.forLocalPeer)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
items.append(ActionSheetButtonItem(title: deleteTitle, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in }, removed: {})
|
||||
}))
|
||||
|
||||
if canStop {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.DialogList_DeleteBotConversationConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
if let strongSelf = self {
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in
|
||||
}, removed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.peerId, isBlocked: true).start()
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
})
|
||||
strongSelf.deletePeerChat(peerId: peerId)
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.chatListNode.peerSelected = { [weak self] peerId, animated, isAd in
|
||||
@@ -860,6 +656,36 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
self?.toolbarActionSelected(action: action)
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.chatListNode.activateChatPreview = { [weak self] item, node, gesture in
|
||||
guard let strongSelf = self else {
|
||||
gesture?.cancel()
|
||||
return
|
||||
}
|
||||
switch item.content {
|
||||
case let .groupReference(groupReference):
|
||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupReference.groupId, controlsHistoryPreload: false, enableDebugActions: false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node)), items: archiveContextMenuItems(context: strongSelf.context, groupId: groupReference.groupId, chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
case let .peer(peer):
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peer.peerId, source: .chatList, chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.peerContextAction = { [weak self] peer, source, node, gesture in
|
||||
guard let strongSelf = self else {
|
||||
gesture?.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, source: .search(source), chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
let context = self.context
|
||||
let peerIdsAndOptions: Signal<(ChatListSelectionOptions, Set<PeerId>)?, NoError> = self.chatListDisplayNode.chatListNode.state
|
||||
|> map { state -> Set<PeerId>? in
|
||||
@@ -951,7 +777,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
if !self.didSetup3dTouch && self.traitCollection.forceTouchCapability != .unknown {
|
||||
self.didSetup3dTouch = true
|
||||
self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
//self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1069,6 +895,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
if !self.didSetup3dTouch {
|
||||
self.didSetup3dTouch = true
|
||||
//self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func viewWillDisappear(_ animated: Bool) {
|
||||
@@ -1448,6 +1281,240 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
}
|
||||
|
||||
func toggleArchivedFolderHiddenByDefault() {
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> Bool in
|
||||
var updatedValue = false
|
||||
updateChatArchiveSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.isHiddenByDefault = !settings.isHiddenByDefault
|
||||
updatedValue = settings.isHiddenByDefault
|
||||
return settings
|
||||
})
|
||||
return updatedValue
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState { state in
|
||||
var state = state
|
||||
if value {
|
||||
state.archiveShouldBeTemporaryRevealed = false
|
||||
}
|
||||
state.peerIdWithRevealedOptions = nil
|
||||
return state
|
||||
}
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitActionAndReplacementAnimation()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if value {
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .hidArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveHiddenText, undo: false), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if !shouldCommit {
|
||||
let _ = (strongSelf.context.account.postbox.transaction { transaction -> Bool in
|
||||
var updatedValue = false
|
||||
updateChatArchiveSettings(transaction: transaction, { settings in
|
||||
var settings = settings
|
||||
settings.isHiddenByDefault = false
|
||||
updatedValue = settings.isHiddenByDefault
|
||||
return settings
|
||||
})
|
||||
return updatedValue
|
||||
}).start()
|
||||
}
|
||||
}), in: .current)
|
||||
} else {
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .revealedArchive(title: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedTitle, text: strongSelf.presentationData.strings.ChatList_UndoArchiveRevealedText, undo: false), elevatedLayout: false, animateInAsReplacement: true, action: { _ in
|
||||
}), in: .current)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func deletePeerChat(peerId: PeerId) {
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> RenderedPeer? in
|
||||
guard let peer = transaction.getPeer(peerId) else {
|
||||
return nil
|
||||
}
|
||||
if let associatedPeerId = peer.associatedPeerId {
|
||||
if let associatedPeer = transaction.getPeer(associatedPeerId) {
|
||||
return RenderedPeer(peerId: peerId, peers: SimpleDictionary([peer.id: peer, associatedPeer.id: associatedPeer]))
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
return RenderedPeer(peer: peer)
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
guard let strongSelf = self, let peer = peer, let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
|
||||
return
|
||||
}
|
||||
|
||||
var canRemoveGlobally = false
|
||||
let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 }
|
||||
if peer.peerId.namespace == Namespaces.Peer.CloudUser && peer.peerId != strongSelf.context.account.peerId {
|
||||
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
|
||||
if let user = chatPeer as? TelegramUser, user.botInfo == nil, canRemoveGlobally {
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in }, removed: {})
|
||||
} else {
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
var canClear = true
|
||||
var canStop = false
|
||||
|
||||
var deleteTitle = strongSelf.presentationData.strings.Common_Delete
|
||||
if let channel = chatPeer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
canClear = false
|
||||
deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel
|
||||
} else {
|
||||
deleteTitle = strongSelf.presentationData.strings.Group_LeaveGroup
|
||||
}
|
||||
if let addressName = channel.addressName, !addressName.isEmpty {
|
||||
canClear = false
|
||||
}
|
||||
} else if let user = chatPeer as? TelegramUser, user.botInfo != nil {
|
||||
canStop = !user.flags.contains(.isSupport)
|
||||
canClear = user.botInfo == nil
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
} else if let _ = chatPeer as? TelegramSecretChat {
|
||||
deleteTitle = strongSelf.presentationData.strings.ChatList_DeleteChat
|
||||
}
|
||||
|
||||
var canRemoveGlobally = false
|
||||
let limitsConfiguration = strongSelf.context.currentLimitsConfiguration.with { $0 }
|
||||
if chatPeer is TelegramUser && chatPeer.id != strongSelf.context.account.peerId {
|
||||
if limitsConfiguration.maxMessageRevokeIntervalInPrivateChats == LimitsConfiguration.timeIntervalForever {
|
||||
canRemoveGlobally = true
|
||||
}
|
||||
}
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: strongSelf.presentationData.strings))
|
||||
if canClear {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.DialogList_ClearHistoryConfirmation, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let beginClear: (InteractiveHistoryClearingType) -> Void = { type in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.insert(peer.peerId)
|
||||
return state
|
||||
})
|
||||
strongSelf.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitActionAndReplacementAnimation()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
strongSelf.present(UndoOverlayController(context: strongSelf.context, content: .removedChat(text: strongSelf.presentationData.strings.Undo_ChatCleared), elevatedLayout: false, animateInAsReplacement: true, action: { shouldCommit in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if shouldCommit {
|
||||
let _ = clearHistoryInteractively(postbox: strongSelf.context.account.postbox, peerId: peerId, type: type).start(completed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
})
|
||||
} else {
|
||||
strongSelf.chatListDisplayNode.chatListNode.updateState({ state in
|
||||
var state = state
|
||||
state.pendingClearHistoryPeerIds.remove(peer.peerId)
|
||||
return state
|
||||
})
|
||||
}
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
if canRemoveGlobally {
|
||||
let actionSheet = ActionSheetController(presentationTheme: strongSelf.presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: strongSelf.presentationData.strings))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forLocalPeer)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
} else {
|
||||
beginClear(.forLocalPeer)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
items.append(ActionSheetButtonItem(title: deleteTitle, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in }, removed: {})
|
||||
}))
|
||||
|
||||
if canStop {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.DialogList_DeleteBotConversationConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
if let strongSelf = self {
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in
|
||||
}, removed: {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let _ = requestUpdatePeerIsBlocked(account: strongSelf.context.account, peerId: peer.peerId, isBlocked: true).start()
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])
|
||||
])
|
||||
strongSelf.present(actionSheet, in: .window(.root))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
public func maybeAskForPeerChatRemoval(peer: RenderedPeer, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) {
|
||||
guard let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
|
||||
completion(false)
|
||||
@@ -1502,7 +1569,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
}
|
||||
|
||||
private func archiveChats(peerIds: [PeerId]) {
|
||||
func archiveChats(peerIds: [PeerId]) {
|
||||
guard !peerIds.isEmpty else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import ActivityIndicator
|
||||
import AccountContext
|
||||
import SearchBarNode
|
||||
import SearchUI
|
||||
import ContextUI
|
||||
|
||||
private final class ChatListControllerNodeView: UITracingLayerView, PreviewingHostView {
|
||||
var previewingDelegate: PreviewingHostViewDelegate? {
|
||||
@@ -64,6 +65,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
var requestOpenRecentPeerOptions: ((Peer) -> Void)?
|
||||
var requestOpenMessageFromSearch: ((Peer, MessageId) -> Void)?
|
||||
var requestAddContact: ((String) -> Void)?
|
||||
var peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
var dismissSelf: (() -> Void)?
|
||||
var isEmptyUpdated: ((Bool) -> Void)?
|
||||
|
||||
@@ -272,7 +274,7 @@ final class ChatListControllerNode: ASDisplayNode {
|
||||
if let requestAddContact = self?.requestAddContact {
|
||||
requestAddContact(phoneNumber)
|
||||
}
|
||||
}), cancel: { [weak self] in
|
||||
}, peerContextAction: self.peerContextAction), cancel: { [weak self] in
|
||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import SearchUI
|
||||
import ContactsPeerItem
|
||||
import ChatListSearchItemHeader
|
||||
import ContactListUI
|
||||
import ContextUI
|
||||
|
||||
private enum ChatListRecentEntryStableId: Hashable {
|
||||
case topPeers
|
||||
@@ -77,7 +78,7 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
func item(context: AccountContext, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, peerLongTapped: @escaping (Peer) -> Void, clearRecentlySearchedPeers: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, deletePeer: @escaping (PeerId) -> Void) -> ListViewItem {
|
||||
func item(context: AccountContext, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, peerLongTapped: @escaping (Peer) -> Void, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, deletePeer: @escaping (PeerId) -> Void) -> ListViewItem {
|
||||
switch self {
|
||||
case let .topPeers(peers, theme, strings):
|
||||
return ChatListRecentPeersListItem(theme: theme, strings: strings, account: context.account, peers: peers, peerSelected: { peer in
|
||||
@@ -173,7 +174,13 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||
peerSelected(chatPeer)
|
||||
}
|
||||
}, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer)
|
||||
}, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture in
|
||||
if let chatPeer = peer.peer.peers[peer.peer.peerId] {
|
||||
peerContextAction(chatPeer, .recentSearch, node, gesture)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -316,7 +323,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
|
||||
public func item(context: AccountContext, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction) -> ListViewItem {
|
||||
public func item(context: AccountContext, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?) -> ListViewItem {
|
||||
switch self {
|
||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder):
|
||||
let primaryPeer: Peer
|
||||
@@ -372,6 +379,14 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: context.account, peerMode: .generalSearch, peer: .peer(peer: primaryPeer, chatPeer: chatPeer), status: .none, badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.peerSelected(peer)
|
||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture in
|
||||
if let chatPeer = chatPeer {
|
||||
peerContextAction(chatPeer, .search, node, gesture)
|
||||
} else {
|
||||
gesture?.cancel()
|
||||
}
|
||||
}
|
||||
})
|
||||
case let .globalPeer(peer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder):
|
||||
var enabled = true
|
||||
@@ -416,6 +431,10 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
||||
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: context.account, peerMode: .generalSearch, peer: .peer(peer: peer.peer, chatPeer: peer.peer), status: .addressName(suffixString), badge: badge, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.peerSelected(peer.peer)
|
||||
}, contextAction: peerContextAction.flatMap { peerContextAction in
|
||||
return { node, gesture in
|
||||
peerContextAction(peer.peer, .search, node, gesture)
|
||||
}
|
||||
})
|
||||
case let .message(message, peer, readState, presentationData):
|
||||
return ChatListItem(presentationData: presentationData, context: context, peerGroupId: .root, index: ChatListIndex(pinningIndex: nil, messageIndex: message.index), content: .peer(message: message, peer: peer, combinedReadState: readState, notificationSettings: nil, presence: nil, summaryInfo: ChatListMessageTagSummaryInfo(), embeddedState: nil, inputActivities: nil, isAd: false, ignoreUnreadBadge: true), editing: false, hasActiveRevealControls: false, selected: false, header: enableHeaders ? ChatListSearchItemHeader(type: .messages, theme: presentationData.theme, strings: presentationData.strings, actionTitle: nil, action: nil) : nil, enableContextActions: false, hiddenOffset: false, interaction: interaction)
|
||||
@@ -447,22 +466,22 @@ public struct ChatListSearchContainerTransition {
|
||||
}
|
||||
}
|
||||
|
||||
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, peerLongTapped: @escaping (Peer) -> Void, clearRecentlySearchedPeers: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, deletePeer: @escaping (PeerId) -> Void) -> ChatListSearchContainerRecentTransition {
|
||||
private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [ChatListRecentEntry], to toEntries: [ChatListRecentEntry], context: AccountContext, filter: ChatListNodePeersFilter, peerSelected: @escaping (Peer) -> Void, peerLongTapped: @escaping (Peer) -> Void, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, clearRecentlySearchedPeers: @escaping () -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, deletePeer: @escaping (PeerId) -> Void) -> ChatListSearchContainerRecentTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, filter: filter, peerSelected: peerSelected, peerLongTapped: peerLongTapped, clearRecentlySearchedPeers: clearRecentlySearchedPeers, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, filter: filter, peerSelected: peerSelected, peerLongTapped: peerLongTapped, clearRecentlySearchedPeers: clearRecentlySearchedPeers, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, filter: filter, peerSelected: peerSelected, peerLongTapped: peerLongTapped, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, filter: filter, peerSelected: peerSelected, peerLongTapped: peerLongTapped, peerContextAction: peerContextAction, clearRecentlySearchedPeers: clearRecentlySearchedPeers, setPeerIdWithRevealedOptions: setPeerIdWithRevealedOptions, deletePeer: deletePeer), directionHint: nil) }
|
||||
|
||||
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||
}
|
||||
|
||||
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, context: AccountContext, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction) -> ChatListSearchContainerTransition {
|
||||
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, context: AccountContext, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?) -> ChatListSearchContainerTransition {
|
||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||
|
||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, enableHeaders: enableHeaders, filter: filter, interaction: interaction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, enableHeaders: enableHeaders, filter: filter, interaction: interaction), directionHint: nil) }
|
||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, enableHeaders: enableHeaders, filter: filter, interaction: interaction, peerContextAction: peerContextAction), directionHint: nil) }
|
||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, enableHeaders: enableHeaders, filter: filter, interaction: interaction, peerContextAction: peerContextAction), directionHint: nil) }
|
||||
|
||||
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults)
|
||||
}
|
||||
@@ -517,6 +536,12 @@ private struct ChatListSearchMessagesContext {
|
||||
let loadMoreIndex: MessageIndex?
|
||||
}
|
||||
|
||||
public enum ChatListSearchContextActionSource {
|
||||
case recentPeers
|
||||
case recentSearch
|
||||
case search
|
||||
}
|
||||
|
||||
public final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
|
||||
private let context: AccountContext
|
||||
|
||||
@@ -547,7 +572,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
|
||||
private let filter: ChatListNodePeersFilter
|
||||
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer: @escaping (Peer, Bool) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?) {
|
||||
public init(context: AccountContext, filter: ChatListNodePeersFilter, groupId: PeerGroupId, openPeer: @escaping (Peer, Bool) -> Void, openRecentPeerOptions: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||
self.context = context
|
||||
self.filter = filter
|
||||
self.dimNode = ASDisplayNode()
|
||||
@@ -847,6 +872,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
}, togglePeerMarkedUnread: { _, _ in
|
||||
}, toggleArchivedFolderHiddenByDefault: {
|
||||
}, activateChatPreview: { item, node, gesture in
|
||||
guard let peerContextAction = peerContextAction else {
|
||||
gesture?.cancel()
|
||||
return
|
||||
}
|
||||
switch item.content {
|
||||
case let .peer(peer):
|
||||
if let peer = peer.peer.peer {
|
||||
peerContextAction(peer, .search, node, gesture)
|
||||
}
|
||||
case .groupReference:
|
||||
gesture?.cancel()
|
||||
}
|
||||
})
|
||||
|
||||
let previousRecentItems = Atomic<[ChatListRecentEntry]?>(value: nil)
|
||||
@@ -933,7 +971,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
self?.recentListNode.clearHighlightAnimated(true)
|
||||
}, peerLongTapped: { peer in
|
||||
openRecentPeerOptions(peer)
|
||||
}, clearRecentlySearchedPeers: {
|
||||
}, peerContextAction: peerContextAction,
|
||||
clearRecentlySearchedPeers: {
|
||||
self?.clearRecentSearch()
|
||||
}, setPeerIdWithRevealedOptions: { peerId, fromPeerId in
|
||||
interaction.setPeerIdWithRevealedOptions(peerId, fromPeerId)
|
||||
@@ -954,7 +993,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
let previousEntries = previousSearchItems.swap(entriesAndFlags?.0)
|
||||
|
||||
let firstTime = previousEntries == nil
|
||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entriesAndFlags?.0 ?? [], displayingResults: entriesAndFlags?.0 != nil, context: context, enableHeaders: true, filter: filter, interaction: interaction)
|
||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entriesAndFlags?.0 ?? [], displayingResults: entriesAndFlags?.0 != nil, context: context, enableHeaders: true, filter: filter, interaction: interaction, peerContextAction: peerContextAction)
|
||||
strongSelf.enqueueTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
}))
|
||||
|
||||
@@ -15,6 +15,7 @@ import LocalizedPeerData
|
||||
import PeerPresenceStatusManager
|
||||
import PhotoResources
|
||||
import ChatListSearchItemNode
|
||||
import ContextUI
|
||||
|
||||
public enum ChatListItemContent {
|
||||
case peer(message: Message?, peer: RenderedPeer, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, presence: PeerPresence?, summaryInfo: ChatListMessageTagSummaryInfo, embeddedState: PeerChatListEmbeddedInterfaceState?, inputActivities: [(Peer, PeerInputActivity)]?, isAd: Bool, ignoreUnreadBadge: Bool)
|
||||
@@ -294,6 +295,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
private let backgroundNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
|
||||
let contextContainer: ContextControllerSourceNode
|
||||
|
||||
let avatarNode: AvatarNode
|
||||
let titleNode: TextNode
|
||||
let authorNode: TextNode
|
||||
@@ -410,6 +413,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isLayerBacked = true
|
||||
|
||||
self.contextContainer = ContextControllerSourceNode()
|
||||
|
||||
self.titleNode = TextNode()
|
||||
self.titleNode.isUserInteractionEnabled = false
|
||||
self.titleNode.displaysAsynchronously = true
|
||||
@@ -457,19 +462,22 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.onlineNode)
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.authorNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.contentImageNode)
|
||||
self.addSubnode(self.dateNode)
|
||||
self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.pinnedIconNode)
|
||||
self.addSubnode(self.badgeNode)
|
||||
self.addSubnode(self.mentionBadgeNode)
|
||||
self.addSubnode(self.mutedIconNode)
|
||||
self.addSubnode(self.contextContainer)
|
||||
|
||||
self.contextContainer.addSubnode(self.avatarNode)
|
||||
self.contextContainer.addSubnode(self.onlineNode)
|
||||
|
||||
self.contextContainer.addSubnode(self.titleNode)
|
||||
self.contextContainer.addSubnode(self.authorNode)
|
||||
self.contextContainer.addSubnode(self.textNode)
|
||||
self.contextContainer.addSubnode(self.contentImageNode)
|
||||
self.contextContainer.addSubnode(self.dateNode)
|
||||
self.contextContainer.addSubnode(self.statusNode)
|
||||
self.contextContainer.addSubnode(self.pinnedIconNode)
|
||||
self.contextContainer.addSubnode(self.badgeNode)
|
||||
self.contextContainer.addSubnode(self.mentionBadgeNode)
|
||||
self.contextContainer.addSubnode(self.mutedIconNode)
|
||||
|
||||
self.peerPresenceManager = PeerPresenceStatusManager(update: { [weak self] in
|
||||
if let strongSelf = self, let layoutParams = strongSelf.layoutParams {
|
||||
@@ -477,6 +485,13 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
let _ = apply(false, false)
|
||||
}
|
||||
})
|
||||
|
||||
self.contextContainer.activated = { [weak self] gesture in
|
||||
guard let strongSelf = self, let item = strongSelf.item else {
|
||||
return
|
||||
}
|
||||
item.interaction.activateChatPreview(item, strongSelf, gesture)
|
||||
}
|
||||
}
|
||||
|
||||
func setupItem(item: ChatListItem, synchronousLoads: Bool) {
|
||||
@@ -1110,6 +1125,8 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.layoutParams = (item, first, last, firstWithHeader, nextIsPinned, params, countersSize)
|
||||
strongSelf.contentImageMedia = contentImageMedia
|
||||
|
||||
strongSelf.contextContainer.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
|
||||
var dimensions: CGSize?
|
||||
if let contentImageMedia = contentImageMedia as? TelegramMediaImage {
|
||||
dimensions = largestRepresentationForPhoto(contentImageMedia)?.dimensions
|
||||
@@ -1293,7 +1310,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
iconNode.isLayerBacked = true
|
||||
iconNode.displaysAsynchronously = false
|
||||
iconNode.displayWithoutProcessing = true
|
||||
strongSelf.addSubnode(iconNode)
|
||||
strongSelf.contextContainer.addSubnode(iconNode)
|
||||
strongSelf.secretIconNode = iconNode
|
||||
}
|
||||
iconNode.image = currentSecretIconImage
|
||||
@@ -1315,7 +1332,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
iconNode.isLayerBacked = true
|
||||
iconNode.displaysAsynchronously = false
|
||||
iconNode.displayWithoutProcessing = true
|
||||
strongSelf.addSubnode(iconNode)
|
||||
strongSelf.contextContainer.addSubnode(iconNode)
|
||||
strongSelf.credibilityIconNode = iconNode
|
||||
}
|
||||
iconNode.image = currentCredibilityIconImage
|
||||
@@ -1352,7 +1369,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
var animateInputActivitiesFrame = false
|
||||
if let inputActivities = inputActivities, !inputActivities.isEmpty {
|
||||
if strongSelf.inputActivitiesNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.inputActivitiesNode)
|
||||
strongSelf.contextContainer.addSubnode(strongSelf.inputActivitiesNode)
|
||||
} else {
|
||||
animateInputActivitiesFrame = true
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import TelegramUIPreferences
|
||||
import AccountContext
|
||||
import TelegramNotices
|
||||
import ContactsPeerItem
|
||||
import ContextUI
|
||||
|
||||
public enum ChatListNodeMode {
|
||||
case chatList
|
||||
@@ -54,10 +55,11 @@ public final class ChatListNodeInteraction {
|
||||
let updatePeerGrouping: (PeerId, Bool) -> Void
|
||||
let togglePeerMarkedUnread: (PeerId, Bool) -> Void
|
||||
let toggleArchivedFolderHiddenByDefault: () -> Void
|
||||
let activateChatPreview: (ChatListItem, ASDisplayNode, ContextGesture?) -> Void
|
||||
|
||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, messageSelected: @escaping (Peer, Message, Bool) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void) {
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, messageSelected: @escaping (Peer, Message, Bool) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
self.peerSelected = peerSelected
|
||||
self.togglePeerSelected = togglePeerSelected
|
||||
@@ -71,6 +73,7 @@ public final class ChatListNodeInteraction {
|
||||
self.updatePeerGrouping = updatePeerGrouping
|
||||
self.togglePeerMarkedUnread = togglePeerMarkedUnread
|
||||
self.toggleArchivedFolderHiddenByDefault = toggleArchivedFolderHiddenByDefault
|
||||
self.activateChatPreview = activateChatPreview
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,6 +316,7 @@ public final class ChatListNode: ListView {
|
||||
public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
||||
public var presentAlert: ((String) -> Void)?
|
||||
public var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
||||
public var activateChatPreview: ((ChatListItem, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
private var theme: PresentationTheme
|
||||
|
||||
@@ -469,6 +473,15 @@ public final class ChatListNode: ListView {
|
||||
})
|
||||
}, toggleArchivedFolderHiddenByDefault: { [weak self] in
|
||||
self?.toggleArchivedFolderHiddenByDefault?()
|
||||
}, activateChatPreview: { [weak self] item, node, gesture in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let activateChatPreview = strongSelf.activateChatPreview {
|
||||
activateChatPreview(item, node, gesture)
|
||||
} else {
|
||||
gesture?.cancel()
|
||||
}
|
||||
})
|
||||
|
||||
let viewProcessingQueue = self.viewProcessingQueue
|
||||
|
||||
@@ -348,6 +348,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -529,6 +542,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -792,6 +806,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -837,6 +858,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
@@ -25,6 +25,7 @@ static_library(
|
||||
"//submodules/AlertUI:AlertUI",
|
||||
"//submodules/ShareController:ShareController",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/OverlayStatusController:OverlayStatusController",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -102,6 +102,17 @@
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E2925DE918A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>ContactContextMenus.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/ContactContextMenus.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD71432C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -212,6 +223,7 @@
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E29C95D7ED900000000</string>
|
||||
<string>1DD70E2925DE918A00000000</string>
|
||||
<string>1DD70E29CD71432C00000000</string>
|
||||
<string>1DD70E29C8C4BFFB00000000</string>
|
||||
<string>1DD70E29FD9D368500000000</string>
|
||||
@@ -380,6 +392,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E292417E0B200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -523,6 +548,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libOverlayStatusController.a</string>
|
||||
<key>path</key>
|
||||
<string>libOverlayStatusController.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29928D142900000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -614,6 +652,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E291D58331200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -653,6 +704,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -861,6 +925,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD296A8300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -921,6 +998,7 @@
|
||||
<string>1DD70E297AB043C800000000</string>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E292417E0B200000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
@@ -932,6 +1010,7 @@
|
||||
<string>1DD70E29CE34063500000000</string>
|
||||
<string>1DD70E2936DE2CF900000000</string>
|
||||
<string>1DD70E29C37F741500000000</string>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
<string>1DD70E29928D142900000000</string>
|
||||
<string>1DD70E29D233F68C00000000</string>
|
||||
<string>1DD70E291631B91900000000</string>
|
||||
@@ -939,9 +1018,11 @@
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E293E4DE92B00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E291D58331200000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E291328E99400000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E29524F478E00000000</string>
|
||||
@@ -958,6 +1039,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E2951398CF200000000</string>
|
||||
<string>1DD70E29597BAFBB00000000</string>
|
||||
@@ -1012,6 +1094,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29C95D7ED900000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425DE918A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2925DE918A00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04CD71432C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1082,6 +1171,7 @@
|
||||
<key>files</key>
|
||||
<array>
|
||||
<string>E7A30F04C95D7ED900000000</string>
|
||||
<string>E7A30F0425DE918A00000000</string>
|
||||
<string>E7A30F04CD71432C00000000</string>
|
||||
<string>E7A30F04C8C4BFFB00000000</string>
|
||||
<string>E7A30F04FD9D368500000000</string>
|
||||
@@ -1289,6 +1379,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04C37F741500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1303,6 +1414,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1338,6 +1456,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F041328E99400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1484,13 +1609,18 @@
|
||||
<string>E7A30F042420028600000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F0431752C6000000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F041328E99400000000</string>
|
||||
<string>E7A30F041E16CC6C00000000</string>
|
||||
<string>E7A30F04928D142900000000</string>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftSignalKit
|
||||
import ContextUI
|
||||
import AccountContext
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import Display
|
||||
import AlertUI
|
||||
import OverlayStatusController
|
||||
|
||||
func contactContextMenuItems(context: AccountContext, peerId: PeerId, contactsController: ContactsController?) -> Signal<[ContextMenuItem], NoError> {
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
return context.account.postbox.transaction { [weak contactsController] transaction -> [ContextMenuItem] in
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_SendMessage, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
if let contactsController = contactsController, let navigationController = contactsController.navigationController as? NavigationController {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_StartSecretChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Timer"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.account.postbox.transaction { transaction -> PeerId? in
|
||||
let filteredPeerIds = Array(transaction.getAssociatedPeerIds(peerId)).filter { $0.namespace == Namespaces.Peer.SecretChat }
|
||||
var activeIndices: [ChatListIndex] = []
|
||||
for associatedId in filteredPeerIds {
|
||||
if let state = (transaction.getPeer(associatedId) as? TelegramSecretChat)?.embeddedState {
|
||||
switch state {
|
||||
case .active, .handshake:
|
||||
if let (_, index) = transaction.getPeerChatListIndex(associatedId) {
|
||||
activeIndices.append(index)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
activeIndices.sort()
|
||||
if let index = activeIndices.last {
|
||||
return index.messageIndex.id.peerId
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { currentPeerId in
|
||||
if let currentPeerId = currentPeerId {
|
||||
if let contactsController = contactsController, let navigationController = (contactsController.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(currentPeerId)))
|
||||
}
|
||||
} else {
|
||||
var createSignal = createSecretChat(account: context.account, peerId: peerId)
|
||||
var cancelImpl: (() -> Void)?
|
||||
let progressSignal = Signal<Never, NoError> { subscriber in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: {
|
||||
cancelImpl?()
|
||||
}))
|
||||
contactsController?.present(controller, in: .window(.root))
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.15, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
createSignal = createSignal
|
||||
|> afterDisposed {
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
let createSecretChatDisposable = MetaDisposable()
|
||||
cancelImpl = {
|
||||
createSecretChatDisposable.set(nil)
|
||||
}
|
||||
|
||||
createSecretChatDisposable.set((createSignal
|
||||
|> deliverOnMainQueue).start(next: { peerId in
|
||||
if let navigationController = (contactsController?.navigationController as? NavigationController) {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
}, error: { _ in
|
||||
if let contactsController = contactsController {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
contactsController.present(textAlertController(context: context, title: nil, text: presentationData.strings.Login_UnknownError, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root))
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
var canCall = true
|
||||
if peerId.namespace == Namespaces.Peer.CloudUser, let cachedUserData = transaction.getPeerCachedData(peerId: peerId) as? CachedUserData, cachedUserData.callsPrivate {
|
||||
canCall = false
|
||||
}
|
||||
|
||||
if canCall {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ContactList_Context_Call, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Call"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
if let contactsController = contactsController {
|
||||
let callResult = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, endCurrentIfAny: false)
|
||||
if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult {
|
||||
if currentPeerId == peerId {
|
||||
context.sharedContext.navigateToCurrentCall()
|
||||
} else {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let _ = (context.account.postbox.transaction { transaction -> (Peer?, Peer?) in
|
||||
return (transaction.getPeer(peerId), transaction.getPeer(currentPeerId))
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak contactsController] peer, current in
|
||||
if let contactsController = contactsController, let peer = peer, let current = current {
|
||||
contactsController.present(textAlertController(context: context, title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {
|
||||
let _ = context.sharedContext.callManager?.requestCall(account: context.account, peerId: peerId, endCurrentIfAny: true)
|
||||
})]), in: .window(.root))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import ChatListSearchItemHeader
|
||||
import SearchUI
|
||||
import TelegramPermissionsUI
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
|
||||
private let dropDownIcon = { () -> UIImage in
|
||||
UIGraphicsBeginImageContextWithOptions(CGSize(width: 12.0, height: 12.0), false, 0.0)
|
||||
@@ -98,15 +99,17 @@ private final class ContactListNodeInteraction {
|
||||
fileprivate let authorize: () -> Void
|
||||
fileprivate let suppressWarning: () -> Void
|
||||
fileprivate let openPeer: (ContactListPeer) -> Void
|
||||
fileprivate let contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
let itemHighlighting = ContactItemHighlighting()
|
||||
|
||||
init(activateSearch: @escaping () -> Void, openSortMenu: @escaping () -> Void, authorize: @escaping () -> Void, suppressWarning: @escaping () -> Void, openPeer: @escaping (ContactListPeer) -> Void) {
|
||||
init(activateSearch: @escaping () -> Void, openSortMenu: @escaping () -> Void, authorize: @escaping () -> Void, suppressWarning: @escaping () -> Void, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||
self.activateSearch = activateSearch
|
||||
self.openSortMenu = openSortMenu
|
||||
self.authorize = authorize
|
||||
self.suppressWarning = suppressWarning
|
||||
self.openPeer = openPeer
|
||||
self.contextAction = contextAction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,8 +178,10 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
case let .peer(_, peer, presence, header, selection, theme, strings, dateTimeFormat, nameSortOrder, nameDisplayOrder, enabled):
|
||||
let status: ContactsPeerItemStatus
|
||||
let itemPeer: ContactsPeerItemPeer
|
||||
var isContextActionEnabled = false
|
||||
switch peer {
|
||||
case let .peer(peer, isGlobal, participantCount):
|
||||
isContextActionEnabled = true
|
||||
if isGlobal, let _ = peer.addressName {
|
||||
status = .addressName("")
|
||||
} else {
|
||||
@@ -200,9 +205,22 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
||||
status = .none
|
||||
itemPeer = .deviceContact(stableId: id, contact: contact)
|
||||
}
|
||||
var itemContextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
if isContextActionEnabled, let contextAction = interaction.contextAction {
|
||||
itemContextAction = { node, gesture in
|
||||
switch itemPeer {
|
||||
case let .peer(peer, _):
|
||||
if let peer = peer {
|
||||
contextAction(peer, node, gesture)
|
||||
}
|
||||
case .deviceContact:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return ContactsPeerItem(theme: theme, strings: strings, sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, account: account, peerMode: .peer, peer: itemPeer, status: status, enabled: enabled, selection: selection, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
|
||||
interaction.openPeer(peer)
|
||||
}, itemHighlighting: interaction.itemHighlighting)
|
||||
}, itemHighlighting: interaction.itemHighlighting, contextAction: itemContextAction)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,6 +762,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
public var openPeer: ((ContactListPeer) -> Void)?
|
||||
public var openPrivacyPolicy: (() -> Void)?
|
||||
public var suppressPermissionWarning: (() -> Void)?
|
||||
private let contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
private let previousEntries = Atomic<[ContactListNodeEntry]?>(value: nil)
|
||||
private let disposable = MetaDisposable()
|
||||
@@ -755,10 +774,11 @@ public final class ContactListNode: ASDisplayNode {
|
||||
private var authorizationNode: PermissionContentNode
|
||||
private let displayPermissionPlaceholder: Bool
|
||||
|
||||
public init(context: AccountContext, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false) {
|
||||
public init(context: AccountContext, presentation: Signal<ContactListPresentation, NoError>, filters: [ContactListFilter] = [.excludeSelf], selectionState: ContactListNodeGroupSelectionState? = nil, displayPermissionPlaceholder: Bool = true, displaySortOptions: Bool = false, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? = nil) {
|
||||
self.context = context
|
||||
self.filters = filters
|
||||
self.displayPermissionPlaceholder = displayPermissionPlaceholder
|
||||
self.contextAction = contextAction
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@@ -826,7 +846,7 @@ public final class ContactListNode: ASDisplayNode {
|
||||
self?.suppressPermissionWarning?()
|
||||
}, openPeer: { [weak self] peer in
|
||||
self?.openPeer?(peer)
|
||||
})
|
||||
}, contextAction: contextAction)
|
||||
|
||||
self.indexNode.indexSelected = { [weak self] section in
|
||||
guard let strongSelf = self, let layout = strongSelf.validLayout, let entries = previousEntries.with({ $0 }) else {
|
||||
|
||||
@@ -12,6 +12,7 @@ import AccountContext
|
||||
import SearchBarNode
|
||||
import SearchUI
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
|
||||
private final class ContactsControllerNodeView: UITracingLayerView, PreviewingHostView {
|
||||
var previewingDelegate: PreviewingHostViewDelegate? {
|
||||
@@ -25,6 +26,27 @@ private final class ContactsControllerNodeView: UITracingLayerView, PreviewingHo
|
||||
weak var controller: ContactsController?
|
||||
}
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
weak var sourceNode: ASDisplayNode?
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||
let sourceNode = self.sourceNode
|
||||
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||
if let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
final class ContactsControllerNode: ASDisplayNode {
|
||||
let contactListNode: ContactListNode
|
||||
|
||||
@@ -69,7 +91,11 @@ final class ContactsControllerNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
self.contactListNode = ContactListNode(context: context, presentation: presentation, displaySortOptions: true)
|
||||
var contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
self.contactListNode = ContactListNode(context: context, presentation: presentation, displaySortOptions: true, contextAction: { peer, node, gesture in
|
||||
contextAction?(peer, node, gesture)
|
||||
})
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -106,6 +132,16 @@ final class ContactsControllerNode: ASDisplayNode {
|
||||
strongSelf.openInvite?()
|
||||
}
|
||||
}
|
||||
|
||||
contextAction = { [weak self] peer, node, gesture in
|
||||
guard let strongSelf = self, let contactsController = strongSelf.controller else {
|
||||
return
|
||||
}
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, theme: strongSelf.presentationData.theme, strings: strongSelf.presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node)), items: contactContextMenuItems(context: strongSelf.context, peerId: peer.id, contactsController: contactsController), reactionItems: [], gesture: gesture)
|
||||
contactsController.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
||||
@@ -21,6 +21,7 @@ static_library(
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/ListSectionHeaderNode:ListSectionHeaderNode",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -206,6 +206,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E295915423000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -375,6 +388,32 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -505,6 +544,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD296A8300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -546,6 +598,7 @@
|
||||
<string>1DD70E292420028600000000</string>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
<string>1DD70E29D6F14E1000000000</string>
|
||||
@@ -559,6 +612,8 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -569,6 +624,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E2951398CF200000000</string>
|
||||
</array>
|
||||
@@ -793,6 +849,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04C37F741500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -814,6 +891,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -877,9 +961,13 @@
|
||||
<string>E7A30F042420028600000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
|
||||
@@ -14,6 +14,7 @@ import TelegramStringFormatting
|
||||
import AccountContext
|
||||
import PeerPresenceStatusManager
|
||||
import ItemListPeerItem
|
||||
import ContextUI
|
||||
|
||||
public final class ContactItemHighlighting {
|
||||
public var chatLocation: ChatLocation?
|
||||
@@ -125,6 +126,7 @@ public class ContactsPeerItem: ListViewItem, ListViewItemWithHeader {
|
||||
let setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)?
|
||||
let deletePeer: ((PeerId) -> Void)?
|
||||
let itemHighlighting: ContactItemHighlighting?
|
||||
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
public let selectable: Bool
|
||||
|
||||
@@ -132,7 +134,7 @@ public class ContactsPeerItem: ListViewItem, ListViewItemWithHeader {
|
||||
|
||||
public let header: ListViewItemHeader?
|
||||
|
||||
public init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil) {
|
||||
public init(theme: PresentationTheme, strings: PresentationStrings, sortOrder: PresentationPersonNameOrder, displayOrder: PresentationPersonNameOrder, account: Account, peerMode: ContactsPeerItemPeerMode, peer: ContactsPeerItemPeer, status: ContactsPeerItemStatus, badge: ContactsPeerItemBadge? = nil, enabled: Bool, selection: ContactsPeerItemSelection, editing: ContactsPeerItemEditing, options: [ItemListPeerItemRevealOption] = [], actionIcon: ContactsPeerItemActionIcon = .none, index: PeerNameIndex?, header: ListViewItemHeader?, action: @escaping (ContactsPeerItemPeer) -> Void, setPeerIdWithRevealedOptions: ((PeerId?, PeerId?) -> Void)? = nil, deletePeer: ((PeerId) -> Void)? = nil, itemHighlighting: ContactItemHighlighting? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.sortOrder = sortOrder
|
||||
@@ -153,6 +155,7 @@ public class ContactsPeerItem: ListViewItem, ListViewItemWithHeader {
|
||||
self.header = header
|
||||
self.itemHighlighting = itemHighlighting
|
||||
self.selectable = enabled
|
||||
self.contextAction = contextAction
|
||||
|
||||
if let index = index {
|
||||
var letter: String = "#"
|
||||
@@ -283,6 +286,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
private let separatorNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
|
||||
private let avatarNode: AvatarNode
|
||||
private let titleNode: TextNode
|
||||
private var verificationIconNode: ASImageNode?
|
||||
@@ -325,6 +330,8 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
self.highlightedBackgroundNode = ASDisplayNode()
|
||||
self.highlightedBackgroundNode.isLayerBacked = true
|
||||
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarFont)
|
||||
self.avatarNode.isLayerBacked = !smartInvertColorsEnabled()
|
||||
|
||||
@@ -337,9 +344,10 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
self.containerNode.addSubnode(self.titleNode)
|
||||
self.containerNode.addSubnode(self.statusNode)
|
||||
|
||||
self.peerPresenceManager = PeerPresenceStatusManager(update: { [weak self] in
|
||||
if let strongSelf = self, let layoutParams = strongSelf.layoutParams {
|
||||
@@ -347,6 +355,14 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
let _ = apply()
|
||||
}
|
||||
})
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
guard let strongSelf = self, let item = strongSelf.item, let contextAction = item.contextAction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
}
|
||||
contextAction(strongSelf.containerNode, gesture)
|
||||
}
|
||||
}
|
||||
|
||||
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||
@@ -639,6 +655,9 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.accessibilityLabel = titleAttributedString?.string
|
||||
strongSelf.accessibilityValue = statusAttributedString?.string
|
||||
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: nodeLayout.contentSize)
|
||||
strongSelf.containerNode.isGestureEnabled = item.contextAction != nil
|
||||
|
||||
switch item.peer {
|
||||
case let .peer(peer, _):
|
||||
if let peer = peer {
|
||||
@@ -701,7 +720,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
verificationIconNode.displayWithoutProcessing = true
|
||||
verificationIconNode.displaysAsynchronously = false
|
||||
strongSelf.verificationIconNode = verificationIconNode
|
||||
strongSelf.addSubnode(verificationIconNode)
|
||||
strongSelf.containerNode.addSubnode(verificationIconNode)
|
||||
}
|
||||
if let verificationIconNode = strongSelf.verificationIconNode {
|
||||
verificationIconNode.image = verificationIconImage
|
||||
@@ -720,7 +739,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
actionIconNode.displayWithoutProcessing = true
|
||||
actionIconNode.displaysAsynchronously = false
|
||||
strongSelf.actionIconNode = actionIconNode
|
||||
strongSelf.addSubnode(actionIconNode)
|
||||
strongSelf.containerNode.addSubnode(actionIconNode)
|
||||
}
|
||||
if let actionIconNode = strongSelf.actionIconNode {
|
||||
actionIconNode.image = actionIconImage
|
||||
@@ -744,7 +763,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
badgeBackgroundNode.isLayerBacked = true
|
||||
badgeBackgroundNode.displaysAsynchronously = false
|
||||
badgeBackgroundNode.displayWithoutProcessing = true
|
||||
strongSelf.addSubnode(badgeBackgroundNode)
|
||||
strongSelf.containerNode.addSubnode(badgeBackgroundNode)
|
||||
strongSelf.badgeBackgroundNode = badgeBackgroundNode
|
||||
badgeTransition = .immediate
|
||||
}
|
||||
@@ -758,7 +777,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
||||
let badgeTextNode = badgeTextApply()
|
||||
if badgeTextNode !== strongSelf.badgeTextNode {
|
||||
strongSelf.badgeTextNode?.removeFromSupernode()
|
||||
strongSelf.addSubnode(badgeTextNode)
|
||||
strongSelf.containerNode.addSubnode(badgeTextNode)
|
||||
strongSelf.badgeTextNode = badgeTextNode
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ static_library(
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit#shared",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
|
||||
@@ -146,6 +146,28 @@
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E293607624D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>ContextControllerSourceNode.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/ContextControllerSourceNode.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E2942A6CFDF00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>ContextGesture.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/ContextGesture.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>B401C979EAB5339800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -161,6 +183,8 @@
|
||||
<string>1DD70E2984D0F63E00000000</string>
|
||||
<string>1DD70E2972528DAC00000000</string>
|
||||
<string>1DD70E298B1C7CF000000000</string>
|
||||
<string>1DD70E293607624D00000000</string>
|
||||
<string>1DD70E2942A6CFDF00000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>B401C9795F32B06300000000</key>
|
||||
@@ -448,6 +472,20 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E298B1C7CF000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F043607624D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E293607624D00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0442A6CFDF00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2942A6CFDF00000000</string>
|
||||
</dict>
|
||||
<key>1870857F0000000000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -459,6 +497,8 @@
|
||||
<string>E7A30F0484D0F63E00000000</string>
|
||||
<string>E7A30F0472528DAC00000000</string>
|
||||
<string>E7A30F048B1C7CF000000000</string>
|
||||
<string>E7A30F043607624D00000000</string>
|
||||
<string>E7A30F0442A6CFDF00000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>E7A30F04FF334B1F00000000</key>
|
||||
|
||||
@@ -9,6 +9,19 @@ final class ContextContentContainerNode: ASDisplayNode {
|
||||
super.init()
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
func updateLayout(size: CGSize, scaledSize: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
guard let contentNode = self.contentNode else {
|
||||
return
|
||||
}
|
||||
switch contentNode {
|
||||
case .extracted:
|
||||
break
|
||||
case let .controller(controller):
|
||||
transition.updatePosition(node: controller, position: CGPoint(x: scaledSize.width / 2.0, y: scaledSize.height / 2.0))
|
||||
transition.updateBounds(node: controller, bounds: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateTransformScale(node: controller, scale: scaledSize.width / size.width)
|
||||
controller.updateLayout(size: size, transition: transition)
|
||||
controller.controller.containerLayoutUpdated(ContainerViewLayout(size: size, metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact), deviceMetrics: .iPhoneX, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
public final class ContextContentContainingNode: ASDisplayNode {
|
||||
public let contentNode: ContextContentNode
|
||||
public final class ContextExtractedContentContainingNode: ASDisplayNode {
|
||||
public let contentNode: ContextExtractedContentNode
|
||||
public var contentRect: CGRect = CGRect()
|
||||
public var isExtractedToContextPreview: Bool = false
|
||||
public var willUpdateIsExtractedToContextPreview: ((Bool) -> Void)?
|
||||
@@ -15,7 +15,7 @@ public final class ContextContentContainingNode: ASDisplayNode {
|
||||
public var updateDistractionFreeMode: ((Bool) -> Void)?
|
||||
|
||||
public override init() {
|
||||
self.contentNode = ContextContentNode()
|
||||
self.contentNode = ContextExtractedContentNode()
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -23,5 +23,26 @@ public final class ContextContentContainingNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
public final class ContextContentNode: ASDisplayNode {
|
||||
public final class ContextExtractedContentNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
final class ContextControllerContentNode: ASDisplayNode {
|
||||
let controller: ViewController
|
||||
|
||||
init(controller: ViewController) {
|
||||
self.controller = controller
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(controller.displayNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.controller.displayNode, frame: CGRect(origin: CGPoint(), size: size))
|
||||
}
|
||||
}
|
||||
|
||||
enum ContextContentNode {
|
||||
case extracted(ContextExtractedContentContainingNode)
|
||||
case controller(ContextControllerContentNode)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,52 @@
|
||||
import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
public final class ContextControllerSourceNode: ASDisplayNode {
|
||||
private var contextGesture: ContextGesture?
|
||||
|
||||
public var isGestureEnabled: Bool = true {
|
||||
didSet {
|
||||
self.contextGesture?.isEnabled = self.isGestureEnabled
|
||||
}
|
||||
}
|
||||
public var activated: ((ContextGesture) -> Void)?
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let contextGesture = ContextGesture(target: self, action: nil)
|
||||
self.contextGesture = contextGesture
|
||||
self.view.addGestureRecognizer(contextGesture)
|
||||
|
||||
contextGesture.activationProgress = { [weak self] progress, update in
|
||||
guard let strongSelf = self, !strongSelf.bounds.width.isZero else {
|
||||
return
|
||||
}
|
||||
let minScale: CGFloat = (strongSelf.bounds.width - 20.0) / strongSelf.bounds.width
|
||||
let currentScale = 1.0 * (1.0 - progress) + minScale * progress
|
||||
switch update {
|
||||
case .update:
|
||||
strongSelf.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
case .begin:
|
||||
strongSelf.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
/*let previousProgress: CGFloat = 0.0
|
||||
let previousScale = 1.0 * (1.0 - previousProgress) + minScale * previousProgress
|
||||
strongSelf.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
strongSelf.layer.animate(from: previousScale as NSNumber, to: currentScale as NSNumber, keyPath: "sublayerTransform.scale", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.3, additive: false)*/
|
||||
case let .ended(previousProgress):
|
||||
let previousScale = 1.0 * (1.0 - previousProgress) + minScale * previousProgress
|
||||
strongSelf.layer.sublayerTransform = CATransform3DMakeScale(currentScale, currentScale, 1.0)
|
||||
strongSelf.layer.animate(from: previousScale as NSNumber, to: currentScale as NSNumber, keyPath: "sublayerTransform.scale", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.3)
|
||||
}
|
||||
}
|
||||
contextGesture.activated = { [weak self] gesture in
|
||||
if let activated = self?.activated {
|
||||
activated(gesture)
|
||||
} else {
|
||||
gesture.cancel()
|
||||
}
|
||||
}
|
||||
contextGesture.isEnabled = self.isGestureEnabled
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
|
||||
public enum ContextGestureTransition {
|
||||
case begin
|
||||
case update
|
||||
case ended(CGFloat)
|
||||
}
|
||||
|
||||
private class TimerTargetWrapper: NSObject {
|
||||
let f: () -> Void
|
||||
|
||||
init(_ f: @escaping () -> Void) {
|
||||
self.f = f
|
||||
}
|
||||
|
||||
@objc func timerEvent() {
|
||||
self.f()
|
||||
}
|
||||
}
|
||||
|
||||
private let beginDelay: Double = 0.1
|
||||
|
||||
private func cancelParentGestures(view: UIView) {
|
||||
if let gestureRecognizers = view.gestureRecognizers {
|
||||
for recognizer in gestureRecognizers {
|
||||
recognizer.state = .failed
|
||||
}
|
||||
}
|
||||
if let node = (view as? ListViewBackingView)?.target {
|
||||
node.cancelSelection()
|
||||
}
|
||||
if let superview = view.superview {
|
||||
cancelParentGestures(view: superview)
|
||||
}
|
||||
}
|
||||
|
||||
public final class ContextGesture: UIGestureRecognizer, UIGestureRecognizerDelegate {
|
||||
private var currentProgress: CGFloat = 0.0
|
||||
private var delayTimer: Timer?
|
||||
private var isValidated: Bool = false
|
||||
|
||||
public var activationProgress: ((CGFloat, ContextGestureTransition) -> Void)?
|
||||
public var activated: ((ContextGesture) -> Void)?
|
||||
public var externalUpdated: ((UIView?, CGPoint) -> Void)?
|
||||
public var externalEnded: (((UIView?, CGPoint)?) -> Void)?
|
||||
|
||||
override public init(target: Any?, action: Selector?) {
|
||||
super.init(target: target, action: action)
|
||||
|
||||
self.delegate = self
|
||||
}
|
||||
|
||||
override public func reset() {
|
||||
super.reset()
|
||||
|
||||
self.currentProgress = 0.0
|
||||
self.delayTimer?.invalidate()
|
||||
self.delayTimer = nil
|
||||
self.isValidated = false
|
||||
self.externalUpdated = nil
|
||||
self.externalEnded = nil
|
||||
}
|
||||
|
||||
public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
if otherGestureRecognizer is UIPanGestureRecognizer {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
if self.delayTimer == nil {
|
||||
let delayTimer = Timer(timeInterval: beginDelay, target: TimerTargetWrapper { [weak self] in
|
||||
guard let strongSelf = self, let _ = strongSelf.delayTimer else {
|
||||
return
|
||||
}
|
||||
strongSelf.isValidated = true
|
||||
strongSelf.activationProgress?(strongSelf.currentProgress, .begin)
|
||||
}, selector: #selector(TimerTargetWrapper.timerEvent), userInfo: nil, repeats: false)
|
||||
self.delayTimer = delayTimer
|
||||
RunLoop.main.add(delayTimer, forMode: .common)
|
||||
}
|
||||
}
|
||||
|
||||
override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesMoved(touches, with: event)
|
||||
|
||||
if let touch = touches.first {
|
||||
if #available(iOS 9.0, *) {
|
||||
let maxForce: CGFloat = min(3.0, touch.maximumPossibleForce)
|
||||
let progress = touch.force / maxForce
|
||||
self.currentProgress = progress
|
||||
if self.isValidated {
|
||||
self.activationProgress?(progress, .update)
|
||||
}
|
||||
if touch.force >= maxForce {
|
||||
switch self.state {
|
||||
case .possible:
|
||||
self.delayTimer?.invalidate()
|
||||
self.activated?(self)
|
||||
if let view = self.view?.superview {
|
||||
cancelParentGestures(view: view)
|
||||
}
|
||||
self.state = .began
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.externalUpdated?(self.view, touch.location(in: self.view))
|
||||
}
|
||||
}
|
||||
|
||||
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
|
||||
if let touch = touches.first {
|
||||
if !self.currentProgress.isZero, self.isValidated {
|
||||
if #available(iOS 9.0, *) {
|
||||
self.activationProgress?(0.0, .ended(self.currentProgress))
|
||||
}
|
||||
}
|
||||
|
||||
self.externalEnded?((self.view, touch.location(in: self.view)))
|
||||
}
|
||||
|
||||
self.delayTimer?.invalidate()
|
||||
|
||||
self.state = .failed
|
||||
}
|
||||
|
||||
override public func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
|
||||
if let touch = touches.first, !self.currentProgress.isZero, self.isValidated {
|
||||
if #available(iOS 9.0, *) {
|
||||
self.activationProgress?(0.0, .ended(self.currentProgress))
|
||||
}
|
||||
}
|
||||
|
||||
self.delayTimer?.invalidate()
|
||||
|
||||
self.state = .failed
|
||||
}
|
||||
|
||||
public func cancel() {
|
||||
if !self.currentProgress.isZero, self.isValidated {
|
||||
self.activationProgress?(0.0, .ended(self.currentProgress))
|
||||
|
||||
self.delayTimer?.invalidate()
|
||||
self.state = .failed
|
||||
}
|
||||
}
|
||||
|
||||
public func endPressedAppearance() {
|
||||
if !self.currentProgress.isZero, self.isValidated {
|
||||
let previousProgress = self.currentProgress
|
||||
self.currentProgress = 0.0
|
||||
self.delayTimer?.invalidate()
|
||||
self.isValidated = false
|
||||
self.activationProgress?(0.0, .ended(previousProgress))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,9 +151,8 @@ public func generateImage(_ size: CGSize, opaque: Bool = false, scale: CGFloat?
|
||||
|
||||
guard let provider = CGDataProvider(dataInfo: bytes, data: bytes, size: length, releaseData: { bytes, _, _ in
|
||||
free(bytes)
|
||||
})
|
||||
else {
|
||||
return nil
|
||||
}) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | (opaque ? CGImageAlphaInfo.noneSkipFirst.rawValue : CGImageAlphaInfo.premultipliedFirst.rawValue))
|
||||
|
||||
@@ -26,39 +26,39 @@ private final class ListViewBackingLayer: CALayer {
|
||||
}
|
||||
}
|
||||
|
||||
final class ListViewBackingView: UIView {
|
||||
weak var target: ListView?
|
||||
public final class ListViewBackingView: UIView {
|
||||
public fileprivate(set) weak var target: ListView?
|
||||
|
||||
override class var layerClass: AnyClass {
|
||||
override public class var layerClass: AnyClass {
|
||||
return ListViewBackingLayer.self
|
||||
}
|
||||
|
||||
override func setNeedsLayout() {
|
||||
override public func setNeedsLayout() {
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
override public func layoutSubviews() {
|
||||
}
|
||||
|
||||
override func setNeedsDisplay() {
|
||||
override public func setNeedsDisplay() {
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
self.target?.touchesBegan(touches, with: event)
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
|
||||
override public func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
|
||||
self.target?.touchesCancelled(touches, with: event)
|
||||
}
|
||||
|
||||
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
self.target?.touchesMoved(touches, with: event)
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
self.target?.touchesEnded(touches, with: event)
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if !self.isHidden, let target = self.target {
|
||||
if target.limitHitTestToNodes, !target.internalHitTest(point, with: event) {
|
||||
return nil
|
||||
@@ -70,7 +70,7 @@ final class ListViewBackingView: UIView {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
override func accessibilityScroll(_ direction: UIAccessibilityScrollDirection) -> Bool {
|
||||
override public func accessibilityScroll(_ direction: UIAccessibilityScrollDirection) -> Bool {
|
||||
return self.target?.accessibilityScroll(direction) ?? false
|
||||
}
|
||||
}
|
||||
@@ -3744,6 +3744,13 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
super.touchesMoved(touches, with: event)
|
||||
}
|
||||
|
||||
public func cancelSelection() {
|
||||
if let selectionTouchLocation = self.selectionTouchLocation {
|
||||
self.clearHighlightAnimated(true)
|
||||
self.selectionTouchLocation = nil
|
||||
}
|
||||
}
|
||||
|
||||
override open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
if let selectionTouchLocation = self.selectionTouchLocation {
|
||||
let index = self.itemIndexAtPoint(selectionTouchLocation)
|
||||
|
||||
@@ -166,6 +166,8 @@ private final class WindowRootViewController: UIViewController, UIViewController
|
||||
shouldRegister = true
|
||||
}
|
||||
|
||||
shouldRegister = false
|
||||
|
||||
if shouldRegister != self.registeredForPreviewing {
|
||||
self.registeredForPreviewing = shouldRegister
|
||||
if shouldRegister {
|
||||
|
||||
@@ -18,7 +18,7 @@ private func traceDeceleratingScrollView(_ view: UIView, at point: CGPoint) -> B
|
||||
|
||||
public final class PeekControllerGestureRecognizer: UIPanGestureRecognizer {
|
||||
private let contentAtPoint: (CGPoint) -> Signal<(ASDisplayNode, PeekControllerContent)?, NoError>?
|
||||
private let present: (PeekControllerContent, ASDisplayNode) -> PeekController?
|
||||
private let present: (PeekControllerContent, ASDisplayNode) -> ViewController?
|
||||
private let updateContent: (PeekControllerContent?) -> Void
|
||||
private let activateBySingleTap: Bool
|
||||
|
||||
@@ -36,7 +36,7 @@ public final class PeekControllerGestureRecognizer: UIPanGestureRecognizer {
|
||||
private var menuActivation: PeerkControllerMenuActivation?
|
||||
private weak var presentedController: PeekController?
|
||||
|
||||
public init(contentAtPoint: @escaping (CGPoint) -> Signal<(ASDisplayNode, PeekControllerContent)?, NoError>?, present: @escaping (PeekControllerContent, ASDisplayNode) -> PeekController?, updateContent: @escaping (PeekControllerContent?) -> Void = { _ in }, activateBySingleTap: Bool = false) {
|
||||
public init(contentAtPoint: @escaping (CGPoint) -> Signal<(ASDisplayNode, PeekControllerContent)?, NoError>?, present: @escaping (PeekControllerContent, ASDisplayNode) -> ViewController?, updateContent: @escaping (PeekControllerContent?) -> Void = { _ in }, activateBySingleTap: Bool = false) {
|
||||
self.contentAtPoint = contentAtPoint
|
||||
self.present = present
|
||||
self.updateContent = updateContent
|
||||
@@ -259,29 +259,35 @@ public final class PeekControllerGestureRecognizer: UIPanGestureRecognizer {
|
||||
}
|
||||
} else {
|
||||
if let presentedController = strongSelf.present(content, sourceNode) {
|
||||
if forceActivate {
|
||||
strongSelf.candidateContent = nil
|
||||
if case .press = content.menuActivation() {
|
||||
(presentedController.displayNode as? PeekControllerNode)?.activateMenu()
|
||||
}
|
||||
} else {
|
||||
strongSelf.candidateContent = (sourceNode, content)
|
||||
strongSelf.menuActivation = content.menuActivation()
|
||||
strongSelf.presentedController = presentedController
|
||||
|
||||
strongSelf.state = .began
|
||||
|
||||
switch content.menuActivation() {
|
||||
case .drag:
|
||||
break
|
||||
case .press:
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
if presentedController.traitCollection.forceTouchCapability != .available {
|
||||
if let presentedController = presentedController as? PeekController {
|
||||
if forceActivate {
|
||||
strongSelf.candidateContent = nil
|
||||
if case .press = content.menuActivation() {
|
||||
(presentedController.displayNode as? PeekControllerNode)?.activateMenu()
|
||||
}
|
||||
} else {
|
||||
strongSelf.candidateContent = (sourceNode, content)
|
||||
strongSelf.menuActivation = content.menuActivation()
|
||||
strongSelf.presentedController = presentedController
|
||||
|
||||
strongSelf.state = .began
|
||||
|
||||
switch content.menuActivation() {
|
||||
case .drag:
|
||||
break
|
||||
case .press:
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
if presentedController.traitCollection.forceTouchCapability != .available {
|
||||
strongSelf.startPressTimer()
|
||||
}
|
||||
} else {
|
||||
strongSelf.startPressTimer()
|
||||
}
|
||||
} else {
|
||||
strongSelf.startPressTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if strongSelf.state != .ended {
|
||||
strongSelf.state = .ended
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +220,8 @@ open class ViewControllerPresentationArguments {
|
||||
public var scrollToTopWithTabBar: (() -> Void)?
|
||||
public var longTapWithTabBar: (() -> Void)?
|
||||
|
||||
public var customPresentPreviewingController: ((ViewController, ASDisplayNode) -> ViewController?)?
|
||||
|
||||
open func updateNavigationCustomData(_ data: Any?, progress: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
||||
}
|
||||
@@ -487,12 +489,14 @@ open class ViewControllerPresentationArguments {
|
||||
|
||||
@available(iOSApplicationExtension 9.0, iOS 9.0, *)
|
||||
open func registerForPreviewing(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, theme: PeekControllerTheme, onlyNative: Bool) {
|
||||
if self.traitCollection.forceTouchCapability == .available {
|
||||
if false, self.traitCollection.forceTouchCapability == .available {
|
||||
let _ = super.registerForPreviewing(with: delegate, sourceView: sourceView)
|
||||
} else if !onlyNative {
|
||||
if self.previewingContext == nil {
|
||||
let previewingContext = SimulatedViewControllerPreviewing(theme: theme, delegate: delegate, sourceView: sourceView, node: self.displayNode, present: { [weak self] c, a in
|
||||
self?.presentInGlobalOverlay(c, with: a)
|
||||
}, customPresent: { [weak self] c, n in
|
||||
return self?.customPresentPreviewingController?(c, n)
|
||||
})
|
||||
self.previewingContext = previewingContext
|
||||
}
|
||||
@@ -501,10 +505,12 @@ open class ViewControllerPresentationArguments {
|
||||
|
||||
@available(iOSApplicationExtension 9.0, iOS 9.0, *)
|
||||
public func registerForPreviewingNonNative(with delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, theme: PeekControllerTheme) {
|
||||
if self.traitCollection.forceTouchCapability != .available {
|
||||
if true || self.traitCollection.forceTouchCapability != .available {
|
||||
if self.previewingContext == nil {
|
||||
let previewingContext = SimulatedViewControllerPreviewing(theme: theme, delegate: delegate, sourceView: sourceView, node: self.displayNode, present: { [weak self] c, a in
|
||||
self?.presentInGlobalOverlay(c, with: a)
|
||||
}, customPresent: { [weak self] c, n in
|
||||
return self?.customPresentPreviewingController?(c, n)
|
||||
})
|
||||
self.previewingContext = previewingContext
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import SwiftSignalKit
|
||||
|
||||
@available(iOSApplicationExtension 9.0, iOS 9.0, *)
|
||||
private final class ViewControllerPeekContent: PeekControllerContent {
|
||||
private let controller: ViewController
|
||||
let controller: ViewController
|
||||
private let menu: [PeekControllerMenuItem]
|
||||
|
||||
init(controller: ViewController) {
|
||||
@@ -101,7 +101,7 @@ final class SimulatedViewControllerPreviewing: NSObject, UIViewControllerPreview
|
||||
|
||||
var sourceRect: CGRect = CGRect()
|
||||
|
||||
init(theme: PeekControllerTheme, delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, node: ASDisplayNode, present: @escaping (ViewController, Any?) -> Void) {
|
||||
init(theme: PeekControllerTheme, delegate: UIViewControllerPreviewingDelegate, sourceView: UIView, node: ASDisplayNode, present: @escaping (ViewController, Any?) -> Void, customPresent: ((ViewController, ASDisplayNode) -> ViewController?)?) {
|
||||
self.delegateImpl = delegate
|
||||
self.sourceView = sourceView
|
||||
self.node = node
|
||||
@@ -109,11 +109,16 @@ final class SimulatedViewControllerPreviewing: NSObject, UIViewControllerPreview
|
||||
self.recognizer = PeekControllerGestureRecognizer(contentAtPoint: { point in
|
||||
return contentAtPointImpl?(point)
|
||||
}, present: { content, sourceNode in
|
||||
let controller = PeekController(theme: theme, content: content, sourceNode: {
|
||||
return sourceNode
|
||||
})
|
||||
present(controller, nil)
|
||||
return controller
|
||||
if let content = content as? ViewControllerPeekContent, let controller = customPresent?(content.controller, sourceNode) {
|
||||
present(controller, nil)
|
||||
return controller
|
||||
} else {
|
||||
let controller = PeekController(theme: theme, content: content, sourceNode: {
|
||||
return sourceNode
|
||||
})
|
||||
present(controller, nil)
|
||||
return controller
|
||||
}
|
||||
})
|
||||
|
||||
node.view.addGestureRecognizer(self.recognizer)
|
||||
|
||||
@@ -15,6 +15,7 @@ static_library(
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramBaseController:TelegramBaseController",
|
||||
"//submodules/ChatListUI:ChatListUI",
|
||||
"//submodules/SegmentedControlNode:SegmentedControlNode",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -260,6 +260,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CED1620500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -572,6 +585,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E291D58331200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -611,6 +637,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -832,6 +871,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29B4B05B7A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -921,6 +973,7 @@
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E292F91702000000000</string>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E29CED1620500000000</string>
|
||||
<string>1DD70E292417E0B200000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
@@ -945,9 +998,11 @@
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E293E4DE92B00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E291D58331200000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E291328E99400000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E29524F478E00000000</string>
|
||||
@@ -965,6 +1020,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29B4B05B7A00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E29AE67341000000000</string>
|
||||
@@ -1339,6 +1395,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04CBE117ED00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1346,6 +1423,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1381,6 +1465,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F041328E99400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1486,13 +1577,6 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29E220F5E800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04247D9AC100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1582,12 +1666,17 @@
|
||||
<string>E7A30F047AB043C800000000</string>
|
||||
<string>E7A30F04B6F47D1F00000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F0431752C6000000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F041328E99400000000</string>
|
||||
<string>E7A30F041E16CC6C00000000</string>
|
||||
<string>E7A30F043E4DE92B00000000</string>
|
||||
@@ -1603,7 +1692,6 @@
|
||||
<string>E7A30F042F91702000000000</string>
|
||||
<string>E7A30F04CED1620500000000</string>
|
||||
<string>E7A30F04E220F5E800000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F04247D9AC100000000</string>
|
||||
<string>E7A30F04B4B05B7A00000000</string>
|
||||
<string>E7A30F04490601EB00000000</string>
|
||||
|
||||
@@ -67,6 +67,8 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
}, togglePeerMarkedUnread: { _, _ in
|
||||
}, toggleArchivedFolderHiddenByDefault: {
|
||||
}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
})
|
||||
|
||||
let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil)
|
||||
@@ -76,7 +78,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
let previousEntries = previousSearchItems.swap(entries)
|
||||
|
||||
let firstTime = previousEntries == nil
|
||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, context: strongSelf.context, enableHeaders: false, filter: [], interaction: interaction)
|
||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, context: strongSelf.context, enableHeaders: false, filter: [], interaction: interaction, peerContextAction: nil)
|
||||
strongSelf.controllerNode.enqueueTransition(transition, firstTime: firstTime)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -6,11 +6,12 @@ import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ChatListUI
|
||||
import SegmentedControlNode
|
||||
|
||||
final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
private let toolbarBackgroundNode: ASDisplayNode
|
||||
private let toolbarSeparatorNode: ASDisplayNode
|
||||
private let segmentedControl: UISegmentedControl
|
||||
private let segmentedControlNode: SegmentedControlNode
|
||||
let listNode: ListView
|
||||
|
||||
var chatController: ChatController?
|
||||
@@ -35,9 +36,11 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
self.toolbarSeparatorNode = ASDisplayNode()
|
||||
self.toolbarSeparatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor
|
||||
|
||||
self.segmentedControl = UISegmentedControl(items: [peer?.displayTitle ?? "", strings.HashtagSearch_AllChats])
|
||||
self.segmentedControl.tintColor = theme.rootController.navigationBar.accentTextColor
|
||||
self.segmentedControl.selectedSegmentIndex = 0
|
||||
let items = [
|
||||
peer?.displayTitle ?? "",
|
||||
strings.HashtagSearch_AllChats
|
||||
]
|
||||
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: items.map { SegmentedControlItem(title: $0) }, selectedIndex: 0)
|
||||
|
||||
if let peer = peer {
|
||||
self.chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .inline)
|
||||
@@ -56,7 +59,17 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
self.addSubnode(self.listNode)
|
||||
self.listNode.isHidden = true
|
||||
|
||||
self.segmentedControl.addTarget(self, action: #selector(self.indexChanged), for: .valueChanged)
|
||||
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||
if let strongSelf = self {
|
||||
if index == 0 {
|
||||
strongSelf.chatController?.displayNode.isHidden = false
|
||||
strongSelf.listNode.isHidden = true
|
||||
} else {
|
||||
strongSelf.chatController?.displayNode.isHidden = true
|
||||
strongSelf.listNode.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func enqueueTransition(_ transition: ChatListSearchContainerTransition, firstTime: Bool) {
|
||||
@@ -84,8 +97,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
if self.chatController != nil && self.toolbarBackgroundNode.supernode == nil {
|
||||
self.addSubnode(self.toolbarBackgroundNode)
|
||||
self.addSubnode(self.toolbarSeparatorNode)
|
||||
|
||||
self.view.addSubview(self.segmentedControl)
|
||||
self.addSubnode(self.segmentedControlNode)
|
||||
}
|
||||
|
||||
var insets = layout.insets(options: [.input])
|
||||
@@ -97,10 +109,8 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
transition.updateFrame(node: self.toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY), size: CGSize(width: layout.size.width, height: toolbarHeight)))
|
||||
transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + toolbarHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||
|
||||
var controlSize = self.segmentedControl.sizeThatFits(layout.size)
|
||||
controlSize.width = layout.size.width - 14.0 * 2.0
|
||||
|
||||
transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: panelY + floor((toolbarHeight - controlSize.height) / 2.0)), size: controlSize))
|
||||
let controlSize = self.segmentedControlNode.updateLayout(.stretchToFill(width: layout.size.width - 14.0 * 2.0), transition: transition)
|
||||
transition.updateFrame(node: self.segmentedControlNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: panelY + floor((toolbarHeight - controlSize.height) / 2.0)), size: controlSize))
|
||||
|
||||
if let chatController = self.chatController {
|
||||
insets.top += toolbarHeight - 4.0
|
||||
@@ -146,21 +156,11 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
if !hasValidLayout {
|
||||
hasValidLayout = true
|
||||
if !self.hasValidLayout {
|
||||
self.hasValidLayout = true
|
||||
while !self.enqueuedTransitions.isEmpty {
|
||||
self.dequeueTransition()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func indexChanged() {
|
||||
if self.segmentedControl.selectedSegmentIndex == 0 {
|
||||
self.chatController?.displayNode.isHidden = false
|
||||
self.listNode.isHidden = true
|
||||
} else {
|
||||
self.chatController?.displayNode.isHidden = true
|
||||
self.listNode.isHidden = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -440,6 +453,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -731,6 +745,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -775,6 +796,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
+22
@@ -286,6 +286,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -468,6 +481,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -766,6 +780,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -818,6 +839,7 @@
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
|
||||
@@ -260,6 +260,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -440,6 +453,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -731,6 +745,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -775,6 +796,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
@@ -17,6 +17,7 @@ static_library(
|
||||
"//submodules/PeerPresenceStatusManager:PeerPresenceStatusManager",
|
||||
"//submodules/ItemListUI:ItemListUI",
|
||||
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -143,6 +143,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E295915423000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -286,6 +299,32 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -416,6 +455,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD296A8300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -457,6 +509,7 @@
|
||||
<string>1DD70E292420028600000000</string>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
<string>1DD70E29D6F14E1000000000</string>
|
||||
@@ -468,6 +521,8 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -478,6 +533,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E2951398CF200000000</string>
|
||||
</array>
|
||||
@@ -675,6 +731,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F045915423000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -766,6 +843,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -805,6 +889,9 @@
|
||||
<string>E7A30F042420028600000000</string>
|
||||
<string>E7A30F0484A59C1D00000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F045915423000000000</string>
|
||||
<string>E7A30F04F33FDAC300000000</string>
|
||||
<string>E7A30F0451398CF200000000</string>
|
||||
@@ -818,6 +905,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
|
||||
@@ -11,6 +11,7 @@ import ItemListUI
|
||||
import AvatarNode
|
||||
import TelegramStringFormatting
|
||||
import PeerPresenceStatusManager
|
||||
import ContextUI
|
||||
|
||||
public struct ItemListPeerItemEditing: Equatable {
|
||||
public var editable: Bool
|
||||
@@ -127,12 +128,13 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem {
|
||||
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
||||
let removePeer: (PeerId) -> Void
|
||||
let toggleUpdated: ((Bool) -> Void)?
|
||||
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
let hasTopStripe: Bool
|
||||
let hasTopGroupInset: Bool
|
||||
let noInsets: Bool
|
||||
public let tag: ItemListItemTag?
|
||||
|
||||
public init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, account: Account, peer: Peer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil) {
|
||||
public init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, account: Account, peer: Peer, height: ItemListPeerItemHeight = .peerList, aliasHandling: ItemListPeerItemAliasHandling = .standard, nameColor: ItemListPeerItemNameColor = .primary, nameStyle: ItemListPeerItemNameStyle = .distinctBold, presence: PeerPresence?, text: ItemListPeerItemText, label: ItemListPeerItemLabel, editing: ItemListPeerItemEditing, revealOptions: ItemListPeerItemRevealOptions? = nil, switchValue: ItemListPeerItemSwitch?, enabled: Bool, selectable: Bool, sectionId: ItemListSectionId, action: (() -> Void)?, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, removePeer: @escaping (PeerId) -> Void, toggleUpdated: ((Bool) -> Void)? = nil, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)? = nil, hasTopStripe: Bool = true, hasTopGroupInset: Bool = true, noInsets: Bool = false, tag: ItemListItemTag? = nil) {
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
self.dateTimeFormat = dateTimeFormat
|
||||
@@ -156,6 +158,7 @@ public final class ItemListPeerItem: ListViewItem, ItemListItem {
|
||||
self.setPeerIdWithRevealedOptions = setPeerIdWithRevealedOptions
|
||||
self.removePeer = removePeer
|
||||
self.toggleUpdated = toggleUpdated
|
||||
self.contextAction = contextAction
|
||||
self.hasTopStripe = hasTopStripe
|
||||
self.hasTopGroupInset = hasTopGroupInset
|
||||
self.noInsets = noInsets
|
||||
@@ -221,6 +224,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private var disabledOverlayNode: ASDisplayNode?
|
||||
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
|
||||
fileprivate let avatarNode: AvatarNode
|
||||
private let titleNode: TextNode
|
||||
private let labelNode: TextNode
|
||||
@@ -260,6 +265,8 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
self.bottomStripeNode = ASDisplayNode()
|
||||
self.bottomStripeNode.isLayerBacked = true
|
||||
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
|
||||
self.avatarNode = AvatarNode(font: avatarFont)
|
||||
self.avatarNode.isLayerBacked = !smartInvertColorsEnabled()
|
||||
|
||||
@@ -290,10 +297,11 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
|
||||
self.addSubnode(self.avatarNode)
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.statusNode)
|
||||
self.addSubnode(self.labelNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.avatarNode)
|
||||
self.containerNode.addSubnode(self.titleNode)
|
||||
self.containerNode.addSubnode(self.statusNode)
|
||||
self.containerNode.addSubnode(self.labelNode)
|
||||
|
||||
self.peerPresenceManager = PeerPresenceStatusManager(update: { [weak self] in
|
||||
if let strongSelf = self, let layoutParams = strongSelf.layoutParams {
|
||||
@@ -301,6 +309,14 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
apply(false, true)
|
||||
}
|
||||
})
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
guard let strongSelf = self, let item = strongSelf.layoutParams?.0, let contextAction = item.contextAction else {
|
||||
gesture.cancel()
|
||||
return
|
||||
}
|
||||
contextAction(strongSelf.containerNode, gesture)
|
||||
}
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ItemListPeerItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool, Bool) -> Void) {
|
||||
@@ -568,6 +584,9 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
if let strongSelf = self {
|
||||
strongSelf.layoutParams = (item, params, neighbors)
|
||||
|
||||
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
|
||||
strongSelf.containerNode.isGestureEnabled = item.contextAction != nil
|
||||
|
||||
strongSelf.accessibilityLabel = titleAttributedString?.string
|
||||
var combinedValueString = ""
|
||||
if let statusString = statusAttributedString?.string, !statusString.isEmpty {
|
||||
@@ -627,7 +646,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
}
|
||||
}
|
||||
strongSelf.editableControlNode = editableControlNode
|
||||
strongSelf.insertSubnode(editableControlNode, aboveSubnode: strongSelf.avatarNode)
|
||||
strongSelf.addSubnode(editableControlNode)
|
||||
editableControlNode.frame = editableControlFrame
|
||||
transition.animatePosition(node: editableControlNode, from: CGPoint(x: -editableControlFrame.size.width / 2.0, y: editableControlFrame.midY))
|
||||
editableControlNode.alpha = 0.0
|
||||
@@ -687,11 +706,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
if let currentSwitchNode = currentSwitchNode {
|
||||
if currentSwitchNode !== strongSelf.switchNode {
|
||||
strongSelf.switchNode = currentSwitchNode
|
||||
if let disabledOverlayNode = strongSelf.disabledOverlayNode, disabledOverlayNode.supernode != nil {
|
||||
strongSelf.insertSubnode(currentSwitchNode, belowSubnode: disabledOverlayNode)
|
||||
} else {
|
||||
strongSelf.addSubnode(currentSwitchNode)
|
||||
}
|
||||
strongSelf.containerNode.addSubnode(currentSwitchNode)
|
||||
currentSwitchNode.valueUpdated = { value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.toggleUpdated(value)
|
||||
@@ -710,11 +725,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
if let currentCheckNode = currentCheckNode {
|
||||
if currentCheckNode !== strongSelf.checkNode {
|
||||
strongSelf.checkNode = currentCheckNode
|
||||
if let disabledOverlayNode = strongSelf.disabledOverlayNode, disabledOverlayNode.supernode != nil {
|
||||
strongSelf.insertSubnode(currentCheckNode, belowSubnode: disabledOverlayNode)
|
||||
} else {
|
||||
strongSelf.addSubnode(currentCheckNode)
|
||||
}
|
||||
strongSelf.containerNode.addSubnode(currentCheckNode)
|
||||
}
|
||||
if let checkImage = checkImage {
|
||||
currentCheckNode.image = checkImage
|
||||
@@ -732,7 +743,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
|
||||
if let updatedLabelArrowNode = updatedLabelArrowNode {
|
||||
strongSelf.labelArrowNode = updatedLabelArrowNode
|
||||
strongSelf.addSubnode(updatedLabelArrowNode)
|
||||
strongSelf.containerNode.addSubnode(updatedLabelArrowNode)
|
||||
if let image = updatedLabelArrowNode.image {
|
||||
let labelArrowNodeFrame = CGRect(origin: CGPoint(x: params.width - params.rightInset - rightLabelInset - image.size.width, y: floor((contentSize.height - image.size.height) / 2.0)), size: image.size)
|
||||
transition.updateFrame(node: updatedLabelArrowNode, frame: labelArrowNodeFrame)
|
||||
@@ -755,7 +766,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
|
||||
|
||||
if let updateBadgeImage = updatedLabelBadgeImage {
|
||||
if strongSelf.labelBadgeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.labelBadgeNode, belowSubnode: strongSelf.labelNode)
|
||||
strongSelf.containerNode.insertSubnode(strongSelf.labelBadgeNode, belowSubnode: strongSelf.labelNode)
|
||||
}
|
||||
strongSelf.labelBadgeNode.image = updateBadgeImage
|
||||
}
|
||||
|
||||
@@ -260,6 +260,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -440,6 +453,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -731,6 +745,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -775,6 +796,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
@@ -17,6 +17,7 @@ static_library(
|
||||
"//submodules/SwitchNode:SwitchNode",
|
||||
"//submodules/AnimationUI:AnimationUI",
|
||||
"//submodules/CheckNode:CheckNode",
|
||||
"//submodules/SegmentedControlNode:SegmentedControlNode",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -247,6 +247,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -426,6 +439,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -746,6 +760,17 @@
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E294080C57A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>ItemListMaskAccessory.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/ItemListMaskAccessory.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>1DD70E29613EB66700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -799,6 +824,7 @@
|
||||
<string>1DD70E29AD71BDBE00000000</string>
|
||||
<string>1DD70E29586B50C900000000</string>
|
||||
<string>1DD70E2939FE48C000000000</string>
|
||||
<string>1DD70E294080C57A00000000</string>
|
||||
<string>1DD70E29613EB66700000000</string>
|
||||
<string>1DD70E2978C1317D00000000</string>
|
||||
<string>1DD70E2989E0026900000000</string>
|
||||
@@ -1028,6 +1054,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2939FE48C000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F044080C57A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E294080C57A00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04613EB66700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1079,6 +1112,7 @@
|
||||
<string>E7A30F04AD71BDBE00000000</string>
|
||||
<string>E7A30F04586B50C900000000</string>
|
||||
<string>E7A30F0439FE48C000000000</string>
|
||||
<string>E7A30F044080C57A00000000</string>
|
||||
<string>E7A30F04613EB66700000000</string>
|
||||
<string>E7A30F0478C1317D00000000</string>
|
||||
<string>E7A30F0489E0026900000000</string>
|
||||
@@ -1252,6 +1286,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1289,6 +1330,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
</array>
|
||||
<key>name</key>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
09CE5B922322985500743FF4 /* ItemListMaskAccessory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */; };
|
||||
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 */; };
|
||||
@@ -50,6 +51,7 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListMaskAccessory.swift; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -168,6 +170,7 @@
|
||||
D0D3286322F3366500D07EE2 /* ItemListControllerSearch.swift */,
|
||||
D0D3286122F3366500D07EE2 /* ItemListControllerSegmentedTitleView.swift */,
|
||||
D0D3289922F345C500D07EE2 /* ItemListItem.swift */,
|
||||
09CE5B912322985500743FF4 /* ItemListMaskAccessory.swift */,
|
||||
D060186022F35F6B00796784 /* ItemListRevealOptionsNode.swift */,
|
||||
D06018BA22F3663900796784 /* ItemListEditableDeleteControlNode.swift */,
|
||||
D06018B822F3663800796784 /* ItemListEditableReorderControlNode.swift */,
|
||||
@@ -294,6 +297,7 @@
|
||||
D060185422F35E1F00796784 /* ItemListTextWithLabelItem.swift in Sources */,
|
||||
D0C9BFB222FE327700FAB518 /* ItemListPlaceholderItem.swift in Sources */,
|
||||
D0D3286722F3366600D07EE2 /* ItemListController.swift in Sources */,
|
||||
09CE5B922322985500743FF4 /* ItemListMaskAccessory.swift in Sources */,
|
||||
D0D3286822F3366600D07EE2 /* ItemListControllerSearch.swift in Sources */,
|
||||
D060185722F35E1F00796784 /* ItemListSwitchItem.swift in Sources */,
|
||||
D0D3286622F3366600D07EE2 /* ItemListControllerSegmentedTitleView.swift in Sources */,
|
||||
|
||||
@@ -283,7 +283,7 @@ open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShor
|
||||
if let segmentedTitleView = strongSelf.segmentedTitleView, segmentedTitleView.segments == sections {
|
||||
segmentedTitleView.index = index
|
||||
} else {
|
||||
let segmentedTitleView = ItemListControllerSegmentedTitleView(segments: sections, index: index, color: controllerState.theme.rootController.navigationBar.accentTextColor)
|
||||
let segmentedTitleView = ItemListControllerSegmentedTitleView(theme: controllerState.theme, segments: sections, selectedIndex: index)
|
||||
strongSelf.segmentedTitleView = segmentedTitleView
|
||||
strongSelf.navigationItem.titleView = strongSelf.segmentedTitleView
|
||||
segmentedTitleView.indexUpdated = { index in
|
||||
@@ -406,7 +406,7 @@ open class ItemListController<Entry: ItemListNodeEntry>: ViewController, KeyShor
|
||||
strongSelf.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: strongSelf.theme), strings: NavigationBarStrings(presentationStrings: strongSelf.strings)))
|
||||
strongSelf.statusBar.statusBarStyle = strongSelf.theme.rootController.statusBarStyle.style
|
||||
|
||||
strongSelf.segmentedTitleView?.color = controllerState.theme.rootController.navigationBar.accentTextColor
|
||||
strongSelf.segmentedTitleView?.theme = controllerState.theme
|
||||
|
||||
var items = strongSelf.navigationItem.rightBarButtonItems ?? []
|
||||
for i in 0 ..< strongSelf.rightNavigationButtonTitleAndStyle.count {
|
||||
|
||||
@@ -162,6 +162,8 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
private let navigationBar: NavigationBar
|
||||
|
||||
public let listNode: ListView
|
||||
private let leftOverlayNode: ASDisplayNode
|
||||
private let rightOverlayNode: ASDisplayNode
|
||||
private var emptyStateItem: ItemListControllerEmptyStateItem?
|
||||
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
|
||||
|
||||
@@ -204,6 +206,8 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
self.updateNavigationOffset = updateNavigationOffset
|
||||
|
||||
self.listNode = ListView()
|
||||
self.leftOverlayNode = ASDisplayNode()
|
||||
self.rightOverlayNode = ASDisplayNode()
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -351,15 +355,45 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
|
||||
var insets = layout.insets(options: [.input])
|
||||
insets.top += navigationBarHeight
|
||||
insets.left += layout.safeInsets.left
|
||||
insets.right += layout.safeInsets.right
|
||||
|
||||
var addedInsets: UIEdgeInsets?
|
||||
if case .tablet = layout.deviceMetrics.type, layout.size.width > 460.0 {
|
||||
let inset = max(20.0, floor((layout.size.width - 674.0) / 2.0))
|
||||
insets.left += inset
|
||||
insets.right += inset
|
||||
addedInsets = UIEdgeInsets(top: 0.0, left: inset, bottom: 0.0, right: inset)
|
||||
|
||||
if self.leftOverlayNode.supernode == nil {
|
||||
self.addSubnode(self.leftOverlayNode)
|
||||
}
|
||||
if self.rightOverlayNode.supernode == nil {
|
||||
self.addSubnode(self.rightOverlayNode)
|
||||
}
|
||||
} else {
|
||||
insets.left += layout.safeInsets.left
|
||||
insets.right += layout.safeInsets.right
|
||||
|
||||
if self.leftOverlayNode.supernode != nil {
|
||||
self.leftOverlayNode.removeFromSupernode()
|
||||
}
|
||||
if self.rightOverlayNode.supernode != nil {
|
||||
self.rightOverlayNode.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height)
|
||||
self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0)
|
||||
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous, .LowLatency], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: listViewCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
self.leftOverlayNode.frame = CGRect(x: 0.0, y: insets.top + 1.0, width: insets.left, height: layout.size.height - insets.top)
|
||||
self.rightOverlayNode.frame = CGRect(x: layout.size.width - insets.right, y: insets.top + 1.0, width: insets.right, height: layout.size.height - insets.top)
|
||||
|
||||
if let emptyStateNode = self.emptyStateNode {
|
||||
var layout = layout
|
||||
if let addedInsets = addedInsets {
|
||||
layout = layout.addedInsets(insets: addedInsets)
|
||||
}
|
||||
emptyStateNode.updateLayout(layout: layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
}
|
||||
|
||||
@@ -401,9 +435,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
case .plain:
|
||||
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.leftOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.rightOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
case .blocks:
|
||||
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.leftOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -416,9 +454,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
case .plain:
|
||||
self.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.listNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.leftOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
self.rightOverlayNode.backgroundColor = transition.theme.list.plainBackgroundColor
|
||||
case .blocks:
|
||||
self.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.listNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.leftOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
self.rightOverlayNode.backgroundColor = transition.theme.list.blocksBackgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -553,10 +595,6 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
if itemTag.isEqual(to: ensureVisibleItemTag) {
|
||||
if let itemNode = itemNode as? ListViewItemNode {
|
||||
strongSelf.listNode.ensureItemNodeVisible(itemNode)
|
||||
/*itemNode.setHighlighted(true, at: CGPoint(), animated: false)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
itemNode.setHighlighted(false, at: CGPoint(), animated: true)
|
||||
})*/
|
||||
applied = true
|
||||
}
|
||||
}
|
||||
@@ -613,21 +651,13 @@ open class ItemListControllerNode<Entry: ItemListNodeEntry>: ASDisplayNode, UISc
|
||||
|
||||
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
let distanceFromEquilibrium = scrollView.contentOffset.y - scrollView.contentSize.height / 3.0
|
||||
|
||||
//let transition = 1.0 - min(1.0, max(0.0, abs(distanceFromEquilibrium) / 50.0))
|
||||
|
||||
self.updateNavigationOffset(-distanceFromEquilibrium)
|
||||
|
||||
/*if let toolbarNode = toolbarNode {
|
||||
toolbarNode.layer.position = CGPoint(x: toolbarNode.layer.position.x, y: self.bounds.size.height - toolbarNode.bounds.size.height / 2.0 + (1.0 - transition) * toolbarNode.bounds.size.height)
|
||||
}*/
|
||||
}
|
||||
|
||||
open func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
|
||||
targetContentOffset.pointee = scrollView.contentOffset
|
||||
|
||||
let scrollVelocity = scrollView.panGestureRecognizer.velocity(in: scrollView)
|
||||
|
||||
if abs(scrollVelocity.y) > 200.0 {
|
||||
self.animateOut()
|
||||
}
|
||||
|
||||
@@ -1,50 +1,49 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SegmentedControlNode
|
||||
import TelegramPresentationData
|
||||
|
||||
public final class ItemListControllerSegmentedTitleView: UIView {
|
||||
private let segmentedControlNode: SegmentedControlNode
|
||||
|
||||
public var theme: PresentationTheme {
|
||||
didSet {
|
||||
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||
}
|
||||
}
|
||||
public var segments: [String] {
|
||||
didSet {
|
||||
if self.segments != oldValue {
|
||||
self.control.removeAllSegments()
|
||||
var index = 0
|
||||
for segment in self.segments {
|
||||
self.control.insertSegment(withTitle: segment, at: index, animated: false)
|
||||
index += 1
|
||||
}
|
||||
self.segmentedControlNode.items = self.segments.map { SegmentedControlItem(title: $0) }
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var index: Int {
|
||||
didSet {
|
||||
self.control.selectedSegmentIndex = self.index
|
||||
get {
|
||||
return self.segmentedControlNode.selectedIndex
|
||||
}
|
||||
set {
|
||||
self.segmentedControlNode.selectedIndex = newValue
|
||||
}
|
||||
}
|
||||
|
||||
private let control: UISegmentedControl
|
||||
|
||||
public var indexUpdated: ((Int) -> Void)?
|
||||
|
||||
public var color: UIColor {
|
||||
didSet {
|
||||
self.control.tintColor = self.color
|
||||
}
|
||||
}
|
||||
|
||||
public init(segments: [String], index: Int, color: UIColor) {
|
||||
public init(theme: PresentationTheme, segments: [String], selectedIndex: Int) {
|
||||
self.theme = theme
|
||||
self.segments = segments
|
||||
self.index = index
|
||||
self.color = color
|
||||
|
||||
self.control = UISegmentedControl(items: segments)
|
||||
self.control.selectedSegmentIndex = index
|
||||
self.control.tintColor = color
|
||||
self.segmentedControlNode = SegmentedControlNode(theme: SegmentedControlTheme(theme: theme), items: segments.map { SegmentedControlItem(title: $0) }, selectedIndex: selectedIndex)
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.addSubview(self.control)
|
||||
self.control.addTarget(self, action: #selector(indexChanged), for: .valueChanged)
|
||||
self.segmentedControlNode.selectedIndexChanged = { [weak self] index in
|
||||
self?.indexUpdated?(index)
|
||||
}
|
||||
|
||||
self.addSubnode(self.segmentedControlNode)
|
||||
}
|
||||
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
@@ -55,13 +54,7 @@ public final class ItemListControllerSegmentedTitleView: UIView {
|
||||
super.layoutSubviews()
|
||||
|
||||
let size = self.bounds.size
|
||||
|
||||
var controlSize = self.control.sizeThatFits(size)
|
||||
controlSize.width = min(size.width, max(160.0, controlSize.width))
|
||||
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 private func indexChanged() {
|
||||
self.indexUpdated?(self.control.selectedSegmentIndex)
|
||||
let controlSize = self.segmentedControlNode.updateLayout(.sizeToFit(maximumWidth: size.width, minimumWidth: 160.0), transition: .immediate)
|
||||
self.segmentedControlNode.frame = CGRect(origin: CGPoint(x: floor((size.width - controlSize.width) / 2.0), y: floor((size.height - controlSize.height) / 2.0)), size: controlSize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ public protocol ItemListItem {
|
||||
}
|
||||
|
||||
public extension ItemListItem {
|
||||
//let accessoryItem: ListViewAccessoryItem?
|
||||
|
||||
var isAlwaysPlain: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
|
||||
final class ItemListMaskAccessoryItem: ListViewAccessoryItem {
|
||||
private let sectionId: Int32
|
||||
|
||||
init(sectionId: Int32) {
|
||||
self.sectionId = sectionId
|
||||
}
|
||||
|
||||
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
|
||||
if case let other as ItemListMaskAccessoryItem = other {
|
||||
return self.sectionId == other.sectionId
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func node(synchronous: Bool) -> ListViewAccessoryItemNode {
|
||||
let node = ItemListMaskAccessoryItemItemNode()
|
||||
node.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
final class ItemListMaskAccessoryItemItemNode: ListViewAccessoryItemNode {
|
||||
let node: ASDisplayNode
|
||||
|
||||
override init() {
|
||||
self.node = ASDisplayNode()
|
||||
self.node.backgroundColor = .red
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.node)
|
||||
}
|
||||
}
|
||||
@@ -92,6 +92,7 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let titleNode: TextNode
|
||||
|
||||
@@ -107,7 +108,7 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.backgroundColor = .white
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
self.topStripeNode.isLayerBacked = true
|
||||
|
||||
@@ -216,7 +217,9 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||
}
|
||||
|
||||
if strongSelf.maskNode.supernode != nil {
|
||||
strongSelf.maskNode.removeFromSupernode()
|
||||
}
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||
case .blocks:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
@@ -228,11 +231,19 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
}
|
||||
|
||||
let hasCorners = params.width > 480
|
||||
var hasTopCorners = false
|
||||
var hasBottomCorners = false
|
||||
switch neighbors.top {
|
||||
case .sameSection(false):
|
||||
strongSelf.topStripeNode.isHidden = true
|
||||
default:
|
||||
strongSelf.topStripeNode.isHidden = false
|
||||
hasTopCorners = true
|
||||
strongSelf.topStripeNode.isHidden = hasCorners
|
||||
}
|
||||
let bottomStripeInset: CGFloat
|
||||
let bottomStripeOffset: CGFloat
|
||||
@@ -243,8 +254,14 @@ public class ItemListActionItemNode: ListViewItemNode, ItemListItemNode {
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
bottomStripeOffset = 0.0
|
||||
hasBottomCorners = true
|
||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
let iconNode: ASImageNode
|
||||
let titleNode: TextNode
|
||||
@@ -137,6 +138,8 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.backgroundColor = .white
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
self.topStripeNode.isLayerBacked = true
|
||||
|
||||
@@ -357,7 +360,9 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||
}
|
||||
|
||||
if strongSelf.maskNode.supernode != nil {
|
||||
strongSelf.maskNode.removeFromSupernode()
|
||||
}
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||
case .blocks:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
@@ -369,11 +374,19 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
}
|
||||
|
||||
let hasCorners = params.width > 480
|
||||
var hasTopCorners = false
|
||||
var hasBottomCorners = false
|
||||
switch neighbors.top {
|
||||
case .sameSection(false):
|
||||
strongSelf.topStripeNode.isHidden = true
|
||||
default:
|
||||
strongSelf.topStripeNode.isHidden = false
|
||||
hasTopCorners = true
|
||||
strongSelf.topStripeNode.isHidden = hasCorners
|
||||
}
|
||||
let bottomStripeInset: CGFloat
|
||||
switch neighbors.bottom {
|
||||
@@ -381,10 +394,15 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
|
||||
bottomStripeInset = leftInset
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
hasBottomCorners = true
|
||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
private let topStripeNode: ASDisplayNode
|
||||
private let bottomStripeNode: ASDisplayNode
|
||||
private let highlightedBackgroundNode: ASDisplayNode
|
||||
private let maskNode: ASImageNode
|
||||
|
||||
private let titleNode: TextNode
|
||||
private var switchNode: ASDisplayNode & ItemListSwitchNodeImpl
|
||||
@@ -133,6 +134,8 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
self.backgroundNode.isLayerBacked = true
|
||||
self.backgroundNode.backgroundColor = .white
|
||||
|
||||
self.maskNode = ASImageNode()
|
||||
|
||||
self.topStripeNode = ASDisplayNode()
|
||||
self.topStripeNode.isLayerBacked = true
|
||||
|
||||
@@ -299,7 +302,9 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0)
|
||||
}
|
||||
|
||||
if strongSelf.maskNode.supernode != nil {
|
||||
strongSelf.maskNode.removeFromSupernode()
|
||||
}
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight))
|
||||
case .blocks:
|
||||
if strongSelf.backgroundNode.supernode == nil {
|
||||
@@ -311,11 +316,19 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
if strongSelf.bottomStripeNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2)
|
||||
}
|
||||
if strongSelf.maskNode.supernode == nil {
|
||||
strongSelf.insertSubnode(strongSelf.maskNode, at: 3)
|
||||
}
|
||||
|
||||
let hasCorners = params.width > 480
|
||||
var hasTopCorners = false
|
||||
var hasBottomCorners = false
|
||||
switch neighbors.top {
|
||||
case .sameSection(false):
|
||||
strongSelf.topStripeNode.isHidden = true
|
||||
default:
|
||||
strongSelf.topStripeNode.isHidden = false
|
||||
hasTopCorners = true
|
||||
strongSelf.topStripeNode.isHidden = hasCorners
|
||||
}
|
||||
let bottomStripeInset: CGFloat
|
||||
switch neighbors.bottom {
|
||||
@@ -323,9 +336,14 @@ public class ItemListSwitchItemNode: ListViewItemNode, ItemListItemNode {
|
||||
bottomStripeInset = 16.0 + params.leftInset
|
||||
default:
|
||||
bottomStripeInset = 0.0
|
||||
hasBottomCorners = true
|
||||
strongSelf.bottomStripeNode.isHidden = hasCorners
|
||||
}
|
||||
|
||||
strongSelf.maskNode.image = hasCorners ? PresentationResourcesItemList.cornersImage(item.theme, top: hasTopCorners, bottom: hasBottomCorners) : nil
|
||||
|
||||
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
|
||||
strongSelf.maskNode.frame = strongSelf.backgroundNode.frame.insetBy(dx: params.leftInset, dy: 0.0)
|
||||
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
|
||||
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - separatorHeight), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public final class ItemListTextEmptyStateItemNode: ItemListControllerEmptyStateI
|
||||
self.validLayout = (layout, navigationBarHeight)
|
||||
var insets = layout.insets(options: [.statusBar])
|
||||
insets.top += navigationBarHeight
|
||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 40.0 - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - textSize.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - textSize.height) / 2.0)), size: textSize)
|
||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 40.0 - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: layout.safeInsets.left + layout.intrinsicInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - textSize.width) / 2.0), y: insets.top + floor((layout.size.height - insets.top - insets.bottom - textSize.height) / 2.0)), size: textSize)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +143,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E295915423000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -299,6 +312,32 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -429,6 +468,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD296A8300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -470,6 +522,7 @@
|
||||
<string>1DD70E292420028600000000</string>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
<string>1DD70E29D6F14E1000000000</string>
|
||||
@@ -482,6 +535,8 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -492,6 +547,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E2951398CF200000000</string>
|
||||
</array>
|
||||
@@ -772,6 +828,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0497B4D6D800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -800,6 +877,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -855,10 +939,14 @@
|
||||
<string>E7A30F043594DCC000000000</string>
|
||||
<string>E7A30F042420028600000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
|
||||
+22
@@ -260,6 +260,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -440,6 +453,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -731,6 +745,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -775,6 +796,7 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
@implementation OggOpusReader
|
||||
|
||||
- (instancetype _Nullable)init:(NSString *)path {
|
||||
- (instancetype _Nullable)initWithPath:(NSString *)path {
|
||||
self = [super init];
|
||||
if (self != nil) {
|
||||
int error = OPUS_OK;
|
||||
|
||||
@@ -572,6 +572,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -867,6 +880,7 @@
|
||||
<string>1DD70E291D58331200000000</string>
|
||||
<string>1DD70E29CF967D4300000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
@@ -2163,6 +2177,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2250,6 +2271,7 @@
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F04F523B9DE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F049856EB2400000000</string>
|
||||
|
||||
@@ -273,6 +273,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E293594DCC000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -454,6 +467,7 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E2925BBFEEE00000000</string>
|
||||
@@ -812,6 +826,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -857,6 +878,7 @@
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
</array>
|
||||
|
||||
@@ -832,6 +832,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1264,6 +1277,7 @@
|
||||
<string>1DD70E29CF967D4300000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E291328E99400000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E29135DFEDE00000000</string>
|
||||
@@ -2379,6 +2393,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04C37F741500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2393,6 +2428,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2428,6 +2470,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F041328E99400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2547,27 +2596,6 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E292F91702000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04A59C927400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2715,13 +2743,6 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2937C1167400000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F049856EB2400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -2819,13 +2840,18 @@
|
||||
<string>E7A30F042420028600000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F0431752C6000000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F041328E99400000000</string>
|
||||
<string>E7A30F041E16CC6C00000000</string>
|
||||
<string>E7A30F04928D142900000000</string>
|
||||
@@ -2843,9 +2869,6 @@
|
||||
<string>E7A30F04524F478E00000000</string>
|
||||
<string>E7A30F04DF758A8500000000</string>
|
||||
<string>E7A30F042F91702000000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04A59C927400000000</string>
|
||||
<string>E7A30F04AE190FC000000000</string>
|
||||
<string>E7A30F04247D9AC100000000</string>
|
||||
@@ -2867,7 +2890,6 @@
|
||||
<string>E7A30F04A3994F2C00000000</string>
|
||||
<string>E7A30F048ED1FB1300000000</string>
|
||||
<string>E7A30F0437C1167400000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F049856EB2400000000</string>
|
||||
<string>E7A30F04C7165FF900000000</string>
|
||||
<string>E7A30F04135DFEDE00000000</string>
|
||||
|
||||
@@ -94,7 +94,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
contextController.setItems(items)
|
||||
contextController.setItems(.single(items))
|
||||
} else {
|
||||
contextController?.dismiss()
|
||||
parent.view.endEditing(true)
|
||||
|
||||
@@ -766,6 +766,30 @@ private func getUserPeer(postbox: Postbox, peerId: PeerId) -> Signal<(Peer?, Cac
|
||||
}
|
||||
}
|
||||
|
||||
public func openAddPersonContactImpl(context: AccountContext, peerId: PeerId, present: @escaping (ViewController, Any?) -> Void) {
|
||||
let _ = (getUserPeer(postbox: context.account.postbox, peerId: peerId)
|
||||
|> deliverOnMainQueue).start(next: { peer, cachedData in
|
||||
guard let user = peer as? TelegramUser, let contactData = DeviceContactExtendedData(peer: user) else {
|
||||
return
|
||||
}
|
||||
|
||||
var shareViaException = false
|
||||
if let cachedData = cachedData as? CachedUserData, let peerStatusSettings = cachedData.peerStatusSettings {
|
||||
shareViaException = peerStatusSettings.contains(.addExceptionWhenAddingContact)
|
||||
}
|
||||
|
||||
present(deviceContactInfoController(context: context, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
||||
if let peer = peer as? TelegramUser {
|
||||
if let phone = peer.phone, !phone.isEmpty {
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
present(OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).0, true)), nil)
|
||||
}
|
||||
}), completed: nil, cancelled: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})
|
||||
}
|
||||
|
||||
public func userInfoController(context: AccountContext, peerId: PeerId, mode: PeerInfoControllerMode = .generic) -> ViewController {
|
||||
let statePromise = ValuePromise(UserInfoState(), ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: UserInfoState())
|
||||
@@ -892,26 +916,8 @@ public func userInfoController(context: AccountContext, peerId: PeerId, mode: Pe
|
||||
}, openChat: {
|
||||
openChatImpl?()
|
||||
}, addContact: {
|
||||
let _ = (getUserPeer(postbox: context.account.postbox, peerId: peerId)
|
||||
|> deliverOnMainQueue).start(next: { peer, cachedData in
|
||||
guard let user = peer as? TelegramUser, let contactData = DeviceContactExtendedData(peer: user) else {
|
||||
return
|
||||
}
|
||||
|
||||
var shareViaException = false
|
||||
if let cachedData = cachedData as? CachedUserData, let peerStatusSettings = cachedData.peerStatusSettings {
|
||||
shareViaException = peerStatusSettings.contains(.addExceptionWhenAddingContact)
|
||||
}
|
||||
|
||||
presentControllerImpl?(deviceContactInfoController(context: context, subject: .create(peer: user, contactData: contactData, isSharing: true, shareViaException: shareViaException, completion: { peer, stableId, contactData in
|
||||
if let peer = peer as? TelegramUser {
|
||||
if let phone = peer.phone, !phone.isEmpty {
|
||||
}
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .genericSuccess(presentationData.strings.AddContact_StatusSuccess(peer.compactDisplayTitle).0, true)), nil)
|
||||
}
|
||||
}), completed: nil, cancelled: nil), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
openAddPersonContactImpl(context: context, peerId: peerId, present: { c, a in
|
||||
presentControllerImpl?(c, a)
|
||||
})
|
||||
}, shareContact: {
|
||||
shareContactImpl?()
|
||||
|
||||
@@ -156,6 +156,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E292417E0B200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -377,6 +390,32 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29524F478E00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -546,6 +585,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29CD296A8300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -588,6 +640,7 @@
|
||||
<string>1DD70E292420028600000000</string>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E292417E0B200000000</string>
|
||||
<string>1DD70E295915423000000000</string>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
@@ -605,6 +658,8 @@
|
||||
<string>1DD70E290F1A3C6400000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29524F478E00000000</string>
|
||||
<string>1DD70E293594DCC000000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
@@ -618,6 +673,7 @@
|
||||
<string>1DD70E292395015100000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E2951398CF200000000</string>
|
||||
</array>
|
||||
@@ -933,6 +989,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -961,6 +1024,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29A54A195300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04D233F68C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1049,10 +1133,14 @@
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04BF0846EE00000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F0405A95CB400000000</string>
|
||||
<string>E7A30F04A54A195300000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
|
||||
@@ -34,7 +34,7 @@ private func generateBackgroundImage(foreground: UIColor, diameter: CGFloat, sha
|
||||
private func generateBackgroundShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? {
|
||||
return generateImage(CGSize(width: diameter * 2.0 + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.setFillColor(shadow.cgColor)
|
||||
context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor)
|
||||
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
|
||||
@@ -61,7 +61,7 @@ private func generateBubbleImage(foreground: UIColor, diameter: CGFloat, shadowB
|
||||
private func generateBubbleShadowImage(shadow: UIColor, diameter: CGFloat, shadowBlur: CGFloat) -> UIImage? {
|
||||
return generateImage(CGSize(width: diameter + shadowBlur * 2.0, height: diameter + shadowBlur * 2.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
context.setFillColor(shadow.cgColor)
|
||||
context.setShadow(offset: CGSize(), blur: shadowBlur, color: shadow.cgColor)
|
||||
context.fillEllipse(in: CGRect(origin: CGPoint(x: shadowBlur, y: shadowBlur), size: CGSize(width: diameter, height: diameter)))
|
||||
context.setShadow(offset: CGSize(), blur: 1.0, color: shadow.cgColor)
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
load("//Config:buck_rule_macros.bzl", "static_library")
|
||||
|
||||
static_library(
|
||||
name = "SegmentedControlNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit#shared",
|
||||
"//submodules/Display:Display#shared",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
"$SDKROOT/System/Library/Frameworks/UIKit.framework",
|
||||
],
|
||||
)
|
||||
@@ -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>
|
||||
@@ -0,0 +1,511 @@
|
||||
<?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>archiveVersion</key>
|
||||
<string>1</string>
|
||||
<key>classes</key>
|
||||
<dict>
|
||||
</dict>
|
||||
<key>objectVersion</key>
|
||||
<string>46</string>
|
||||
<key>objects</key>
|
||||
<dict>
|
||||
<key>1DD70E299315E66800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode-Debug.xcconfig</string>
|
||||
<key>path</key>
|
||||
<string>../../buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Debug.xcconfig</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>text.xcconfig</string>
|
||||
</dict>
|
||||
<key>1DD70E290A5883D200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode-Profile.xcconfig</string>
|
||||
<key>path</key>
|
||||
<string>../../buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Profile.xcconfig</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>text.xcconfig</string>
|
||||
</dict>
|
||||
<key>1DD70E297DEF2F3400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode-Release.xcconfig</string>
|
||||
<key>path</key>
|
||||
<string>../../buck-out/gen/submodules/SegmentedControlNode/SegmentedControlNode-Release.xcconfig</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>text.xcconfig</string>
|
||||
</dict>
|
||||
<key>B401C9792F7F325000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>Buck (Do Not Modify)</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E299315E66800000000</string>
|
||||
<string>1DD70E290A5883D200000000</string>
|
||||
<string>1DD70E297DEF2F3400000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>B401C979B781F65D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>Configurations</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>B401C9792F7F325000000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>1DD70E29FF334B1F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libDisplay.dylib</string>
|
||||
<key>path</key>
|
||||
<string>libDisplay.dylib</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>compiled.mach-o.dylib</string>
|
||||
</dict>
|
||||
<key>1DD70E2936DE2CF900000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libMediaResources.a</string>
|
||||
<key>path</key>
|
||||
<string>libMediaResources.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29DB6520C800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libPostbox.dylib</string>
|
||||
<key>path</key>
|
||||
<string>libPostbox.dylib</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>compiled.mach-o.dylib</string>
|
||||
</dict>
|
||||
<key>1DD70E29D65BA68200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSwiftSignalKit.dylib</string>
|
||||
<key>path</key>
|
||||
<string>libSwiftSignalKit.dylib</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>compiled.mach-o.dylib</string>
|
||||
</dict>
|
||||
<key>1DD70E29119CDA0700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTelegramCore.dylib</string>
|
||||
<key>path</key>
|
||||
<string>libTelegramCore.dylib</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>compiled.mach-o.dylib</string>
|
||||
</dict>
|
||||
<key>1DD70E2984A59C1D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTelegramPresentationData.a</string>
|
||||
<key>path</key>
|
||||
<string>libTelegramPresentationData.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E292395015100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTelegramUIPreferences.a</string>
|
||||
<key>path</key>
|
||||
<string>libTelegramUIPreferences.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>B401C97968022A5500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>Frameworks</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
<string>1DD70E2936DE2CF900000000</string>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
<string>1DD70E29119CDA0700000000</string>
|
||||
<string>1DD70E2984A59C1D00000000</string>
|
||||
<string>1DD70E292395015100000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>B401C979C806358400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>Products</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>1DD70E29001F47FB00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>BUCK</string>
|
||||
<key>path</key>
|
||||
<string>BUCK</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>text.script.python</string>
|
||||
</dict>
|
||||
<key>1DD70E29D782379200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode.swift</string>
|
||||
<key>path</key>
|
||||
<string>Sources/SegmentedControlNode.swift</string>
|
||||
<key>sourceTree</key>
|
||||
<string>SOURCE_ROOT</string>
|
||||
</dict>
|
||||
<key>B401C979EAB5339800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>Sources</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E29D782379200000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>B401C979B84A82AD00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>1DD70E29001F47FB00000000</string>
|
||||
<string>B401C979EAB5339800000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>B401C979EFB6AC4600000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXGroup</string>
|
||||
<key>name</key>
|
||||
<string>mainGroup</string>
|
||||
<key>sourceTree</key>
|
||||
<string><![CDATA[<group>]]></string>
|
||||
<key>children</key>
|
||||
<array>
|
||||
<string>B401C979B781F65D00000000</string>
|
||||
<string>B401C97968022A5500000000</string>
|
||||
<string>B401C979C806358400000000</string>
|
||||
<string>B401C979B84A82AD00000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>E7A30F04D782379200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29D782379200000000</string>
|
||||
</dict>
|
||||
<key>1870857F0000000000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXSourcesBuildPhase</string>
|
||||
<key>files</key>
|
||||
<array>
|
||||
<string>E7A30F04D782379200000000</string>
|
||||
</array>
|
||||
</dict>
|
||||
<key>E7A30F04FF334B1F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29FF334B1F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04DB6520C800000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29DB6520C800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04D65BA68200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29D65BA68200000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04119CDA0700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29119CDA0700000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0436DE2CF900000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2936DE2CF900000000</string>
|
||||
</dict>
|
||||
<key>E7A30F042395015100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E292395015100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0484A59C1D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2984A59C1D00000000</string>
|
||||
</dict>
|
||||
<key>FAF5FAC90000000000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXCopyFilesBuildPhase</string>
|
||||
<key>files</key>
|
||||
<array>
|
||||
<string>E7A30F04FF334B1F00000000</string>
|
||||
<string>E7A30F04DB6520C800000000</string>
|
||||
<string>E7A30F04D65BA68200000000</string>
|
||||
<string>E7A30F04119CDA0700000000</string>
|
||||
<string>E7A30F0436DE2CF900000000</string>
|
||||
<string>E7A30F042395015100000000</string>
|
||||
<string>E7A30F0484A59C1D00000000</string>
|
||||
</array>
|
||||
<key>name</key>
|
||||
<string>Fake Swift Dependencies (Copy Files Phase)</string>
|
||||
<key>runOnlyForDeploymentPostprocessing</key>
|
||||
<integer>1</integer>
|
||||
<key>dstSubfolderSpec</key>
|
||||
<integer>16</integer>
|
||||
<key>dstPath</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
<key>4952437303EDA63300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Debug</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
<key>baseConfigurationReference</key>
|
||||
<string>1DD70E299315E66800000000</string>
|
||||
</dict>
|
||||
<key>4952437350C7218900000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Profile</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
<key>baseConfigurationReference</key>
|
||||
<string>1DD70E290A5883D200000000</string>
|
||||
</dict>
|
||||
<key>49524373A439BFE700000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Release</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
<key>baseConfigurationReference</key>
|
||||
<string>1DD70E297DEF2F3400000000</string>
|
||||
</dict>
|
||||
<key>218C37090000000000000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCConfigurationList</string>
|
||||
<key>buildConfigurations</key>
|
||||
<array>
|
||||
<string>4952437303EDA63300000000</string>
|
||||
<string>4952437350C7218900000000</string>
|
||||
<string>49524373A439BFE700000000</string>
|
||||
</array>
|
||||
<key>defaultConfigurationIsVisible</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>E66DC04EB84A82AD00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXNativeTarget</string>
|
||||
<key>name</key>
|
||||
<string>SegmentedControlNode</string>
|
||||
<key>productName</key>
|
||||
<string>SegmentedControlNode</string>
|
||||
<key>productReference</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<key>productType</key>
|
||||
<string>com.apple.product-type.library.static</string>
|
||||
<key>dependencies</key>
|
||||
<array>
|
||||
</array>
|
||||
<key>buildPhases</key>
|
||||
<array>
|
||||
<string>1870857F0000000000000000</string>
|
||||
<string>FAF5FAC90000000000000000</string>
|
||||
</array>
|
||||
<key>buildConfigurationList</key>
|
||||
<string>218C37090000000000000000</string>
|
||||
</dict>
|
||||
<key>4952437303EDA63300000001</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Debug</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>4952437350C7218900000001</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Profile</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>49524373A439BFE700000001</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCBuildConfiguration</string>
|
||||
<key>name</key>
|
||||
<string>Release</string>
|
||||
<key>buildSettings</key>
|
||||
<dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>218C37090000000000000001</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>XCConfigurationList</string>
|
||||
<key>buildConfigurations</key>
|
||||
<array>
|
||||
<string>4952437303EDA63300000001</string>
|
||||
<string>4952437350C7218900000001</string>
|
||||
<string>49524373A439BFE700000001</string>
|
||||
</array>
|
||||
<key>defaultConfigurationIsVisible</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>96C84793B84A82AD00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXProject</string>
|
||||
<key>mainGroup</key>
|
||||
<string>B401C979EFB6AC4600000000</string>
|
||||
<key>targets</key>
|
||||
<array>
|
||||
<string>E66DC04EB84A82AD00000000</string>
|
||||
</array>
|
||||
<key>buildConfigurationList</key>
|
||||
<string>218C37090000000000000001</string>
|
||||
<key>compatibilityVersion</key>
|
||||
<string>Xcode 3.2</string>
|
||||
<key>attributes</key>
|
||||
<dict>
|
||||
<key>LastUpgradeCheck</key>
|
||||
<string>9999</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>rootObject</key>
|
||||
<string>96C84793B84A82AD00000000</string>
|
||||
</dict>
|
||||
</plist>
|
||||
+1
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Scheme LastUpgradeVersion="9999" version="1.7"><BuildAction buildImplicitDependencies="YES" parallelizeBuildables="YES"><BuildActionEntries><BuildActionEntry buildForAnalyzing="YES" buildForArchiving="YES" buildForProfiling="YES" buildForRunning="YES" buildForTesting="YES"><BuildableReference BlueprintIdentifier="E66DC04EB84A82AD00000000" BlueprintName="SegmentedControlNode" BuildableIdentifier="primary" BuildableName="libSegmentedControlNode.a" ReferencedContainer="container:SegmentedControlNode.xcodeproj"/></BuildActionEntry></BuildActionEntries></BuildAction><TestAction buildConfiguration="Debug" shouldUseLaunchSchemeArgsEnv="YES"><Testables/></TestAction><LaunchAction buildConfiguration="Debug"/><ProfileAction buildConfiguration="Release"/><AnalyzeAction buildConfiguration="Debug"/><ArchiveAction buildConfiguration="Release" revealArchiveInOrganizer="YES"/></Scheme>
|
||||
@@ -0,0 +1,563 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 50;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
09CE5B9023225AC200743FF4 /* TelegramPresentationData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */; };
|
||||
D060188A22F3604000796784 /* SegmentedControlNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D060188822F3604000796784 /* SegmentedControlNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D060189522F3615800796784 /* SegmentedControlNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D060189422F3615800796784 /* SegmentedControlNode.swift */; };
|
||||
D060189822F3616300796784 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189722F3616300796784 /* Foundation.framework */; };
|
||||
D060189A22F3616600796784 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189922F3616600796784 /* UIKit.framework */; };
|
||||
D060189C22F3616A00796784 /* AsyncDisplayKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189B22F3616A00796784 /* AsyncDisplayKit.framework */; };
|
||||
D060189E22F3616E00796784 /* LegacyComponents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D060189D22F3616E00796784 /* LegacyComponents.framework */; };
|
||||
D0A0B53922F370DF00628AF3 /* Display.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0A0B53822F370DF00628AF3 /* Display.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = TelegramPresentationData.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D060188522F3604000796784 /* SegmentedControlNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SegmentedControlNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D060188822F3604000796784 /* SegmentedControlNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SegmentedControlNode.h; sourceTree = "<group>"; };
|
||||
D060188922F3604000796784 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
D060189422F3615800796784 /* SegmentedControlNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SegmentedControlNode.swift; sourceTree = "<group>"; };
|
||||
D060189722F3616300796784 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
D060189922F3616600796784 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||
D060189B22F3616A00796784 /* AsyncDisplayKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AsyncDisplayKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D060189D22F3616E00796784 /* LegacyComponents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = LegacyComponents.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D0A0B53822F370DF00628AF3 /* Display.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Display.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D060188222F3604000796784 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
09CE5B9023225AC200743FF4 /* TelegramPresentationData.framework in Frameworks */,
|
||||
D0A0B53922F370DF00628AF3 /* Display.framework in Frameworks */,
|
||||
D060189E22F3616E00796784 /* LegacyComponents.framework in Frameworks */,
|
||||
D060189C22F3616A00796784 /* AsyncDisplayKit.framework in Frameworks */,
|
||||
D060189A22F3616600796784 /* UIKit.framework in Frameworks */,
|
||||
D060189822F3616300796784 /* Foundation.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D060187B22F3604000796784 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D060188922F3604000796784 /* Info.plist */,
|
||||
D060188722F3604000796784 /* Sources */,
|
||||
D060188622F3604000796784 /* Products */,
|
||||
D060189622F3616300796784 /* Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D060188622F3604000796784 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D060188522F3604000796784 /* SegmentedControlNode.framework */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D060188722F3604000796784 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D060189422F3615800796784 /* SegmentedControlNode.swift */,
|
||||
D060188822F3604000796784 /* SegmentedControlNode.h */,
|
||||
);
|
||||
path = Sources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D060189622F3616300796784 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09CE5B8F23225AC200743FF4 /* TelegramPresentationData.framework */,
|
||||
D0A0B53822F370DF00628AF3 /* Display.framework */,
|
||||
D060189D22F3616E00796784 /* LegacyComponents.framework */,
|
||||
D060189B22F3616A00796784 /* AsyncDisplayKit.framework */,
|
||||
D060189922F3616600796784 /* UIKit.framework */,
|
||||
D060189722F3616300796784 /* Foundation.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
D060188022F3604000796784 /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D060188A22F3604000796784 /* SegmentedControlNode.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D060188422F3604000796784 /* SegmentedControlNode */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D060188D22F3604000796784 /* Build configuration list for PBXNativeTarget "SegmentedControlNode" */;
|
||||
buildPhases = (
|
||||
D060188022F3604000796784 /* Headers */,
|
||||
D060188122F3604000796784 /* Sources */,
|
||||
D060188222F3604000796784 /* Frameworks */,
|
||||
D060188322F3604000796784 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = SegmentedControlNode;
|
||||
productName = SegmentedControlNode;
|
||||
productReference = D060188522F3604000796784 /* SegmentedControlNode.framework */;
|
||||
productType = "com.apple.product-type.framework";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
D060187C22F3604000796784 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
DefaultBuildSystemTypeForWorkspace = Latest;
|
||||
LastUpgradeCheck = 1010;
|
||||
ORGANIZATIONNAME = "Telegram Messenger LLP";
|
||||
TargetAttributes = {
|
||||
D060188422F3604000796784 = {
|
||||
CreatedOnToolsVersion = 10.1;
|
||||
LastSwiftMigration = 1010;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = D060187F22F3604000796784 /* Build configuration list for PBXProject "SegmentedControlNode_Xcode" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
);
|
||||
mainGroup = D060187B22F3604000796784;
|
||||
productRefGroup = D060188622F3604000796784 /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D060188422F3604000796784 /* SegmentedControlNode */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
D060188322F3604000796784 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D060188122F3604000796784 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D060189522F3615800796784 /* SegmentedControlNode.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
D060188B22F3604000796784 /* 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;
|
||||
};
|
||||
D060188C22F3604000796784 /* 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;
|
||||
};
|
||||
D060188E22F3604000796784 /* 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.SegmentedControlNode;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = DebugAppStoreLLC;
|
||||
};
|
||||
D060188F22F3604000796784 /* 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.SegmentedControlNode;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = ReleaseAppStoreLLC;
|
||||
};
|
||||
D060189022F360BF00796784 /* 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;
|
||||
};
|
||||
D060189122F360BF00796784 /* 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.SegmentedControlNode;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = DebugHockeyapp;
|
||||
};
|
||||
D060189222F360CA00796784 /* 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;
|
||||
};
|
||||
D060189322F360CA00796784 /* 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.SegmentedControlNode;
|
||||
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = ReleaseHockeyappInternal;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
D060187F22F3604000796784 /* Build configuration list for PBXProject "SegmentedControlNode_Xcode" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D060188B22F3604000796784 /* DebugAppStoreLLC */,
|
||||
D060189022F360BF00796784 /* DebugHockeyapp */,
|
||||
D060188C22F3604000796784 /* ReleaseAppStoreLLC */,
|
||||
D060189222F360CA00796784 /* ReleaseHockeyappInternal */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||
};
|
||||
D060188D22F3604000796784 /* Build configuration list for PBXNativeTarget "SegmentedControlNode" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D060188E22F3604000796784 /* DebugAppStoreLLC */,
|
||||
D060189122F360BF00796784 /* DebugHockeyapp */,
|
||||
D060188F22F3604000796784 /* ReleaseAppStoreLLC */,
|
||||
D060189322F360CA00796784 /* ReleaseHockeyappInternal */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = ReleaseAppStoreLLC;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = D060187C22F3604000796784 /* Project object */;
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,11 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
//! Project version number for SegmentedControlNode.
|
||||
FOUNDATION_EXPORT double SegmentedControlNodeVersionNumber;
|
||||
|
||||
//! Project version string for SegmentedControlNode.
|
||||
FOUNDATION_EXPORT const unsigned char SegmentedControlNodeVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <SegmentedControlNode/PublicHeader.h>
|
||||
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
import Foundation
|
||||
import Display
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import TelegramPresentationData
|
||||
|
||||
private let textFont = Font.regular(13.0)
|
||||
private let selectedTextFont = Font.bold(13.0)
|
||||
|
||||
public enum SegmentedControlLayout {
|
||||
case stretchToFill(width: CGFloat)
|
||||
case sizeToFit(maximumWidth: CGFloat, minimumWidth: CGFloat)
|
||||
}
|
||||
|
||||
public final class SegmentedControlTheme: Equatable {
|
||||
public let backgroundColor: UIColor
|
||||
public let foregroundColor: UIColor
|
||||
public let shadowColor: UIColor
|
||||
public let textColor: UIColor
|
||||
public let dividerColor: UIColor
|
||||
|
||||
public init(backgroundColor: UIColor, foregroundColor: UIColor, shadowColor: UIColor, textColor: UIColor, dividerColor: UIColor) {
|
||||
self.backgroundColor = backgroundColor
|
||||
self.foregroundColor = foregroundColor
|
||||
self.shadowColor = shadowColor
|
||||
self.textColor = textColor
|
||||
self.dividerColor = dividerColor
|
||||
}
|
||||
|
||||
public static func ==(lhs: SegmentedControlTheme, rhs: SegmentedControlTheme) -> Bool {
|
||||
if lhs.backgroundColor != rhs.backgroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.foregroundColor != rhs.foregroundColor {
|
||||
return false
|
||||
}
|
||||
if lhs.shadowColor != rhs.shadowColor {
|
||||
return false
|
||||
}
|
||||
if lhs.textColor != rhs.textColor {
|
||||
return false
|
||||
}
|
||||
if lhs.dividerColor != rhs.dividerColor {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
public extension SegmentedControlTheme {
|
||||
convenience init(theme: PresentationTheme) {
|
||||
self.init(backgroundColor: theme.rootController.navigationSearchBar.inputFillColor, foregroundColor: theme.rootController.navigationBar.backgroundColor, shadowColor: .black, textColor: theme.rootController.navigationBar.primaryTextColor, dividerColor: theme.list.freeInputField.strokeColor)
|
||||
}
|
||||
}
|
||||
|
||||
private func generateSelectionImage(theme: SegmentedControlTheme) -> UIImage? {
|
||||
return generateImage(CGSize(width: 20.0, height: 20.0), rotatedContext: { size, context in
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
context.clear(bounds)
|
||||
|
||||
if theme.shadowColor != .clear {
|
||||
context.setShadow(offset: CGSize(width: 0.0, height: -3.0), blur: 6.0, color: theme.shadowColor.withAlphaComponent(0.12).cgColor)
|
||||
}
|
||||
context.setFillColor(theme.foregroundColor.cgColor)
|
||||
context.fillEllipse(in: CGRect(x: 2.0, y: 2.0, width: 16.0, height: 16.0))
|
||||
})?.stretchableImage(withLeftCapWidth: 10, topCapHeight: 10)
|
||||
}
|
||||
|
||||
public struct SegmentedControlItem: Equatable {
|
||||
public let title: String
|
||||
|
||||
public init(title: String) {
|
||||
self.title = title
|
||||
}
|
||||
}
|
||||
|
||||
public final class SegmentedControlNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
private var theme: SegmentedControlTheme
|
||||
private var _items: [SegmentedControlItem]
|
||||
private var _selectedIndex: Int = 0
|
||||
|
||||
private var validLayout: SegmentedControlLayout?
|
||||
|
||||
private let selectionNode: ASImageNode
|
||||
private var itemNodes: [HighlightTrackingButtonNode]
|
||||
private var dividerNodes: [ASDisplayNode]
|
||||
|
||||
private var gestureRecognizer: UIPanGestureRecognizer?
|
||||
private var gestureSelectedIndex: Int?
|
||||
|
||||
public var items: [SegmentedControlItem] {
|
||||
get {
|
||||
return self._items
|
||||
}
|
||||
set {
|
||||
let previousItems = self._items
|
||||
self._items = newValue
|
||||
guard previousItems != newValue else {
|
||||
return
|
||||
}
|
||||
|
||||
self.itemNodes.forEach { $0.removeFromSupernode() }
|
||||
self.itemNodes = self._items.map { item in
|
||||
let itemNode = HighlightTrackingButtonNode()
|
||||
itemNode.setTitle(item.title, with: textFont, with: self.theme.textColor, for: .normal)
|
||||
itemNode.setTitle(item.title, with: selectedTextFont, with: self.theme.textColor, for: .selected)
|
||||
itemNode.setTitle(item.title, with: selectedTextFont, with: self.theme.textColor, for: [.selected, .highlighted])
|
||||
return itemNode
|
||||
}
|
||||
self.setupButtons()
|
||||
self.itemNodes.forEach(self.addSubnode(_:))
|
||||
|
||||
let dividersCount = self._items.count > 2 ? self._items.count - 1 : 0
|
||||
if self.dividerNodes.count != dividersCount {
|
||||
self.dividerNodes.forEach { $0.removeFromSupernode() }
|
||||
self.dividerNodes = (0 ..< dividersCount).map { _ in ASDisplayNode() }
|
||||
}
|
||||
|
||||
if let layout = self.validLayout {
|
||||
let _ = self.updateLayout(layout, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var selectedIndex: Int {
|
||||
get {
|
||||
return self._selectedIndex
|
||||
}
|
||||
set {
|
||||
guard newValue != self._selectedIndex else {
|
||||
return
|
||||
}
|
||||
self._selectedIndex = newValue
|
||||
if let layout = self.validLayout {
|
||||
let _ = self.updateLayout(layout, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var selectedIndexChanged: (Int) -> Void = { _ in }
|
||||
|
||||
public init(theme: SegmentedControlTheme, items: [SegmentedControlItem], selectedIndex: Int) {
|
||||
self.theme = theme
|
||||
self._items = items
|
||||
self._selectedIndex = selectedIndex
|
||||
|
||||
self.selectionNode = ASImageNode()
|
||||
self.selectionNode.displaysAsynchronously = false
|
||||
self.selectionNode.displayWithoutProcessing = true
|
||||
|
||||
self.itemNodes = items.map { item in
|
||||
let itemNode = HighlightTrackingButtonNode()
|
||||
itemNode.setTitle(item.title, with: textFont, with: theme.textColor, for: .normal)
|
||||
itemNode.setTitle(item.title, with: selectedTextFont, with: theme.textColor, for: .selected)
|
||||
itemNode.setTitle(item.title, with: selectedTextFont, with: theme.textColor, for: [.selected, .highlighted])
|
||||
return itemNode
|
||||
}
|
||||
|
||||
let dividersCount = items.count > 2 ? items.count - 1 : 0
|
||||
self.dividerNodes = (0 ..< dividersCount).map { _ in
|
||||
let node = ASDisplayNode()
|
||||
node.backgroundColor = theme.dividerColor
|
||||
return node
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
self.cornerRadius = 9.0
|
||||
|
||||
self.addSubnode(self.selectionNode)
|
||||
self.itemNodes.forEach(self.addSubnode(_:))
|
||||
self.setupButtons()
|
||||
self.dividerNodes.forEach(self.addSubnode(_:))
|
||||
|
||||
self.backgroundColor = self.theme.backgroundColor
|
||||
self.selectionNode.image = generateSelectionImage(theme: self.theme)
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.view.disablesInteractiveTransitionGestureRecognizer = true
|
||||
|
||||
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:)))
|
||||
gestureRecognizer.delegate = self
|
||||
self.view.addGestureRecognizer(gestureRecognizer)
|
||||
self.gestureRecognizer = gestureRecognizer
|
||||
}
|
||||
|
||||
private func setupButtons() {
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
itemNode.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: .touchUpInside)
|
||||
itemNode.highligthedChanged = { [weak self, weak itemNode] highlighted in
|
||||
if let strongSelf = self, let itemNode = itemNode {
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||
if strongSelf.selectedIndex == i {
|
||||
if let gestureRecognizer = strongSelf.gestureRecognizer, case .began = gestureRecognizer.state {
|
||||
} else {
|
||||
strongSelf.updateButtonsHighlights(highlightedIndex: highlighted ? i : nil, gestureSelectedIndex: strongSelf.gestureSelectedIndex)
|
||||
}
|
||||
} else if highlighted {
|
||||
transition.updateAlpha(node: itemNode, alpha: 0.4)
|
||||
}
|
||||
if !highlighted {
|
||||
transition.updateAlpha(node: itemNode, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateButtonsHighlights(highlightedIndex: Int?, gestureSelectedIndex: Int?) {
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||
if highlightedIndex == nil && gestureSelectedIndex == nil {
|
||||
transition.updateTransformScale(node: self.selectionNode, scale: 1.0)
|
||||
} else {
|
||||
transition.updateTransformScale(node: self.selectionNode, scale: 0.92)
|
||||
}
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
if i == highlightedIndex || i == gestureSelectedIndex {
|
||||
transition.updateTransformScale(node: itemNode, scale: 0.92)
|
||||
} else {
|
||||
transition.updateTransformScale(node: itemNode, scale: 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func updateButtonsHighlights() {
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .easeInOut)
|
||||
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
transition.updateTransformScale(node: itemNode, scale: i == gestureSelectedIndex ? 0.92 : 1.0)
|
||||
}
|
||||
} else {
|
||||
for itemNode in self.itemNodes {
|
||||
transition.updateTransformScale(node: itemNode, scale: 1.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateTheme(_ theme: SegmentedControlTheme) {
|
||||
guard theme != self.theme else {
|
||||
return
|
||||
}
|
||||
self.theme = theme
|
||||
|
||||
self.backgroundColor = self.theme.backgroundColor
|
||||
self.selectionNode.image = generateSelectionImage(theme: self.theme)
|
||||
|
||||
for itemNode in self.itemNodes {
|
||||
if let title = itemNode.attributedTitle(for: .normal)?.string {
|
||||
itemNode.setTitle(title, with: textFont, with: self.theme.textColor, for: .normal)
|
||||
itemNode.setTitle(title, with: selectedTextFont, with: self.theme.textColor, for: .selected)
|
||||
itemNode.setTitle(title, with: selectedTextFont, with: self.theme.textColor, for: [.selected, .highlighted])
|
||||
}
|
||||
}
|
||||
|
||||
for dividerNode in self.dividerNodes {
|
||||
dividerNode.backgroundColor = theme.dividerColor
|
||||
}
|
||||
}
|
||||
|
||||
public func updateLayout(_ layout: SegmentedControlLayout, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
self.validLayout = layout
|
||||
|
||||
let calculatedWidth: CGFloat = 0.0
|
||||
|
||||
let width: CGFloat
|
||||
switch layout {
|
||||
case let .stretchToFill(targetWidth):
|
||||
width = targetWidth
|
||||
case let .sizeToFit(maximumWidth, minimumWidth):
|
||||
width = max(minimumWidth, min(maximumWidth, calculatedWidth))
|
||||
}
|
||||
|
||||
let size = CGSize(width: width, height: 32.0)
|
||||
if !self.itemNodes.isEmpty {
|
||||
let itemSize = CGSize(width: floorToScreenPixels(size.width / CGFloat(self.itemNodes.count)), height: size.height)
|
||||
|
||||
let selectedIndex: Int
|
||||
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||
selectedIndex = gestureSelectedIndex
|
||||
} else {
|
||||
selectedIndex = self.selectedIndex
|
||||
}
|
||||
|
||||
transition.updateBounds(node: self.selectionNode, bounds: CGRect(origin: CGPoint(), size: itemSize))
|
||||
transition.updatePosition(node: self.selectionNode, position: CGPoint(x: itemSize.width / 2.0 + itemSize.width * CGFloat(selectedIndex), y: size.height / 2.0))
|
||||
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
transition.updateFrame(node: itemNode, frame: CGRect(origin: CGPoint(x: itemSize.width * CGFloat(i), y: (size.height - itemSize.height) / 2.0), size: itemSize))
|
||||
|
||||
let isSelected = selectedIndex == i
|
||||
if itemNode.isSelected != isSelected {
|
||||
if case .animated = transition {
|
||||
UIView.transition(with: itemNode.view, duration: 0.2, options: .transitionCrossDissolve, animations: {
|
||||
itemNode.isSelected = isSelected
|
||||
}, completion: nil)
|
||||
} else {
|
||||
itemNode.isSelected = isSelected
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !self.dividerNodes.isEmpty {
|
||||
let dividerSize = CGSize(width: 1.0, height: 16.0)
|
||||
let delta: CGFloat = size.width / CGFloat(self.dividerNodes.count + 1)
|
||||
for i in 0 ..< self.dividerNodes.count {
|
||||
let dividerNode = self.dividerNodes[i]
|
||||
transition.updateFrame(node: dividerNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels(delta * CGFloat(i + 1) - dividerSize.width / 2.0), y: (size.height - dividerSize.height) / 2.0), size: dividerSize))
|
||||
|
||||
let dividerAlpha: CGFloat
|
||||
if (self.selectedIndex - 1 ... self.selectedIndex).contains(i) {
|
||||
dividerAlpha = 0.0
|
||||
} else {
|
||||
dividerAlpha = 1.0
|
||||
}
|
||||
transition.updateAlpha(node: dividerNode, alpha: dividerAlpha)
|
||||
}
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
@objc private func buttonPressed(_ button: HighlightTrackingButtonNode) {
|
||||
guard let index = self.itemNodes.firstIndex(of: button) else {
|
||||
return
|
||||
}
|
||||
|
||||
self._selectedIndex = index
|
||||
self.selectedIndexChanged(index)
|
||||
if let layout = self.validLayout {
|
||||
let _ = self.updateLayout(layout, transition: .animated(duration: 0.2, curve: .slide))
|
||||
}
|
||||
}
|
||||
|
||||
public override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
let location = gestureRecognizer.location(in: self.view)
|
||||
return self.selectionNode.frame.contains(location)
|
||||
}
|
||||
|
||||
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
|
||||
let location = recognizer.location(in: self.view)
|
||||
switch recognizer.state {
|
||||
case .changed:
|
||||
if !self.selectionNode.frame.contains(location) {
|
||||
let point = CGPoint(x: max(0.0, min(self.bounds.width, location.x)), y: 1.0)
|
||||
for i in 0 ..< self.itemNodes.count {
|
||||
let itemNode = self.itemNodes[i]
|
||||
if itemNode.frame.contains(point) {
|
||||
if i != self.gestureSelectedIndex {
|
||||
self.gestureSelectedIndex = i
|
||||
self.updateButtonsHighlights(highlightedIndex: nil, gestureSelectedIndex: i)
|
||||
if let layout = self.validLayout {
|
||||
let _ = self.updateLayout(layout, transition: .animated(duration: 0.35, curve: .slide))
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
case .ended:
|
||||
if let gestureSelectedIndex = self.gestureSelectedIndex {
|
||||
if gestureSelectedIndex != self.selectedIndex {
|
||||
self._selectedIndex = gestureSelectedIndex
|
||||
self.selectedIndexChanged(self._selectedIndex)
|
||||
}
|
||||
self.gestureSelectedIndex = nil
|
||||
self.updateButtonsHighlights(highlightedIndex: nil, gestureSelectedIndex: nil)
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ static_library(
|
||||
"//submodules/GridMessageSelectionNode:GridMessageSelectionNode",
|
||||
"//submodules/InstantPageCache:InstantPageCache",
|
||||
"//submodules/AppBundle:AppBundle",
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
],
|
||||
frameworks = [
|
||||
"$SDKROOT/System/Library/Frameworks/Foundation.framework",
|
||||
|
||||
@@ -286,6 +286,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E296C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>path</key>
|
||||
<string>libContextUI.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2915F6A49D00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1001,6 +1014,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libReactionSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E291D58331200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1053,6 +1079,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E2957B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libSegmentedControlNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29097DBE9200000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1339,6 +1378,19 @@
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXFileReference</string>
|
||||
<key>name</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>path</key>
|
||||
<string>libTextSelectionNode.a</string>
|
||||
<key>sourceTree</key>
|
||||
<string>BUILT_PRODUCTS_DIR</string>
|
||||
<key>explicitFileType</key>
|
||||
<string>archive.ar</string>
|
||||
</dict>
|
||||
<key>1DD70E29B4B05B7A00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -1482,6 +1534,7 @@
|
||||
<string>1DD70E2997B4D6D800000000</string>
|
||||
<string>1DD70E292F91702000000000</string>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
<string>1DD70E2915F6A49D00000000</string>
|
||||
<string>1DD70E29016F454200000000</string>
|
||||
<string>1DD70E2979E58A0000000000</string>
|
||||
@@ -1537,10 +1590,12 @@
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
<string>1DD70E29AA32BBC600000000</string>
|
||||
<string>1DD70E293E4DE92B00000000</string>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
<string>1DD70E291D58331200000000</string>
|
||||
<string>1DD70E29CF967D4300000000</string>
|
||||
<string>1DD70E29EA9CBB5B00000000</string>
|
||||
<string>1DD70E291328E99400000000</string>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
<string>1DD70E29097DBE9200000000</string>
|
||||
<string>1DD70E2981AE180900000000</string>
|
||||
<string>1DD70E29524F478E00000000</string>
|
||||
@@ -1563,6 +1618,7 @@
|
||||
<string>1DD70E29F18DE1D900000000</string>
|
||||
<string>1DD70E29BA06E3A600000000</string>
|
||||
<string>1DD70E29F0C15F9C00000000</string>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
<string>1DD70E29B4B05B7A00000000</string>
|
||||
<string>1DD70E29CD296A8300000000</string>
|
||||
<string>1DD70E29AE67341000000000</string>
|
||||
@@ -4117,6 +4173,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29CBE117ED00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0457B5522500000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2957B5522500000000</string>
|
||||
</dict>
|
||||
<key>E7A30F0425BBFEEE00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -4222,6 +4285,27 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29B6F47D1F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04AD66967300000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29AD66967300000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04F40A586F00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29F40A586F00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F046C9831F100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E296C9831F100000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04D233F68C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -4243,6 +4327,13 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E2931752C6000000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F041328E99400000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -4327,13 +4418,6 @@
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29E220F5E800000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04BBAF750C00000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
<string>PBXBuildFile</string>
|
||||
<key>fileRef</key>
|
||||
<string>1DD70E29BBAF750C00000000</string>
|
||||
</dict>
|
||||
<key>E7A30F04247D9AC100000000</key>
|
||||
<dict>
|
||||
<key>isa</key>
|
||||
@@ -4703,6 +4787,7 @@
|
||||
<string>E7A30F0497B4D6D800000000</string>
|
||||
<string>E7A30F04C37F741500000000</string>
|
||||
<string>E7A30F04CBE117ED00000000</string>
|
||||
<string>E7A30F0457B5522500000000</string>
|
||||
<string>E7A30F0425BBFEEE00000000</string>
|
||||
<string>E7A30F045A26607D00000000</string>
|
||||
<string>E7A30F042417E0B200000000</string>
|
||||
@@ -4718,9 +4803,13 @@
|
||||
<string>E7A30F0471ED41B100000000</string>
|
||||
<string>E7A30F047AB043C800000000</string>
|
||||
<string>E7A30F04B6F47D1F00000000</string>
|
||||
<string>E7A30F04AD66967300000000</string>
|
||||
<string>E7A30F04F40A586F00000000</string>
|
||||
<string>E7A30F046C9831F100000000</string>
|
||||
<string>E7A30F04D233F68C00000000</string>
|
||||
<string>E7A30F049A24C4DE00000000</string>
|
||||
<string>E7A30F0431752C6000000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F041328E99400000000</string>
|
||||
<string>E7A30F041E16CC6C00000000</string>
|
||||
<string>E7A30F043E4DE92B00000000</string>
|
||||
@@ -4733,7 +4822,6 @@
|
||||
<string>E7A30F042F91702000000000</string>
|
||||
<string>E7A30F04CED1620500000000</string>
|
||||
<string>E7A30F04E220F5E800000000</string>
|
||||
<string>E7A30F04BBAF750C00000000</string>
|
||||
<string>E7A30F04247D9AC100000000</string>
|
||||
<string>E7A30F04B4B05B7A00000000</string>
|
||||
<string>E7A30F04490601EB00000000</string>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
091EABA5231DAC7500A0EC14 /* ThemeNameGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */; };
|
||||
09B4A9B823102B7A005C2E08 /* EditThemeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09B4A9B723102B7A005C2E08 /* EditThemeController.swift */; };
|
||||
09CE5B8E2322154400743FF4 /* SegmentedControlNode.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */; };
|
||||
D03E465223075D930049C28B /* SettingsUI.h in Headers */ = {isa = PBXBuildFile; fileRef = D03E465023075D930049C28B /* SettingsUI.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
D03E466823075E660049C28B /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465C23075E630049C28B /* TabBarAccountSwitchControllerNode.swift */; };
|
||||
D03E466923075E660049C28B /* LogoutOptionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E465D23075E630049C28B /* LogoutOptionsController.swift */; };
|
||||
@@ -194,6 +195,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
091EABA4231DAC7500A0EC14 /* ThemeNameGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeNameGenerator.swift; sourceTree = "<group>"; };
|
||||
09B4A9B723102B7A005C2E08 /* EditThemeController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditThemeController.swift; sourceTree = "<group>"; };
|
||||
09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SegmentedControlNode.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D03E464D23075D930049C28B /* SettingsUI.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SettingsUI.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D03E465023075D930049C28B /* SettingsUI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SettingsUI.h; sourceTree = "<group>"; };
|
||||
D03E465123075D930049C28B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
@@ -384,6 +386,7 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D0EFF26A2319825B00CF5164 /* AppBundle.framework in Frameworks */,
|
||||
09CE5B8E2322154400743FF4 /* SegmentedControlNode.framework in Frameworks */,
|
||||
D03E493A2308678D0049C28B /* InstantPageCache.framework in Frameworks */,
|
||||
D03E490E2308661A0049C28B /* GridMessageSelectionNode.framework in Frameworks */,
|
||||
D03E48E22308649C0049C28B /* CounterContollerTitleView.framework in Frameworks */,
|
||||
@@ -688,6 +691,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0EFF2692319825B00CF5164 /* AppBundle.framework */,
|
||||
09CE5B8D2322154400743FF4 /* SegmentedControlNode.framework */,
|
||||
D03E49392308678D0049C28B /* InstantPageCache.framework */,
|
||||
D03E490D2308661A0049C28B /* GridMessageSelectionNode.framework */,
|
||||
D03E48E12308649C0049C28B /* CounterContollerTitleView.framework */,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ func openEditSettings(context: AccountContext, accountsAndPeers: Signal<((Accoun
|
||||
}
|
||||
openEditingDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { peer, cachedData, canAddAccounts in
|
||||
pushController(editSettingsController(context: context, currentName: .personName(firstName: peer.firstName ?? "", lastName: peer.lastName ?? ""), currentBioText: cachedData.about ?? "", accountManager: context.sharedContext.accountManager, canAddAccounts: canAddAccounts, focusOnItemTag: focusOnItemTag))
|
||||
pushController(editSettingsController(context: context, currentName: .personName(firstName: peer.firstName ?? "", lastName: peer.lastName ?? " "), currentBioText: cachedData.about ?? "", accountManager: context.sharedContext.accountManager, canAddAccounts: canAddAccounts, focusOnItemTag: focusOnItemTag))
|
||||
}))
|
||||
return openEditingDisposable
|
||||
}
|
||||
|
||||
+4
-4
@@ -85,15 +85,15 @@ final class RecentSessionsEmptyStateItemNode: ItemListControllerEmptyStateItemNo
|
||||
let imageSize = self.imageNode.image?.size ?? CGSize()
|
||||
let imageHeight = layout.size.width < layout.size.height ? imageSize.height + imageSpacing : 0.0
|
||||
|
||||
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
let titleSize = self.titleNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
let textSize = self.textNode.measure(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right - 50.0, height: max(1.0, layout.size.height - insets.top - insets.bottom)))
|
||||
|
||||
let totalHeight = imageHeight + titleSize.height + textSpacing + textSize.height
|
||||
let topOffset = insets.top + floor((layout.size.height - insets.top - insets.bottom - totalHeight) / 2.0)
|
||||
|
||||
transition.updateAlpha(node: self.imageNode, alpha: imageHeight > 0.0 ? 1.0 : 0.0)
|
||||
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - imageSize.width) / 2.0), y: topOffset), size: imageSize))
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - titleSize.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right) / 2.0), y: topOffset + imageHeight), size: titleSize))
|
||||
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - textSize.width - layout.safeInsets.left - layout.safeInsets.right - layout.intrinsicInsets.left - layout.intrinsicInsets.right) / 2.0), y: self.titleNode.frame.maxY + textSpacing), size: textSize))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,11 +33,33 @@ import WebSearchUI
|
||||
import PeerAvatarGalleryUI
|
||||
import MapResourceToAvatarSizes
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
|
||||
private let maximumNumberOfAccounts = 3
|
||||
|
||||
private let avatarFont = UIFont(name: ".SFCompactRounded-Semibold", size: 13.0)!
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
weak var sourceNode: ASDisplayNode?
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||
let sourceNode = self.sourceNode
|
||||
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||
if let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private enum SettingsEntryTag: Equatable, ItemListItemTag {
|
||||
case account(AccountRecordId)
|
||||
|
||||
@@ -80,6 +102,7 @@ private struct SettingsItemArguments {
|
||||
let removeAccount: (AccountRecordId) -> Void
|
||||
let keepPhone: () -> Void
|
||||
let openPhoneNumberChange: () -> Void
|
||||
let accountContextAction: (AccountRecordId, ASDisplayNode, ContextGesture?) -> Void
|
||||
}
|
||||
|
||||
private enum SettingsSection: Int32 {
|
||||
@@ -409,6 +432,8 @@ private enum SettingsEntry: ItemListNodeEntry {
|
||||
arguments.setAccountIdWithRevealedOptions(lhsAccountId, rhsAccountId)
|
||||
}, removePeer: { _ in
|
||||
arguments.removeAccount(account.id)
|
||||
}, contextAction: { node, gesture in
|
||||
arguments.accountContextAction(account.id, node, gesture)
|
||||
}, tag: SettingsEntryTag.account(account.id))
|
||||
case let .addAccount(theme, text):
|
||||
return ItemListPeerActionItem(theme: theme, icon: PresentationResourcesItemList.plusIconImage(theme), title: text, alwaysPlain: false, sectionId: self.section, height: .generic, editing: false, action: {
|
||||
@@ -627,6 +652,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var presentInGlobalOverlayImpl: ((ViewController, Any?) -> Void)?
|
||||
var dismissInputImpl: (() -> Void)?
|
||||
var setDisplayNavigationBarImpl: ((Bool) -> Void)?
|
||||
var getNavigationControllerImpl: (() -> NavigationController?)?
|
||||
@@ -695,6 +721,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
return cachedFaqInstantPage(context: context)
|
||||
}
|
||||
|
||||
var removeAccountImpl: ((AccountRecordId) -> Void)?
|
||||
var switchToAccountImpl: ((AccountRecordId) -> Void)?
|
||||
|
||||
let displayPhoneNumberConfirmation = ValuePromise<Bool>(false)
|
||||
@@ -873,27 +900,7 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
return state
|
||||
}
|
||||
}, removeAccount: { id in
|
||||
let _ = (contextValue.get()
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)).start(next: { context in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = ActionSheetController(presentationTheme: presentationData.theme)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.Settings_LogoutConfirmationText.trimmingCharacters(in: .whitespacesAndNewlines)))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Settings_Logout, color: .destructive, action: {
|
||||
dismissAction()
|
||||
let _ = logoutFromAccount(id: id, accountManager: context.sharedContext.accountManager, alreadyLoggedOutRemotely: false).start()
|
||||
}))
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})
|
||||
removeAccountImpl?(id)
|
||||
}, keepPhone: {
|
||||
displayPhoneNumberConfirmation.set(false)
|
||||
}, openPhoneNumberChange: {
|
||||
@@ -907,6 +914,37 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
pushControllerImpl?(ChangePhoneNumberIntroController(context: context, phoneNumber: formatPhoneNumber(phoneNumber)))
|
||||
})
|
||||
})
|
||||
}, accountContextAction: { id, node, gesture in
|
||||
var selectedAccount: Account?
|
||||
let _ = (accountsAndPeers.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { accountsAndPeers in
|
||||
for (account, _, _) in accountsAndPeers.1 {
|
||||
if account.id == id {
|
||||
selectedAccount = account
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
var sharedContext: SharedAccountContext?
|
||||
let _ = (contextValue.get()
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)).start(next: { context in
|
||||
sharedContext = context.sharedContext
|
||||
})
|
||||
if let selectedAccount = selectedAccount, let sharedContext = sharedContext {
|
||||
let accountContext = sharedContext.makeTempAccountContext(account: selectedAccount)
|
||||
let chatListController = accountContext.sharedContext.makeChatListController(context: accountContext, groupId: .root, controlsHistoryPreload: false, hideNetworkActivityStatus: true, enableDebugActions: enableDebugActions)
|
||||
|
||||
let presentationData = accountContext.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let contextController = ContextController(account: accountContext.account, theme: presentationData.theme, strings: presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: chatListController, sourceNode: node)), items: accountContextMenuItems(context: accountContext, logout: {
|
||||
removeAccountImpl?(id)
|
||||
}), reactionItems: [], gesture: gesture)
|
||||
presentInGlobalOverlayImpl?(contextController, nil)
|
||||
} else {
|
||||
gesture?.cancel()
|
||||
}
|
||||
})
|
||||
|
||||
changeProfilePhotoImpl = {
|
||||
@@ -1269,6 +1307,9 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
presentControllerImpl = { [weak controller] value, arguments in
|
||||
controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet), blockInteraction: true)
|
||||
}
|
||||
presentInGlobalOverlayImpl = { [weak controller] value, arguments in
|
||||
controller?.presentInGlobalOverlay(value, with: arguments)
|
||||
}
|
||||
dismissInputImpl = { [weak controller] in
|
||||
controller?.view.window?.endEditing(true)
|
||||
}
|
||||
@@ -1357,6 +1398,29 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
}
|
||||
})
|
||||
}
|
||||
removeAccountImpl = { id in
|
||||
let _ = (contextValue.get()
|
||||
|> deliverOnMainQueue
|
||||
|> take(1)).start(next: { context in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let controller = ActionSheetController(presentationTheme: presentationData.theme)
|
||||
let dismissAction: () -> Void = { [weak controller] in
|
||||
controller?.dismissAnimated()
|
||||
}
|
||||
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetTextItem(title: presentationData.strings.Settings_LogoutConfirmationText.trimmingCharacters(in: .whitespacesAndNewlines)))
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Settings_Logout, color: .destructive, action: {
|
||||
dismissAction()
|
||||
let _ = logoutFromAccount(id: id, accountManager: context.sharedContext.accountManager, alreadyLoggedOutRemotely: false).start()
|
||||
}))
|
||||
controller.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
|
||||
])
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})
|
||||
}
|
||||
switchToAccountImpl = { id in
|
||||
let _ = (contextValue.get()
|
||||
|> take(1)
|
||||
@@ -1459,3 +1523,28 @@ public func settingsController(context: AccountContext, accountManager: AccountM
|
||||
return controller
|
||||
}
|
||||
|
||||
private func accountContextMenuItems(context: AccountContext, logout: @escaping () -> Void) -> Signal<[ContextMenuItem], NoError> {
|
||||
let strings = context.sharedContext.currentPresentationData.with({ $0 }).strings
|
||||
return context.account.postbox.transaction { transaction -> [ContextMenuItem] in
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
if !transaction.getUnreadChatListPeerIds(groupId: .root).isEmpty {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAllAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
|
||||
let _ = (context.account.postbox.transaction { transaction in
|
||||
markAllChatsAsReadInteractively(transaction: transaction, viewTracker: context.account.viewTracker, groupId: .root)
|
||||
}
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
f(.default)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Settings_Context_Logout, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Logout"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
logout()
|
||||
f(.default)
|
||||
})))
|
||||
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +219,9 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {})
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
})
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
|
||||
@@ -231,7 +231,7 @@ private enum ThemeAutoNightSettingsControllerEntry: ItemListNodeEntry {
|
||||
return ThemeSettingsThemeItem(context: arguments.context, theme: theme, strings: strings, sectionId: self.section, themes: themes, themeSpecificAccentColors: themeSpecificAccentColors, currentTheme: currentTheme, updatedTheme: { theme in
|
||||
arguments.updateTheme(theme)
|
||||
}, longTapped: { _ in
|
||||
})
|
||||
}, contextAction: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,9 +335,10 @@ func generateThemeName(accentColor: UIColor) -> String {
|
||||
|
||||
if let color = nearest?.color, let colorName = colors[color]?.capitalized {
|
||||
if arc4random() % 2 == 0 {
|
||||
return "\(adjectives[Int(arc4random()) % adjectives.count].capitalized) \(colorName)"
|
||||
|
||||
return "\((adjectives.randomElement() ?? "").capitalized) \(colorName)"
|
||||
} else {
|
||||
return "\(colorName) \(subjectives[Int(arc4random()) % subjectives.count].capitalized)"
|
||||
return "\(colorName) \((subjectives.randomElement() ?? "").capitalized)"
|
||||
}
|
||||
} else {
|
||||
return ""
|
||||
|
||||
@@ -15,6 +15,7 @@ import OverlayStatusController
|
||||
import AppBundle
|
||||
|
||||
public enum ThemePreviewSource {
|
||||
case settings(PresentationThemeReference)
|
||||
case theme(TelegramTheme)
|
||||
case slug(String, TelegramMediaFile)
|
||||
case media(AnyMediaReference)
|
||||
@@ -83,14 +84,21 @@ public final class ThemePreviewController: ViewController {
|
||||
themeName = previewTheme.name.string
|
||||
}
|
||||
|
||||
var isPreview = false
|
||||
if case .settings = source {
|
||||
isPreview = true
|
||||
}
|
||||
|
||||
let titleView = CounterContollerTitleView(theme: self.previewTheme)
|
||||
titleView.title = CounterContollerTitle(title: themeName, counter: " ")
|
||||
titleView.title = CounterContollerTitle(title: themeName, counter: isPreview ? "" : " ")
|
||||
self.navigationItem.titleView = titleView
|
||||
|
||||
self.statusBar.statusBarStyle = self.previewTheme.rootController.statusBarStyle.style
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: self.previewTheme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(self.actionPressed))
|
||||
if !isPreview {
|
||||
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: self.previewTheme.rootController.navigationBar.accentTextColor), style: .plain, target: self, action: #selector(self.actionPressed))
|
||||
}
|
||||
|
||||
self.disposable = (combineLatest(self.theme.get(), self.presentationTheme.get())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] theme, presentationTheme in
|
||||
@@ -134,6 +142,10 @@ public final class ThemePreviewController: ViewController {
|
||||
override public func loadDisplayNode() {
|
||||
super.loadDisplayNode()
|
||||
|
||||
var isPreview = false
|
||||
if case .settings = self.source {
|
||||
isPreview = true
|
||||
}
|
||||
self.displayNode = ThemePreviewControllerNode(context: self.context, previewTheme: self.previewTheme, dismiss: { [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.dismiss()
|
||||
@@ -142,7 +154,7 @@ public final class ThemePreviewController: ViewController {
|
||||
if let strongSelf = self {
|
||||
strongSelf.apply()
|
||||
}
|
||||
})
|
||||
}, isPreview: isPreview)
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
let previewTheme = self.previewTheme
|
||||
@@ -166,6 +178,8 @@ public final class ThemePreviewController: ViewController {
|
||||
let disposable = self.applyDisposable
|
||||
|
||||
switch self.source {
|
||||
case let .settings(reference):
|
||||
theme = .single(reference)
|
||||
case .theme, .slug:
|
||||
theme = combineLatest(self.theme.get() |> take(1), wallpaperPromise.get() |> take(1))
|
||||
|> mapToSignal { theme, wallpaper -> Signal<PresentationThemeReference?, NoError> in
|
||||
@@ -334,6 +348,8 @@ public final class ThemePreviewController: ViewController {
|
||||
let subject: ShareControllerSubject
|
||||
let preferredAction: ShareControllerPreferredAction
|
||||
switch self.source {
|
||||
case let .settings(reference):
|
||||
return
|
||||
case let .theme(theme):
|
||||
subject = .url("https://t.me/addtheme/\(theme.slug)")
|
||||
preferredAction = .default
|
||||
|
||||
@@ -31,6 +31,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private var previewTheme: PresentationTheme
|
||||
private var presentationData: PresentationData
|
||||
private let isPreview: Bool
|
||||
|
||||
public let wallpaperPromise = Promise<TelegramWallpaper>()
|
||||
|
||||
@@ -59,9 +60,10 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private var statusDisposable: Disposable?
|
||||
private var fetchDisposable = MetaDisposable()
|
||||
|
||||
init(context: AccountContext, previewTheme: PresentationTheme, dismiss: @escaping () -> Void, apply: @escaping () -> Void) {
|
||||
init(context: AccountContext, previewTheme: PresentationTheme, dismiss: @escaping () -> Void, apply: @escaping () -> Void, isPreview: Bool) {
|
||||
self.context = context
|
||||
self.previewTheme = previewTheme
|
||||
self.isPreview = isPreview
|
||||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
@@ -83,6 +85,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.chatListBackgroundNode = ASDisplayNode()
|
||||
|
||||
self.chatContainerNode = ASDisplayNode()
|
||||
self.chatContainerNode.clipsToBounds = true
|
||||
self.instantChatBackgroundNode = WallpaperBackgroundNode()
|
||||
self.instantChatBackgroundNode.displaysAsynchronously = false
|
||||
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: previewTheme, wallpaper: previewTheme.chat.defaultWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
|
||||
@@ -94,7 +97,6 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.remoteChatBackgroundNode.view.contentMode = .scaleAspectFill
|
||||
|
||||
self.blurredNode = BlurredImageNode()
|
||||
self.blurredNode.clipsToBounds = true
|
||||
self.blurredNode.blurView.contentMode = .scaleAspectFill
|
||||
|
||||
self.toolbarNode = WallpaperGalleryToolbarNode(theme: self.previewTheme, strings: self.presentationData.strings)
|
||||
@@ -131,9 +133,11 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
self.addSubnode(self.scrollNode)
|
||||
self.chatListBackgroundNode.addSubnode(self.maskNode)
|
||||
self.addSubnode(self.pageControlBackgroundNode)
|
||||
self.addSubnode(self.pageControlNode)
|
||||
self.addSubnode(self.toolbarNode)
|
||||
if !isPreview {
|
||||
self.addSubnode(self.pageControlBackgroundNode)
|
||||
self.addSubnode(self.pageControlNode)
|
||||
self.addSubnode(self.toolbarNode)
|
||||
}
|
||||
|
||||
self.scrollNode.addSubnode(self.chatListBackgroundNode)
|
||||
self.scrollNode.addSubnode(self.chatContainerNode)
|
||||
@@ -307,7 +311,9 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
private func updateChatsLayout(layout: ContainerViewLayout, topInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {})
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _ in }, togglePeerSelected: { _ in }, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
})
|
||||
let chatListPresentationData = ChatListPresentationData(theme: self.previewTheme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true)
|
||||
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
@@ -473,7 +479,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
self.toolbarNode.updateLayout(size: CGSize(width: layout.size.width, height: 49.0), layout: layout, transition: transition)
|
||||
|
||||
self.updateChatsLayout(layout: layout, topInset: navigationBarHeight, transition: transition)
|
||||
self.updateMessagesLayout(layout: layout, bottomInset: toolbarHeight + 66.0, transition: transition)
|
||||
self.updateMessagesLayout(layout: layout, bottomInset: self.isPreview ? 0.0 : (toolbarHeight + 66.0), transition: transition)
|
||||
|
||||
let pageControlSize = self.pageControlNode.measure(CGSize(width: bounds.width, height: 100.0))
|
||||
let pageControlFrame = CGRect(origin: CGPoint(x: floor((bounds.width - pageControlSize.width) / 2.0), y: layout.size.height - toolbarHeight - 42.0), size: pageControlSize)
|
||||
|
||||
@@ -11,6 +11,28 @@ import AlertUI
|
||||
import WallpaperResources
|
||||
import ShareController
|
||||
import AccountContext
|
||||
import ContextUI
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
let controller: ViewController
|
||||
weak var sourceNode: ASDisplayNode?
|
||||
|
||||
init(controller: ViewController, sourceNode: ASDisplayNode?) {
|
||||
self.controller = controller
|
||||
self.sourceNode = sourceNode
|
||||
}
|
||||
|
||||
func transitionInfo() -> ContextControllerTakeControllerInfo? {
|
||||
let sourceNode = self.sourceNode
|
||||
return ContextControllerTakeControllerInfo(contentAreaInScreenSpace: CGRect(origin: CGPoint(), size: CGSize(width: 10.0, height: 10.0)), sourceNode: { [weak sourceNode] in
|
||||
if let sourceNode = sourceNode {
|
||||
return (sourceNode, sourceNode.bounds)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func themeDisplayName(strings: PresentationStrings, reference: PresentationThemeReference) -> String {
|
||||
let name: String
|
||||
@@ -47,8 +69,9 @@ private final class ThemeSettingsControllerArguments {
|
||||
let selectAppIcon: (String) -> Void
|
||||
let presentThemeMenu: (PresentationThemeReference, Bool) -> Void
|
||||
let editTheme: (PresentationCloudTheme) -> Void
|
||||
let contextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void
|
||||
|
||||
init(context: AccountContext, updateTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, PresentationThemeAccentColor?) -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, presentThemeMenu: @escaping (PresentationThemeReference, Bool) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void) {
|
||||
init(context: AccountContext, updateTheme: @escaping (PresentationThemeReference) -> Void, selectFontSize: @escaping (PresentationFontSize) -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, PresentationThemeAccentColor?) -> Void, openAutoNightTheme: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (String) -> Void, presentThemeMenu: @escaping (PresentationThemeReference, Bool) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, contextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void) {
|
||||
self.context = context
|
||||
self.updateTheme = updateTheme
|
||||
self.selectFontSize = selectFontSize
|
||||
@@ -61,6 +84,7 @@ private final class ThemeSettingsControllerArguments {
|
||||
self.selectAppIcon = selectAppIcon
|
||||
self.presentThemeMenu = presentThemeMenu
|
||||
self.editTheme = editTheme
|
||||
self.contextAction = contextAction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +324,9 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry {
|
||||
arguments.updateTheme(theme)
|
||||
}
|
||||
}, longTapped: { theme in
|
||||
arguments.presentThemeMenu(theme, theme.index == currentTheme.index)
|
||||
//arguments.presentThemeMenu(theme, theme.index == currentTheme.index)
|
||||
}, contextAction: { theme, node, gesture in
|
||||
arguments.contextAction(theme.index == currentTheme.index, theme, node, gesture)
|
||||
})
|
||||
case let .iconHeader(theme, text):
|
||||
return ItemListSectionHeaderItem(theme: theme, text: text, sectionId: self.section)
|
||||
@@ -368,6 +394,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData,
|
||||
public func themeSettingsController(context: AccountContext, focusOnItemTag: ThemeSettingsEntryTag? = nil) -> ViewController {
|
||||
var pushControllerImpl: ((ViewController) -> Void)?
|
||||
var presentControllerImpl: ((ViewController, Any?) -> Void)?
|
||||
var presentInGlobalOverlayImpl: ((ViewController, Any?) -> Void)?
|
||||
var getNavigationControllerImpl: (() -> NavigationController?)?
|
||||
|
||||
var updateThemeImpl: ((PresentationThemeReference) -> Void)?
|
||||
@@ -500,6 +527,77 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
}
|
||||
})
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}, contextAction: { isCurrent, reference, node, gesture in
|
||||
let _ = (context.account.postbox.transaction { transaction in
|
||||
return makePresentationTheme(mediaBox: context.sharedContext.accountManager.mediaBox, themeReference: reference, accentColor: nil, serviceBackgroundColor: defaultServiceBackgroundColor, baseColor: .blue)
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { theme in
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let strings = presentationData.strings
|
||||
let themeController = ThemePreviewController(context: context, previewTheme: theme, source: .settings(reference))
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Theme_Context_Apply, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ApplyTheme"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
updateThemeImpl?(reference)
|
||||
})
|
||||
})))
|
||||
|
||||
if case let .cloud(theme) = reference {
|
||||
if theme.theme.isCreator {
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_EditTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Edit"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
let controller = editThemeController(context: context, mode: .edit(theme), navigateToChat: { peerId in
|
||||
if let navigationController = getNavigationControllerImpl?() {
|
||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId)))
|
||||
}
|
||||
})
|
||||
|
||||
c.dismiss(completion: {
|
||||
presentControllerImpl?(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
})
|
||||
})))
|
||||
}
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_ShareTheme, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Share"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
let controller = ShareController(context: context, subject: .url("https://t.me/addtheme/\(theme.theme.slug)"), preferredAction: .default)
|
||||
presentControllerImpl?(controller, nil)
|
||||
})
|
||||
})))
|
||||
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Appearance_RemoveTheme, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
let actionSheet = ActionSheetController(presentationTheme: presentationData.theme)
|
||||
var items: [ActionSheetItem] = []
|
||||
items.append(ActionSheetButtonItem(title: presentationData.strings.Appearance_RemoveThemeConfirmation, color: .destructive, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
let _ = (cloudThemes.get() |> delay(0.5, queue: Queue.mainQueue())
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { themes in
|
||||
if isCurrent, let themeIndex = themes.firstIndex(where: { $0.id == theme.theme.id }) {
|
||||
let newTheme: PresentationThemeReference
|
||||
if themeIndex > 0 {
|
||||
newTheme = .cloud(PresentationCloudTheme(theme: themes[themeIndex - 1], resolvedWallpaper: nil))
|
||||
} else {
|
||||
newTheme = .builtin(.nightAccent)
|
||||
}
|
||||
updateThemeImpl?(newTheme)
|
||||
}
|
||||
|
||||
let _ = deleteThemeInteractively(account: context.account, accountManager: context.sharedContext.accountManager, theme: theme.theme).start()
|
||||
})
|
||||
}))
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
presentControllerImpl?(actionSheet, nil)
|
||||
})
|
||||
})))
|
||||
}
|
||||
|
||||
let contextController = ContextController(account: context.account, theme: presentationData.theme, strings: presentationData.strings, source: .controller(ContextControllerContentSourceImpl(controller: themeController, sourceNode: node)), items: .single(items), reactionItems: [], gesture: gesture)
|
||||
presentInGlobalOverlayImpl?(contextController, nil)
|
||||
})
|
||||
})
|
||||
|
||||
let signal = combineLatest(queue: .mainQueue(), context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.presentationThemeSettings]), cloudThemes.get(), availableAppIcons, currentAppIconName.get())
|
||||
@@ -548,6 +646,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The
|
||||
presentControllerImpl = { [weak controller] c, a in
|
||||
controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
}
|
||||
presentInGlobalOverlayImpl = { [weak controller] c, a in
|
||||
controller?.presentInGlobalOverlay(c, with: a)
|
||||
}
|
||||
getNavigationControllerImpl = { [weak controller] in
|
||||
return controller?.navigationController as? NavigationController
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import ItemListUI
|
||||
import WallpaperResources
|
||||
import AccountContext
|
||||
import AppBundle
|
||||
import ContextUI
|
||||
|
||||
private var borderImages: [String: UIImage] = [:]
|
||||
|
||||
@@ -88,9 +89,10 @@ class ThemeSettingsThemeItem: ListViewItem, ItemListItem {
|
||||
let currentTheme: PresentationThemeReference
|
||||
let updatedTheme: (PresentationThemeReference) -> Void
|
||||
let longTapped: (PresentationThemeReference) -> Void
|
||||
let contextAction: ((PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void)?
|
||||
let tag: ItemListItemTag?
|
||||
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, themes: [PresentationThemeReference], themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], currentTheme: PresentationThemeReference, updatedTheme: @escaping (PresentationThemeReference) -> Void, longTapped: @escaping (PresentationThemeReference) -> Void, tag: ItemListItemTag? = nil) {
|
||||
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, sectionId: ItemListSectionId, themes: [PresentationThemeReference], themeSpecificAccentColors: [Int64: PresentationThemeAccentColor], currentTheme: PresentationThemeReference, updatedTheme: @escaping (PresentationThemeReference) -> Void, longTapped: @escaping (PresentationThemeReference) -> Void, contextAction: ((PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void)?, tag: ItemListItemTag? = nil) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.strings = strings
|
||||
@@ -99,6 +101,7 @@ class ThemeSettingsThemeItem: ListViewItem, ItemListItem {
|
||||
self.currentTheme = currentTheme
|
||||
self.updatedTheme = updatedTheme
|
||||
self.longTapped = longTapped
|
||||
self.contextAction = contextAction
|
||||
self.tag = tag
|
||||
self.sectionId = sectionId
|
||||
}
|
||||
@@ -138,11 +141,13 @@ class ThemeSettingsThemeItem: ListViewItem, ItemListItem {
|
||||
}
|
||||
|
||||
private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
|
||||
private let containerNode: ContextControllerSourceNode
|
||||
private let imageNode: TransformImageNode
|
||||
private let overlayNode: ASImageNode
|
||||
private let textNode: ASTextNode
|
||||
private var action: (() -> Void)?
|
||||
private var longTapAction: (() -> Void)?
|
||||
private var contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||
|
||||
private var theme: PresentationThemeReference?
|
||||
private var currentTheme: PresentationTheme?
|
||||
@@ -151,6 +156,8 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
|
||||
private var selected: Bool?
|
||||
|
||||
override init() {
|
||||
self.containerNode = ContextControllerSourceNode()
|
||||
|
||||
self.imageNode = TransformImageNode()
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: 98.0, height: 62.0))
|
||||
self.imageNode.isLayerBacked = true
|
||||
@@ -165,12 +172,21 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.imageNode)
|
||||
self.addSubnode(self.overlayNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.containerNode)
|
||||
self.containerNode.addSubnode(self.imageNode)
|
||||
self.containerNode.addSubnode(self.overlayNode)
|
||||
self.containerNode.addSubnode(self.textNode)
|
||||
|
||||
self.containerNode.activated = { [weak self] gesture in
|
||||
guard let strongSelf = self else {
|
||||
gesture.cancel()
|
||||
return
|
||||
}
|
||||
strongSelf.contextAction?(strongSelf.containerNode, gesture)
|
||||
}
|
||||
}
|
||||
|
||||
func setup(context: AccountContext, theme: PresentationThemeReference, accentColor: UIColor?, currentTheme: PresentationTheme, title: NSAttributedString, bordered: Bool, selected: Bool, action: @escaping () -> Void, longTapAction: @escaping () -> Void) {
|
||||
func setup(context: AccountContext, theme: PresentationThemeReference, accentColor: UIColor?, currentTheme: PresentationTheme, title: NSAttributedString, bordered: Bool, selected: Bool, action: @escaping () -> Void, longTapAction: @escaping () -> Void, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) {
|
||||
let updatedTheme = self.currentTheme == nil || currentTheme !== self.currentTheme!
|
||||
if case let .cloud(theme) = theme, theme.theme.file == nil {
|
||||
if updatedTheme || accentColor != self.accentColor {
|
||||
@@ -198,6 +214,8 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
|
||||
self.longTapAction = {
|
||||
longTapAction()
|
||||
}
|
||||
self.contextAction = contextAction
|
||||
self.containerNode.isGestureEnabled = !selected
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
@@ -234,6 +252,8 @@ private final class ThemeSettingsThemeItemIconNode : ASDisplayNode {
|
||||
|
||||
let bounds = self.bounds
|
||||
|
||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: bounds.size)
|
||||
|
||||
let imageSize = CGSize(width: 98.0, height: 62.0)
|
||||
self.imageNode.frame = CGRect(origin: CGPoint(x: 10.0, y: 14.0), size: imageSize)
|
||||
let makeLayout = self.imageNode.asyncLayout()
|
||||
@@ -381,6 +401,11 @@ class ThemeSettingsThemeItemNode: ListViewItemNode, ItemListItemNode {
|
||||
}
|
||||
}, longTapAction: {
|
||||
item.longTapped(theme)
|
||||
}, contextAction: item.contextAction.flatMap {
|
||||
contextAction in
|
||||
return { node, gesture in
|
||||
contextAction(theme, node, gesture)
|
||||
}
|
||||
})
|
||||
|
||||
imageNode.frame = CGRect(origin: CGPoint(x: nodeOffset, y: 0.0), size: nodeSize)
|
||||
|
||||
@@ -5,6 +5,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[570911930] = { return $0.readInt64() }
|
||||
dict[571523412] = { return $0.readDouble() }
|
||||
dict[-1255641564] = { return parseString($0) }
|
||||
dict[-475111160] = { return Api.MessageReactionsList.parse_messageReactionsList($0) }
|
||||
dict[-1240849242] = { return Api.messages.StickerSet.parse_stickerSet($0) }
|
||||
dict[-457104426] = { return Api.InputGeoPoint.parse_inputGeoPointEmpty($0) }
|
||||
dict[-206066487] = { return Api.InputGeoPoint.parse_inputGeoPoint($0) }
|
||||
@@ -240,6 +241,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[967122427] = { return Api.Update.parse_updateNewScheduledMessage($0) }
|
||||
dict[-1870238482] = { return Api.Update.parse_updateDeleteScheduledMessages($0) }
|
||||
dict[-2112423005] = { return Api.Update.parse_updateTheme($0) }
|
||||
dict[357013699] = { return Api.Update.parse_updateMessageReactions($0) }
|
||||
dict[1558266229] = { return Api.PopularContact.parse_popularContact($0) }
|
||||
dict[-373643672] = { return Api.FolderPeer.parse_folderPeer($0) }
|
||||
dict[367766557] = { return Api.ChannelParticipant.parse_channelParticipant($0) }
|
||||
@@ -281,6 +283,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) }
|
||||
dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) }
|
||||
dict[1158290442] = { return Api.messages.FoundGifs.parse_foundGifs($0) }
|
||||
dict[-1199954735] = { return Api.MessageReactions.parse_messageReactions($0) }
|
||||
dict[-1132476723] = { return Api.FileLocation.parse_fileLocationToBeDeprecated($0) }
|
||||
dict[-716006138] = { return Api.Poll.parse_poll($0) }
|
||||
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
|
||||
@@ -558,7 +561,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1820043071] = { return Api.User.parse_user($0) }
|
||||
dict[-2082087340] = { return Api.Message.parse_messageEmpty($0) }
|
||||
dict[-1642487306] = { return Api.Message.parse_messageService($0) }
|
||||
dict[1160515173] = { return Api.Message.parse_message($0) }
|
||||
dict[-1752573244] = { return Api.Message.parse_message($0) }
|
||||
dict[186120336] = { return Api.messages.RecentStickers.parse_recentStickersNotModified($0) }
|
||||
dict[586395571] = { return Api.messages.RecentStickers.parse_recentStickers($0) }
|
||||
dict[-182231723] = { return Api.InputFileLocation.parse_inputEncryptedFileLocation($0) }
|
||||
@@ -612,6 +615,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) }
|
||||
dict[-332168592] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) }
|
||||
dict[398898678] = { return Api.help.Support.parse_support($0) }
|
||||
dict[1873957073] = { return Api.ReactionCount.parse_reactionCount($0) }
|
||||
dict[1474492012] = { return Api.MessagesFilter.parse_inputMessagesFilterEmpty($0) }
|
||||
dict[-1777752804] = { return Api.MessagesFilter.parse_inputMessagesFilterPhotos($0) }
|
||||
dict[-1614803355] = { return Api.MessagesFilter.parse_inputMessagesFilterVideo($0) }
|
||||
@@ -638,6 +642,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) }
|
||||
dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) }
|
||||
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
|
||||
dict[-764945220] = { return Api.MessageUserReaction.parse_messageUserReaction($0) }
|
||||
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
|
||||
dict[982505656] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
|
||||
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
|
||||
@@ -837,6 +842,8 @@ public struct Api {
|
||||
|
||||
public static func serializeObject(_ object: Any, buffer: Buffer, boxed: Swift.Bool) {
|
||||
switch object {
|
||||
case let _1 as Api.MessageReactionsList:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.StickerSet:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputGeoPoint:
|
||||
@@ -969,6 +976,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.FoundGifs:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessageReactions:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.FileLocation:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.Poll:
|
||||
@@ -1257,6 +1266,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.Support:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.ReactionCount:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessagesFilter:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.messages.Dialogs:
|
||||
@@ -1267,6 +1278,8 @@ public struct Api {
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.help.InviteText:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.MessageUserReaction:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.BotInlineMessage:
|
||||
_1.serialize(buffer, boxed)
|
||||
case let _1 as Api.InputPeerNotifySettings:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user