From fafaa4e37dd71cbe9d7bacd346e57b58fc209938 Mon Sep 17 00:00:00 2001 From: overtake <> Date: Fri, 7 Feb 2020 18:53:40 +0400 Subject: [PATCH] - bugfixes and improvements - memoryleak bugfix --- Telegram-Mac/Appearance.swift | 13 +- Telegram-Mac/ApplicationContext.swift | 10 +- .../ApplicationSpecificPreferencesKeys.swift | 2 +- .../Icon_FilterAdd.imageset/Contents.json | 22 + .../Icon_FilterAdd.imageset/ic_add.png | Bin 0 -> 243 bytes .../Icon_FilterAdd.imageset/ic_add@2x.png | Bin 0 -> 390 bytes .../Icon_FilterBots.imageset/Contents.json | 22 + .../Icon_FilterBots.imageset/ic_bot.png | Bin 0 -> 546 bytes .../Icon_FilterBots.imageset/ic_bot@2x.png | Bin 0 -> 979 bytes .../Contents.json | 22 + .../ic_channel.png | Bin 0 -> 495 bytes .../ic_channel@2x.png | Bin 0 -> 906 bytes .../Icon_FilterCustom.imageset/Contents.json | 22 + .../ic_customlist.png | Bin 0 -> 217 bytes .../ic_customlist@2x.png | Bin 0 -> 320 bytes .../Icon_FilterGroups.imageset/Contents.json | 22 + .../Icon_FilterGroups.imageset/ic_group.png | Bin 0 -> 540 bytes .../ic_group@2x.png | Bin 0 -> 1161 bytes .../Icon_FilterMuted.imageset/Contents.json | 22 + .../Icon_FilterMuted.imageset/ic_muted.png | Bin 0 -> 549 bytes .../Icon_FilterMuted.imageset/ic_muted@2x.png | Bin 0 -> 936 bytes .../Contents.json | 22 + .../ic_user.png | Bin 0 -> 416 bytes .../ic_user@2x.png | Bin 0 -> 790 bytes .../Icon_FilterRead.imageset/Contents.json | 22 + .../Icon_FilterRead.imageset/ic_read.png | Bin 0 -> 516 bytes .../Icon_FilterRead.imageset/ic_read@2x.png | Bin 0 -> 976 bytes .../Contents.json | 22 + .../ic_secretchat.png | Bin 0 -> 534 bytes .../ic_secretchat@2x.png | Bin 0 -> 1043 bytes .../Icon_FilterUnmuted.imageset/Contents.json | 22 + .../ic_unmuted.png | Bin 0 -> 485 bytes .../ic_unmuted@2x.png | Bin 0 -> 842 bytes .../Icon_FilterUnread.imageset/Contents.json | 22 + .../Icon_FilterUnread.imageset/ic_unread.png | Bin 0 -> 495 bytes .../ic_unread@2x.png | Bin 0 -> 967 bytes .../Icon_TabChatList.imageset/Contents.json | 4 +- .../Icon_TabChatList.imageset/ic_chats.png | Bin 0 -> 730 bytes .../Icon_TabChatList.imageset/ic_chats@2x.png | Bin 0 -> 1435 bytes .../ic_chats_1@1x.png | Bin 1047 -> 0 bytes .../ic_chats_1@2x.png | Bin 2458 -> 0 bytes .../Contents.json | 4 +- .../ic_chats.png | Bin 0 -> 730 bytes .../ic_chats@2x.png | Bin 0 -> 1435 bytes .../ic_chats_2@1x.png | Bin 889 -> 0 bytes .../ic_chats_2@2x.png | Bin 1835 -> 0 bytes .../Icon_TabContacts.imageset/Contents.json | 4 +- .../Icon_TabContacts.imageset/ic_contacts.png | Bin 0 -> 729 bytes .../ic_contacts@2x.png | Bin 0 -> 1374 bytes .../ic_contacts_1@1x.png | Bin 1207 -> 0 bytes .../ic_contacts_1@2x.png | Bin 2809 -> 0 bytes .../Contents.json | 4 +- .../ic_contacts.png | Bin 0 -> 729 bytes .../ic_contacts@2x.png | Bin 0 -> 1374 bytes .../ic_contacts_2@1x.png | Bin 994 -> 0 bytes .../ic_contacts_2@2x.png | Bin 2114 -> 0 bytes .../Contents.json | 4 +- .../Icon_TabRecentCalls.imageset/ic_calls.png | Bin 0 -> 557 bytes .../ic_calls@2x.png | Bin 0 -> 1035 bytes .../ic_calls_1@1x.png | Bin 948 -> 0 bytes .../ic_calls_1@2x.png | Bin 2177 -> 0 bytes .../Contents.json | 4 +- .../ic_calls.png | Bin 0 -> 557 bytes .../ic_calls@2x.png | Bin 0 -> 1035 bytes .../ic_calls_2@1x.png | Bin 720 -> 0 bytes .../ic_calls_2@2x.png | Bin 1439 -> 0 bytes .../Icon_TabSettings.imageset/Contents.json | 4 +- .../Icon_TabSettings.imageset/ic_settings.png | Bin 0 -> 852 bytes .../ic_settings@2x.png | Bin 0 -> 2028 bytes .../ic_settings_1@1x.png | Bin 1076 -> 0 bytes .../ic_settings_1@2x.png | Bin 2448 -> 0 bytes .../Contents.json | 4 +- .../ic_settings.png | Bin 0 -> 852 bytes .../ic_settings@2x.png | Bin 0 -> 2028 bytes .../ic_settings_2@1x.png | Bin 1239 -> 0 bytes .../ic_settings_2@2x.png | Bin 2850 -> 0 bytes Telegram-Mac/ChatController.swift | 2 +- Telegram-Mac/ChatHistoryEntry.swift | 2 +- Telegram-Mac/ChatInterfaceInteraction.swift | 31 +- Telegram-Mac/ChatListController.swift | 339 +++++++---- Telegram-Mac/ChatListEmptyRowItem.swift | 70 ++- Telegram-Mac/ChatListFilterPreferences.swift | 301 ++++++++-- Telegram-Mac/ChatListPresetController.swift | 60 +- .../ChatListPresetListController.swift | 65 ++- Telegram-Mac/ChatListRevealItem.swift | 165 ++++-- Telegram-Mac/ChatSelectText.swift | 13 +- Telegram-Mac/GeneralRowItem.swift | 5 - Telegram-Mac/GlobalBadgeNode.swift | 345 +++++------ Telegram-Mac/Info.plist | 2 +- Telegram-Mac/InstantPageMedia.swift | 2 +- Telegram-Mac/Localizable.swift | 42 +- Telegram-Mac/LottiePlayer.swift | 2 +- Telegram-Mac/MainViewController.swift | 4 +- Telegram-Mac/PeersListController.swift | 105 ++-- .../PreparedChatHistoryViewTransition.swift | 1 + Telegram-Mac/SImageView.swift | 4 + Telegram-Mac/SearchController.swift | 4 +- Telegram-Mac/Spotlight.swift | 1 + Telegram-Mac/TelegramIconsTheme.swift | 178 +++++- Telegram-Mac/WalletBalanceItem.swift | 2 +- Telegram-Mac/WalletInfoCreatedItem.swift | 2 +- Telegram-Mac/WalletInfoTransactionItem.swift | 4 +- .../WalletProcessTransactionController.swift | 8 +- Telegram-Mac/WalletSendController.swift | 2 +- Telegram-Mac/WalletSendProccessingView.swift | 6 +- Telegram-Mac/WalletSplashController.swift | 8 +- Telegram-Mac/WalletSplashHelps.swift | 43 +- Telegram-Mac/WalletSplashRowItem.swift | 4 +- Telegram-Mac/WalletTransactionTextItem.swift | 2 +- Telegram-Mac/en.lproj/Localizable.strings | Bin 356484 -> 358042 bytes .../{wallet => tgs}/brilliant_loading.tgs | Bin .../{wallet => tgs}/brilliant_static.tgs | Bin Telegram-Mac/{wallet => tgs}/chiken_born.tgs | Bin Telegram-Mac/{wallet => tgs}/fly_dollar.tgs | Bin Telegram-Mac/{wallet => tgs}/gift.tgs | Bin .../{wallet => tgs}/keyboard_typing.tgs | Bin Telegram-Mac/{wallet => tgs}/keychain.tgs | Bin Telegram-Mac/{wallet => tgs}/monkey_see.tgs | Bin Telegram-Mac/{wallet => tgs}/monkey_unsee.tgs | Bin Telegram-Mac/{wallet => tgs}/sad_man.tgs | Bin Telegram-Mac/{wallet => tgs}/smart_guy.tgs | Bin Telegram-Mac/{wallet => tgs}/swap_money.tgs | Bin Telegram-Mac/tgs/think_spectacular.tgs | Bin 0 -> 6752 bytes .../wallet_success_created.tgs | Bin Telegram-Mac/{wallet => tgs}/write_words.tgs | Bin Telegram.xcodeproj/project.pbxproj | 16 +- TelegramShare/Info.plist | 2 +- .../TGUIKit/TGUIKit.xcodeproj/project.pbxproj | 16 + submodules/TGUIKit/TGUIKit/Control.swift | 22 +- submodules/TGUIKit/TGUIKit/Extensions.swift | 5 + .../TGUIKit/TGUIKit}/MergeLists.swift | 0 .../TGUIKit/TGUIKit/SPopoverRowItem.swift | 17 +- .../TGUIKit/SPopoverViewController.swift | 9 +- .../TGUIKit/ScrollableSegmentController.swift | 13 + .../TGUIKit/ScrollableSegmentView.swift | 542 ++++++++++++++++++ submodules/TGUIKit/TGUIKit/TGClipView.swift | 7 +- .../TGUIKit/TGUIKit/TableStickView.swift | 4 + submodules/TGUIKit/TGUIKit/TableView.swift | 35 +- submodules/TGUIKit/TGUIKit/TextView.swift | 27 +- submodules/telegram-ios | 2 +- tools/generate-images.swift | 12 + 141 files changed, 2216 insertions(+), 636 deletions(-) create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/ic_bot.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/ic_bot@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/ic_channel.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/ic_channel@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterMuted.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterMuted.imageset/ic_muted.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterMuted.imageset/ic_muted@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterSecretChats.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterSecretChats.imageset/ic_secretchat.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterSecretChats.imageset/ic_secretchat@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnmuted.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnmuted.imageset/ic_unmuted.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnmuted.imageset/ic_unmuted@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/Contents.json create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats_1@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats_1@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats_2@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats_2@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls_1@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls_1@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls_2@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls_2@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings_1@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings_1@2x.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings.png create mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings@2x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings_2@1x.png delete mode 100644 Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings_2@2x.png rename Telegram-Mac/{wallet => tgs}/brilliant_loading.tgs (100%) rename Telegram-Mac/{wallet => tgs}/brilliant_static.tgs (100%) rename Telegram-Mac/{wallet => tgs}/chiken_born.tgs (100%) rename Telegram-Mac/{wallet => tgs}/fly_dollar.tgs (100%) rename Telegram-Mac/{wallet => tgs}/gift.tgs (100%) rename Telegram-Mac/{wallet => tgs}/keyboard_typing.tgs (100%) rename Telegram-Mac/{wallet => tgs}/keychain.tgs (100%) rename Telegram-Mac/{wallet => tgs}/monkey_see.tgs (100%) rename Telegram-Mac/{wallet => tgs}/monkey_unsee.tgs (100%) rename Telegram-Mac/{wallet => tgs}/sad_man.tgs (100%) rename Telegram-Mac/{wallet => tgs}/smart_guy.tgs (100%) rename Telegram-Mac/{wallet => tgs}/swap_money.tgs (100%) create mode 100644 Telegram-Mac/tgs/think_spectacular.tgs rename Telegram-Mac/{wallet => tgs}/wallet_success_created.tgs (100%) rename Telegram-Mac/{wallet => tgs}/write_words.tgs (100%) rename {Telegram-Mac => submodules/TGUIKit/TGUIKit}/MergeLists.swift (100%) create mode 100644 submodules/TGUIKit/TGUIKit/ScrollableSegmentController.swift create mode 100644 submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift diff --git a/Telegram-Mac/Appearance.swift b/Telegram-Mac/Appearance.swift index 63d632023..279127510 100644 --- a/Telegram-Mac/Appearance.swift +++ b/Telegram-Mac/Appearance.swift @@ -2018,7 +2018,18 @@ private func generateIcons(from palette: ColorPalette, bubbled: Bool) -> Telegra poll_selected_incorrect_incoming: { generatePollIcon(NSImage(named: "Icon_PollSelectedIncorrect")!, backgound: palette.redBubble_incoming) }, poll_selected_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelected")!, backgound: palette.webPreviewActivityBubble_outgoing) }, poll_selected_correct_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelected")!, backgound: palette.greenBubble_outgoing) }, - poll_selected_incorrect_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelectedIncorrect")!, backgound: palette.redBubble_outgoing) } + poll_selected_incorrect_outgoing: { generatePollIcon(NSImage(named: "Icon_PollSelectedIncorrect")!, backgound: palette.redBubble_outgoing) }, + chat_filter_add: { NSImage(named: "Icon_FilterAdd")!.precomposed(palette.accentIcon) }, + chat_filter_bots: { NSImage(named: "Icon_FilterBots")!.precomposed(palette.accentIcon) }, + chat_filter_channels: { NSImage(named: "Icon_FilterChannels")!.precomposed(palette.accentIcon) }, + chat_filter_custom: { NSImage(named: "Icon_FilterCustom")!.precomposed(palette.accentIcon) }, + chat_filter_groups: { NSImage(named: "Icon_FilterGroups")!.precomposed(palette.accentIcon) }, + chat_filter_muted: { NSImage(named: "Icon_FilterMuted")!.precomposed(palette.accentIcon) }, + chat_filter_private_chats: { NSImage(named: "Icon_FilterPrivateChats")!.precomposed(palette.accentIcon) }, + chat_filter_read: { NSImage(named: "Icon_FilterRead")!.precomposed(palette.accentIcon) }, + chat_filter_secret_chats: { NSImage(named: "Icon_FilterSecretChats")!.precomposed(palette.accentIcon) }, + chat_filter_unmuted: { NSImage(named: "Icon_FilterUnmuted")!.precomposed(palette.accentIcon) }, + chat_filter_unread: { NSImage(named: "Icon_FilterUnread")!.precomposed(palette.accentIcon) } ) } diff --git a/Telegram-Mac/ApplicationContext.swift b/Telegram-Mac/ApplicationContext.swift index 74d12bb9d..e51d62dbd 100644 --- a/Telegram-Mac/ApplicationContext.swift +++ b/Telegram-Mac/ApplicationContext.swift @@ -350,15 +350,7 @@ final class AuthorizedApplicationContext: NSObject, SplitViewDelegate { let applyChatPreset:(Int?)->Void = { atIndex in - if let index = atIndex { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withSelectedAtIndex(index) - }).start() - } else { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withUpdatedCurrentPreset(nil) - }).start() - } + } diff --git a/Telegram-Mac/ApplicationSpecificPreferencesKeys.swift b/Telegram-Mac/ApplicationSpecificPreferencesKeys.swift index cc6af8e2b..8261b0664 100644 --- a/Telegram-Mac/ApplicationSpecificPreferencesKeys.swift +++ b/Telegram-Mac/ApplicationSpecificPreferencesKeys.swift @@ -30,7 +30,7 @@ private enum ApplicationSpecificPreferencesKeyValues: Int32 { case walletPasscodeTimeout = 37 case passcodeSettings = 38 case appConfiguration = 39 - case chatListSettings = 46 + case chatListSettings = 47 } struct ApplicationSpecificPreferencesKeys { diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/Contents.json new file mode 100644 index 000000000..32fa579a1 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_add.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_add@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add.png b/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add.png new file mode 100644 index 0000000000000000000000000000000000000000..d1421de1828f214777d85bff86f9ce4b55732a30 GIT binary patch literal 243 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{?Gzopr0Kuj{`2YX_ literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterAdd.imageset/ic_add@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..fd6fdb33fb576998beaea0b2a1a72a6731ebc11d GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|u)CkWs zUtb0-Ae)1Mu|1Q41;}CqVksbIU|?Fn1Q#(_z>HvnB!B$(GXqjTJzX3_GFabEd&qgn zfv0u#j;`VtGP`;%Tew@dAHKo8x4FUI=a!xKNA4G`llGmieb4pMiit^}fq~`U%ma=U z6_@vg{!Nd(e`v4DrSG@4nC9(N=@Yu@`Q^=)+IMpL{!`f_?!`JZGP5XndKWl!nJe@$ zGkRPSl9}*`x8tz`!=x=LM!nls8d;x@@p^v!R&D&Xh0iWN4dn`-ne;a#bMjOD`uOEH z?$$FeZ^x?j$8l$ literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/Contents.json new file mode 100644 index 000000000..501805ac2 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_bot.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_bot@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/ic_bot.png b/Telegram-Mac/Assets.xcassets/Icon_FilterBots.imageset/ic_bot.png new file mode 100644 index 0000000000000000000000000000000000000000..1531619419826085be8d399fa77ae882aea35e36 GIT binary patch literal 546 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_ods;7%%hzIY}skZto zfg)|~8@hTsSXys5z1HUHRM5Kp;)+-2k^Bh(8GqP%gI4@tp5*H?;ld9smqimMESRvO zhUL8Vxtw=>yEkuNaLc^%*_k=N=M{gyxASJ_qN>Y0++qi_xXS)Xq@Ud{9CckFVa^d_ zwq}FGf3=S!We&`Hx<@g)Nl)vVLv#`I@(+xY!t7Y~Zs6tqz;N)?!;r(;66aT3nql*4 zm0E-bkz*W%SX=ZOk0E&g z#}qd&n(}Y!zL;HVdS7CHdFC~#MSPK5_2fxtZ`RetI^SnxJ&=%d)PE;i_KUgReRuYE<+1rWcu(E-z-Zs<+Lwnn z@vI8v|JwC*ox;h#nSZ`>-qF3aVSZhH;Ax(_i&DHpW`Ege_OHNW7fa>;0@tv4LMxt4 zzmxomkMF|*FVdQ&MBb@048T+NacnHKH|zl4QM(3cou;aC-$lImL_ zchISRaKP2b#u`QSdY2V^W0uDsh2we4j{AGA$38G zp9AnyR@cvSd(9MIbrL2!gof>|gZHiauAH31tgfHu_P*&1l{s%ue@^8Cmt8cqR6K&I(k)LJcouv%~q|0f+h#tFkt1D5W3Ab^f zNm|(?Xdn6}>^`ox$_~mK4^N~Cr=qu;dN?J}FKe&%!3m#Kd?lO|rd%Ixsf^*ez?jf{ zCR7%ifFD#U$A5@n2~ovZ-tlAbV_Q_p*+$C`sUTxFfr5+Kh^l)7jh3xoP;3`^A^!QG zfsf4%ip9S}JArE()%Dz_85>Wf6PrL^t$RWbe9TJx!~AKV6B zx>uF_=*jv49wA_>>^ BsV)Ej literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/Contents.json new file mode 100644 index 000000000..2595db3b7 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_channel.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_channel@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/ic_channel.png b/Telegram-Mac/Assets.xcassets/Icon_FilterChannels.imageset/ic_channel.png new file mode 100644 index 0000000000000000000000000000000000000000..36e6cf8395b46d62597e7ba55d8d10d33c7d4418 GIT binary patch literal 495 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_ny$_VW6d%0lLRHxln?HyY3{wgn7%%|7K7gZqG&i81+g}$z4y`VQb zT}?l}{dHvW-0^H(M3=Mtj|twN?i5eotuoKN!)}ekM8kCjT_@xE%-uHH)+EdK-*EL; z@)bS%OEPl*BSH7hBLz>+yiIA{qNcW?L(1xy$8qa<+Yi{D%@aH5;+DDop+t0rYZ8m> zW6xB*80Gem7tgHU3Vqrj#{ae3#PqZO8<%yr{O5dkI9=4fYVR`J!&_W}OR6`Om!3A@ zy|Cc5(XzW(>KGgz#S8gwP8Zd9g+HBD^iy3$= znEzVcyAYZY`Q@wKk1N->o3qCHmVA0F_;<$N7{SK!64u9=) TS-z+=fNS%G|u)CkWs zUtb0-Ae)1Mu|1Q41;}CqVksbIU|?Fn1Q#(_z>HvnB!B$(GXpC5>*?YclEM0RhINLh zqexqR%@J{p4vi%NK^?8VKb*Lk9R;|xw{{-gDxeb4(XV$SLZhQYAxb0Zf*ZHDqe#e> z4yAnt5lcKB0z_IARwRgg{XN;zAjWL>=AAcRvpj3BKRYYmvb zAGogdM?WXwfpq~-RG9OV*f-M;DNUKxxageJ?cXbYFgwebNwZc7wdF}HWzyK(^5lK68ZTsC70M{~dwpb2P$I+9U3{Dl z)+hL`ub$>>a_;o<2@G38Z#6D9l^1nlig;FO^WJ&e8`UArpLv_P_eT(~7pKaOu zTI8hRyOnQZGY+jS3a^&F+8q02&;7WQw=-S{eR8hxOcY;p`1QJnGM{E%_RVp$%wv7x zw_@oI>3xltn^v+UFuy*1O5u5aw4(FA<$0=aT9`M8-)rzyPLa;760o|kx%hPH7KW8G zXTOz}Huh!2l;IM0x)$$QN%ktr(w8?4C{pWJd7oRWtar5qO(Utu3 z^uqI2UZ`AyRKJP)TD3z3Mi-&%bC8(zWA4A!Lilv-PViz{gUT*;^E=G zXM1j?Ol~dH`YLnd@1$S1Hh)%z;uPN3P-MESfX3h^Vf4$@@f5_!|_@%aw*ReD4cTU Zfc=H(k0aXm=1&J@2v1i(mvv4FO#mF#km~>d literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/Contents.json new file mode 100644 index 000000000..15fc6bb37 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_customlist.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_customlist@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist.png b/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist.png new file mode 100644 index 0000000000000000000000000000000000000000..635068a6abe9be7da31d87ea0bfa37aca1d6d428 GIT binary patch literal 217 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{?H;c)B=-c&4ml(3QOxjBMB!O;m*65hM$sn>ANglEsYx*R{_8&`|MZd`i<|PyvPA0) lAGzKqj>4jg`6LerFfg3F$Ire^{M#Oo`JS$RF6*2UngA-7G9~~3 literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterCustom.imageset/ic_customlist@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..430b2793e6a5d9ed69488a77bd84db04eb75bd6f GIT binary patch literal 320 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|u)CkWs zUtb0-Ae)1Mu|1Q41;}CqVksbIU|?Fn1Q#(_z>HvnB!B$(GXqkaJzX3_GFabEy~x>M zz{9$FM~A%M0};JP0eX)_&OK<)=J>@V+NHpuxuT-+!ZkC)d7AnxJWK)&3@i!^j2wTa zI}|>?Y&}=<(ayNX6WxLWZA`W6rpo``>3%x*{f;f4ik>S= zU+uM8n|n#j%lXZBvrpmM1ELIyIUE?6DmfP%dDJOXJ&Q~A+XZDYpbZWVomW{jHa=Hd ka73=^h!X?U(#CeqH=C~JtjvCO{1eCzopr0ACekO#lD@ literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/Contents.json new file mode 100644 index 000000000..152058a20 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_group.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_group@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group.png b/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group.png new file mode 100644 index 0000000000000000000000000000000000000000..60dec9ec122d20345159c7d3bc480fb9714a063c GIT binary patch literal 540 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_pI-_yl0#Dn+k6kBb# zM2X|_lN?3T*d%pMB~0d5Pz};CYo4ONpoVcW&pox&4HFJ3bWNEgv?xcZ+f`Gji*djF z^DCc=`ku=i{qpDa_dDOe7TrHzyY97}`ee$*_!~boYtyJTj*WB|pz8vpc>=KtK!}d_7Z=uYxgOi_o&)>-8 zIyIqVjq41aP5Ki43spA+^Ul-i&BPYU>8yLNIi_coXc!f9Su$7I&npd4UhuL=|uwP4HSe3vy?;+>81K*wJ zycRD$qZ^;~p1?jUNxDxf_VNC|u>IC$)u}tzowR%-!Y93jOPjH_=kJ5^Wo(m9#r%Hp%cp|(?~c39 z+9~(fIOlk8XP-X7W!lN^f|R0fX}1Eij$1OZ_I7(6`_A#XKuB1B=l`8d^Ut1+WD$CQ Q8x)BQp00i_>zopr0Aruk5dZ)H literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterGroups.imageset/ic_group@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..230c153ae1325ab6282fec6ad056b677ec93b7e5 GIT binary patch literal 1161 zcmV;41a|w0P)El zwu!$Yq>eT;!xB@}t6O5UN;xX~AS5Nyo(ZFqEHfO9dOUiaKJ+_Hqkv!39oWB;Aiayq>z*eHYL!2Oj zwW4*Xwznqx2O8638-!5-s!h_2aXNxDM{KUDT<_{;DP0q3AJk&V09XOgBeHcep~0(M z=<@Ae-EuD!ZD$R4sf1!OBh1`~3PO4f^E z@l~SGhs*}SO7Ozk!)B8~I;3Cb^8G4d1Mt&I6}aai`J$jqQOiX;ctz>NKM^$FUu2vG zW`2%1UE~WGFY_BQ7dXuG#L40$C;p(cOXTi<@9GjyxJHkNFU20wKY-*viwr0VI=n@^ zEWQwD?St-h+wsNPMkr(fli}=Petq)9GEE5$@$`9N54;RRkvAe6obJM+Sg-( zUlCV{zGD^tzz)^;TkMs}dqmDmD9~bqt*sV5w~IlTDb*(toL!gFtTQywG`NIMeA72#5wjou?*Ser z!(+?jNVlrp_Bu1wnL}SlGd^u)iABtQ@Uj{nSw`t`@r2mz)miqwGVQLg!lm34hg^Oz z5`6C$neeK(0Nm*!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_odhNp{ThzIZ6DSP!< z0!5A+IXF2Bc%r>?ld#kIAo#ZOs?)2j85yOWC2 zkGXGVm!>~|`{vBG>PeHUpWi9If4B1eTNX!N(Xs{WobFC*uZ$=-WcTrw*ykt0GY(H; z)BVT!US_KIYA(gt{RJmWw+r+J+S z|K}XD?mamYd|GAe<4w*rzK=VqF5AU#oMhITD7TC^bJ0KEr(YLcTrGAa?+{yvNEw&n zjncq}+;)dgDC@RuVT`r7s^ilAtL=pHdhtwVwii3hW1j*!`FbXg>sqwut-E9#SsM2> z<(Szy@f*?04)bLe-&<>RuVqiiqSfZJR~%urUNZj@e@H&hzW%$qeSQ^E#cJ~3Cb%u+ ztCO@lSZcx1ouQHT|0MIuxaj+`j^c?N`<(AqE@VA-khy}@^a;vIS3j3^P6A7v!CBzNNFma*(2NSq3;$j{5Gj4C_nk2=0mILGcMCaWQU6>*TieIGP*rL%k=X~ zJlu5-7kq6*d=myDz|3av#RTbMz&Ngmr2-4gY!)LOM}&(3W;XL>e>sG)sR%H*nqX$J zwPNwcdlX@8A_5HX_*Vuyx$*2{0XHhx>WTovcwi^Dqhc`Or4ej(M1WyDu#?*@F_`c` z4YpAtz%U-zNo}*xy@8wDHAac>UG1yz;Yen8h3slwYsgY1;%a~kM-sa%R3}fx!dJ$+ zgfS6o1i+u7@!{&!LSh~v4z)lJvAA_|j%|{Emm?zV*J(RDsp$Y3_;fqC!R(lbts133 z=7PJ@rYlER2N%@rE#jW4eOMfi(@=w(53G;q@PtI#6?+Gl?5Au0=D?TpqkK0000< KMNUMnLSTXl^_k!R literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/Contents.json new file mode 100644 index 000000000..7cf411fdb --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_user.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_user@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user.png b/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user.png new file mode 100644 index 0000000000000000000000000000000000000000..b319abe040c638aadf56d0dec9bfda9438782115 GIT binary patch literal 416 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_o7*we)^#Dn+kl#PB& zjv}t&NvSBjb6)%_og!rA}j5 z_&}|FZsq%ZiOl?&&W{bZO3oFji zu@6)Xt*!9vwC+zm6SMNw(wn-f=J%A&Z~UbC{!I3+Pq|CxEI9hg)}rz82mj!C`UULo z6~lgBT<}QD?jiHM2X+r`?09i8+S7f9`v*4h0*;M6GcPZ`J}V{m;TGQIoT61-$M*@i32`Tia)m?nFK@mcbZCPo|QuAIsGhg8h2KW6wG rZqaQ2tbR}Bi;0fXYwl(rxB9@`chlnT5sTT{pkVTJ^>bP0l+XkKZo8m2 literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterPrivateChats.imageset/ic_user@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..bb0c4901054d2730e7ea631cf2ac521b189244f6 GIT binary patch literal 790 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|u)CkWs zUtb0-Ae)1Mu|1Q41;}CqVksbIU|?Fn1Q#(_z>HvnB!B$(GXpB=^mK6y$zXju!`3^- zQKap!$AJbnA#TMmr5S!}Kd}cr7gyoB#UUp4k8`z1SyY7NR!>2J)d{ne8XH1|A~$kq zy6F625aj)3_r})f-MZHma;dYCg^A@(O*>!OKtDln%<~G_T zZ<8qD-YPt$jrDu1amyxwsDPKrHhN@OuKEo zp3%RURsMQ-@cZ41g}HMR|L1kE{;2L=AeqEy?H7|j=bvwE`0=fKJ^#lYoBc~* z^1@~N-Lm(d*fDXLvB*EyV|pfE!#TwoHV99dJePC#`%KAXzPSmL_W7}UKTTHc3Urcr z#`tjOg{i9FJl-zcpevJ-+?vVpqxnPR5A7Z7+r#8#OEy+skT_sSlggPi7eA6m~xAN?+VbH$7`*G^vf zxAshVc*Er~vG^Z6YT8Lk#xk444@Ru+e6USAZ)4T2sw3s>=VUGmuwP%e`&#R47sd0Z zeE*(T|GIpA+WwX1YFoIo5AAW7+a_`<&FcXBrog;IHFlzBmpPQZW43>K{M?*fi7nfo z?-HnHjDNEDy!jKGuRK3H9)vF5*XYsz->05)sr3z&t5X^w(0yK`w*>pg{0S50KLRCA MPgg&ebxsLQ0PIv$c>n+a literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/Contents.json new file mode 100644 index 000000000..39a49c5b0 --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_read.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_read@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read.png b/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read.png new file mode 100644 index 0000000000000000000000000000000000000000..76f59b0f6b581810d35dab945c2acaacab2343bf GIT binary patch literal 516 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_pI+|$J|#Dn+k6l-s0 zM}gz#*)tX|31GQ+?bM}HPCBfDEC;=;yBnrP{E*DK;w9Z3!npR*4-H)x?SuUa9AS@` z1zF{P{63r#+2>Pq(ltlshheetX5-@O-P2Y6f4Xjc;USMfb3Bjr$1S^i7AKuc{o?&~ z=jAyYZ#{h|p_Y{HRy}Wz5Kq<5S-+&8?P;;92$vPW#*vCOuGaYifui&llZ2T!HhOx(s7JAV#-_PO==bGGhc)cxmAj)r(m-Y_j{07OowavY176c7`r?*eq`u zHS4U8`31qVzp7VUUHH)OeDUPc-(N3=DtoM*KX+Y~pq@j1NZYG+nS=Kl6gyle`yY~9 zbF49nSLC{gllupu66fQN`9%UmmGQ#ps4V4^>bP0l+XkKA4JQc literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterRead.imageset/ic_read@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..edb935ca519546e8c73e6a2abb767cdf02a90fd9 GIT binary patch literal 976 zcmV;>126oEP)-JRLoRF7G^~eG*Sf5UG@8|^=4~(r?2W` zN9+gR)a&Z1_rCY4`gKpWT8%UrXfn`bpvl1hoPnW$;5Tc|h_EJLZqk&ey4j5xuu1*D z6Yj@Mo9`Z$dRmwgFjNI*WS7K5<+wV2IuJ;1S*sc2LKUQaoBaaVEx%u!?_X*c1-M+D zNkZoD3LQ7-huS;BW8t0aE31iap|%X)6IMG17u9y1p1EP$Se9N&-=2A9v4O1mbHRLH z3pHnZ{<{p+MV?*ZZ&~!Tozgcxs*PpfX5SIjbdqiJ%PO!ML2^K|%+Q%23;8Eq@O-|P z-p+4ge#SAW765wHf)6SUKB+uZpj26wI->XhO5dXL7cmRjF=0p`fKlO*P)N#H0f`6+G>EivnPv5211lo{j6>S?wjV@VxwO^m_lE9~ z4yv!c+1ZpEZW!f}Jx+`45jt~PtMx)H34^T3PAS9g0=;WD{I-q&@D~l@x<}%J^uxj@ zuP?J&M-?(M1aV5>c`*4Z<%lqC9eLZjR={}KN?cV3&%>xts9e?^0D%z1guwGKEfkWa z2mr#b3$gYl*ZB;1Zp%}f0Lsf{n5Co@`0SZn@9A}^zE7Xa0{=+?_;0>l3ue`G;rsNt zWknk{G65eo;Ae73k@G4N+% zJagBTG)XVAJPx;M@I%4KLwc`JDS6p1Bu6#dwu;|Qs-LYi@Ule=ed6f11RmmlMyM{| y1S-vCA??MeA%iEYM9JQqgU7C6)MOwz1AhPx5Ce%zIl5B-0000!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_pI)6>N<#Dn+k6hm(o zLxI-!As75Mh)DlsoYvH_BP%sMSMmA!Py8{ZQ|GQ#h~N+_yQNW{lds&N@anhEreklO zoQX|+*u34^`g7VOAG4Pw|0MWKs;90bhELn zKI<5H2u2uf_UfK&^WjKe(WzoaX$}(tG;^X$D=(Cqc^Hv92$cUM-$Ne6nJzU2 zWSMxdXE3#GRJh;$eZN%U<*9rD-dj_(?)H2aNnUWfCoQxtJGJ-EcHg{~w#2-mRmrZ( zhTmr|`}Je?oP{&WRIk!3{m6xsi)Y>TG3VUc7SZ`o;OZv*Bi<9e-^pJte;}Nw?ytW1IByatay(uA KT-G@yGywoqtlKUC literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterSecretChats.imageset/ic_secretchat@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterSecretChats.imageset/ic_secretchat@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..65ea4cc9a2c86681f35dcd1fbd229ce198934205 GIT binary patch literal 1043 zcmV+u1nm2XP)Gj4q+!?r}?!o^O1pc#NwoV+$n3@^+K3b4+7Ub+emVnDnb9G=K zp=l>ZnYw=#eML4au87~n-xcH;ZD@Vj93-fd?? zxeoaBBY|co7|4swQ?7N>#za#)fE~WQ7TQ6?4AVn-u#7)a`BTtiyNCEj1E7g^EA(Y; zi`1IRDPNl=BS5fdpvC)uHZfG9ZUk<~l0^tS7IByxXrKkqCWcDXb>OD6eC5iyi(bpe zut&G91J?_S_qu-BW1X)8Ew&`UV)%Pk`Wx!Nd9^)Lv}bRViet{;v@6FJO_LaiWh6o! zxZo_lx^hhMtQx&^4PU5i?~8(9TX~8zM#J>bZjGh~ znkK@@2bx%sCP&Ix-`0-LZk8h@0=(?0hkEQ{LGW1*^#n30u8KB4$reN27WnX)M+2=a zn3h-HiA~+}((&a;1vc2?!;*q;G_r#Ixt~sm^NF1oV-`Ew(ALhq7Cb(aGw*kdvX2Ju z#DX~L$6dAn97fnn*&c>{4ZJE|5k0navm`EyyZ*s`lm`-dD%xUa*^IejgDpM|9ITeJ zBKsEG0FLTJ=l|enI)y?R!zWqg7-(B!rV>+XLmXqAfpG@L88}24_ybY^`(a0J2!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_ny!qdeu#Dn+kl)ZW` zjxtBDyK`6xafxzH{J>@<=-;5BDKgLHuy6$nE32*)C%=Nw$B%3#E=o=J`){V?85O_3 z8~b$LlQ(~!*Poj?^UR%`#TQ+V@_q?)!f<2CHS9 z#ozO8v1`hbO>Fw2ThsjdqSv)=SH5iN4W2ZwOmSnA?bgXHVXIAhUrVo>vg7I(pQ#m_ zE@_=ompNhe&&0NB@`sB>67Cgk@|MmQzP#{Vl+$b|)V6wod%jSr^qC12KFhj%fr?J# z8gx`k&QlLQ`iwPrZ(3He{B!O(YbIV;T)w{T`}IwS*U!J_cGuyDrSLfgH9oMkY zwpgw19Z~b)=8aq8{!V|7STN0gf7#!bJ$~W+JrYfNPp;ND7V_^^kIFttZ{k8TeQ%%WvhamQQWhhyLH~?ADI6cS@X5nbo~c~wWq6} J%Q~loCICR-z(@c9 literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterUnmuted.imageset/ic_unmuted@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterUnmuted.imageset/ic_unmuted@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5117cbce30ad9b42557cef0f30394f9e9ec882c3 GIT binary patch literal 842 zcmV-Q1GW5#P)min%CmAPAG08JhYJM8O|mBBGIzOQN8dOf(<}YT%ZL;5d3drwpQV)dE-A^U8N zF36>Zjer4G=W<7kp5%oLc4}M?R;RK{Y$ks^12eV80kgKOtzEHNa3s`S4|ZKM)<(?A zIJp}*92lMiyRP{(6hzG6PMf(K*jd1S(fTe;k&M1o6b!_etG`wJnY)241^&m1JgGEe z7&DbS75ncu@L_5s^&Q6O>kA5ZgQ%1%~&*&NYp}x5J2C z2`^^@`vUS}uyf6b5wR=b|DHL-Bv|EOZoU;N@mszf(7O$DIBfI z4I%s8O&VR^+l!O~SmgF3PTx}IsfWULt{Fiv2cz_2Iq3p=aq Uj7y?OkN^Mx07*qoM6N<$f&wOQpa1{> literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/Contents.json new file mode 100644 index 000000000..0fc3beb1c --- /dev/null +++ b/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ic_unread.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "ic_unread@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread.png b/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread.png new file mode 100644 index 0000000000000000000000000000000000000000..1ff9519368490b635d5ab01f451b7f588e6a4eb1 GIT binary patch literal 495 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-QsS%!O zzP=1vKsE;hV|yk83y{SK#8N=az`(SC2`(bBfEmFCNgn(gJ{_ny$^yo#68tM$SzmZ`J4yll?DnR9Z^ zO-bwBn?vqBnfdeF_qp@m|JfGxUuqLmu=AtRL)jrhrPC*g{0ZR|kkU;tO|;FBbY7vuW^Iny zRXwpY_d54jG2ec&)zi_)bgtvIz^pe*{>O2Mm|Ol(|Mvegqs=0@tA(kz<@`W8pdYsK1KW24cHzscwtEk#XPiIevei5PeF0PG>6;Y?;$QD5Oe_1q``X=V U-GkTmji6BXboFyt=akR{0HCPC3IG5A literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread@2x.png b/Telegram-Mac/Assets.xcassets/Icon_FilterUnread.imageset/ic_unread@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa1df6eb35626a74d140bfd82774808f00f0fb4 GIT binary patch literal 967 zcmV;&133JNP)W4fR|L`scE_U0z)mJ_%a^kkN-u zl%`n$%haCetmPf=Bqp;)d&N8#E|?(lT$cQ*@IBI>B~E23%v`L!DN9x&%=bz#-CyD# z3ri00$gCgTa`s-UJ@_VxmzcTPD$8~tvqhh6r;I63Y6S|)4GQkLx!7GO&$1wp(T5IX zWB#@>e%o9DwrBs_LYCQ)mK+-SkhK|r{2b(dAPE%RQtGONaE7zZCEQ*4q2VJgsmx%ya#B$T156J zCwnJChr&BED|=rE^>W(Sz*g0YNo6poDxr~5@MGupi;~}ReJneF)Iz(2hr%Ka5!b~# z!WS9|VyheqYYCl3yUMPd`($B7uuOjwe_m*fn!L~)ke4rnG# z-ZFtAM@^F^8Lj-|ktFOf`3LJpfgq2NB=wa-ZRXIrsx}-NefqS z2yPVWUchmT#l-Q#{fo65&g`38d4A^d-5c1?otyppo$dR3Gk1SZ%gS1{BCatce1Tc$ z7vBQz_WlpdHLTJLKXAW0Boou}d&8O!JvsXh{r_Op_-W$$q*F}HDTOSPh5FBFyKVg5 z*b?ZRQjGvsD@Y{OcvYA6B>!tfHxSzcQ1H`@)fV#(9%3vhv5w`DAxj zZr{3fZpCXA9tb|pXMMiWc|Oy;<63v~E@jBM9lBq%uGdh|j`f9DyVG3PACr%UrF_y% z*so!=_o0IR#hi&%=^I67)^J7WclqTd7*;-kLE# z;k3xDl9HpFyy_%%Gx?@oxN~TpW!$0_XVr2ApM^Tjz7fZ{*Yb_y2f3^FKWuZ25y*~v zrj}e%HG{j&Z_0nC`$}B#%iEJ5U0s#6e!+=_@1h*OG^b68xXT&6Cn{vEl#KP71fhT? z?*i#ndrQi%+_ryUaV35Eg7ar9GafB+Kf21bIk`pj%%kHy)xu#{wtr&TVyoBN*Y(ch z!pW3fqEqVw{@O5?hUQi@7E0wgO-{KJs9Tv{@n*-R;6KM6l<#2NYPr()N>-NT)_Iz* z)E{>>NBQe!bo~e_6rHdksz7X&>iLJ#5gQ9~&vxlr1m@}L K=d#Wzp$PzXjyO;N literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2715b079b0718d6833f42b73d2f6fe408038c112 GIT binary patch literal 1435 zcmV;M1!Ve(P)tSzbI+MM zbIv{I-1(C)GiS~`zWmk&AMDFpL%R54pnJ$;5EZXQ_)=4CkJwoZ8t8q0psMtBIT#RnSQ{vn6~|q3pojE zLgpjz88`tHZofDWr)9luq3PWT&!}CpU5wb_f}j-&2$=6&3Q9Zq_)YI#}uJO_HeG7kH$ha^l{wOsbcg z>?Mses&kdTCP&%2aiQbHr|N}r#jNKWLGU}Eb0$k=X+tbw!)l>G0S+ z4DDb&ibf7C&RhvOlB=+5BBM#CqwJKXJa$nM6R)Q}=b8%l@wnD0h-}V#mzeao# z4l{1n&Mb)u810N*`W;0%g5Yz(G*{G;n1D~N$feK^!%Nws3cFfv6epj=1n{keyco}b zWQ#fhZE~YH`6MQQ=PY?K`5Q0>q@x~3b2D~gNld^kC(P36q)!^gL{z@3lv$e(WU%> znE?Zb(w+qM2boSouKb2)-d2Di&sWkGH_CXel6rN>zcA!^PHLa&>~TZKqKFr_j{2kg zQ45ZHGp)Krj!O}bdE<)as(nAW$gia^oaE1rru{S0%Z<$f(}#emldkLQUd*~+!7CT* zzxwHzgn}Cu&bpd}L5!`wnz-MR48vp&$4Y(3DYCpP{bJv20O@J_fc3f6-Yqem0 z2Z$KnK8wD%HlL;4~n&G08tb zTSjt;SlWM6<#>;Pprc>Dm2eVZ)U=>fZvs+^$WJdrNuI+n4f~ra$JzpP0k+4-eQ3K5 z;F4Ad+Xyd$K7D*vnC-|*Zk8sen>tR6*ciDL#`yHecwFb~Wt2~h=_!{9zU9nsm~IS{ zGDd2Q*a~A@0(cCditqttTP?ig@-h!-2e_wP1#IGam5;b)q*f?93vYyT?~$iqjE1Px&(Md!>R7efwmRU$tVHC%m>!?{Ng18YSnMGL8BDM%h(S}AsghD}Pfisvoflq;$ zSX2)_1Uf24HDXfaLspV4*i&UfW<&%bmRJvBR4ORrHerL0s{V*VVEmWtJS)0W@hFfGJBu|C|Z;M#{3z2W-u5Y78MosXy-mnvl_+NR*aQH zDS);>?a)W|Vl04lH0$-yUg$9U*H8tGI5_wi`Iknc@hW)X1qB7~y(3qR*45Q* znVOn$jhEXP% zQeTdq66qV8&9+4NG8FNQIV~b0;+A@{06!X5nqXtthSAc|(a~3=KTzNmQn7=%BR4m9 zYys@45E@p8hAq+GhjEX3pB4eisH|e{m(2o?ehpiNjfsi5%;F4R`BJH=15#_Nau?}` z8!-v=O+MHxG4=^cSOi<~r1y&_F4yP*Uvjp>r~M8_a#K@NxTk&C{$W$34p-cC;( z_R_DD6*|v%7LSL9hE8}2__H1!9zKTtbMGq{92{&Q(s8wxgk8y|w5FzJr9Z|*SG$52 zz&z)TH8wVu!1d`=jnb;#B2Y;U?qGPix3I5!X@fX_7vLKjrcM>!ehymQy;r#O-#Vt9 zFwLm zbs7cOa{!*rzE#dJn2rO@2zEd#>~?!Rvk@8h-xW%+3$Q=_T_Fqk$Xj@$RfB@7i&XB{ z$jC@9=U1T3&~6lt^DMPX`=TC7R8*9m?jl`m-a&-L=aD zZGnM-CTcV)!X}f+PU^SOw6Ed)AV>24zM#1b;LK01NEoS45m6Ae8f{YmiM|C@B_ozI{zd~vF_ zwziNPU_rhT%7@I9NWN}$=&p?G(4Sc%q9j)8n1TbrU=4A0-SvR`gZ=O6{sN9Y*m+yq RjL!f7002ovPDHLkV1g=k?%4nU diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats_1@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabChatList.imageset/ic_chats_1@2x.png deleted file mode 100644 index e3829970c1bb8c66297f731b2f13538ce679b480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2458 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 K=d#Wzp$PzXjyO;N literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabChatList_Highlighted.imageset/ic_chats@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2715b079b0718d6833f42b73d2f6fe408038c112 GIT binary patch literal 1435 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 Z@INq)H#azL@f837002ovPDHLkV1ivLb|wG- diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/Contents.json index 2d057742d..6d3745d5e 100644 --- a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/Contents.json +++ b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "ic_contacts_1@1x.png", + "filename" : "ic_contacts.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "ic_contacts_1@2x.png", + "filename" : "ic_contacts@2x.png", "scale" : "2x" }, { diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..37b6eb9c95c18c5b0bd8634b6413919da2b584e5 GIT binary patch literal 729 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QY`6?zK#qG8~eHcB(ehe7O4@Q zX}-P;T0k}j17mw80}GJF2*grA%)r33fC(;Quz(rPRsc!PkiWSFsKm$9#W5s;^X-hi zUd)ant-|$LuC9&(;ySF-iV7KP_ccfSVu<=7)>Ibew&9wWG`F|o2SKHkBCM{CxhAiE z`mkLqEh}$JF&8X;FyUtP`8(C=Y2|6=txn>1B{Qr7VjUOFar&E$-Z;x2Qy8BO~ zw}mwE&cEnd-#PR2yD4VBZ%=#Fo2j12z@zaw^uYwLThBF<0(+SEy*SgpzSEa4{fmY6 zYbU=O3#Ztf=lnOFMP4sy@?pt+%p5XG`YIXEglmq8&TtdkFU=(tR}}p_aF(ZcQO=K? z+CyeV7Kh7OW0?3oN;KDX1_RyErq9cBOtSXesa+Gcdx;llyxqm2J4?D-_u7-)OjmDs ztSzp1s!{bUwR^Yl4zx~{CSKvfvUE?FNDeF(|P}l3+#+Y=toh|pr zLDRRJ-poAwO{;L#8ezGa7cU(bIj6sQ-s#mXpK9cPs{Nd~Zm*v|6NgRx7t=zc`d)>V zjJthYReo+Xtorxq&)kk93Sx%Eu0NWe1CYwr}Nn!~3}*mGzBF?+b;yynAi_G3LpWy`l$aSZJT?{Hr8y&i-iE3F!>?2H6(& ziA^(Nr9UpryqR~oOEkdN{y<-d5c5a>zZ;iU?fy}3{DIZ>^Z)nTUAT)u>C4mA&t;uc GLK6V;=PyYB literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..65e44c6a3eac80170e8245170ed553565b2c73ef GIT binary patch literal 1374 zcmV-k1)=(hP)45pf)V3}3xa}ziXKHs z4(dfv4=VnHT=k?k|3R+)fe3=4H&F=cNrkA0;K@URg3HMjgSaFT^?h_&Vq4v*rK@MA zr#^V;>FRHNtEa0{)sw!yB#D8DohCXg)xD)B%TaxlHEz+mM|mybObio;sakvEE#~TQDIhaCA~-=U-(QN zArgvYKo>@YFG3NKq3!r42C8VcWggZaqiR9E1!gDuYe5af@eoSEI(T)Mvwu8y7 z*4a^=OA*Yyp9!mkQ28tecZKIIM_Y8Y!Kiv&% zpSyQ%TG!^DIDQVXCDd`pc+TpvJ79$}I^dkuzXp^4o;sa{*b?Y~Kn>9(b_X0$=1T&z zXGY>HA-2RMcWQ_xu{&U>g3LDr_z1Dh!d6j3=Ig&>><(Z9JyiAwI0&)L!d6j3=BxH2 zOAn^mg-hF4`Pk@@IX2k3#4_npL)XeXWo|0Uwe5lj1K7C6G3ir7*UGdqHx=d6cG`gj zbbVr&Y^b4YrOFO~oO42d2^(BP$3&!WThtDSy&TQgcXbJ2K9^q0=)7=4c+qmOS;s@d zu;8+0)G{wU@CL=2QjHG2Sj8ahd*@bV_cSKIv8SP3J%eZwAGL`d^9 zZ`%dB#%#(%0Cy6bBW0by<7I~sTXre{vC48G*T&ra8KEO3MUU%Rf2LT&k#XXVP}B+J z+BjjRQuHgBp*B>@0B!03awOMAO3}-?yV_7KkD`1BFwL#?<=i&Z{rhJ@`NA(NkwrBo z!}OaeWBN(jC@>j zA*Y@a3O0QcAcsfN?h4t!*A*d8Jm=)lbL6Y$zru5u!7on^ZP$f;g3qEMHrV2$$bZi~ z^Tk1_F!LyyqS7&MgiFG(!0ctEkQdsxh7P*e1^Zmt~kvJ{g zS1s^4YcD(En;4Cq=c~40VF_SVU@@$WOqXl;!e`@_7gSR;fvi))En!A*Ask(7u*FBm z67Ms(sh-+}oi*N49ujz0lV35?wp>86f7rwZ`h>t%=$H_7Ge!QBBnA=#iGjpGVjwY) g7)T5x2D*`fUliEZiMaproB#j-07*qoM6N<$f@R!ta{vGU literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@1x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@1x.png deleted file mode 100644 index 99e010ace86546ac2d6a022fe2b609fa47bb13e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207 zcmV;o1W5adP)Px(aY;l$R7efwmTgFzR}{yM8rSKkX#=TB+f7*eK|5H5jzZg5#u&odI*N?p#+K4L z;|sLV^^I-NA+FtE%xHoW^~>lw$3{D--G{BA_GK@~pfggj@k3j*)vZNJhI78{cfxZX zZk{C4@4awy?)m@EJ^%aM*JNcqDaG|TA388F@YMMD_)eG0wR>r4sggd$)FSEw>ST6y z_R#Y3^7*o|vP;#~)pKAgmK8-Kkx1_F@bEswJ|xQ+_B;Yt5SYl#&3&-2uuue6!a%lx z?Iz}V?8%CXik_;fs)bC-8AUrfI@Xck9Q8h(kG8b5+{lzf@%Hxi7ifRNK)lpFO-)U= zl{0NxQ3SUj_C0~E&CSgr?a0Ml0^pkK4n1_0Y8YJeL#)zeVBmIvP_d3GAnVhs! zM8o0m`uX|!>p3|&{>H|}AGHICwlj@qNpzNkKg;yuZ=n4#^$+5Y5r0$T8Q`n%J;ZNy zesPkhtYI`79U`!cz_2Fh>+4$;kH^RG-{Gq+DK56ZzyIl}si`**ZY?Y<+*nsv_el9* zFc_eHpuD`i(p=+g4G=prGO`~tX$lIC;10|~r=W1PwY9V0eGGJDW@cuuU|PUK4CbDd zSK%yMRE`DH@d3;co3$Dwe2%6)bxz*$uOYDB$*~MaB(LOG&K8ZuVlM-ZGP+?U4I8KZ zpW&x#7BIMfoJ1fH_!Df@%AcTZQM^6Wa|zV(!`ZwAw7~%U%^9?8Y6U7!~ zlrNI}suB)6jlYq^NgGdN1gH3zO8Kgk!p^=b`IWFm0g53el`t)9;={iPzii^#w(tly z)Juw)mO)M6%hj1EwkX6i9*^gt5)K=K-^3Ak)`2Hn!Qm?yoGe31k-YGQO4y=|_CDur zwGyV~2n{mzKY<-GaicAGgsbw3f!R$fuPjlb*rIrMNL*s!DTYA>0c*^yFF}@H1K*L- z$pZMwQh1r-M6pF7qTH)K3r{gzaWTNlJaH#YlA~~(zQ1tPMorvoBj_V$NHJTK9d-s% zo~M5}a02ZC6*hA6?ot>RM%D~^m{ees3vxbI- zD7jAHze27Z5~n4dXfYy#B)Ea~A@)Unety{R_y47xGFg_Uh(7PZAEaKUZYn4!*y`+? zA}R^3k;}XJtJmwTm*-3H$0_o@PESvNj`(W~yo#9_bM{LsDnatsgd65-nqI#4eKy(! zk}NqBsL#5)=jP`264M6uJ8K=Nudn}GdDCVTl^{mzLi}ySWo_JupTUljcpPqm>Y=X1 zuLOUW_FdYavWDN{XDlmX!fj002ovPDHLkV1nk;Y0dxu diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts.imageset/ic_contacts_1@2x.png deleted file mode 100644 index 0fd0b01ce0dd90b323b9d52c5b6053d2f085809b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2809 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 LNkvXXu0mjfezs;r diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/Contents.json index 25e4e5877..6d3745d5e 100644 --- a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/Contents.json +++ b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "ic_contacts_2@1x.png", + "filename" : "ic_contacts.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "ic_contacts_2@2x.png", + "filename" : "ic_contacts@2x.png", "scale" : "2x" }, { diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts.png new file mode 100644 index 0000000000000000000000000000000000000000..37b6eb9c95c18c5b0bd8634b6413919da2b584e5 GIT binary patch literal 729 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QY`6?zK#qG8~eHcB(ehe7O4@Q zX}-P;T0k}j17mw80}GJF2*grA%)r33fC(;Quz(rPRsc!PkiWSFsKm$9#W5s;^X-hi zUd)ant-|$LuC9&(;ySF-iV7KP_ccfSVu<=7)>Ibew&9wWG`F|o2SKHkBCM{CxhAiE z`mkLqEh}$JF&8X;FyUtP`8(C=Y2|6=txn>1B{Qr7VjUOFar&E$-Z;x2Qy8BO~ zw}mwE&cEnd-#PR2yD4VBZ%=#Fo2j12z@zaw^uYwLThBF<0(+SEy*SgpzSEa4{fmY6 zYbU=O3#Ztf=lnOFMP4sy@?pt+%p5XG`YIXEglmq8&TtdkFU=(tR}}p_aF(ZcQO=K? z+CyeV7Kh7OW0?3oN;KDX1_RyErq9cBOtSXesa+Gcdx;llyxqm2J4?D-_u7-)OjmDs ztSzp1s!{bUwR^Yl4zx~{CSKvfvUE?FNDeF(|P}l3+#+Y=toh|pr zLDRRJ-poAwO{;L#8ezGa7cU(bIj6sQ-s#mXpK9cPs{Nd~Zm*v|6NgRx7t=zc`d)>V zjJthYReo+Xtorxq&)kk93Sx%Eu0NWe1CYwr}Nn!~3}*mGzBF?+b;yynAi_G3LpWy`l$aSZJT?{Hr8y&i-iE3F!>?2H6(& ziA^(Nr9UpryqR~oOEkdN{y<-d5c5a>zZ;iU?fy}3{DIZ>^Z)nTUAT)u>C4mA&t;uc GLK6V;=PyYB literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..65e44c6a3eac80170e8245170ed553565b2c73ef GIT binary patch literal 1374 zcmV-k1)=(hP)45pf)V3}3xa}ziXKHs z4(dfv4=VnHT=k?k|3R+)fe3=4H&F=cNrkA0;K@URg3HMjgSaFT^?h_&Vq4v*rK@MA zr#^V;>FRHNtEa0{)sw!yB#D8DohCXg)xD)B%TaxlHEz+mM|mybObio;sakvEE#~TQDIhaCA~-=U-(QN zArgvYKo>@YFG3NKq3!r42C8VcWggZaqiR9E1!gDuYe5af@eoSEI(T)Mvwu8y7 z*4a^=OA*Yyp9!mkQ28tecZKIIM_Y8Y!Kiv&% zpSyQ%TG!^DIDQVXCDd`pc+TpvJ79$}I^dkuzXp^4o;sa{*b?Y~Kn>9(b_X0$=1T&z zXGY>HA-2RMcWQ_xu{&U>g3LDr_z1Dh!d6j3=Ig&>><(Z9JyiAwI0&)L!d6j3=BxH2 zOAn^mg-hF4`Pk@@IX2k3#4_npL)XeXWo|0Uwe5lj1K7C6G3ir7*UGdqHx=d6cG`gj zbbVr&Y^b4YrOFO~oO42d2^(BP$3&!WThtDSy&TQgcXbJ2K9^q0=)7=4c+qmOS;s@d zu;8+0)G{wU@CL=2QjHG2Sj8ahd*@bV_cSKIv8SP3J%eZwAGL`d^9 zZ`%dB#%#(%0Cy6bBW0by<7I~sTXre{vC48G*T&ra8KEO3MUU%Rf2LT&k#XXVP}B+J z+BjjRQuHgBp*B>@0B!03awOMAO3}-?yV_7KkD`1BFwL#?<=i&Z{rhJ@`NA(NkwrBo z!}OaeWBN(jC@>j zA*Y@a3O0QcAcsfN?h4t!*A*d8Jm=)lbL6Y$zru5u!7on^ZP$f;g3qEMHrV2$$bZi~ z^Tk1_F!LyyqS7&MgiFG(!0ctEkQdsxh7P*e1^Zmt~kvJ{g zS1s^4YcD(En;4Cq=c~40VF_SVU@@$WOqXl;!e`@_7gSR;fvi))En!A*Ask(7u*FBm z67Ms(sh-+}oi*N49ujz0lV35?wp>86f7rwZ`h>t%=$H_7Ge!QBBnA=#iGjpGVjwY) g7)T5x2D*`fUliEZiMaproB#j-07*qoM6N<$f@R!ta{vGU literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@1x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@1x.png deleted file mode 100644 index eda01248f0d8474442f7588e7c20bc8e72f77566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 994 zcmV<810DQ{P)Px&oJmAMR7ef&R$XWuRTTct?5+uDtw~I~yM1UCq12bu8X`Wl1t|zhNeji7QhX3! zT4-s6AfaX_ix1*22&GSbX-j>u0fYD^7E&rGg(?;)6wwOVU6Zu&uQX+nIevGxGjnHm zW>TN^!tOoyJLi1g{l5eJSBgB)KtI+VEVW*M>L`2+Gp7pC0jS)f-GGBD5Sc+=`70ci zduws#i@I8b-+T=MmxATB$SB-`GS;b_hAS&s@!6tpH#Wo5&q%U8D>)Mve20?k!-?w6 zw3u|!dh0o?_@4th*qtOE@gIpVa%4|%2A=GWF^DXn=NPujhK(!4hwPxXEz_u14|L;1Ty=ov z8FuzyivN2!)nR*$8Eh55^*UQAfLcxTu}gd1O7G;i~71R zib*p>x2C}{Ce_$Zu`K>r6xfjx8biwCkz2fxT(`wif4jMk<5*+8$t%uu$Qg^)DwjFEH*?oj%ysAd9VQ3$ zqm?^+Z8G1^fKM=oZROc8FBTOpwxGse`e+TY=rOo`zlX^|JtlXVbA;r4@=}W7Q+*S! z#Ix9aZPglIaJpXP#wY|7B7aisEDD7W@K*Wf6xudqoQ^aJB8o`LEAEgH`Wc zj&O;?ISjYDm=>KaYNC}-)l};ce1C#F^fz{KhUhFxr8#(y-$H3|0G_vr*e;H2lyxr! z-$%XjDecUXFKVaN8_)8p+fVYH{B7dqGGfaVxxo%yPx# diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabContacts_Highlighted.imageset/ic_contacts_2@2x.png deleted file mode 100644 index dc03a4ef21adafca146d23635eaa987c08556ceb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2114 zcmV-I2)*}-P)Px+{7FPXRA>e5T6>5URT%%ix$Ew_y1okCyBeit52@%u55g!DDl4)-LaabYf}*En znP#r1)lzyP3Wa}EW<+HVlE~^0rT(Z4EP`HCTG->>)pS*C-F4kNr{6boZ+q{ZGk509 ztWvNa+)6mVdXw1Q55!1i|Rr@B8+dGR$<40E@9by+WABFtKM7)Wd`c0%x z_`^;=TzX)DuGn`H9qnmHfOAo6PPjXZ9A*~`_!g*HQJV6M&v5rRC%e^FwVS&IJ+PeV7cn@j)_!oZv|NV^cm$@=I8Pl z97XNf$INp5+-RUGe-lR6jVM9LmOJP-5_odx4N~Lh1o%-5r5nl3zYbrr;E147EJz)m zO)C3VErr@Z)xj~O|K5p`9u*rT@gZu+Ora&?q+i;T(siWsSQ6?<(aJ@zOb3XEPbM|8 zGfc+`%kcQRYl$65XgPXwVvyog`m*MyJ^zt^#a1R2A+gq=aG)xG3QG0v8oK5z*ZIJl zVZn9kwpd8}q7tjb975qhNw0uTL;NON^x!x@hxoE!pST0UN8%}z#twTIq=?V{Zh2 zz1V}AW}qxU6H=jXTtdx$HMMU9#)qbUhQ(7z>_MR3ltPzTn647#mMVt*t5cY4uT<2~ zh+QyLQ4lB{z8=jsL9;1YcF!t3B~IPG3li&ku?vPuG62;Ui|k5c-kZx88Mt;Vsg*RO z-Qvch-$)Rs9Au@V3F*{DTc4BCMqs@h1WG(9m6HrFPNgr(j+1C}-S0Pu!2nc`=vPSa zqDHi8&}KsEd4u9dDW-rTg!4!%;_FklD*WnHj96%=*#Jj{WXtEn4$37AW-73Jt2*=g;b;`5_K$!ZQ|SfeUMGNSSh-5wpaTN0e)?z9bJrWmG|+lF$6MFQ!uh6)QNEkE9_nWTK1|V`X~9BxwfP(DV|( z;$DLr@k@7N;8K^#aRsm7M9WktRKG}!5-ZM`>W9Btoh$EVp#DAN2Gj=QZW4VpDS3so zCsKRZ(fxkGMoO9mycoT1@*F)fVxLLK3{)hUR^q?A*ufLlDnCxDB^u~MEnV=p#1vpO z4}~d%5c6K5q3vPv;XqaEZ%}^5Q)D@Mv>AcDCD?s&?nM3#Otr4Y^X&j^u`)wUUTn~0 zUPfwksBSn=iD0<13I={bi4BLrZei6VrcR8qE4?d;_VH_L%9=9U$G-r7Q($8`Qq)ic zNlX$O@pm+}WnC@l=v_v8{zB^0pTbBTz!vAKYLmDgBw9yK_Dx(V^i=02dS9a(XfH0f znC=9aX#pED*Gqkp?xniA>C`sv^MFhlBO0g(x8?4K!PO{bnFe~`*guM7{*btCF{!cs zYO2iefIg}{=aSp^1Y(%!*_9bV%gH^(Mq<2T)MtEyujxrOJz zl76xUju)a3zA6_PuxFJ!A6@22*qec0H@XbAf7$i6_LBh>FYSBIqrSeE(S*OK)K3W`#FHyoLaAQbn|0r_1uS4D}tWRbEWIb%++Mbru)Yj)|HYYx~O9!+R zt$Y*M(={J8D|6mhkIiyLuRp;s@DWza-;%dbDwOog5?=mMuvfu`b! z^J+|AmqW+@B#0>oplir!T4!BgrMSw{fdN`FC^eklJrh&FT(GV}EjO34Vx?Z~@q4Jv zw@J5tfW?Q!WpHf|0}Hg=mwa79dAYEXRn1h?&Y1w-f?6MecUf?Bg0~x>cA+M*vT{Bq s8n+$b24D{i>w`2{0)r*+zbb)$0OYoMhI|)nFaQ7m07*qoM6N<$g4AmI$N&HU diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/Contents.json index b24728a36..45a0013e5 100644 --- a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/Contents.json +++ b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "ic_calls_1@1x.png", + "filename" : "ic_calls.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "ic_calls_1@2x.png", + "filename" : "ic_calls@2x.png", "scale" : "2x" }, { diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..beaa6d49a7487b38ddaa5c458b3cf73dc5dbd2aa GIT binary patch literal 557 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QY`6?zK#qG8~eHcB(ehe7O4@Q zX}-P;T0k}j17mw80}GJF2*grA%)r33fC(;Quz(rPRsc!PkiWSFsCa>=i(^Ox=iBLL zwOt)0+TXjH9XjM?X6F^C5p5l>xpC{p#KhF>!}f{!YdzM8oOGMWD!seAHONUU$^B== zy`rpH%Z$^X-8(mP^5<)pEsfvr`TnQQxcuDQXf4seGY9_9Yy744X8Ovx&8`_uTu;trtaaAK$VuUnrJ7M)kHGuk+potfK^?Z}CgS!%Cr+P*VAr0YkZYp(tGvjt1Ou-4vg*kv3L z?)dI{Q`p+h?8UXbyE;pMeOVtYUK?G&uWrEW*uqiGbhl;C%&7k&=Zb1gdu}e(@3_x* z^GZKk5`Mw=r^J`0H~Y0M k+M_iV&1g(wvq^g(-ga+#xlUW^DNvkwy85}Sb4q9e0FmeB$N&HU literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4baf298c68c24d2bb9af50798dabeac757f68dd4 GIT binary patch literal 1035 zcmeAS@N?(olHy`uVBq!ia0vp^2|(|7?|rkT^vIy7~jtF z?6~3}(sn#H<^ZF3fa7si8;vF|F0Lven~Kj1G%5rIMOlvCR#2`AoUysX;KkLi3SEaz zRD4*%E_iUU@eZRM3m>#S{$x9&O(6KL=W?yPK7aY^CWY*;np(5|(#j>P7CWmkDJdW! z0qI6g-F*)_x9sOR>o7mMMlaCRzI*jsSNRL~1NSCY%ba8qj&T2TeFdA{-nV>r>aIKt zFZ>$+>cIAtKTg^c&lorEJRy7 zOxjkvMrh5V^wO$^?T4Lvw($hIGTBw`_|z(wv?aAeOUU5O!&7hHR{BJVa{gf3S+4rh zRwvT_*Q;>F3uib^ytSprP1kv(_jl1KS9&o*I+zkAjX)c0lEZe4A#m}S|fwdTUpe9i?1ayvf|NSwSN_P6w5ll3ct z9X=?z3!UQ*wP4y^tn$FzPWsT?CZ+GsJq{_@NwKoN(mvh!TiIRc-J|60?J0~LH$0Ai z74VxjpZmf#C#M6`=H7Ahys_@D+#itCs`l+CSnVR$l{YhRZkRB8!rq^1iMzjTExXde zx?%5;5=Z~(-$ioj4gaNIVAxdI`Z_~>R!a&e6PqUQ?a~^?`)-SsqpRwLcDhA>+n6ss zsaI%2`zO~YP4o2jx3ABBI%lo(*87)BH}&a1HkUuCkg)fg)G4N^q2IXfpVi3x=5zA* z#r0yB)9&&uUZu8T((~J8zb9KRj$XmG{NgpWs$UnvuJq~d(;kzW{FE%!2y;m}Gk)q_HJx>E#h^sfnTd-FANW3Hv|;)!B$1qCe#V*1Yz@_tFP+Ko76P>%F;^>bP0l+XkKDMrB+ literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls_1@1x.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCalls.imageset/ic_calls_1@1x.png deleted file mode 100644 index 83781c5aab063a443bbb814bcb0486699eb060ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 948 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 DUkwIT diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/Contents.json index cda2d9a02..45a0013e5 100644 --- a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/Contents.json +++ b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "ic_calls_2@1x.png", + "filename" : "ic_calls.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "ic_calls_2@2x.png", + "filename" : "ic_calls@2x.png", "scale" : "2x" }, { diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls.png new file mode 100644 index 0000000000000000000000000000000000000000..beaa6d49a7487b38ddaa5c458b3cf73dc5dbd2aa GIT binary patch literal 557 zcmeAS@N?(olHy`uVBq!ia0vp^20*O9!3HEluKbn(QY`6?zK#qG8~eHcB(ehe7O4@Q zX}-P;T0k}j17mw80}GJF2*grA%)r33fC(;Quz(rPRsc!PkiWSFsCa>=i(^Ox=iBLL zwOt)0+TXjH9XjM?X6F^C5p5l>xpC{p#KhF>!}f{!YdzM8oOGMWD!seAHONUU$^B== zy`rpH%Z$^X-8(mP^5<)pEsfvr`TnQQxcuDQXf4seGY9_9Yy744X8Ovx&8`_uTu;trtaaAK$VuUnrJ7M)kHGuk+potfK^?Z}CgS!%Cr+P*VAr0YkZYp(tGvjt1Ou-4vg*kv3L z?)dI{Q`p+h?8UXbyE;pMeOVtYUK?G&uWrEW*uqiGbhl;C%&7k&=Zb1gdu}e(@3_x* z^GZKk5`Mw=r^J`0H~Y0M k+M_iV&1g(wvq^g(-ga+#xlUW^DNvkwy85}Sb4q9e0FmeB$N&HU literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..4baf298c68c24d2bb9af50798dabeac757f68dd4 GIT binary patch literal 1035 zcmeAS@N?(olHy`uVBq!ia0vp^2|(|7?|rkT^vIy7~jtF z?6~3}(sn#H<^ZF3fa7si8;vF|F0Lven~Kj1G%5rIMOlvCR#2`AoUysX;KkLi3SEaz zRD4*%E_iUU@eZRM3m>#S{$x9&O(6KL=W?yPK7aY^CWY*;np(5|(#j>P7CWmkDJdW! z0qI6g-F*)_x9sOR>o7mMMlaCRzI*jsSNRL~1NSCY%ba8qj&T2TeFdA{-nV>r>aIKt zFZ>$+>cIAtKTg^c&lorEJRy7 zOxjkvMrh5V^wO$^?T4Lvw($hIGTBw`_|z(wv?aAeOUU5O!&7hHR{BJVa{gf3S+4rh zRwvT_*Q;>F3uib^ytSprP1kv(_jl1KS9&o*I+zkAjX)c0lEZe4A#m}S|fwdTUpe9i?1ayvf|NSwSN_P6w5ll3ct z9X=?z3!UQ*wP4y^tn$FzPWsT?CZ+GsJq{_@NwKoN(mvh!TiIRc-J|60?J0~LH$0Ai z74VxjpZmf#C#M6`=H7Ahys_@D+#itCs`l+CSnVR$l{YhRZkRB8!rq^1iMzjTExXde zx?%5;5=Z~(-$ioj4gaNIVAxdI`Z_~>R!a&e6PqUQ?a~^?`)-SsqpRwLcDhA>+n6ss zsaI%2`zO~YP4o2jx3ABBI%lo(*87)BH}&a1HkUuCkg)fg)G4N^q2IXfpVi3x=5zA* z#r0yB)9&&uUZu8T((~J8zb9KRj$XmG{NgpWs$UnvuJq~d(;kzW{FE%!2y;m}Gk)q_HJx>E#h^sfnTd-FANW3Hv|;)!B$1qCe#V*1Yz@_tFP+Ko76P>%F;^>bP0l+XkKDMrB+ literal 0 HcmV?d00001 diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls_2@1x.png b/Telegram-Mac/Assets.xcassets/Icon_TabRecentCallsHighlighted.imageset/ic_calls_2@1x.png deleted file mode 100644 index 48c80fef5316d56708ba1e330cdd9852601f90a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 720 zcmV;>0x$iEP)Px%ib+I4R7efwRljQ#K@|SpCQ)-1NhHYKUSVUYjg4A}CIqn(0+J?((MBy!Bm~69 zOh8N_#v+2)s3?Lc!5~;D@kbD}P&@HI$n9aFDfHrb$v)o{b9=k9ce{6ImxJZaeD8hV z$D5sf2W*xfS&b@o;Cq)qn3UXS(Dretz8_Xy2Y?ge&T%i;TLAbPm9}#H+C|UXweqqI-@P?cvmp8d1_(KC zp|TCX>E@A4Si)0wl_=LOgwKyU0j6C^hS|->M`rPA~q&1W4 z+|(%D;U0LUQ5gPx)SxH1eRA>e5T5D(=RTTct>~5O0wLxQ&-7VAyB7&fZiq;n>mHMCtL8&NK(N+`$ zB|cIbvU@i%K@qBgKk6Iu!{;Bdl~gH(Dn!KoQADt65izry#uQsIX*TR$&s`bZ&dg5k z?9A?tuosd$_uTXP?zwyS+_M9;TYClCD-h)sAYaaj{9P!^ogiGsaz`L3gVEGSzI3#R zSr6!L*@YANJ&3))gf!iR``%kAwZ?rPdiF_|k$xi`!rK|e{6SVqbh%^6mosS67 z@bp6*yMRG{RTHEVmPkV`zT&AT0+Y2PD&{VPT>g@`YoC^%Mr;d2a-SA&3z*!2j?bk~ zT%Kl-=W6>D@h$A!y24zIVsXDOkZLt5TX^9m?S*MFqZ6o#H#_2#{t(Jn0wSQZWt?r#bN0Ns@ zbTqJIglX(rHy>C}ND7=liEku?Hv;Q7jETTHLR8=cs+1>U?*O!1za2V+Y>IC@(P{2L zhx=zivd*Yh?x;^k2jah;xC2#l9r00)s{g~pz`J}AKm7jzs-kLOw?BtDnsE&KlW7ij z?T9M-U5OX@VDgbEaiUO^_cX_Ke^$JK4)y*8gC6&%lE#tC-{?=K@!akgZ@b-$`5|98 z@3xaY#`7=|S3~su?7`F2Des6{t{7_`<;NLosL}Uu8DxXOc#RrhlLgD+nsHldvV7(#aXk_(a9Uqmg#V)lH<($`!m zJli5^^_9rd0B24MTKpk0`HQG!So9wS#Rhn|Xpyvf6~l58tdN={?ggNW^c&NZ(Jc{JEI{ zl<_R@fNLuAMBgLESz0D_$d!KuVsN0!K*oH6PvVzXu;rX490$d>^6vPrd?U;&7$9FJ zSxM5oP!TRrKdhxI6#%b%*+t~ucMyJTi<|S*-4Jx82{bRAiez}`i;NSckrS1 zIm>A^Z-rVas+dGRgK{}nMe*^-UtKE!v}-fyEp&E1g`H=euus{?;R03K>yE75HO(>M zcNoSaT)LU^k_aEDvL?(Yxq#i=U)Bh3qpNGMR&*N!RDrFW#`GF*$Cw&6rB$L!+mTIw zX1CWkpvsac+<|iGeST_UQeXM3--prl?^T1XKVhiWQtMeHKYSs)Hy`8=BK$XQxZoFzEuXJ;Y+LFF)4bTeMo|DL>ws5g+ zgrlopsjz#jGd7%wOJfhCT26_=O?*gA^0Z@%)e_OB6HOwQe!$M(oULoOs>(9PT7Dsf zLVk~szCm|N74jUdH4&|LBWK=O`E^{qz7weNZK#trVpnR;O-<{8DzDUAEQ`y}@U3N# z6O1)(j(XCFj`1z%TCX~CG=N$t#%KGnT*@-w?F=|!kv)5&UqOk@5WPpd_@V{W@>Bs{ zDm}!*9Srz9i|ptL-=U-977X|19dkB9G=W-9s`BbsfiL3nX1=GYi}*!ckW29)R^YFw t573H002ovPDHLkV1hg(xe)*W diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/Contents.json b/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/Contents.json index 5f66cf2b1..25de093c5 100644 --- a/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/Contents.json +++ b/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/Contents.json @@ -2,12 +2,12 @@ "images" : [ { "idiom" : "universal", - "filename" : "ic_settings_1@1x.png", + "filename" : "ic_settings.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "ic_settings_1@2x.png", + "filename" : "ic_settings@2x.png", "scale" : "2x" }, { diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings.png b/Telegram-Mac/Assets.xcassets/Icon_TabSettings.imageset/ic_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..2dffab770159ed24aa46e025b54c18122e05809c GIT binary patch literal 852 zcmV-a1FQUrP)=1+0008VNklt2nq@bgpd^8KoAqHVqvL`5`UjZ=fF5**M!Z^ZbDvo zcIKOzGjryDw$<9u`W}JnbWhf-7V%t$S`FUK!>z*0Q+)qQ7|&%{ZM5x4BRyIFHQqsR z5T3wh*aGJg1b_6J--*Nz!pE=;v>gh~;6;q~a>MDN@Ej)&!{@96!|#06O&++MqVU0T_c(*asoY%z-xAMklPZfxgSl_Y+(KG4fNy_dw_Y z5gp92gIBw+@$}by|1d3qyCSFZ%!@X-P*sSybuhBx#QDY4F?+r}NOI=VrGK)2*|Lyj8z|je0yDOYz(}Z)}oQPma_gJXeLa1*QD5H^Ok5i?7)yPW1;WuyO- zBVFoSnNaI{rAz1$j^!g9@eibrK(!^54^X*@-xp3!^6l)Nflixvmb`&%V%lw$$LK}U zVr19EF}l=6_AGVcsy#&AF0vQo`|NH*biCR{*6As+6K6bWRJW(ZEAj{Wl$gf>A6_%i z=`nYMycpRCy|^xe>)s=D3e2nim}_V>9&MeT(-dhP2WR3e?1fO9$Qm(mB8*w^CzGb!1cBu6o@0^*w$?5K=Zc@2N e?uORw2>b@RWGE_dno5fR0000-P)WJuqpx_e| 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 e?uORw2>b@RWGE_dno5fR0000-P)WJuqpx_e| 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 BTo(WU diff --git a/Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings_2@2x.png b/Telegram-Mac/Assets.xcassets/Icon_TabSettings_Highlighted.imageset/ic_settings_2@2x.png deleted file mode 100644 index 180d7240aef25100de62427ddd0c2d5c5d2dc3eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2850 zcmV+-3*GdIP)Px<+(|@1RA>e5T78UMRTV$??QFY+E~VCXcc*c+f~mH}wt_WK3oBA7O7su3QU5^* z0gUA%jfmEE_U*P+F=}kVAXvrEXo~uWLG1@xu&97Y+w_AH5kr&C>~3jXy3lRAGw=HQ zoi}ej-`kxxI|YqPyRoN)*_aG)T** zS=w56xp9Je9s9(Xlgf#eTco%D(kia3DG{`!93Zj}`w~ctG#dns-Hf`^yD%GFK5u5f zI8C>Tm%9Sr7h?mOi#D2Tpj;2a9D-oaqwep(eH^&o#gty8{f&7{dXgW|aswWT2GA%a z@dQ4)@)Zlj%l^60XbYvF;6U&N_~7q4;NoRUu}G_75KquldK*T54;cEK^maU4#>H1o z%#hPVi%>^qVJX&N#$H5u2flWTlXy-NEl1=`>yY-FG}J2DQ=Jg-UFfk4zpK$_j6+HodI{4voBkS=%R`z0Mz89>w=<;wBI4x0^l(f?q4*T`r!v1a+NI!gRc` zPR$9tIpcf9IJ;2wh$;;g;-=pTh2D!vZ`WZRVkjJ?Cu`@ zK|!klIU}ba;2jX~L9KE#Z^MkN0p6$aJ~u!c<2?)-KZ7OQ1A$-g>7;LlfSVv-OIcr9 zlRNvyvbr%o>JSuOiyhfh)UG*(`S~z}d`8FG3X?mKK8W(%F~*K)HY4KLZ;K>T;+j*K z-Akab-$7wBwS!tw^WwtnM^LG(4z~Kr`si=2Nt&wyglukJrb4donpdx+ z_fu>d?UL$v9BrFp@=}h@qsPlVskAu;$KseAo10%uh!&K7W^ejpac%Jk;&$)vuGB2o z%KZUl1!I=7Xoa@Ey_%Tcm$3<>8 zln|}ZvW`(7^s+jZ=$h?5x)VHH1s)!Ow)djP`|(?XF|fnSX>LIF1G?DTOmI$#Na` zD>4btt+RG52KWew6tt8CVW^O5)dtR2an{HJd^hj2p5!y?({);9-oy&(^AmfUlh2B9uOe= zd1!T#Uk-U%y8`RxCN;N&xgPyOWEijnTX43}~EL(CLyM!CK9H6lI^`7*z78o%$v(Sr`X-V`M|@A>4uv z;#4>&Q`?`e45d~J%D8LU*;pb`aA~%7T5SHTy&S$Uy(u{C`K1t>NJ$6fWr!7wRCM9p zg^7XJgwkM|zW5^i3Q%pj3@-n#Lx>F3Gs+0MA6$mX!gMuqXO}^CM;QL#t>2hephZ8@ zP^(gm`IB^aY=Vg;V7gD$ZMs2ZfxMj3!7+zsH=KxrYPuqa?^L;9MM*bZS&21KIY zZ~+~2qnfPEbVEqoLdFGf0h@oX6f``FQjxb&36Cu((*znp$NI7sp$+)Gch4Mx`Tk^7 z%4~FGHI9=b(wliNtl{o4@y9}7@Qi*gdC(Xzcp`6M>5mFp(SkCo)t$Z{HwHx8ITP?# z6>_Wmcj6lm_Dlu6;-@j&AmkR9Y>Q+qO_p)maR6M$MAO%l0As&?0X%^>@yK z1Kg$OJtl#?lIMv0Y`CD!blGg1a>2F8gpV;BFoVCzcixE{O@^8ydhv0)wLMR`)*{QZJFllKtFn`1}|15M0NGIi$~W`INkQm2NP{hEPI z<`$UdgL>;9QS;6#Mt*~M(#N3ra}crH3*2|GYyH5GYSX3p*}NGv9{{c6($YG&keAT_ zUIs2-Vz3bWt{5;{&`mkmYVYjyz`qfo{ zkcp<{l4^sp5#_TMfi^_#ou*G|J|+gu_=1wSoBpN7R~b}haG7ye2C#G9T+H$|?6Oy2 z1KL%wzGJWjRAUann}TJ)(O7?Mu8fS}E{yOe^Du7mUee+~S1mn+ygi)q7D8WC{JAYrsbFk`=hu;|%L1ap7rP1bya ziaDc5?HgGPCuvnx64p=c{}5V7G(W%g$CKLUIXSuYGle5WwTlO>%Gmob&YrWE+7AYc zdb{Zj*p2hoF!-Sbw=t?iWqnB>Is-k)b(I+Pepg?->!rkgR+g4@KY)#;j=$d^;OzsG zM-78`raRiO^iFJsAr>TjFf&XOq}mv0D?;i2kmy!c{*Q>a5dRXvf3(2$?3h;Y%8FF# zDuw&Hb&-M#=BMtsLLaCSQfVS2S%A`VzLJVzUjk`4nd(ek9yRW(fr7%%WPZ|^Bgkrf zDU=b$T>~gB2X%b2FKLjLmw2VLX*}h|3Ce5R, Notifable, Tab if let message = message { self?.chatInteraction.update({$0.withEditMessage(message)}) } else { - self?.chatInteraction.cancelEditing() + self?.chatInteraction.cancelEditing(true) } self?.chatInteraction.focusInputField() } diff --git a/Telegram-Mac/ChatHistoryEntry.swift b/Telegram-Mac/ChatHistoryEntry.swift index c999f46c8..8a27e6fe3 100644 --- a/Telegram-Mac/ChatHistoryEntry.swift +++ b/Telegram-Mac/ChatHistoryEntry.swift @@ -7,7 +7,7 @@ // import Cocoa - +import TGUIKit import Postbox import TelegramCore import SyncCore diff --git a/Telegram-Mac/ChatInterfaceInteraction.swift b/Telegram-Mac/ChatInterfaceInteraction.swift index c066070a0..714f0ed22 100644 --- a/Telegram-Mac/ChatInterfaceInteraction.swift +++ b/Telegram-Mac/ChatInterfaceInteraction.swift @@ -255,24 +255,27 @@ final class ChatInteraction : InterfaceObserver { return selectedRange.lowerBound ..< selectedRange.lowerBound + text.length } - func cancelEditing() { + func cancelEditing(_ force: Bool = false) { if let editState = self.presentation.interfaceState.editState { let oldState = ChatEditState(message: editState.message) - switch editState.loadingState { - case .loading, .progress: - editDisposable.set(nil) - self.update({$0.updatedInterfaceState({$0.updatedEditState({$0?.withUpdatedLoadingState(.none)})})}) - return - default: - if oldState != editState { - confirm(for: context.window, information: L10n.chatEditCancelText, okTitle: L10n.alertDiscard, cancelTitle: L10n.alertNO, successHandler: { [weak self] _ in - self?.update({$0.withoutEditMessage().updatedUrlPreview(nil)}) - }) - } else { - self.update({$0.withoutEditMessage().updatedUrlPreview(nil)}) + if force { + self.update({$0.withoutEditMessage().updatedUrlPreview(nil)}) + } else { + switch editState.loadingState { + case .loading, .progress: + editDisposable.set(nil) + self.update({$0.updatedInterfaceState({$0.updatedEditState({$0?.withUpdatedLoadingState(.none)})})}) + return + default: + if oldState != editState { + confirm(for: context.window, information: L10n.chatEditCancelText, okTitle: L10n.alertDiscard, cancelTitle: L10n.alertNO, successHandler: { [weak self] _ in + self?.update({$0.withoutEditMessage().updatedUrlPreview(nil)}) + }) + } else { + self.update({$0.withoutEditMessage().updatedUrlPreview(nil)}) + } } } - } } diff --git a/Telegram-Mac/ChatListController.swift b/Telegram-Mac/ChatListController.swift index 362c64c37..7191105fd 100644 --- a/Telegram-Mac/ChatListController.swift +++ b/Telegram-Mac/ChatListController.swift @@ -56,6 +56,13 @@ private func chatListFilterPredicate(for preset: ChatListFilterPreset?) -> ((Pee return false } } + + if !preset.includeCategories.contains(.secretChats) { + if let _ = peer as? TelegramSecretChat { + return false + } + } + if !preset.includeCategories.contains(.bots) { if let user = peer as? TelegramUser { if user.botInfo != nil { @@ -63,15 +70,27 @@ private func chatListFilterPredicate(for preset: ChatListFilterPreset?) -> ((Pee } } } - if !preset.includeCategories.contains(.groups) { + if !preset.includeCategories.contains(.privateGroups) { if let _ = peer as? TelegramGroup { return false } else if let channel = peer as? TelegramChannel { if case .group = channel.info { - return false + if channel.username == nil { + return false + } } } } + if !preset.includeCategories.contains(.publicGroups) { + if let channel = peer as? TelegramChannel { + if case .group = channel.info { + if channel.username != nil { + return false + } + } + } + } + if !preset.includeCategories.contains(.channels) { if let channel = peer as? TelegramChannel { if case .broadcast = channel.info { @@ -90,6 +109,7 @@ enum UIChatListEntryId : Hashable { case chatId(PeerId) case groupId(PeerGroupId) case reveal + case empty } struct ChatListInputActivity : Equatable { @@ -123,8 +143,8 @@ struct ChatListState: Equatable { enum UIChatListEntry : Identifiable, Comparable { case chat(ChatListEntry, [ChatListInputActivity], isSponsored: Bool) case group(Int, PeerGroupId, [ChatListGroupReferencePeer], Message?, PeerGroupUnreadCountersCombinedSummary, TotalUnreadCountDisplayCategory, Bool, HiddenArchiveStatus) - case reveal(ChatListFilterPreset?) - + case reveal([ChatListFilterPreset], ChatListFilterPreset?, [Int32: Int32]) + case empty(ChatListFilterPreset?) static func == (lhs: UIChatListEntry, rhs: UIChatListEntry) -> Bool { switch lhs { case let .chat(entry, activity, isSponsored): @@ -145,8 +165,14 @@ enum UIChatListEntry : Identifiable, Comparable { } else { return false } - case let .reveal(filter): - if case .reveal(filter) = rhs { + case let .reveal(filters, current, counters): + if case .reveal(filters, current, counters) = rhs { + return true + } else { + return false + } + case let .empty(filter): + if case .empty(filter) = rhs { return true } else { return false @@ -154,30 +180,32 @@ enum UIChatListEntry : Identifiable, Comparable { } } - - static func < (lhs: UIChatListEntry, rhs: UIChatListEntry) -> Bool { - switch lhs { - case let .chat(lhsEntry, _, _): - if case let .chat(rhsEntry, _, _) = rhs { - return lhsEntry < rhsEntry - } else { - return true - } - case let .group(lhsIndex, _, _, _, _, _, _, _): - if case let .group(rhsIndex, _, _, _, _, _, _, _) = rhs { - return lhsIndex < rhsIndex - } else { - return false + var index: ChatListIndex { + switch self { + case let .chat(entry, _, _): + switch entry { + case let .HoleEntry(hole): + return ChatListIndex(pinningIndex: nil, messageIndex: hole.index) + case let .MessageEntry(values): + return values.0 } case .reveal: - if case .reveal = rhs { - return false - } else { - return true + return ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex.absoluteUpperBound()) + case let .group(values): + var index = MessageIndex.absoluteUpperBound().predecessor() + for _ in 0 ..< values.0 { + index = index.predecessor() } + return ChatListIndex(pinningIndex: 0, messageIndex: index) + case .empty: + return ChatListIndex(pinningIndex: 0, messageIndex: MessageIndex.absoluteUpperBound().predecessor()) } } + static func < (lhs: UIChatListEntry, rhs: UIChatListEntry) -> Bool { + return lhs.index < rhs.index + } + var stableId: UIChatListEntryId { switch self { case let .chat(entry, _, _): @@ -186,6 +214,8 @@ enum UIChatListEntry : Identifiable, Comparable { return .groupId(groupId) case .reveal: return .reveal + case .empty: + return .empty } } @@ -193,7 +223,7 @@ enum UIChatListEntry : Identifiable, Comparable { -fileprivate func prepareEntries(from:[AppearanceWrapperEntry]?, to:[AppearanceWrapperEntry], adIndex: UInt16?, context: AccountContext, initialSize:NSSize, animated:Bool, scrollState:TableScrollState? = nil, groupId: PeerGroupId) -> Signal { +fileprivate func prepareEntries(from:[AppearanceWrapperEntry]?, to:[AppearanceWrapperEntry], adIndex: UInt16?, context: AccountContext, initialSize:NSSize, animated:Bool, scrollState:TableScrollState? = nil, groupId: PeerGroupId, setupFilter: @escaping(ChatListFilterPreset?)->Void, openFilterSettings: @escaping()->Void) -> Signal { return Signal { subscriber in @@ -216,12 +246,10 @@ fileprivate func prepareEntries(from:[AppearanceWrapperEntry]?, } case let .group(_, groupId, peers, message, unreadState, unreadCountDisplayCategory, animated, archiveStatus): return ChatListRowItem(initialSize, context: context, pinnedType: .none, groupId: groupId, peers: peers, message: message, unreadState: unreadState, unreadCountDisplayCategory: unreadCountDisplayCategory, animateGroup: animated, archiveStatus: archiveStatus) - case .reveal: - return ChatListRevealItem(initialSize, context: context, action: { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withUpdatedCurrentPreset(nil) - }).start() - }) + case let .reveal(tabs, selected, counters): + return ChatListRevealItem(initialSize, context: context, tabs: tabs, selected: selected, counters: counters, action: setupFilter, openSettings: openFilterSettings) + case let .empty(filter): + return ChatListEmptyRowItem(initialSize, stableId: entry.stableId, filter: filter, context: context, openFilterSettings: openFilterSettings) } } @@ -281,17 +309,32 @@ enum HiddenArchiveStatus : Equatable { } } +private struct FilterData : Equatable { + let filter: ChatListFilterPreset? + let tabs: [ChatListFilterPreset] + init(filter: ChatListFilterPreset?, tabs: [ChatListFilterPreset]) { + self.filter = filter + self.tabs = tabs + } + func withUpdatedFilter(_ filter: ChatListFilterPreset?) -> FilterData { + return FilterData(filter: filter, tabs: self.tabs) + } + func withUpdatedTabs(_ tabs: [ChatListFilterPreset]) -> FilterData { + return FilterData(filter: self.filter, tabs: tabs) + } +} + class ChatListController : PeersListController { - private let filter = ValuePromise(ignoreRepeated: true) - private let _filterValue = Atomic(value: nil) - var filterValue: ChatListFilterPreset? { + private let filter = ValuePromise(ignoreRepeated: true) + private let _filterValue = Atomic(value: FilterData(filter: nil, tabs: [])) + private var filterValue: FilterData? { return _filterValue.with { $0 } } - private func setPreset(_ value: ChatListFilterPreset?) { - filter.set(_filterValue.modify( { _ in return value })) + private func updateFilter(_ f:(FilterData)->FilterData) { + filter.set(_filterValue.modify(f)) _ = first.swap(true) - self.request.set(.single(.Initial(50, .up(true)))) + setCenterTitle(self.defaultBarTitle) } private let request = Promise() @@ -341,8 +384,6 @@ class ChatListController : PeersListController { statePromise.set(stateValue.modify(f)) } - genericView.tableView.emptyItem = ChatListEmptyRowItem(frame.size, context: context) - let postbox = context.account.postbox let previousPeerCache = Atomic<[PeerId: Peer]>(value: [:]) @@ -436,25 +477,33 @@ class ChatListController : PeersListController { let signal = combineLatest(request.get() |> distinctUntilChanged, filter.get()) - let chatHistoryView: Signal<(ChatListView, ViewUpdateType, Bool, ChatListFilterPreset?), NoError> = signal |> mapToSignal { location, preset -> Signal<(ChatListView, ViewUpdateType, Bool, ChatListFilterPreset?), NoError> in + let chatHistoryView: Signal<(ChatListView, ViewUpdateType, Bool, FilterData), NoError> = signal |> mapToSignal { location, data -> Signal<(ChatListView, ViewUpdateType, Bool, FilterData), NoError> in var signal:Signal<(ChatListView,ViewUpdateType), NoError> var removeNextAnimation: Bool = false switch location { case let .Initial(count, st): - signal = context.account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: chatListFilterPredicate(for: preset), count: count) + signal = context.account.viewTracker.tailChatListView(groupId: groupId, filterPredicate: chatListFilterPredicate(for: data.filter), count: count) scroll = st case let .Index(index, st): - signal = context.account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: chatListFilterPredicate(for: preset), index: index, count: 50) + signal = context.account.viewTracker.aroundChatListView(groupId: groupId, filterPredicate: chatListFilterPredicate(for: data.filter), index: index, count: 150) scroll = st removeNextAnimation = st != nil } - return signal |> map { ($0.0, $0.1, removeNextAnimation, preset)} + return signal |> map { ($0.0, $0.1, removeNextAnimation, data)} } - + let setupFilter:(ChatListFilterPreset?)->Void = { [weak self] filter in + self?.updateFilter { + $0.withUpdatedFilter(filter) + } + self?.scrollup() + } + let openFilterSettings:()->Void = { + context.sharedContext.bindings.rootNavigation().push(ChatListPresetListController(context: context)) + } - let list:Signal = combineLatest(queue: prepareQueue, chatHistoryView, appearanceSignal, statePromise.get(), context.chatUndoManager.allStatuses(), hiddenArchiveState.get(), appNotificationSettings(accountManager: context.sharedContext.accountManager)) |> mapToQueue { value, appearance, state, undoStatuses, archiveIsHidden, inAppSettings -> Signal in + let list:Signal = combineLatest(queue: prepareQueue, chatHistoryView, appearanceSignal, statePromise.get(), context.chatUndoManager.allStatuses(), hiddenArchiveState.get(), appNotificationSettings(accountManager: context.sharedContext.accountManager), filtersBadgeCounters(context: context)) |> mapToQueue { value, appearance, state, undoStatuses, archiveIsHidden, inAppSettings, filtersCounter -> Signal in var removeNextAnimation = value.2 @@ -486,21 +535,39 @@ class ChatListController : PeersListController { return .chat($0, state.activities.activities[$0.index.messageIndex.id.peerId] ?? [], isSponsored: $1) } - if value.3 != nil, mapped.isEmpty {} else { + if value.3.filter != nil, mapped.isEmpty {} else { if value.0.laterIndex == nil { for (i, group) in value.0.groupEntries.reversed().enumerated() { mapped.append(.group(i, group.groupId, group.renderedPeers, group.message, group.unreadState, inAppSettings.totalUnreadCountDisplayCategory, animateGroupNextTransition.swap(nil) == group.groupId, archiveIsHidden)) } } - - if value.3 != nil { - mapped.append(.reveal(value.3)) + } + + + if mapped.isEmpty { + let hasHole = !value.0.entries.filter({ value in + switch value { + case .HoleEntry: + return true + default: + return false + } + }).isEmpty + if !hasHole { + mapped.append(.empty(value.3.filter)) } } - + if !value.3.tabs.isEmpty { + let dict:[Int32: Int32] = filtersCounter.reduce([:], { current, value in + var current = current + current[value.id] = value.count + return current + }) + mapped.append(.reveal(value.3.tabs, value.3.filter, dict)) + } - let entries = mapped.compactMap { entry -> AppearanceWrapperEntry? in + let entries = mapped.sorted().compactMap { entry -> AppearanceWrapperEntry? in switch entry { case let .chat(inner, activities, isSponsored): switch inner { @@ -526,6 +593,8 @@ class ChatListController : PeersListController { return AppearanceWrapperEntry(entry: entry, appearance: appearance) case .reveal: return AppearanceWrapperEntry(entry: entry, appearance: appearance) + case .empty: + return AppearanceWrapperEntry(entry: entry, appearance: appearance) } } @@ -535,7 +604,7 @@ class ChatListController : PeersListController { // if value.3 != previousFilter.swap(value.3) { // animated = false // } - return prepareEntries(from: prev, to: entries, adIndex: nil, context: context, initialSize: initialSize.modify({$0}), animated: animated, scrollState: scroll, groupId: groupId) + return prepareEntries(from: prev, to: entries, adIndex: nil, context: context, initialSize: initialSize.with { $0 }, animated: animated, scrollState: scroll, groupId: groupId, setupFilter: setupFilter, openFilterSettings: openFilterSettings) } @@ -627,23 +696,48 @@ class ChatListController : PeersListController { let filterView = chatListFilterPreferences(postbox: context.account.postbox) |> deliverOnMainQueue switch mode { case .folder: - self.setPreset(nil) + self.updateFilter( { + $0.withUpdatedTabs([]).withUpdatedFilter(nil) + } ) + case let .filter(filterId): + filterDisposable.set(filterView.start(next: { [weak self] settings in + var shouldBack: Bool = false + self?.updateFilter { current in + var current = current + if let updated = settings.presets.first(where: { $0.uniqueId == filterId }) { + current = current.withUpdatedFilter(updated) + } else { + shouldBack = true + current = current.withUpdatedFilter(nil) + } + current = current.withUpdatedTabs([]) + return current + } + if shouldBack { + self?.navigationController?.back() + } + })) default: filterDisposable.set(filterView.start(next: { [weak self] settings in - self?.setPreset(settings.current) + self?.updateFilter( { current in + var current = current + if let filter = current.filter { + if let updated = settings.presets.first(where: { $0.uniqueId == filter.uniqueId }) { + current = current.withUpdatedFilter(updated) + } else { + current = current.withUpdatedFilter(nil) + } + } + + if settings.tabsIsEnabled { + current = current.withUpdatedTabs(settings.presets) + } else { + current = current.withUpdatedTabs([]).withUpdatedFilter(nil) + } + return current + } ) })) } - - -// return account.postbox.unreadMessageCountsView(items: items) |> map { view in -// var totalCount:Int32 = 0 -// if let total = view.count(for: .total(value, .messages)) { -// totalCount = total -// } -// -// return (view, totalCount) -// } - } func collapseOrExpandArchive() { @@ -797,14 +891,17 @@ class ChatListController : PeersListController { let view = self.previousChatList.with { $0 } if self.genericView.tableView.contentOffset.y == 0, view?.laterIndex == nil { - if filterValue != nil { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withUpdatedCurrentPreset(nil) - }).start() + switch mode { + case .folder: + navigationController?.back() return + case .filter: + navigationController?.back() + return + case .plain: + break } - navigationController?.back() - return + } @@ -860,39 +957,22 @@ class ChatListController : PeersListController { return chatListFilterPreferences(postbox: context.account.postbox) |> take(1) |> deliverOnMainQueue - |> map { settings -> [SPopoverItem] in + |> map { [weak self] settings -> [SPopoverItem] in var items:[SPopoverItem] = [] + items.append(SPopoverItem(L10n.chatListFilterSetup, { context.sharedContext.bindings.rootNavigation().push(ChatListPresetListController(context: context)) - }, theme.icons.peerInfoAddMember)) + }, theme.icons.chat_filter_add)) if !settings.presets.isEmpty { - if (settings.presets.count == 1 && settings.presets.first == settings.current) || settings.presets.count > 1 { - items.append(SPopoverItem()) + if (settings.presets.count == 1 && settings.presets.first != self?.filterValue?.filter) || settings.presets.count > 1 { + items.append(SPopoverItem(false)) } } - if settings.current != nil { - - let badge = GlobalBadgeNode(context.account, sharedContext: context.sharedContext, view: View(), layoutChanged: { - - }, getColor: { isSelected in - return isSelected ? .white : theme.colors.accent - }, applyFilter: false) - let additionView: SPopoverAdditionItemView = SPopoverAdditionItemView(context: badge, view: badge.view!, updateIsSelected: { [weak badge] isSelected in - badge?.isSelected = isSelected - }) - - items.append(SPopoverItem(L10n.chatListFilterAll, { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withUpdatedCurrentPreset(nil) - }).start() - }, generateTextIcon(.initialize(string: settings.shortcut(for: nil), color: theme.colors.accent, font: .medium(.text))), additionView: additionView)) - } - for preset in settings.presets { - if preset.uniqueId != settings.current?.uniqueId { + if preset.uniqueId != self?.filterValue?.filter?.uniqueId { let badge = GlobalBadgeNode(context.account, sharedContext: context.sharedContext, view: View(), layoutChanged: { }, getColor: { isSelected in @@ -902,11 +982,18 @@ class ChatListController : PeersListController { badge?.isSelected = isSelected }) - items.append(SPopoverItem(preset.title, { - _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withUpdatedCurrentPreset(preset) - }).start() - }, generateTextIcon(.initialize(string: settings.shortcut(for: preset), color: theme.colors.accent, font: .medium(.text))), additionView: additionView)) + items.append(SPopoverItem(preset.title, { [weak self] in + guard let `self` = self else { + return + } + if settings.tabsIsEnabled { + self.updateFilter { + $0.withUpdatedFilter(preset) + } + } else { + self.navigationController?.push(ChatListController(context, modal: false, filterId: preset.uniqueId)) + } + }, preset.icon, additionView: additionView)) } } return items @@ -977,7 +1064,7 @@ class ChatListController : PeersListController { switch direction { case let .left(_state): - if self.mode.isFolder && checkFolder { + if !self.mode.isPlain && checkFolder { swipeState = nil } else { swipeState = _state @@ -1142,6 +1229,26 @@ class ChatListController : PeersListController { } } + override var removeAfterDisapper: Bool { + switch self.mode { + case .plain: + return false + default: + return true + } + } + + override func backSettings() -> (String, CGImage?) { + switch self.mode { + case .plain: + return super.backSettings() + case .folder: + return (L10n.chatListArchiveBack, super.backSettings().1) + case .filter: + return (L10n.chatListFilterBack, super.backSettings().1) + } + } + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) context.window.removeAllHandlers(for: self) @@ -1168,29 +1275,47 @@ class ChatListController : PeersListController { override var enableBack: Bool { - return mode.groupId != .root + switch mode { + case .folder, .filter: + return true + default: + return false + } } override var defaultBarTitle: String { - switch mode.groupId { - case .root: + switch mode { + case .plain: return super.defaultBarTitle - default: + case .folder: return L10n.chatListArchivedChats + case .filter: + return _filterValue.with { $0.filter?.title ?? "Filter" } } } override func escapeKeyAction() -> KeyHandlerResult { - if mode.isFolder, let navigation = navigationController { + if !mode.isPlain, let navigation = navigationController { navigation.back() return .invoked } return super.escapeKeyAction() } - init(_ context: AccountContext, modal:Bool = false, groupId: PeerGroupId? = nil) { + + init(_ context: AccountContext, modal:Bool = false, groupId: PeerGroupId? = nil, filterId: Int32? = nil) { self.undoTooltipControl = UndoTooltipControl(context: context) - super.init(context, followGlobal:!modal, mode: groupId != nil ? .folder(groupId!) : .plain) + + let mode: PeerListMode + if let filterId = filterId { + mode = .filter(filterId) + } else if let groupId = groupId { + mode = .folder(groupId) + } else { + mode = .plain + } + + super.init(context, followGlobal: !modal, mode: mode) if groupId != nil { context.closeFolderFirst = true diff --git a/Telegram-Mac/ChatListEmptyRowItem.swift b/Telegram-Mac/ChatListEmptyRowItem.swift index 29ba75a55..7babc0dc5 100644 --- a/Telegram-Mac/ChatListEmptyRowItem.swift +++ b/Telegram-Mac/ChatListEmptyRowItem.swift @@ -12,20 +12,32 @@ import SwiftSignalKit import Postbox class ChatListEmptyRowItem: TableRowItem { - private let _stableId: UInt32 = arc4random() + private let _stableId: AnyHashable override var stableId: AnyHashable { return _stableId } let context: AccountContext - init(_ initialSize: NSSize, context: AccountContext) { + let filter: ChatListFilterPreset? + let openFilterSettings: ()->Void + init(_ initialSize: NSSize, stableId: AnyHashable, filter: ChatListFilterPreset?, context: AccountContext, openFilterSettings: @escaping()->Void) { self.context = context + self.filter = filter + self._stableId = stableId + self.openFilterSettings = openFilterSettings super.init(initialSize) } override var height: CGFloat { if let table = table { - return table.frame.height + var tableHeight: CGFloat = 0 + table.enumerateItems { item -> Bool in + if item.index < self.index { + tableHeight += item.height + } + return true + } + return table.frame.height - tableHeight } return initialSize.height } @@ -40,30 +52,34 @@ private class ChatListEmptyRowView : TableRowView { private let disposable = MetaDisposable() private let textView = TextView() private let separator = View() - private var preset: ChatListFilterPreset? = nil { - didSet { - if preset != oldValue { - needsLayout = true - } - } - } + private let sticker: MediaAnimatedStickerView = MediaAnimatedStickerView(frame: NSZeroRect) required init(frame frameRect: NSRect) { super.init(frame: frameRect) addSubview(textView) textView.isSelectable = false addSubview(separator) + addSubview(sticker) } override func set(item: TableRowItem, animated: Bool = false) { super.set(item: item, animated: animated) - if let item = item as? ChatListEmptyRowItem { - let signal = chatListFilterPreferences(postbox: item.context.account.postbox) |> deliverOnMainQueue - disposable.set(signal.start(next: { [weak self] settings in - self?.preset = settings.current - })) + + guard let item = item as? ChatListEmptyRowItem else { + return } + + let animatedSticker: LocalAnimatedSticker + + if let _ = item.filter { + animatedSticker = .think_spectacular + } else { + animatedSticker = .chiken_born + } + sticker.update(with: animatedSticker.file, size: NSMakeSize(112, 112), context: item.context, parent: nil, table: item.table, parameters: animatedSticker.parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: false) + + needsLayout = true } deinit { @@ -76,27 +92,30 @@ private class ChatListEmptyRowView : TableRowView { separator.background = theme.colors.border + guard let item = item as? ChatListEmptyRowItem else { + return + } + + let text: String - if let _ = self.preset { + if let _ = item.filter { text = L10n.chatListFilterEmpty } else { text = L10n.chatListEmptyText } - let attr = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: .normal(.text), textColor: theme.colors.grayText), bold: MarkdownAttributeSet(font: .bold(.text), textColor: theme.colors.grayText), link: MarkdownAttributeSet(font: .normal(.text), textColor: theme.colors.link), linkAttribute: { [weak self] contents in - return (NSAttributedString.Key.link.rawValue, inAppLink.callback(contents, { [weak self] _ in - guard let item = self?.item as? ChatListEmptyRowItem else { - return + let attr = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: .normal(.title), textColor: theme.colors.text), bold: MarkdownAttributeSet(font: .medium(.title), textColor: theme.colors.text), link: MarkdownAttributeSet(font: .normal(.title), textColor: theme.colors.link), linkAttribute: { [weak item] contents in + return (NSAttributedString.Key.link.rawValue, inAppLink.callback(contents, { [weak item] value in + if value == "filter" { + item?.openFilterSettings() } - _ = updateChatListFilterPreferencesInteractively(postbox: item.context.account.postbox, { - $0.withUpdatedCurrentPreset(nil) - }).start() + })) })).mutableCopy() as! NSMutableAttributedString - attr.detectBoldColorInString(with: .bold(.text)) + attr.detectBoldColorInString(with: .medium(.title)) let layout = TextViewLayout(attr, alignment: .center) @@ -106,8 +125,11 @@ private class ChatListEmptyRowView : TableRowView { textView.center() textView.isHidden = frame.width <= 70 + sticker.isHidden = frame.width <= 70 separator.frame = NSMakeRect(frame.width - .borderSize, 0, .borderSize, frame.height) + + sticker.centerX(y: textView.frame.minY - sticker.frame.height - 20) } required init?(coder: NSCoder) { diff --git a/Telegram-Mac/ChatListFilterPreferences.swift b/Telegram-Mac/ChatListFilterPreferences.swift index fe38123d5..b2663a5d2 100644 --- a/Telegram-Mac/ChatListFilterPreferences.swift +++ b/Telegram-Mac/ChatListFilterPreferences.swift @@ -16,7 +16,9 @@ public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding { case unmuted case unread case channels - case groups + case publicGroups + case privateGroups + case secretChats case privateChats case bots case custom(String) @@ -30,10 +32,14 @@ public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding { case 2: self = .privateChats case 3: - self = .groups + self = .publicGroups case 4: - self = .bots + self = .privateGroups case 5: + self = .secretChats + case 6: + self = .bots + case 7: self = .unread case 10: self = .custom(decoder.decodeStringForKey("title", orElse: "Preset")) @@ -51,12 +57,16 @@ public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding { encoder.encodeInt32(1, forKey: "_t") case .privateChats: encoder.encodeInt32(2, forKey: "_t") - case .groups: + case .publicGroups: encoder.encodeInt32(3, forKey: "_t") - case .bots: + case .privateGroups: encoder.encodeInt32(4, forKey: "_t") - case .unread: + case .secretChats: encoder.encodeInt32(5, forKey: "_t") + case .bots: + encoder.encodeInt32(6, forKey: "_t") + case .unread: + encoder.encodeInt32(7, forKey: "_t") case let .custom(title): encoder.encodeInt32(10, forKey: "_t") encoder.encodeString(title, forKey: "title") @@ -70,8 +80,12 @@ public enum ChatListFilterPresetName: Equatable, Hashable, PostboxCoding { return L10n.chatListFilterUnmutedChats case .channels: return L10n.chatListFilterChannels - case .groups: - return L10n.chatListFilterGroups + case .publicGroups: + return L10n.chatListFilterPublicGroups + case .privateGroups: + return L10n.chatListFilterPrivateGroups + case .secretChats: + return L10n.chatListFilterSecretChat case .privateChats: return L10n.chatListFilterPrivateChats case .unread: @@ -118,7 +132,54 @@ struct ChatListFilterPreset: Equatable, PostboxCoding { return name.title } var desc: String { - return self.includeCategories.string + var text: String = L10n.chatListFilterDescCustomized + if includeCategories == [.muted, .read] { + return "\(self.additionallyIncludePeers.count)" + } else if includeCategories == ._unmuted { + text = L10n.chatListFilterDescUnmuted + } else if includeCategories == ._unread { + text = L10n.chatListFilterDescUnread + } else if includeCategories == ._privateChats { + text = L10n.chatListFilterDescPrivateChats + } else if includeCategories == ._groups { + text = L10n.chatListFilterDescGroups + } else if includeCategories == ._privateGroups { + text = L10n.chatListFilterDescPrivateGroups + } else if includeCategories == ._publicGroups { + text = L10n.chatListFilterDescPublicGroups + } else if includeCategories == ._channels { + text = L10n.chatListFilterDescChannels + } else if includeCategories == ._bots { + text = L10n.chatListFilterDescBots + } else if includeCategories == ._secretChats { + text = L10n.chatListFilterDescSecretChats + } + + if !self.additionallyIncludePeers.isEmpty { + text = ", +\(self.additionallyIncludePeers.count)" + } + return text + } + + var icon: CGImage { + + if includeCategories == ._unmuted { + return theme.icons.chat_filter_unmuted + } else if includeCategories == ._unread { + return theme.icons.chat_filter_unread + } else if includeCategories == ._groups || includeCategories == ._publicGroups || includeCategories == ._privateGroups { + return theme.icons.chat_filter_groups + } else if includeCategories == ._channels { + return theme.icons.chat_filter_channels + } else if includeCategories == ._privateChats { + return theme.icons.chat_filter_private_chats + } else if includeCategories == ._bots { + return theme.icons.chat_filter_bots + } else if includeCategories == ._secretChats { + return theme.icons.chat_filter_secret_chats + } + + return theme.icons.chat_filter_custom } static var new: ChatListFilterPreset { @@ -163,21 +224,27 @@ struct ChatListFilter: OptionSet { static let muted = ChatListFilter(rawValue: 1 << 1) static let privateChats = ChatListFilter(rawValue: 1 << 2) - static let groups = ChatListFilter(rawValue: 1 << 3) - static let bots = ChatListFilter(rawValue: 1 << 4) - static let channels = ChatListFilter(rawValue: 1 << 5) - static let read = ChatListFilter(rawValue: 1 << 6) + static let publicGroups = ChatListFilter(rawValue: 1 << 3) + static let privateGroups = ChatListFilter(rawValue: 1 << 4) + static let secretChats = ChatListFilter(rawValue: 1 << 5) + static let bots = ChatListFilter(rawValue: 1 << 6) + static let channels = ChatListFilter(rawValue: 1 << 7) + static let read = ChatListFilter(rawValue: 1 << 8) static let all: ChatListFilter = [ .muted, .privateChats, - .groups, + .privateGroups, + .publicGroups, + .secretChats, .bots, .channels, .read ] - static let _workMode: ChatListFilter = [ + static let _unmuted: ChatListFilter = [ .privateChats, - .groups, + .privateGroups, + .publicGroups, + .secretChats, .bots, .channels, .read] @@ -185,7 +252,9 @@ struct ChatListFilter: OptionSet { static let _unread: ChatListFilter = [ .muted, .privateChats, - .groups, + .privateChats, + .privateGroups, + .secretChats, .bots, .channels] @@ -196,7 +265,23 @@ struct ChatListFilter: OptionSet { ] static let _groups: ChatListFilter = [ .muted, - .groups, + .publicGroups, + .privateGroups, + .read + ] + static let _privateGroups: ChatListFilter = [ + .muted, + .privateGroups, + .read + ] + static let _publicGroups: ChatListFilter = [ + .muted, + .publicGroups, + .read + ] + static let _secretChats: ChatListFilter = [ + .muted, + .secretChats, .read ] static let _privateChats: ChatListFilter = [ @@ -215,9 +300,9 @@ struct ChatListFilter: OptionSet { } struct ChatListFilterPreferences: PreferencesEntry, Equatable { - let current: ChatListFilterPreset? let presets: [ChatListFilterPreset] let needShowTooltip: Bool + let tabsIsEnabled: Bool static var defaultSettings: ChatListFilterPreferences { var presets: [ChatListFilterPreset] = [] @@ -226,31 +311,27 @@ struct ChatListFilterPreferences: PreferencesEntry, Equatable { // presets.append(ChatListFilterPreset(name: .groups, includeCategories: ._groups, additionallyIncludePeers: [], uniqueId: 2)) // presets.append(ChatListFilterPreset(name: .bots, includeCategories: ._bots, additionallyIncludePeers: [], uniqueId: 3)) presets.append(ChatListFilterPreset(name: .unread, includeCategories: ._unread, additionallyIncludePeers: [], applyReadMutedForExceptions: false, uniqueId: 4)) - presets.append(ChatListFilterPreset(name: .unmuted, includeCategories: ._workMode, additionallyIncludePeers: [], applyReadMutedForExceptions: false, uniqueId: 5)) + presets.append(ChatListFilterPreset(name: .unmuted, includeCategories: ._unmuted, additionallyIncludePeers: [], applyReadMutedForExceptions: false, uniqueId: 5)) - return ChatListFilterPreferences(current: nil, presets: presets, needShowTooltip: true) + return ChatListFilterPreferences(presets: presets, needShowTooltip: true, tabsIsEnabled: false) } - init(current: ChatListFilterPreset?, presets: [ChatListFilterPreset], needShowTooltip: Bool) { - self.current = current + init(presets: [ChatListFilterPreset], needShowTooltip: Bool, tabsIsEnabled: Bool) { self.presets = presets self.needShowTooltip = needShowTooltip + self.tabsIsEnabled = tabsIsEnabled } init(decoder: PostboxDecoder) { - self.current = decoder.decodeObjectForKey("current") as? ChatListFilterPreset self.presets = decoder.decodeObjectArrayWithDecoderForKey("presets") self.needShowTooltip = decoder.decodeBoolForKey("needShowTooltip", orElse: true) + self.tabsIsEnabled = decoder.decodeBoolForKey("tabsIsEnabled", orElse: true) } func encode(_ encoder: PostboxEncoder) { - if let current = current { - encoder.encodeObject(current, forKey: "current") - } else { - encoder.encodeNil(forKey: "current") - } encoder.encodeObjectArray(self.presets, forKey: "presets") encoder.encodeBool(self.needShowTooltip, forKey: "needShowTooltip") + encoder.encodeBool(self.tabsIsEnabled, forKey: "tabsIsEnabled") } func isEqual(to: PreferencesEntry) -> Bool { @@ -262,12 +343,9 @@ struct ChatListFilterPreferences: PreferencesEntry, Equatable { } static func ==(lhs: ChatListFilterPreferences, rhs: ChatListFilterPreferences) -> Bool { - return lhs.current == rhs.current && lhs.presets == rhs.presets && lhs.needShowTooltip == rhs.needShowTooltip + return lhs.presets == rhs.presets && lhs.needShowTooltip == rhs.needShowTooltip && lhs.tabsIsEnabled == rhs.tabsIsEnabled } - func withUpdatedCurrentPreset(_ current: ChatListFilterPreset?) -> ChatListFilterPreferences { - return ChatListFilterPreferences(current: current, presets: self.presets, needShowTooltip: false) - } func withAddedPreset(_ preset: ChatListFilterPreset, onlyReplace: Bool = false) -> ChatListFilterPreferences { var presets = self.presets if let index = presets.firstIndex(where: {$0.uniqueId == preset.uniqueId}) { @@ -275,40 +353,30 @@ struct ChatListFilterPreferences: PreferencesEntry, Equatable { } else if !onlyReplace { presets.append(preset) } - var current = self.current - if current?.uniqueId == preset.uniqueId { - current = preset - } - return ChatListFilterPreferences(current: current, presets: presets, needShowTooltip: false) + return ChatListFilterPreferences(presets: presets, needShowTooltip: false, tabsIsEnabled: self.tabsIsEnabled) } func withRemovedPreset(_ preset: ChatListFilterPreset) -> ChatListFilterPreferences { var presets = self.presets presets.removeAll(where: {$0.uniqueId == preset.uniqueId }) - var current = self.current - if current?.uniqueId == preset.uniqueId { - current = nil - } - return ChatListFilterPreferences(current: current, presets: presets, needShowTooltip: false) + return ChatListFilterPreferences(presets: presets, needShowTooltip: false, tabsIsEnabled: self.tabsIsEnabled) } func withMovePreset(_ from: Int, _ to: Int) -> ChatListFilterPreferences { var presets = self.presets presets.insert(presets.remove(at: from), at: to) - return ChatListFilterPreferences(current: self.current, presets: presets, needShowTooltip: false) + return ChatListFilterPreferences(presets: presets, needShowTooltip: false, tabsIsEnabled: self.tabsIsEnabled) } func withSelectedAtIndex(_ index: Int) -> ChatListFilterPreferences { - var current = self.current - if index < self.presets.count { - current = self.presets[index] - } - return ChatListFilterPreferences(current: current, presets: self.presets, needShowTooltip: false) + return ChatListFilterPreferences(presets: self.presets, needShowTooltip: false, tabsIsEnabled: self.tabsIsEnabled) } func withUpdatedNeedShowTooltip(_ needShowTooltip: Bool) -> ChatListFilterPreferences { - return ChatListFilterPreferences(current: self.current, presets: self.presets, needShowTooltip: needShowTooltip) + return ChatListFilterPreferences(presets: self.presets, needShowTooltip: needShowTooltip, tabsIsEnabled: self.tabsIsEnabled) + } + func withUpdatedTabEnable(_ tabsIsEnabled: Bool) -> ChatListFilterPreferences { + return ChatListFilterPreferences(presets: self.presets, needShowTooltip: self.needShowTooltip, tabsIsEnabled: tabsIsEnabled) } - func shortcut(for preset: ChatListFilterPreset?) -> String { if let preset = preset { for (i, value) in self.presets.enumerated() { @@ -347,3 +415,134 @@ func updateChatListFilterPreferencesInteractively(postbox: Postbox, _ f: @escapi }) } } + + + +func filtersBadgeCounters(context: AccountContext) -> Signal<[(id: Int32, count: Int32)], NoError> { + return chatListFilterPreferences(postbox: context.account.postbox) |> map { $0.presets } |> mapToSignal { filters -> Signal<[(id: Int32, count: Int32)], NoError> in + + var signals:[Signal<(id: Int32, count: Int32), NoError>] = [] + for current in filters { + + var unreadCountItems: [UnreadMessageCountsItem] = [] + unreadCountItems.append(.total(nil)) + var keys: [PostboxViewKey] = [] + let unreadKey: PostboxViewKey + + if !current.additionallyIncludePeers.isEmpty { + for peerId in current.additionallyIncludePeers { + unreadCountItems.append(.peer(peerId)) + } + } + unreadKey = .unreadCounts(items: unreadCountItems) + keys.append(unreadKey) + for peerId in current.additionallyIncludePeers { + keys.append(.basicPeer(peerId)) + + } + keys.append(.peerNotificationSettings(peerIds: Set(current.additionallyIncludePeers))) + + let s:Signal<(id: Int32, count: Int32), NoError> = combineLatest(context.account.postbox.combinedView(keys: keys), appNotificationSettings(accountManager: context.sharedContext.accountManager)) |> map { keysView, inAppSettings -> (id: Int32, count: Int32) in + + if let unreadCounts = keysView.views[unreadKey] as? UnreadMessageCountsView { + var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int)] = [:] + var totalState: ChatListTotalUnreadState? + for entry in unreadCounts.entries { + switch entry { + case let .total(_, totalStateValue): + totalState = totalStateValue + case let .peer(peerId, state): + if let state = state, state.isUnread { + let notificationSettings = keysView.views[.peerNotificationSettings(peerIds: Set(current.additionallyIncludePeers))] as? PeerNotificationSettingsView + if let peerView = keysView.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer { + let tag = context.account.postbox.seedConfiguration.peerSummaryCounterTags(peer) + var peerCount = Int(state.count) + let isRemoved = notificationSettings?.notificationSettings[peerId]?.isRemovedFromTotalUnreadCount ?? false + var removable = false + switch inAppSettings.totalUnreadCountDisplayStyle { + case .raw: + removable = true + case .filtered: + if !isRemoved { + removable = true + } + } + if !current.includeCategories.contains(.muted), isRemoved { + removable = false + } + if removable, state.isUnread { + switch inAppSettings.totalUnreadCountDisplayCategory { + case .chats: + peerCount = 1 + case .messages: + peerCount = max(1, peerCount) + } + peerTagAndCount[peerId] = (tag, peerCount) + } + + } + } + } + } + + var tags: [PeerSummaryCounterTags] = [] + if current.includeCategories.contains(.privateChats) { + tags.append(.privateChat) + } + + if current.includeCategories.contains(.publicGroups) { + tags.append(.publicGroup) + } + if current.includeCategories.contains(.privateGroups) { + tags.append(.privateGroup) + } + if current.includeCategories.contains(.secretChats) { + tags.append(.secretChat) + } + if current.includeCategories.contains(.bots) { + tags.append(.bot) + } + if current.includeCategories.contains(.channels) { + tags.append(.channel) + } + + var count:Int32 = 0 + if let totalState = totalState { + for tag in tags { + + if let value = totalState.filteredCounters[tag] { + var removable = false + switch inAppSettings.totalUnreadCountDisplayStyle { + case .raw: + removable = true + case .filtered: + removable = true + } + if removable { + switch inAppSettings.totalUnreadCountDisplayCategory { + case .chats: + count += value.chatCount + case .messages: + count += value.messageCount + } + } + } + } + } + for peerId in current.additionallyIncludePeers { + if let (tag, peerCount) = peerTagAndCount[peerId] { + if !tags.contains(tag) { + count += Int32(peerCount) + } + } + } + return (id: current.uniqueId, count: count) + } else { + return (id: current.uniqueId, count: 0) + } + } + signals.append(s) + } + return combineLatest(signals) + } +} diff --git a/Telegram-Mac/ChatListPresetController.swift b/Telegram-Mac/ChatListPresetController.swift index 001baebc6..ba1a031fb 100644 --- a/Telegram-Mac/ChatListPresetController.swift +++ b/Telegram-Mac/ChatListPresetController.swift @@ -69,7 +69,12 @@ private final class ChatListPresetArguments { private let _id_name_input = InputDataIdentifier("_id_name_input") private let _id_private_chats = InputDataIdentifier("_id_private_chats") -private let _id_groups = InputDataIdentifier("_id_groups") + +private let _id_public_groups = InputDataIdentifier("_id_public_groups") +private let _id_private_groups = InputDataIdentifier("_id_private_groups") +private let _id_secret_chats = InputDataIdentifier("_id_secret_chats") + + private let _id_channels = InputDataIdentifier("_id_channels") private let _id_bots = InputDataIdentifier("_id_bots") private let _id_exclude_muted = InputDataIdentifier("_id_exclude_muted") @@ -91,22 +96,33 @@ private func chatListPresetEntries(state: ChatListPresetState, peers: [Peer], ar entries.append(.sectionId(sectionId, type: .normal)) sectionId += 1 - entries.append(.desc(sectionId: sectionId, index: index, text: .plain("NAME"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) + entries.append(.desc(sectionId: sectionId, index: index, text: .plain("FILTER NAME"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) index += 1 - entries.append(.input(sectionId: sectionId, index: index, value: .string(state.preset.title), error: nil, identifier: _id_name_input, mode: .plain, data: .init(viewType: .singleItem), placeholder: nil, inputPlaceholder: "preset name", filter: { $0 }, limit: 144)) + entries.append(.input(sectionId: sectionId, index: index, value: .string(state.preset.title), error: nil, identifier: _id_name_input, mode: .plain, data: .init(viewType: .singleItem), placeholder: nil, inputPlaceholder: "Filter Name", filter: { $0 }, limit: 144)) index += 1 entries.append(.sectionId(sectionId, type: .normal)) sectionId += 1 + entries.append(.desc(sectionId: sectionId, index: index, text: .plain("INCLUDE CHAT TYPES"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) + index += 1 + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_private_chats, data: .init(name: L10n.chatListFilterPrivateChats, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.privateChats)), viewType: .firstItem, enabled: true, action: { arguments.toggleOption(.privateChats) }))) index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_groups, data: .init(name: L10n.chatListFilterGroups, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.groups)), viewType: .innerItem, enabled: true, action: { - arguments.toggleOption(.groups) + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_secret_chats, data: .init(name: L10n.chatListFilterSecretChat, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.secretChats)), viewType: .innerItem, enabled: true, action: { + arguments.toggleOption(.secretChats) + }))) + index += 1 + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_public_groups, data: .init(name: L10n.chatListFilterPublicGroups, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.publicGroups)), viewType: .innerItem, enabled: true, action: { + arguments.toggleOption(.publicGroups) + }))) + index += 1 + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_private_groups, data: .init(name: L10n.chatListFilterPrivateGroups, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.privateGroups)), viewType: .innerItem, enabled: true, action: { + arguments.toggleOption(.privateGroups) }))) index += 1 entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_channels, data: .init(name: L10n.chatListFilterChannels, color: theme.colors.text, type: .selectable(state.preset.includeCategories.contains(.channels)), viewType: .innerItem, enabled: true, action: { @@ -127,55 +143,27 @@ private func chatListPresetEntries(state: ChatListPresetState, peers: [Peer], ar }))) index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_exclude_read, data: .init(name: "Exclude Read", color: theme.colors.text, type: .switchable(!state.preset.includeCategories.contains(.read)), viewType: .innerItem, enabled: true, action: { + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_exclude_read, data: .init(name: "Exclude Read", color: theme.colors.text, type: .switchable(!state.preset.includeCategories.contains(.read)), viewType: .lastItem, enabled: true, action: { arguments.toggleOption(.read) }))) index += 1 - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_apply_exception, data: .init(name: "Apply for Exceptions", color: theme.colors.text, type: .switchable(state.preset.applyReadMutedForExceptions), viewType: .lastItem, enabled: true, action: { - arguments.toggleApplyForExceptions(!state.preset.applyReadMutedForExceptions) - }))) - index += 1 - - var applyText: String? = nil - if state.preset.applyReadMutedForExceptions { - if !state.preset.includeCategories.contains(.read) { - applyText = "All **Read** chats including the exceptions will be excluded from exceptions list." - if !state.preset.includeCategories.contains(.muted) { - applyText = "All **Read** and **Muted** chats including the exceptions will be excluded from chat list." - } - } else if !state.preset.includeCategories.contains(.muted) { - applyText = "All **Muted** chats including the exceptions will be excluded from chat list." - } - if applyText == nil { - applyText = "You can exclude **Read** or **Muted** chats even if a chat in the exceptions." - } - } else { - applyText = "You can exclude **Read** or **Muted** chats even if a chat in the exceptions." - } - if let applyText = applyText { - entries.append(.desc(sectionId: sectionId, index: index, text: .plain(applyText), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textBottomItem))) - index += 1 - } entries.append(.sectionId(sectionId, type: .normal)) sectionId += 1 - entries.append(.desc(sectionId: sectionId, index: index, text: .plain("EXCEPTIONS"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) + entries.append(.desc(sectionId: sectionId, index: index, text: .plain("ALWAYS INCLUDE"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) index += 1 entries.append(.custom(sectionId: sectionId, index: index, value: .none, identifier: _id_add_exception, equatable: InputDataEquatable(state), item: { initialSize, stableId in - return GeneralInteractedRowItem(initialSize, stableId: stableId.hashValue, name: "Add", nameStyle: blueActionButton, type: .none, viewType: peers.isEmpty ? .singleItem : .firstItem, action: arguments.addPeer, thumb: GeneralThumbAdditional(thumb: theme.icons.peerInfoAddMember, textInset: 46, thumbInset: 5)) + return GeneralInteractedRowItem(initialSize, stableId: stableId.hashValue, name: "Add Chats", nameStyle: blueActionButton, type: .none, viewType: peers.isEmpty ? .singleItem : .firstItem, action: arguments.addPeer, thumb: GeneralThumbAdditional(thumb: theme.icons.peerInfoAddMember, textInset: 46, thumbInset: 5)) })) index += 1 - - - var fake:[Int] = [] fake.append(0) for (i, _) in peers.enumerated() { diff --git a/Telegram-Mac/ChatListPresetListController.swift b/Telegram-Mac/ChatListPresetListController.swift index f6a504fa4..547abc67d 100644 --- a/Telegram-Mac/ChatListPresetListController.swift +++ b/Telegram-Mac/ChatListPresetListController.swift @@ -18,16 +18,19 @@ private final class ChatListPresetArguments { let context: AccountContext let openPreset:(ChatListFilterPreset)->Void let removePreset: (ChatListFilterPreset)->Void - init(context: AccountContext, openPreset: @escaping(ChatListFilterPreset)->Void, removePreset: @escaping(ChatListFilterPreset)->Void) { + let toggleTabsIsEnabled:(Bool)->Void + init(context: AccountContext, openPreset: @escaping(ChatListFilterPreset)->Void, removePreset: @escaping(ChatListFilterPreset)->Void, toggleTabsIsEnabled: @escaping(Bool)->Void) { self.context = context self.openPreset = openPreset self.removePreset = removePreset + self.toggleTabsIsEnabled = toggleTabsIsEnabled } } private func _id_preset(_ preset: ChatListFilterPreset) -> InputDataIdentifier { return InputDataIdentifier("_id_preset_\(preset.uniqueId)") } private let _id_add_new = InputDataIdentifier("_id_add_new") +private let _id_add_tabs = InputDataIdentifier("_id_add_tabs") private func chatListPresetEntries(state: ChatListFilterPreferences, arguments: ChatListPresetArguments) -> [InputDataEntry] { var entries: [InputDataEntry] = [] @@ -38,18 +41,31 @@ private func chatListPresetEntries(state: ChatListFilterPreferences, arguments: entries.append(.sectionId(sectionId, type: .normal)) sectionId += 1 - for (i, preset) in state.presets.enumerated() { + + if !state.presets.isEmpty { + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_add_tabs, data: InputDataGeneralData(name: "Show Tabs", color: theme.colors.text, type: .switchable(state.tabsIsEnabled), viewType: .singleItem, action: { + arguments.toggleTabsIsEnabled(!state.tabsIsEnabled) + }))) + index += 1 + + entries.append(.desc(sectionId: sectionId, index: index, text: .plain("Display filter tabs on main screen for quick switching."), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textBottomItem))) + index += 1 + + entries.append(.sectionId(sectionId, type: .normal)) + sectionId += 1 + } + + entries.append(.desc(sectionId: sectionId, index: index, text: .plain("FILTERS"), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textTopItem))) + index += 1 + + for preset in state.presets { var viewType = bestGeneralViewType(state.presets, for: preset) if state.presets.count == 1 { viewType = .firstItem } else if preset == state.presets.last, state.presets.count < 10 { viewType = .innerItem } - var shortCut: String = "⌃⌘\(i + 2)" - if i + 2 == 11 { - shortCut = "⌃⌘-" - } - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_preset(preset), data: .init(name: preset.title, color: theme.colors.text, type: .nextContext(shortCut), viewType: viewType, enabled: true, description: nil, justUpdate: arc4random64(), action: { + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_preset(preset), data: .init(name: preset.title, color: theme.colors.text, type: .nextContext(preset.desc), viewType: viewType, enabled: true, description: nil, justUpdate: arc4random64(), action: { arguments.openPreset(preset) }, menuItems: { return [ContextMenuItem("Remove", handler: { @@ -60,9 +76,10 @@ private func chatListPresetEntries(state: ChatListFilterPreferences, arguments: } if state.presets.count < 10 { - entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_add_new, data: InputDataGeneralData(name: L10n.chatListFilterListAddNew, color: theme.colors.accent, icon: theme.icons.peerInfoAddMember, type: .next, viewType: .lastItem, action: { + entries.append(.general(sectionId: sectionId, index: index, value: .none, error: nil, identifier: _id_add_new, data: InputDataGeneralData(name: L10n.chatListFilterListAddNew, color: theme.colors.accent, icon: theme.icons.peerInfoAddMember, type: .next, viewType: state.presets.isEmpty ? .singleItem : .lastItem, action: { arguments.openPreset(ChatListFilterPreset.new) }))) + index += 1 entries.append(.desc(sectionId: sectionId, index: index, text: .plain("You can add up to 10 filters. Drag and drop filter to sort it."), data: .init(color: theme.colors.listGrayText, detectBold: true, viewType: .textBottomItem))) index += 1 @@ -85,6 +102,10 @@ func ChatListPresetListController(context: AccountContext) -> InputDataControlle _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { $0.withRemovedPreset(preset) }).start() + }, toggleTabsIsEnabled: { value in + _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { + $0.withUpdatedTabEnable(value) + }).start() }) let dataSignal = chatListFilterPreferences(postbox: context.account.postbox) |> deliverOnPrepareQueue |> map { state in @@ -109,15 +130,35 @@ func ChatListPresetListController(context: AccountContext) -> InputDataControlle controller.afterTransaction = { controller in - let count = controller.tableView.count - 3 - if count > 0 { - controller.tableView.resortController = TableResortController(resortRange: NSMakeRange(1, controller.tableView.count - 4), start: { row in + var range: NSRange = NSMakeRange(NSNotFound, 0) + + controller.tableView.enumerateItems(with: { item in + if let stableId = item.stableId.base as? InputDataEntryId { + switch stableId { + case let .general(identifier): + if identifier.identifier.hasPrefix("_id_preset") { + if range.location == NSNotFound { + range.location = item.index + } + range.length += 1 + } + default: + if range.location != NSNotFound { + return false + } + } + } + return true + }) + + if range.location != NSNotFound { + controller.tableView.resortController = TableResortController(resortRange: range, start: { row in }, resort: { row in }, complete: { from, to in _ = updateChatListFilterPreferencesInteractively(postbox: context.account.postbox, { - $0.withMovePreset(from - 1, to - 1) + $0.withMovePreset(from - range.location, to - range.location) }).start() }) } else { diff --git a/Telegram-Mac/ChatListRevealItem.swift b/Telegram-Mac/ChatListRevealItem.swift index 258d1806c..26c0f7ef4 100644 --- a/Telegram-Mac/ChatListRevealItem.swift +++ b/Telegram-Mac/ChatListRevealItem.swift @@ -14,17 +14,29 @@ import SwiftSignalKit import SyncCore class ChatListRevealItem: TableStickItem { - fileprivate let action:(()->Void)? + fileprivate let action:((ChatListFilterPreset?)->Void)? fileprivate let context: AccountContext? - init(_ initialSize: NSSize, context: AccountContext, action: (()->Void)? = nil) { + fileprivate let tabs: [ChatListFilterPreset] + fileprivate let selected: ChatListFilterPreset? + fileprivate let openSettings: (()->Void)? + fileprivate let counters: [Int32: Int32] + init(_ initialSize: NSSize, context: AccountContext, tabs: [ChatListFilterPreset], selected: ChatListFilterPreset?, counters: [Int32 : Int32], action: ((ChatListFilterPreset?)->Void)? = nil, openSettings: (()->Void)? = nil) { self.action = action self.context = context + self.tabs = tabs + self.selected = selected + self.openSettings = openSettings + self.counters = counters super.init(initialSize) } required init(_ initialSize: NSSize) { self.action = nil self.context = nil + self.tabs = [] + self.selected = nil + self.openSettings = nil + self.counters = [:] super.init(initialSize) } @@ -35,25 +47,30 @@ class ChatListRevealItem: TableStickItem { override func viewClass() -> AnyClass { return ChatListRevealView.self } + + override var identifier: String { + return "ChatListRevealView" + } + + override var height: CGFloat { + return 36 + } } private final class ChatListRevealView : TableStickView { - private let textView: TextView = TextView() - private let separator: View = View() - private var badgeNode: GlobalBadgeNode? private let containerView = View() + private var animated: Bool = false + private let segmentView: ScrollableSegmentView = ScrollableSegmentView(frame: NSZeroRect) required init(frame frameRect: NSRect) { super.init(frame: frameRect) addSubview(containerView) - containerView.addSubview(textView) - containerView.addSubview(separator) - textView.userInteractionEnabled = false - textView.isSelectable = false - textView.isEventLess = true - containerView.isEventLess = true + containerView.addSubview(segmentView) border = [.Right] - separator.change(opacity: 0, animated: false) + } + + override func scrollWheel(with event: NSEvent) { + segmentView.scrollWheel(with: event) } override func mouseUp(with event: NSEvent) { @@ -61,19 +78,17 @@ private final class ChatListRevealView : TableStickView { } override func mouseDown(with event: NSEvent) { if mouseInside() { - if let item = item as? ChatListRevealItem { - item.action?() - } } } + override func updateIsVisible(_ visible: Bool, animated: Bool) { super.updateIsVisible(visible, animated: animated) - var visible = visible - if let table = item?.table { - visible = visible && table.documentOffset.y > 0 - } - separator.change(opacity: visible ? 1 : 0, animated: false) +// var visible = visible +// if let table = item?.table { +// visible = visible && table.documentOffset.y > 0 +// } +// separator.change(opacity: visible ? 1 : 0, animated: false) } override var backdorColor: NSColor { @@ -82,7 +97,6 @@ private final class ChatListRevealView : TableStickView { override func updateColors() { super.updateColors() - separator.backgroundColor = theme.colors.border } override func set(item: TableRowItem, animated: Bool = false) { @@ -91,36 +105,101 @@ private final class ChatListRevealView : TableStickView { guard let item = item as? ChatListRevealItem else { return } - if let context = item.context, self.badgeNode == nil { - self.badgeNode = GlobalBadgeNode(context.account, sharedContext: context.sharedContext, view: View(), layoutChanged: { [weak self] in - self?.needsLayout = true - }, getColor: { _ in return theme.colors.accent }, fontSize: 9, applyFilter: false) - containerView.addSubview(self.badgeNode!.view!) - } + let animated = self.animated || animated + self.animated = true + + let segmentTheme = ScrollableSegmentTheme(border: presentation.colors.border, selector: presentation.colors.accent, inactiveText: presentation.colors.grayText, activeText: presentation.colors.accent, textFont: .normal(.title)) + var index: Int = 0 + let insets = NSEdgeInsets(left: 10, right: 10, bottom: 6) + var items:[ScrollableSegmentItem] = [.init(title: L10n.chatListFilterAllChats, index: 0, uniqueId: -1, selected: item.selected == nil, insets: insets, icon: nil, theme: segmentTheme, equatable: UIEquatable(0))] + index += 1 + for tab in item.tabs { + + let unreadCount = item.counters[tab.uniqueId] + let icon: CGImage? + if let unreadCount = unreadCount, unreadCount > 0 { + let attributedString = NSAttributedString.initialize(string: "\(Int(unreadCount).prettyNumber)", color: theme.colors.background, font: .medium(.text), coreText: true) + let textLayout = TextNode.layoutText(maybeNode: nil, attributedString, nil, 1, .start, NSMakeSize(CGFloat.greatestFiniteMagnitude, CGFloat.greatestFiniteMagnitude), nil, false, .center) + + icon = generateImage(NSMakeSize(textLayout.0.size.width + 12, textLayout.0.size.height + 4), rotatedContext: { size, ctx in + let rect = NSMakeRect(0, 0, size.width, size.height) + ctx.clear(rect) + + ctx.setFillColor(theme.colors.accent.cgColor) + + + ctx.round(size, size.height/2.0) + ctx.fill(rect) + + let focus = NSMakePoint((rect.width - textLayout.0.size.width) / 2, (rect.height - textLayout.0.size.height) / 2) + textLayout.1.draw(NSMakeRect(focus.x, 2, textLayout.0.size.width, textLayout.0.size.height), in: ctx, backingScaleFactor: 2.0, backgroundColor: .white) + + })! + } else { + icon = nil + } + + + items.append(ScrollableSegmentItem(title: tab.title, index: index, uniqueId: tab.uniqueId, selected: item.selected == tab, insets: insets, icon: icon, theme: segmentTheme, equatable: UIEquatable(unreadCount ?? 0))) + index += 1 + } + if let _ = item.openSettings { + items.append(.init(title: "", index: index, uniqueId: -2, selected: false, insets: NSEdgeInsets(left: 5, right: 10, bottom: 6), icon: theme.icons.chat_filter_add, theme: segmentTheme, equatable: UIEquatable(0))) + index += 1 + } + + + + segmentView.updateItems(items, animated: animated) + + segmentView.didChangeSelectedItem = { [weak item] selected in + if let item = item { + if selected.uniqueId == -1 { + item.action?(nil) + } else if selected.uniqueId == -2 { + item.openSettings?() + } else { + item.action?(item.tabs[selected.index - 1]) + } + } + } } + override var isHidden: Bool { + didSet { + if isHidden { + var bp:Int = 0 + bp += 1 + } + } + } + + override var isAlwaysUp: Bool { + return true + } + + override func removeFromSuperview() { + super.removeFromSuperview() + } + + public override func setFrameOrigin(_ newOrigin: NSPoint) { + super.setFrameOrigin(newOrigin) + } + + deinit { + var bp:Int = 0 + bp += 1 + } + override func layout() { super.layout() - containerView.frame = bounds + containerView.frame = NSMakeRect(0, 0, bounds.width - 1, bounds.height) - - let layout = TextViewLayout(.initialize(string: self.frame.width < 200 ? L10n.chatListCloseFilterShort : L10n.chatListCloseFilter, color: theme.colors.accent, font: .normal(.text)), maximumNumberOfLines: 1) - layout.measure(width: frame.width - 40) - textView.update(layout) - - let badgeSize = self.frame.width < 200 ? .zero : self.badgeNode?.view?.frame.size ?? .zero - if badgeSize == .zero { - textView.center() - } else { - textView.centerY(x: floorToScreenPixels(backingScaleFactor, (frame.width - (textView.frame.width + badgeSize.width + 10)) / 2)) - } - self.badgeNode?.view?.isHidden = self.frame.width < 200 - separator.frame = NSMakeRect(0, frame.height - .borderSize, frame.width, .borderSize) - - self.badgeNode?.view?.setFrameOrigin(NSMakePoint(textView.frame.maxX + 10, 6)) + segmentView.frame = containerView.bounds + } required init?(coder: NSCoder) { diff --git a/Telegram-Mac/ChatSelectText.swift b/Telegram-Mac/ChatSelectText.swift index 1ec0699cf..25bfae848 100644 --- a/Telegram-Mac/ChatSelectText.swift +++ b/Telegram-Mac/ChatSelectText.swift @@ -214,6 +214,7 @@ class ChatSelectText : NSObject { private var startMessageId:MessageId? = nil private var lastPressureEventStage = 0 private var inPressedState = false + private var locationInWindow: NSPoint? = nil private var lastSelectdMessageId: MessageId? @@ -249,6 +250,7 @@ class ChatSelectText : NSObject { self?.started = false self?.inPressedState = false + self?.locationInWindow = event.locationInWindow if let table = self?.table, let superview = table.superview, let documentView = table.documentView { let point = superview.convert(event.locationInWindow, from: nil) @@ -297,6 +299,7 @@ class ChatSelectText : NSObject { window.set(mouseHandler: { [weak self] event -> KeyHandlerResult in self?.beginInnerLocation = NSZeroPoint + self?.locationInWindow = nil Queue.mainQueue().justDispatch { guard let table = self?.table else {return} @@ -337,7 +340,15 @@ class ChatSelectText : NSObject { window.set(mouseHandler: { [weak self] event -> KeyHandlerResult in guard let `self` = self else {return .rejected} - + + if let locationInWindow = self.locationInWindow { + let old = (ceil(locationInWindow.x), ceil(locationInWindow.y)) + let new = (ceil(event.locationInWindow.x), round(event.locationInWindow.y)) + if abs(old.0 - new.0) <= 1 && abs(old.1 - new.1) <= 1 { + return .rejected + } + } + self.endInnerLocation = self.table.documentView?.convert(window.mouseLocationOutsideOfEventStream, from: nil) ?? NSZeroPoint // if let overView = window.contentView?.hitTest(window.mouseLocationOutsideOfEventStream) as? Control { diff --git a/Telegram-Mac/GeneralRowItem.swift b/Telegram-Mac/GeneralRowItem.swift index 9d124da9c..0fe96a16d 100644 --- a/Telegram-Mac/GeneralRowItem.swift +++ b/Telegram-Mac/GeneralRowItem.swift @@ -139,11 +139,6 @@ enum GeneralViewItemPosition : Equatable { } -extension NSEdgeInsets : Equatable { - public static func ==(lhs: NSEdgeInsets, rhs: NSEdgeInsets) -> Bool { - return lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right && lhs.bottom == rhs.bottom - } -} enum GeneralViewType : Equatable { case legacy diff --git a/Telegram-Mac/GlobalBadgeNode.swift b/Telegram-Mac/GlobalBadgeNode.swift index c12ac22b7..e1023011f 100644 --- a/Telegram-Mac/GlobalBadgeNode.swift +++ b/Telegram-Mac/GlobalBadgeNode.swift @@ -95,68 +95,184 @@ class GlobalBadgeNode: Node { let total:Int32 } - let signal:Signal = chatListFilterPreferences(postbox: account.postbox) |> mapToSignal { settings -> Signal in - var items:[UnreadMessageCountsItem] = [] - let peerSignal: Signal<(Peer, Bool)?, NoError> - - - - - if let peerId = excludePeerId { - items.append(.peer(peerId)) - let notificationKeyView: PostboxViewKey = .peerNotificationSettings(peerIds: Set([peerId])) - peerSignal = combineLatest(account.postbox.loadedPeerWithId(peerId), account.postbox.combinedView(keys: [notificationKeyView]) |> map { view in - return ((view.views[notificationKeyView] as? PeerNotificationSettingsView)?.notificationSettings[peerId])?.isRemovedFromTotalUnreadCount ?? false + var items:[UnreadMessageCountsItem] = [] + let peerSignal: Signal<(Peer, Bool)?, NoError> + + + + + if let peerId = excludePeerId { + items.append(.peer(peerId)) + let notificationKeyView: PostboxViewKey = .peerNotificationSettings(peerIds: Set([peerId])) + peerSignal = combineLatest(account.postbox.loadedPeerWithId(peerId), account.postbox.combinedView(keys: [notificationKeyView]) |> map { view in + return ((view.views[notificationKeyView] as? PeerNotificationSettingsView)?.notificationSettings[peerId])?.isRemovedFromTotalUnreadCount ?? false }) |> map {Optional($0)} - } else { - peerSignal = .single(nil) + } else { + peerSignal = .single(nil) + } + + let signal: Signal<[(Int32, RenderedTotalUnreadCountType)], NoError> + if collectAllAccounts { + signal = sharedContext.activeAccountsWithInfo |> mapToSignal { primaryId, accounts in + return combineLatest(accounts.filter { $0.account.id != account.id }.map { renderedTotalUnreadCount(accountManager: sharedContext.accountManager, postbox: $0.account.postbox) }) } - - let signal: Signal<[(Int32, RenderedTotalUnreadCountType)], NoError> - if collectAllAccounts { - signal = sharedContext.activeAccountsWithInfo |> mapToSignal { primaryId, accounts in - return combineLatest(accounts.filter { $0.account.id != account.id }.map { renderedTotalUnreadCount(accountManager: sharedContext.accountManager, postbox: $0.account.postbox) }) - } - } else { - signal = renderedTotalUnreadCount(accountManager: sharedContext.accountManager, postbox: account.postbox) |> map { [$0] } - } - - var unreadCountItems: [UnreadMessageCountsItem] = [] - unreadCountItems.append(.total(nil)) - var keys: [PostboxViewKey] = [] - let unreadKey: PostboxViewKey - if let current = preset ?? settings.current, applyFilter { - if !current.additionallyIncludePeers.isEmpty { - for peerId in current.additionallyIncludePeers { - unreadCountItems.append(.peer(peerId)) - } - } - unreadKey = .unreadCounts(items: unreadCountItems) - keys.append(unreadKey) + } else { + signal = renderedTotalUnreadCount(accountManager: sharedContext.accountManager, postbox: account.postbox) |> map { [$0] } + } + + var unreadCountItems: [UnreadMessageCountsItem] = [] + unreadCountItems.append(.total(nil)) + var keys: [PostboxViewKey] = [] + let unreadKey: PostboxViewKey + if let current = preset, applyFilter { + if !current.additionallyIncludePeers.isEmpty { for peerId in current.additionallyIncludePeers { - keys.append(.basicPeer(peerId)) - + unreadCountItems.append(.peer(peerId)) } - keys.append(.peerNotificationSettings(peerIds: Set(current.additionallyIncludePeers))) - } else { - unreadKey = .unreadCounts(items: []) } - - return combineLatest(signal, account.postbox.unreadMessageCountsView(items: items), account.postbox.combinedView(keys: keys), appNotificationSettings(accountManager: sharedContext.accountManager), peerSignal) |> map { (counts, view, keysView, inAppSettings, peerSettings) in + unreadKey = .unreadCounts(items: unreadCountItems) + keys.append(unreadKey) + for peerId in current.additionallyIncludePeers { + keys.append(.basicPeer(peerId)) - if !applyFilter || (settings.current == nil && preset == nil) { - var excludeTotal: Int32 = 0 - - var dockText: String? - let totalValue = !inAppSettings.badgeEnabled ? 0 : (collectAllAccounts && !inAppSettings.notifyAllAccounts ? 0 : max(0, counts.reduce(0, { $0 + $1.0 }))) - if totalValue > 0 { - dockText = "\(totalValue)" + } + keys.append(.peerNotificationSettings(peerIds: Set(current.additionallyIncludePeers))) + } else { + unreadKey = .unreadCounts(items: []) + } + + let s:Signal = combineLatest(signal, account.postbox.unreadMessageCountsView(items: items), account.postbox.combinedView(keys: keys), appNotificationSettings(accountManager: sharedContext.accountManager), peerSignal) |> map { (counts, view, keysView, inAppSettings, peerSettings) in + + if !applyFilter || preset == nil { + var excludeTotal: Int32 = 0 + + var dockText: String? + let totalValue = !inAppSettings.badgeEnabled ? 0 : (collectAllAccounts && !inAppSettings.notifyAllAccounts ? 0 : max(0, counts.reduce(0, { $0 + $1.0 }))) + if totalValue > 0 { + dockText = "\(totalValue)" + } + + excludeTotal = totalValue + + if items.count == 1, let peerSettings = peerSettings { + if let count = view.count(for: items[0]), inAppSettings.totalUnreadCountIncludeTags.contains(peerSettings.0.peerSummaryTags), count > 0 { + var removable = false + switch inAppSettings.totalUnreadCountDisplayStyle { + case .raw: + removable = true + case .filtered: + if !peerSettings.1 { + removable = true + } + } + if removable { + switch inAppSettings.totalUnreadCountDisplayCategory { + case .chats: + excludeTotal -= 1 + case .messages: + excludeTotal -= count + } + } + } + } + return Result(dockText: dockText, total: excludeTotal) + } else if let preset = preset { + if let unreadCounts = keysView.views[unreadKey] as? UnreadMessageCountsView { + var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int)] = [:] + var totalState: ChatListTotalUnreadState? + for entry in unreadCounts.entries { + switch entry { + case let .total(_, totalStateValue): + totalState = totalStateValue + case let .peer(peerId, state): + if let state = state, state.isUnread { + let notificationSettings = keysView.views[.peerNotificationSettings(peerIds: Set(preset.additionallyIncludePeers))] as? PeerNotificationSettingsView + if let peerView = keysView.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer { + let tag = account.postbox.seedConfiguration.peerSummaryCounterTags(peer) + var peerCount = Int(state.count) + let isRemoved = notificationSettings?.notificationSettings[peerId]?.isRemovedFromTotalUnreadCount ?? false + var removable = false + switch inAppSettings.totalUnreadCountDisplayStyle { + case .raw: + removable = true + case .filtered: + if !isRemoved { + removable = true + } + } + if !preset.includeCategories.contains(.muted), isRemoved { + removable = false + } + if removable, state.isUnread { + switch inAppSettings.totalUnreadCountDisplayCategory { + case .chats: + peerCount = 1 + case .messages: + peerCount = max(1, peerCount) + } + peerTagAndCount[peerId] = (tag, peerCount) + } + + } + } + } } - excludeTotal = totalValue + var tags: [PeerSummaryCounterTags] = [] + if preset.includeCategories.contains(.privateChats) { + tags.append(.privateChat) + } + + if preset.includeCategories.contains(.publicGroups) { + tags.append(.publicGroup) + } + if preset.includeCategories.contains(.privateGroups) { + tags.append(.privateGroup) + } + if preset.includeCategories.contains(.secretChats) { + tags.append(.secretChat) + } + if preset.includeCategories.contains(.bots) { + tags.append(.bot) + } + if preset.includeCategories.contains(.channels) { + tags.append(.channel) + } + + + var count:Int32 = 0 + if let totalState = totalState { + for tag in tags { + + if let value = totalState.filteredCounters[tag] { + var removable = false + switch inAppSettings.totalUnreadCountDisplayStyle { + case .raw: + removable = true + case .filtered: + removable = true + } + if removable { + switch inAppSettings.totalUnreadCountDisplayCategory { + case .chats: + count += value.chatCount + case .messages: + count += value.messageCount + } + } + } + } + } + for peerId in preset.additionallyIncludePeers { + if let (tag, peerCount) = peerTagAndCount[peerId] { + if !tags.contains(tag) { + count += Int32(peerCount) + } + } + } if items.count == 1, let peerSettings = peerSettings { - if let count = view.count(for: items[0]), inAppSettings.totalUnreadCountIncludeTags.contains(peerSettings.0.peerSummaryTags), count > 0 { + if let current = view.count(for: items[0]), inAppSettings.totalUnreadCountIncludeTags.contains(peerSettings.0.peerSummaryTags), current > 0 { var removable = false switch inAppSettings.totalUnreadCountDisplayStyle { case .raw: @@ -169,136 +285,23 @@ class GlobalBadgeNode: Node { if removable { switch inAppSettings.totalUnreadCountDisplayCategory { case .chats: - excludeTotal -= 1 + count -= 1 case .messages: - excludeTotal -= count + count -= current } } } } - return Result(dockText: dockText, total: excludeTotal) - } else if let preset = preset ?? settings.current { - if let unreadCounts = keysView.views[unreadKey] as? UnreadMessageCountsView { - var peerTagAndCount: [PeerId: (PeerSummaryCounterTags, Int)] = [:] - var totalState: ChatListTotalUnreadState? - for entry in unreadCounts.entries { - switch entry { - case let .total(_, totalStateValue): - totalState = totalStateValue - case let .peer(peerId, state): - if let state = state, state.isUnread { - let notificationSettings = keysView.views[.peerNotificationSettings(peerIds: Set(preset.additionallyIncludePeers))] as? PeerNotificationSettingsView - if let peerView = keysView.views[.basicPeer(peerId)] as? BasicPeerView, let peer = peerView.peer { - let tag = account.postbox.seedConfiguration.peerSummaryCounterTags(peer) - var peerCount = Int(state.count) - let isRemoved = notificationSettings?.notificationSettings[peerId]?.isRemovedFromTotalUnreadCount ?? false - var removable = false - switch inAppSettings.totalUnreadCountDisplayStyle { - case .raw: - removable = true - case .filtered: - if !isRemoved { - removable = true - } - } - if !preset.includeCategories.contains(.muted), isRemoved { - removable = false - } - if removable, state.isUnread { - switch inAppSettings.totalUnreadCountDisplayCategory { - case .chats: - peerCount = 1 - case .messages: - peerCount = max(1, peerCount) - } - peerTagAndCount[peerId] = (tag, peerCount) - } - - } - } - } - } - - var tags: [PeerSummaryCounterTags] = [] - if preset.includeCategories.contains(.privateChats) { - tags.append(.privateChat) - } - - if preset.includeCategories.contains(.groups) { - tags.append(.privateGroup) - tags.append(.publicGroup) - } - if preset.includeCategories.contains(.bots) { - tags.append(.bot) - } - if preset.includeCategories.contains(.channels) { - tags.append(.channel) - } - - - var count:Int32 = 0 - if let totalState = totalState { - for tag in tags { - - if let value = totalState.filteredCounters[tag] { - var removable = false - switch inAppSettings.totalUnreadCountDisplayStyle { - case .raw: - removable = true - case .filtered: - removable = true - } - if removable { - switch inAppSettings.totalUnreadCountDisplayCategory { - case .chats: - count += value.chatCount - case .messages: - count += value.messageCount - } - } - } - } - } - for peerId in preset.additionallyIncludePeers { - if let (tag, peerCount) = peerTagAndCount[peerId] { - if !tags.contains(tag) { - count += Int32(peerCount) - } - } - } - - if items.count == 1, let peerSettings = peerSettings { - if let current = view.count(for: items[0]), inAppSettings.totalUnreadCountIncludeTags.contains(peerSettings.0.peerSummaryTags), current > 0 { - var removable = false - switch inAppSettings.totalUnreadCountDisplayStyle { - case .raw: - removable = true - case .filtered: - if !peerSettings.1 { - removable = true - } - } - if removable { - switch inAppSettings.totalUnreadCountDisplayCategory { - case .chats: - count -= 1 - case .messages: - count -= current - } - } - } - } - - return Result(dockText: nil, total: count) - } + + return Result(dockText: nil, total: count) } - return Result(dockText: nil, total: 0) } + return Result(dockText: nil, total: 0) } |> deliverOnMainQueue - self.disposable.set(signal.start(next: { [weak self] result in + self.disposable.set(s.start(next: { [weak self] result in if let strongSelf = self { if result.total == 0 { diff --git a/Telegram-Mac/Info.plist b/Telegram-Mac/Info.plist index a04057dc4..14f430302 100644 --- a/Telegram-Mac/Info.plist +++ b/Telegram-Mac/Info.plist @@ -36,7 +36,7 @@ CFBundleVersion - 190408 + 190681 LSApplicationCategoryType public.app-category.social-networking LSFileQuarantineEnabled diff --git a/Telegram-Mac/InstantPageMedia.swift b/Telegram-Mac/InstantPageMedia.swift index f6892385f..4a4418fc2 100644 --- a/Telegram-Mac/InstantPageMedia.swift +++ b/Telegram-Mac/InstantPageMedia.swift @@ -10,7 +10,7 @@ import Cocoa import Postbox import TelegramCore import SyncCore - +import TGUIKit diff --git a/Telegram-Mac/Localizable.swift b/Telegram-Mac/Localizable.swift index c324b464a..7f7d12c56 100644 --- a/Telegram-Mac/Localizable.swift +++ b/Telegram-Mac/Localizable.swift @@ -1867,9 +1867,9 @@ internal final class L10n { internal static var chatInputShowNext: String { return L10n.tr("Localizable", "ChatInput.ShowNext") } /// Archived Chats internal static var chatListArchivedChats: String { return L10n.tr("Localizable", "ChatList.ArchivedChats") } - /// Show All Chats - internal static var chatListCloseFilter: String { return L10n.tr("Localizable", "ChatList.CloseFilter") } /// Show All + internal static var chatListCloseFilter: String { return L10n.tr("Localizable", "ChatList.CloseFilter") } + /// All internal static var chatListCloseFilterShort: String { return L10n.tr("Localizable", "ChatList.CloseFilterShort") } /// Draft: internal static var chatListDraft: String { return L10n.tr("Localizable", "ChatList.Draft") } @@ -1895,6 +1895,8 @@ internal final class L10n { internal static var chatListAddPlaceholder: String { return L10n.tr("Localizable", "ChatList.Add.Placeholder") } /// Add internal static var chatListAddSave: String { return L10n.tr("Localizable", "ChatList.Add.Save") } + /// Chats + internal static var chatListArchiveBack: String { return L10n.tr("Localizable", "ChatList.Archive.Back") } /// Call internal static var chatListContextCall: String { return L10n.tr("Localizable", "ChatList.Context.Call") } /// Clear History @@ -1927,25 +1929,53 @@ internal final class L10n { internal static var chatListContextUnpin: String { return L10n.tr("Localizable", "ChatList.Context.Unpin") } /// All internal static var chatListFilterAll: String { return L10n.tr("Localizable", "ChatList.Filter.All") } + /// All Chats + internal static var chatListFilterAllChats: String { return L10n.tr("Localizable", "ChatList.Filter.AllChats") } + /// Chats + internal static var chatListFilterBack: String { return L10n.tr("Localizable", "ChatList.Filter.Back") } /// Bots internal static var chatListFilterBots: String { return L10n.tr("Localizable", "ChatList.Filter.Bots") } /// Channels internal static var chatListFilterChannels: String { return L10n.tr("Localizable", "ChatList.Filter.Channels") } /// The filter is empty.\n[Show All Chats]() internal static var chatListFilterEmpty: String { return L10n.tr("Localizable", "ChatList.Filter.Empty") } - /// Groups - internal static var chatListFilterGroups: String { return L10n.tr("Localizable", "ChatList.Filter.Groups") } /// Private Chats internal static var chatListFilterPrivateChats: String { return L10n.tr("Localizable", "ChatList.Filter.PrivateChats") } + /// Private Groups + internal static var chatListFilterPrivateGroups: String { return L10n.tr("Localizable", "ChatList.Filter.PrivateGroups") } + /// Public Groups + internal static var chatListFilterPublicGroups: String { return L10n.tr("Localizable", "ChatList.Filter.PublicGroups") } + /// Secret Chats + internal static var chatListFilterSecretChat: String { return L10n.tr("Localizable", "ChatList.Filter.SecretChat") } /// Filters internal static var chatListFilterSetup: String { return L10n.tr("Localizable", "ChatList.Filter.Setup") } /// Unmuted Chats internal static var chatListFilterUnmutedChats: String { return L10n.tr("Localizable", "ChatList.Filter.UnmutedChats") } /// Unread Chats internal static var chatListFilterUnreadChats: String { return L10n.tr("Localizable", "ChatList.Filter.UnreadChats") } - /// Add New + /// All Bots + internal static var chatListFilterDescBots: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Bots") } + /// All Channels + internal static var chatListFilterDescChannels: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Channels") } + /// Customized + internal static var chatListFilterDescCustomized: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Customized") } + /// All Groups + internal static var chatListFilterDescGroups: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Groups") } + /// All Private Chats + internal static var chatListFilterDescPrivateChats: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.PrivateChats") } + /// All Private Groups + internal static var chatListFilterDescPrivateGroups: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.PrivateGroups") } + /// All Public Groups + internal static var chatListFilterDescPublicGroups: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.PublicGroups") } + /// All SecretChats + internal static var chatListFilterDescSecretChats: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.SecretChats") } + /// All Unmuted + internal static var chatListFilterDescUnmuted: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Unmuted") } + /// All Unread + internal static var chatListFilterDescUnread: String { return L10n.tr("Localizable", "ChatList.Filter.Desc.Unread") } + /// Create New Filter internal static var chatListFilterListAddNew: String { return L10n.tr("Localizable", "ChatList.Filter.List.AddNew") } - /// Chat List + /// Filters internal static var chatListFilterListTitle: String { return L10n.tr("Localizable", "ChatList.Filter.List.Title") } /// New Filter internal static var chatListFilterPresetNewName: String { return L10n.tr("Localizable", "ChatList.Filter.Preset.NewName") } diff --git a/Telegram-Mac/LottiePlayer.swift b/Telegram-Mac/LottiePlayer.swift index d0d85d848..8a3c379ff 100644 --- a/Telegram-Mac/LottiePlayer.swift +++ b/Telegram-Mac/LottiePlayer.swift @@ -406,7 +406,7 @@ private final class PlayerRenderer { framesTask?.cancel() } case .onceEnd: - if current.frame == currentState(stateValue)?.endFrame { + if let state = currentState(stateValue), state.endFrame - current.frame <= 1 { renderer.finished = true renderer.timer?.invalidate() framesTask?.cancel() diff --git a/Telegram-Mac/MainViewController.swift b/Telegram-Mac/MainViewController.swift index 69c9f412b..8259e6750 100644 --- a/Telegram-Mac/MainViewController.swift +++ b/Telegram-Mac/MainViewController.swift @@ -368,10 +368,10 @@ class MainViewController: TelegramViewController { private func _showFastChatSettings(_ control: Control, items: [SPopoverItem]) { switch self.chatList.mode { - case .plain: + case .plain, .filter: if self.tabController.current == chatListNavigation, !items.isEmpty { showPopover(for: control, with: SPopoverViewController(items: items, visibility: 10), edge: .maxX, inset: NSMakePoint(control.frame.width + 40, 0)) - } + } default: break } diff --git a/Telegram-Mac/PeersListController.swift b/Telegram-Mac/PeersListController.swift index 7f82b376f..f768c387c 100644 --- a/Telegram-Mac/PeersListController.swift +++ b/Telegram-Mac/PeersListController.swift @@ -231,6 +231,23 @@ final class RevealAllChatsView : Control { } } +final class FilterTabsView : View { + let tabs: ScrollableSegmentView = ScrollableSegmentView(frame: NSZeroRect) + required init(frame frameRect: NSRect) { + super.init(frame: frameRect) + addSubview(tabs) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layout() { + super.layout() + tabs.frame = bounds + } +} + class PeerListContainerView : View { private let backgroundView = BackgroundView(frame: NSZeroRect) var tableView = TableView(frame:NSZeroRect, drawBorder: true) { @@ -239,55 +256,15 @@ class PeerListContainerView : View { addSubview(tableView) } } + private let searchContainer: View = View() + let searchView:SearchView = SearchView(frame:NSMakeRect(10, 0, 0, 0)) let compose:ImageButton = ImageButton() fileprivate let proxyButton:ImageButton = ImageButton() private let proxyConnecting: ProgressIndicator = ProgressIndicator(frame: NSMakeRect(0, 0, 11, 11)) private var searchState: SearchFieldState = .None -// private var revealView: RevealAllChatsView? -// -// -// func setNeedShowReveal(_ showReveal: Bool, animated: Bool, callback: @escaping()->Void) -> Void { -// if showReveal { -// if self.revealView == nil { -// self.revealView = RevealAllChatsView(frame: NSMakeRect(0, 0, frame.width - 60, 30)) -// self.addSubview(self.revealView!) -// -// guard let revealView = self.revealView else { -// return -// } -// revealView.frame = NSMakeRect(30, frame.height - revealView.frame.height - 10, revealView.textView.frame.width + 40, 30) -// -// -// if animated { -// revealView.layer?.animatePosition(from: NSMakePoint(revealView.frame.minX, frame.height), to: revealView.frame.origin, timingFunction: .spring) -// revealView.layer?.animateAlpha(from: 0, to: 0.1, duration: 0.4, timingFunction: .spring) -// } -// } -// -// revealView?.removeAllHandlers() -// revealView?.set(handler: { _ in -// callback() -// }, for: .Click) -// -// } else { -// if animated { -// if let revealView = self.revealView { -// self.revealView = nil -// revealView.change(pos: NSMakePoint(revealView.frame.minX, frame.height), animated: true, timingFunction: .spring) -// revealView.layer?.animateAlpha(from: 1, to: 0, duration: 0.4, timingFunction: .spring, removeOnCompletion: false, completion: { [weak revealView] _ in -// revealView?.removeFromSuperview() -// -// }) -// } -// } else { -// self.revealView?.removeFromSuperview() -// self.revealView = nil -// } -// } -// } -// + var mode: PeerListMode = .plain { didSet { switch mode { @@ -295,6 +272,8 @@ class PeerListContainerView : View { compose.isHidden = true case .plain: compose.isHidden = false + case .filter: + compose.isHidden = true } needsLayout = true } @@ -304,10 +283,11 @@ class PeerListContainerView : View { self.border = [.Right] compose.autohighlight = false autoresizesSubviews = false + addSubview(searchContainer) addSubview(tableView) - addSubview(compose) - addSubview(proxyButton) - addSubview(searchView) + searchContainer.addSubview(compose) + searchContainer.addSubview(proxyButton) + searchContainer.addSubview(searchView) proxyButton.addSubview(proxyConnecting) setFrameSize(frameRect.size) updateLocalizationAndTheme(theme: theme) @@ -343,7 +323,7 @@ class PeerListContainerView : View { func searchStateChanged(_ state: SearchFieldState, animated: Bool) { self.searchState = state - searchView.change(size: NSMakeSize(state == .Focus || mode.isFolder ? frame.width - searchView.frame.minX * 2 : (frame.width - (36 + compose.frame.width) - (proxyButton.isHidden ? 0 : proxyButton.frame.width + 12)), 30), animated: animated) + searchView.change(size: NSMakeSize(state == .Focus || !mode.isPlain ? frame.width - searchView.frame.minX * 2 : (frame.width - (36 + compose.frame.width) - (proxyButton.isHidden ? 0 : proxyButton.frame.width + 12)), 30), animated: animated) compose.change(opacity: state == .Focus ? 0 : 1, animated: animated) proxyButton.change(opacity: state == .Focus ? 0 : 1, animated: animated) } @@ -391,16 +371,21 @@ class PeerListContainerView : View { } } - searchView.setFrameSize(NSMakeSize(searchState == .Focus || mode.isFolder ? frame.width - searchView.frame.minX * 2 : (frame.width - (36 + compose.frame.width) - (proxyButton.isHidden ? 0 : proxyButton.frame.width + 12)), 30)) + searchContainer.frame = NSMakeRect(0, 0, frame.width, offset) + + + searchView.setFrameSize(NSMakeSize(searchState == .Focus || !mode.isPlain ? frame.width - searchView.frame.minX * 2 : (frame.width - (36 + compose.frame.width) - (proxyButton.isHidden ? 0 : proxyButton.frame.width + 12)), 30)) + + tableView.setFrameSize(frame.width, frame.height - offset) searchView.isHidden = frame.width < 200 if searchView.isHidden { - compose.centerX(y: floorToScreenPixels(backingScaleFactor, (49 - compose.frame.height)/2.0)) + compose.center() proxyButton.setFrameOrigin(-proxyButton.frame.width, 0) } else { - compose.setFrameOrigin(frame.width - 12 - compose.frame.width, floorToScreenPixels(backingScaleFactor, (offset - compose.frame.height)/2.0)) - proxyButton.setFrameOrigin(frame.width - 12 - compose.frame.width - proxyButton.frame.width - 6, floorToScreenPixels(backingScaleFactor, (offset - proxyButton.frame.height)/2.0)) + compose.setFrameOrigin(searchContainer.frame.width - 12 - compose.frame.width, floorToScreenPixels(backingScaleFactor, (searchContainer.frame.height - compose.frame.height)/2.0)) + proxyButton.setFrameOrigin(searchContainer.frame.width - 12 - compose.frame.width - proxyButton.frame.width - 6, floorToScreenPixels(backingScaleFactor, (searchContainer.frame.height - proxyButton.frame.height)/2.0)) } searchView.setFrameOrigin(10, floorToScreenPixels(backingScaleFactor, (offset - searchView.frame.height)/2.0)) tableView.setFrameOrigin(0, offset) @@ -419,10 +404,11 @@ class PeerListContainerView : View { enum PeerListMode { case plain case folder(PeerGroupId) + case filter(Int32) - var isFolder:Bool { + var isPlain:Bool { switch self { - case .folder: + case .plain: return true default: return false @@ -436,6 +422,14 @@ enum PeerListMode { return .root } } + var filterId: Int32? { + switch self { + case let .filter(id): + return id + default: + return nil + } + } } @@ -471,7 +465,7 @@ class PeersListController: TelegramGenericViewController, self.mode = mode self.searchOptions = searchOptions super.init(context) - self.bar = .init(height: mode.isFolder ? 50 : 0) + self.bar = .init(height: !mode.isPlain ? 50 : 0) } override var redirectUserInterfaceCalls: Bool { @@ -680,6 +674,7 @@ class PeersListController: TelegramGenericViewController, self.genericView.tableView.change(opacity: 0, animated: animated, completion: { [weak self] _ in self?.genericView.tableView.isHidden = true }) + searchController.defaultQuery = self.genericView.searchView.query searchController.navigationController = self.navigationController searchController.viewWillAppear(true) @@ -780,6 +775,8 @@ class PeersListController: TelegramGenericViewController, self.navigationController?.push(ChatListController(context, modal: false, groupId: groupId)) case .reveal: break + case .empty: + break } if close { self.genericView.searchView.cancel(true) diff --git a/Telegram-Mac/PreparedChatHistoryViewTransition.swift b/Telegram-Mac/PreparedChatHistoryViewTransition.swift index 4946b62db..d6991f0af 100644 --- a/Telegram-Mac/PreparedChatHistoryViewTransition.swift +++ b/Telegram-Mac/PreparedChatHistoryViewTransition.swift @@ -11,6 +11,7 @@ import SwiftSignalKit import Postbox import TelegramCore import SyncCore +import TGUIKit struct ChatHistoryViewTransition { let historyView: ChatHistoryView diff --git a/Telegram-Mac/SImageView.swift b/Telegram-Mac/SImageView.swift index 865d9dc01..94debc373 100644 --- a/Telegram-Mac/SImageView.swift +++ b/Telegram-Mac/SImageView.swift @@ -24,6 +24,10 @@ class SImageView: NSView { fatalError("init(frame:) has not been implemented") } + override func hitTest(_ point: NSPoint) -> NSView? { + return nil + } + var data: (CGImage, NSEdgeInsets)? { didSet { if let image = data { diff --git a/Telegram-Mac/SearchController.swift b/Telegram-Mac/SearchController.swift index e85f28b70..14faa4c7f 100644 --- a/Telegram-Mac/SearchController.swift +++ b/Telegram-Mac/SearchController.swift @@ -419,6 +419,8 @@ class SearchController: GenericViewController,TableViewDelegate { } + var defaultQuery: String? = nil + private let context:AccountContext private var marked: Bool = false private let arguments:SearchControllerArguments @@ -928,7 +930,7 @@ class SearchController: GenericViewController,TableViewDelegate { override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - request(with: nil) + request(with: self.defaultQuery) } override func viewDidDisappear(_ animated: Bool) { diff --git a/Telegram-Mac/Spotlight.swift b/Telegram-Mac/Spotlight.swift index 67d97066c..eba38912b 100644 --- a/Telegram-Mac/Spotlight.swift +++ b/Telegram-Mac/Spotlight.swift @@ -12,6 +12,7 @@ import TelegramCore import SyncCore import Postbox import SwiftSignalKit +import TGUIKit enum SpotlightIdentifierSource : Equatable { case peerId(PeerId) diff --git a/Telegram-Mac/TelegramIconsTheme.swift b/Telegram-Mac/TelegramIconsTheme.swift index bc0bdb30c..56c26e881 100644 --- a/Telegram-Mac/TelegramIconsTheme.swift +++ b/Telegram-Mac/TelegramIconsTheme.swift @@ -5763,6 +5763,149 @@ final class TelegramIconsTheme { return image } } + var chat_filter_add: CGImage { + if let image = cached.with({ $0["chat_filter_add"] }) { + return image + } else { + let image = _chat_filter_add() + _ = cached.modify { current in + var current = current + current["chat_filter_add"] = image + return current + } + return image + } + } + var chat_filter_bots: CGImage { + if let image = cached.with({ $0["chat_filter_bots"] }) { + return image + } else { + let image = _chat_filter_bots() + _ = cached.modify { current in + var current = current + current["chat_filter_bots"] = image + return current + } + return image + } + } + var chat_filter_channels: CGImage { + if let image = cached.with({ $0["chat_filter_channels"] }) { + return image + } else { + let image = _chat_filter_channels() + _ = cached.modify { current in + var current = current + current["chat_filter_channels"] = image + return current + } + return image + } + } + var chat_filter_custom: CGImage { + if let image = cached.with({ $0["chat_filter_custom"] }) { + return image + } else { + let image = _chat_filter_custom() + _ = cached.modify { current in + var current = current + current["chat_filter_custom"] = image + return current + } + return image + } + } + var chat_filter_groups: CGImage { + if let image = cached.with({ $0["chat_filter_groups"] }) { + return image + } else { + let image = _chat_filter_groups() + _ = cached.modify { current in + var current = current + current["chat_filter_groups"] = image + return current + } + return image + } + } + var chat_filter_muted: CGImage { + if let image = cached.with({ $0["chat_filter_muted"] }) { + return image + } else { + let image = _chat_filter_muted() + _ = cached.modify { current in + var current = current + current["chat_filter_muted"] = image + return current + } + return image + } + } + var chat_filter_private_chats: CGImage { + if let image = cached.with({ $0["chat_filter_private_chats"] }) { + return image + } else { + let image = _chat_filter_private_chats() + _ = cached.modify { current in + var current = current + current["chat_filter_private_chats"] = image + return current + } + return image + } + } + var chat_filter_read: CGImage { + if let image = cached.with({ $0["chat_filter_read"] }) { + return image + } else { + let image = _chat_filter_read() + _ = cached.modify { current in + var current = current + current["chat_filter_read"] = image + return current + } + return image + } + } + var chat_filter_secret_chats: CGImage { + if let image = cached.with({ $0["chat_filter_secret_chats"] }) { + return image + } else { + let image = _chat_filter_secret_chats() + _ = cached.modify { current in + var current = current + current["chat_filter_secret_chats"] = image + return current + } + return image + } + } + var chat_filter_unmuted: CGImage { + if let image = cached.with({ $0["chat_filter_unmuted"] }) { + return image + } else { + let image = _chat_filter_unmuted() + _ = cached.modify { current in + var current = current + current["chat_filter_unmuted"] = image + return current + } + return image + } + } + var chat_filter_unread: CGImage { + if let image = cached.with({ $0["chat_filter_unread"] }) { + return image + } else { + let image = _chat_filter_unread() + _ = cached.modify { current in + var current = current + current["chat_filter_unread"] = image + return current + } + return image + } + } private let _dialogMuteImage: ()->CGImage private let _dialogMuteImageSelected: ()->CGImage @@ -6207,6 +6350,17 @@ final class TelegramIconsTheme { private let _poll_selected_outgoing: ()->CGImage private let _poll_selected_correct_outgoing: ()->CGImage private let _poll_selected_incorrect_outgoing: ()->CGImage + private let _chat_filter_add: ()->CGImage + private let _chat_filter_bots: ()->CGImage + private let _chat_filter_channels: ()->CGImage + private let _chat_filter_custom: ()->CGImage + private let _chat_filter_groups: ()->CGImage + private let _chat_filter_muted: ()->CGImage + private let _chat_filter_private_chats: ()->CGImage + private let _chat_filter_read: ()->CGImage + private let _chat_filter_secret_chats: ()->CGImage + private let _chat_filter_unmuted: ()->CGImage + private let _chat_filter_unread: ()->CGImage init( dialogMuteImage: @escaping()->CGImage, @@ -6651,7 +6805,18 @@ final class TelegramIconsTheme { poll_selected_incorrect_incoming: @escaping()->CGImage, poll_selected_outgoing: @escaping()->CGImage, poll_selected_correct_outgoing: @escaping()->CGImage, - poll_selected_incorrect_outgoing: @escaping()->CGImage + poll_selected_incorrect_outgoing: @escaping()->CGImage, + chat_filter_add: @escaping()->CGImage, + chat_filter_bots: @escaping()->CGImage, + chat_filter_channels: @escaping()->CGImage, + chat_filter_custom: @escaping()->CGImage, + chat_filter_groups: @escaping()->CGImage, + chat_filter_muted: @escaping()->CGImage, + chat_filter_private_chats: @escaping()->CGImage, + chat_filter_read: @escaping()->CGImage, + chat_filter_secret_chats: @escaping()->CGImage, + chat_filter_unmuted: @escaping()->CGImage, + chat_filter_unread: @escaping()->CGImage ) { self._dialogMuteImage = dialogMuteImage self._dialogMuteImageSelected = dialogMuteImageSelected @@ -7096,5 +7261,16 @@ final class TelegramIconsTheme { self._poll_selected_outgoing = poll_selected_outgoing self._poll_selected_correct_outgoing = poll_selected_correct_outgoing self._poll_selected_incorrect_outgoing = poll_selected_incorrect_outgoing + self._chat_filter_add = chat_filter_add + self._chat_filter_bots = chat_filter_bots + self._chat_filter_channels = chat_filter_channels + self._chat_filter_custom = chat_filter_custom + self._chat_filter_groups = chat_filter_groups + self._chat_filter_muted = chat_filter_muted + self._chat_filter_private_chats = chat_filter_private_chats + self._chat_filter_read = chat_filter_read + self._chat_filter_secret_chats = chat_filter_secret_chats + self._chat_filter_unmuted = chat_filter_unmuted + self._chat_filter_unread = chat_filter_unread } } \ No newline at end of file diff --git a/Telegram-Mac/WalletBalanceItem.swift b/Telegram-Mac/WalletBalanceItem.swift index 74c15f2e7..fa0164a3a 100644 --- a/Telegram-Mac/WalletBalanceItem.swift +++ b/Telegram-Mac/WalletBalanceItem.swift @@ -324,7 +324,7 @@ private final class WalletBalanceView : TableRowView { return } - crystalView.update(with: WalletAnimatedSticker.brilliant_static.file, size: NSMakeSize(44, 44), context: item.context, parent: nil, table: nil, parameters: WalletAnimatedSticker.brilliant_static.parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) + crystalView.update(with: LocalAnimatedSticker.brilliant_static.file, size: NSMakeSize(44, 44), context: item.context, parent: nil, table: nil, parameters: LocalAnimatedSticker.brilliant_static.parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) sendButton.isHidden = item.walletState?.balance == -1 diff --git a/Telegram-Mac/WalletInfoCreatedItem.swift b/Telegram-Mac/WalletInfoCreatedItem.swift index fffe352e5..c4ab7ad5c 100644 --- a/Telegram-Mac/WalletInfoCreatedItem.swift +++ b/Telegram-Mac/WalletInfoCreatedItem.swift @@ -17,7 +17,7 @@ class WalletInfoCreatedItem: GeneralRowItem { fileprivate let headerView: TextViewLayout fileprivate let yourWalletAddress: TextViewLayout fileprivate let context: AccountContext - fileprivate let animation: TelegramMediaFile = WalletAnimatedSticker.chiken_born.file + fileprivate let animation: TelegramMediaFile = LocalAnimatedSticker.chiken_born.file private var _h: CGFloat = 0 init(_ initialSize: NSSize, stableId: AnyHashable, context: AccountContext, address: String, viewType: GeneralViewType) { diff --git a/Telegram-Mac/WalletInfoTransactionItem.swift b/Telegram-Mac/WalletInfoTransactionItem.swift index 27ab9a43f..b81860d43 100644 --- a/Telegram-Mac/WalletInfoTransactionItem.swift +++ b/Telegram-Mac/WalletInfoTransactionItem.swift @@ -306,9 +306,9 @@ private final class WalletInfoTransactionView: TableRowView { } } - let parameters = ChatAnimatedStickerMediaLayoutParameters(playPolicy: .once, media: WalletAnimatedSticker.brilliant_static.file) + let parameters = ChatAnimatedStickerMediaLayoutParameters(playPolicy: .once, media: LocalAnimatedSticker.brilliant_static.file) - crystalView.update(with: WalletAnimatedSticker.brilliant_static.file, size: NSMakeSize(16, 16), context: item.context, parent: nil, table: nil, parameters: parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) + crystalView.update(with: LocalAnimatedSticker.brilliant_static.file, size: NSMakeSize(16, 16), context: item.context, parent: nil, table: nil, parameters: parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) needsLayout = true diff --git a/Telegram-Mac/WalletProcessTransactionController.swift b/Telegram-Mac/WalletProcessTransactionController.swift index a9322f83f..a501ee1af 100644 --- a/Telegram-Mac/WalletProcessTransactionController.swift +++ b/Telegram-Mac/WalletProcessTransactionController.swift @@ -103,15 +103,15 @@ private func entries(state: WalletTransactionState, arguments: WalletTransaction return DynamicHeightRowItem(initialSize, stableId: stableId, side: .top) })) - let animation: WalletAnimatedSticker? + let animation: LocalAnimatedSticker? switch state.mode { case .passcode: - animation = WalletAnimatedSticker.keychain + animation = LocalAnimatedSticker.keychain case .sending: - animation = WalletAnimatedSticker.fly_dollar + animation = LocalAnimatedSticker.fly_dollar case .sent: - animation = WalletAnimatedSticker.gift + animation = LocalAnimatedSticker.gift case .none: animation = nil } diff --git a/Telegram-Mac/WalletSendController.swift b/Telegram-Mac/WalletSendController.swift index c875610ce..b1fccb187 100644 --- a/Telegram-Mac/WalletSendController.swift +++ b/Telegram-Mac/WalletSendController.swift @@ -128,7 +128,7 @@ private func WalletSendEntries(state: WalletSendState, arguments: WalletSendArgu let range = balance.nsstring.range(of: ":") if range.location != NSNotFound { - text?.addAttributes([InputDataTextInsertAnimatedViewData.attributeKey : InputDataTextInsertAnimatedViewData(context: arguments.context, file: WalletAnimatedSticker.brilliant_static.file)], range: NSMakeRange(range.location + 1, 3)) + text?.addAttributes([InputDataTextInsertAnimatedViewData.attributeKey : InputDataTextInsertAnimatedViewData(context: arguments.context, file: LocalAnimatedSticker.brilliant_static.file)], range: NSMakeRange(range.location + 1, 3)) } } else { text = nil diff --git a/Telegram-Mac/WalletSendProccessingView.swift b/Telegram-Mac/WalletSendProccessingView.swift index 06146c110..d1458abd5 100644 --- a/Telegram-Mac/WalletSendProccessingView.swift +++ b/Telegram-Mac/WalletSendProccessingView.swift @@ -32,7 +32,7 @@ final class WalletSendProccessingView : Control { } func setup(context: AccountContext) { - self.animationView.update(with: WalletAnimatedSticker.fly_dollar.file, size: NSMakeSize(200, 200), context: context, parent: nil, table: nil, parameters: WalletAnimatedSticker.fly_dollar.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) + self.animationView.update(with: LocalAnimatedSticker.fly_dollar.file, size: NSMakeSize(200, 200), context: context, parent: nil, table: nil, parameters: LocalAnimatedSticker.fly_dollar.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) needsLayout = true } @@ -101,7 +101,7 @@ final class WalletSentView : Control { func setup(context: AccountContext, amount: String, callback: @escaping()->Void) { self.amount = amount - self.animationView.update(with: WalletAnimatedSticker.success.file, size: NSMakeSize(150, 150), context: context, parent: nil, table: nil, parameters: WalletAnimatedSticker.success.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) + self.animationView.update(with: LocalAnimatedSticker.success.file, size: NSMakeSize(150, 150), context: context, parent: nil, table: nil, parameters: LocalAnimatedSticker.success.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) walletButton.removeAllHandlers() @@ -187,7 +187,7 @@ final class WalletPasscodeView : Control { } func setup(context: AccountContext, decryptedKey: @escaping(Data)->Void) { - self.animationView.update(with: WalletAnimatedSticker.keychain.file, size: NSMakeSize(150, 150), context: context, parent: nil, table: nil, parameters: WalletAnimatedSticker.success.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) + self.animationView.update(with: LocalAnimatedSticker.keychain.file, size: NSMakeSize(150, 150), context: context, parent: nil, table: nil, parameters: LocalAnimatedSticker.success.parameters, animated: false, positionFlags: nil, approximateSynchronousValue: true) let inputItem = InputDataRowItem(NSMakeSize(350, 40), stableId: 0, mode: .secure, error: nil, viewType: .singleItem, currentText: "", placeholder: nil, inputPlaceholder: "Passcode", filter: { $0 }, updated: { updated in diff --git a/Telegram-Mac/WalletSplashController.swift b/Telegram-Mac/WalletSplashController.swift index 03e45e66f..a45ef0ab8 100644 --- a/Telegram-Mac/WalletSplashController.swift +++ b/Telegram-Mac/WalletSplashController.swift @@ -105,14 +105,14 @@ private func splashEntries(state: WalletSplashState, arguments: WalletSplashArgu - let animation: WalletAnimatedSticker? + let animation: LocalAnimatedSticker? switch state.mode { case .createPasscode: switch state.passcodeState { case .secure: - animation = WalletAnimatedSticker.keychain + animation = LocalAnimatedSticker.keychain case .plain: - animation = WalletAnimatedSticker.keychain + animation = LocalAnimatedSticker.keychain } default: animation = state.mode.animation @@ -125,7 +125,7 @@ private func splashEntries(state: WalletSplashState, arguments: WalletSplashArgu struct WalletSplashEquatable : Equatable { let mode: WalletSplashMode - let animation: WalletAnimatedSticker? + let animation: LocalAnimatedSticker? } let splashEquatable = WalletSplashEquatable(mode: state.mode, animation: animation) diff --git a/Telegram-Mac/WalletSplashHelps.swift b/Telegram-Mac/WalletSplashHelps.swift index f545c1b6b..84f27cedd 100644 --- a/Telegram-Mac/WalletSplashHelps.swift +++ b/Telegram-Mac/WalletSplashHelps.swift @@ -63,46 +63,46 @@ extension WalletSplashMode { var animationFile: TelegramMediaFile? { switch self { case .intro: - return WalletAnimatedSticker.brilliant_loading.file + return LocalAnimatedSticker.brilliant_loading.file case .success: - return WalletAnimatedSticker.success.file + return LocalAnimatedSticker.success.file case .save24Words: - return WalletAnimatedSticker.write_words.file + return LocalAnimatedSticker.write_words.file case .created: - return WalletAnimatedSticker.gift.file + return LocalAnimatedSticker.gift.file case .restoreFailed: - return WalletAnimatedSticker.sad.file + return LocalAnimatedSticker.sad.file case .testWords: - return WalletAnimatedSticker.write_words.file + return LocalAnimatedSticker.write_words.file case .importExist: return nil case .createPasscode: - return WalletAnimatedSticker.keychain.file + return LocalAnimatedSticker.keychain.file case .unavailable: - return WalletAnimatedSticker.sad.file + return LocalAnimatedSticker.sad.file } } - var animation: WalletAnimatedSticker? { + var animation: LocalAnimatedSticker? { switch self { case .intro: - return WalletAnimatedSticker.brilliant_loading + return LocalAnimatedSticker.brilliant_loading case .success: - return WalletAnimatedSticker.success + return LocalAnimatedSticker.success case .save24Words: - return WalletAnimatedSticker.write_words + return LocalAnimatedSticker.write_words case .created: - return WalletAnimatedSticker.gift + return LocalAnimatedSticker.gift case .restoreFailed: - return WalletAnimatedSticker.sad + return LocalAnimatedSticker.sad case .testWords: - return WalletAnimatedSticker.smart_guy + return LocalAnimatedSticker.smart_guy case .importExist: return nil case .createPasscode: - return WalletAnimatedSticker.keychain + return LocalAnimatedSticker.keychain case .unavailable: - return WalletAnimatedSticker.sad + return LocalAnimatedSticker.sad } } @@ -304,7 +304,7 @@ func formatBalanceText(_ value: Int64) -> String { } -enum WalletAnimatedSticker { +enum LocalAnimatedSticker { case brilliant_static case brilliant_loading case smart_guy @@ -319,6 +319,7 @@ enum WalletAnimatedSticker { case success case monkey_unsee case monkey_see + case think_spectacular var file: TelegramMediaFile { let resource:LocalBundleResource switch self { @@ -350,6 +351,8 @@ enum WalletAnimatedSticker { resource = LocalBundleResource(name: "monkey_unsee", ext: "tgs") case .monkey_see: resource = LocalBundleResource(name: "monkey_see", ext: "tgs") + case .think_spectacular: + resource = LocalBundleResource(name: "think_spectacular", ext: "tgs") } return TelegramMediaFile(fileId: MediaId(namespace: 0, id: MediaId.Id(resource.name.hashValue)), partialReference: nil, resource: resource, previewRepresentations: [], immediateThumbnailData: nil, mimeType: "application/x-tgsticker", size: nil, attributes: [.Sticker(displayText: "", packReference: nil, maskData: nil), .Animated, .FileName(fileName: "telegram-animoji.tgs")]) } @@ -378,7 +381,7 @@ enum WalletAnimatedSticker { case .write_words: playPolicy = .once case .chiken_born: - playPolicy = .loop + playPolicy = .onceEnd case .sad: playPolicy = .once case .success: @@ -387,6 +390,8 @@ enum WalletAnimatedSticker { playPolicy = .once case .monkey_see: playPolicy = .once + case .think_spectacular: + playPolicy = .once } return ChatAnimatedStickerMediaLayoutParameters(playPolicy: playPolicy, alwaysAccept: alwaysAccept, media: self.file) } diff --git a/Telegram-Mac/WalletSplashRowItem.swift b/Telegram-Mac/WalletSplashRowItem.swift index b31bac59b..8b9410e4e 100644 --- a/Telegram-Mac/WalletSplashRowItem.swift +++ b/Telegram-Mac/WalletSplashRowItem.swift @@ -16,10 +16,10 @@ import SyncCore class WalletSplashRowItem: GeneralRowItem { fileprivate let descLayout: TextViewLayout fileprivate let titleLayout: TextViewLayout - fileprivate let animation: WalletAnimatedSticker? + fileprivate let animation: LocalAnimatedSticker? fileprivate let context: AccountContext private var h: CGFloat = 0 - init(_ initialSize: NSSize, stableId: AnyHashable, context: AccountContext, title: String, desc: String, animation: WalletAnimatedSticker?, viewType: GeneralViewType, action:@escaping(String)->Void) { + init(_ initialSize: NSSize, stableId: AnyHashable, context: AccountContext, title: String, desc: String, animation: LocalAnimatedSticker?, viewType: GeneralViewType, action:@escaping(String)->Void) { self.context = context self.animation = animation diff --git a/Telegram-Mac/WalletTransactionTextItem.swift b/Telegram-Mac/WalletTransactionTextItem.swift index bf5f355ce..ccc06e2f0 100644 --- a/Telegram-Mac/WalletTransactionTextItem.swift +++ b/Telegram-Mac/WalletTransactionTextItem.swift @@ -114,7 +114,7 @@ private final class WalletTransactionTextView : TableRowView { self.textView.update(item.textLayout) self.subTextView.update(item.subTextLayout) - crystalView.update(with: WalletAnimatedSticker.brilliant_static.file, size: NSMakeSize(40, 40), context: item.context, parent: nil, table: nil, parameters: WalletAnimatedSticker.brilliant_static.parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) + crystalView.update(with: LocalAnimatedSticker.brilliant_static.file, size: NSMakeSize(40, 40), context: item.context, parent: nil, table: nil, parameters: LocalAnimatedSticker.brilliant_static.parameters, animated: animated, positionFlags: nil, approximateSynchronousValue: true) needsLayout = true } diff --git a/Telegram-Mac/en.lproj/Localizable.strings b/Telegram-Mac/en.lproj/Localizable.strings index 287dc4fbc6981da2b59082d092844cb6fed4e6a5..133e91987e5f6926101874e27af79356c4f14e8f 100644 GIT binary patch delta 746 zcmZWn&1(}u6o0cj)0$;jlk7(tzq$m)Mzmi1MnU2S#gh^&lvYY}q}`*4 zFoy>{Rs9Q;NG?{S7mu;vNh72lyeaC@i@u#r(xNQG&b;^g{oZ@OnQ+Tp{pLOlS*V42 zoevf9>o~XUVJN^9Ov7Esfe#mGz!`kT1uS4FKNP@bA=bHlt`-Kr^PD6msRdz z`!hFX?U^ONuQ;j)9JQ&~y$UzvY~7Sc*OK_&7ANF~4F}shI<2Rjmu_^ryFz6`e^plOHU5-ibf5h^eTWvEenX4`>(v$&NMgGwQ@t#A|OiMvD^ z#6`xL-QNk}(*d4|#vSPI!12?fo>fjIBFq9&rtn5x8^j-uFng%xYwb|%=L1_5df~|m z-y2P@QoFAcy$tv1)}qQjHf?dT3zd`gxQsF>(Q6i8RH>uLT%{q~D>-FNmxs&|`{UG1 z=;234JC%@w_s=| Kukq6pa_lc-)xH7% delta 257 zcmbRBRxaIlVE0ReE}ZEUU!y0Apsc>3W{59Mk<`SXHJwShEUj?~`Tai39*6q(rU& diff --git a/Telegram-Mac/wallet/brilliant_loading.tgs b/Telegram-Mac/tgs/brilliant_loading.tgs similarity index 100% rename from Telegram-Mac/wallet/brilliant_loading.tgs rename to Telegram-Mac/tgs/brilliant_loading.tgs diff --git a/Telegram-Mac/wallet/brilliant_static.tgs b/Telegram-Mac/tgs/brilliant_static.tgs similarity index 100% rename from Telegram-Mac/wallet/brilliant_static.tgs rename to Telegram-Mac/tgs/brilliant_static.tgs diff --git a/Telegram-Mac/wallet/chiken_born.tgs b/Telegram-Mac/tgs/chiken_born.tgs similarity index 100% rename from Telegram-Mac/wallet/chiken_born.tgs rename to Telegram-Mac/tgs/chiken_born.tgs diff --git a/Telegram-Mac/wallet/fly_dollar.tgs b/Telegram-Mac/tgs/fly_dollar.tgs similarity index 100% rename from Telegram-Mac/wallet/fly_dollar.tgs rename to Telegram-Mac/tgs/fly_dollar.tgs diff --git a/Telegram-Mac/wallet/gift.tgs b/Telegram-Mac/tgs/gift.tgs similarity index 100% rename from Telegram-Mac/wallet/gift.tgs rename to Telegram-Mac/tgs/gift.tgs diff --git a/Telegram-Mac/wallet/keyboard_typing.tgs b/Telegram-Mac/tgs/keyboard_typing.tgs similarity index 100% rename from Telegram-Mac/wallet/keyboard_typing.tgs rename to Telegram-Mac/tgs/keyboard_typing.tgs diff --git a/Telegram-Mac/wallet/keychain.tgs b/Telegram-Mac/tgs/keychain.tgs similarity index 100% rename from Telegram-Mac/wallet/keychain.tgs rename to Telegram-Mac/tgs/keychain.tgs diff --git a/Telegram-Mac/wallet/monkey_see.tgs b/Telegram-Mac/tgs/monkey_see.tgs similarity index 100% rename from Telegram-Mac/wallet/monkey_see.tgs rename to Telegram-Mac/tgs/monkey_see.tgs diff --git a/Telegram-Mac/wallet/monkey_unsee.tgs b/Telegram-Mac/tgs/monkey_unsee.tgs similarity index 100% rename from Telegram-Mac/wallet/monkey_unsee.tgs rename to Telegram-Mac/tgs/monkey_unsee.tgs diff --git a/Telegram-Mac/wallet/sad_man.tgs b/Telegram-Mac/tgs/sad_man.tgs similarity index 100% rename from Telegram-Mac/wallet/sad_man.tgs rename to Telegram-Mac/tgs/sad_man.tgs diff --git a/Telegram-Mac/wallet/smart_guy.tgs b/Telegram-Mac/tgs/smart_guy.tgs similarity index 100% rename from Telegram-Mac/wallet/smart_guy.tgs rename to Telegram-Mac/tgs/smart_guy.tgs diff --git a/Telegram-Mac/wallet/swap_money.tgs b/Telegram-Mac/tgs/swap_money.tgs similarity index 100% rename from Telegram-Mac/wallet/swap_money.tgs rename to Telegram-Mac/tgs/swap_money.tgs diff --git a/Telegram-Mac/tgs/think_spectacular.tgs b/Telegram-Mac/tgs/think_spectacular.tgs new file mode 100644 index 0000000000000000000000000000000000000000..2dd379959696b3135759896343bb55d43143f0cf GIT binary patch literal 6752 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 5.9.1 CFBundleVersion - 190408 + 190681 LSMinimumSystemVersion $(MACOSX_DEPLOYMENT_TARGET) NSExtension diff --git a/submodules/TGUIKit/TGUIKit.xcodeproj/project.pbxproj b/submodules/TGUIKit/TGUIKit.xcodeproj/project.pbxproj index e1e964fdc..70b01e45d 100644 --- a/submodules/TGUIKit/TGUIKit.xcodeproj/project.pbxproj +++ b/submodules/TGUIKit/TGUIKit.xcodeproj/project.pbxproj @@ -12,6 +12,8 @@ 9F6281292037389200B2D3C9 /* CheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F6281282037389200B2D3C9 /* CheckBox.swift */; }; 9F9B5EAF2255FEDA00728CDC /* TooltipController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9B5EAE2255FEDA00728CDC /* TooltipController.swift */; }; 9FC76CAD20DBDDA30050CE3B /* SegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FC76CAC20DBDDA30050CE3B /* SegmentController.swift */; }; + A789ECFE23EAE99100AEB34A /* ScrollableSegmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A789ECFD23EAE99100AEB34A /* ScrollableSegmentView.swift */; }; + A789ED0023EAFDE600AEB34A /* MergeLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = A789ECFF23EAFDE600AEB34A /* MergeLists.swift */; }; A7C41DB92359E69400CF9402 /* CatalinaStyledSegmentController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7C41DB82359E69400CF9402 /* CatalinaStyledSegmentController.swift */; }; A7D28203236C3B5D0000A9BF /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A7D28202236C3B5D0000A9BF /* SwiftSignalKit.framework */; }; A7D49478235F226C003E9A25 /* SpinningProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A7D49477235F226C003E9A25 /* SpinningProgressView.swift */; }; @@ -117,6 +119,8 @@ 9F6281282037389200B2D3C9 /* CheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBox.swift; sourceTree = ""; }; 9F9B5EAE2255FEDA00728CDC /* TooltipController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipController.swift; sourceTree = ""; }; 9FC76CAC20DBDDA30050CE3B /* SegmentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SegmentController.swift; sourceTree = ""; }; + A789ECFD23EAE99100AEB34A /* ScrollableSegmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollableSegmentView.swift; sourceTree = ""; }; + A789ECFF23EAFDE600AEB34A /* MergeLists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MergeLists.swift; sourceTree = ""; }; A7C41DB82359E69400CF9402 /* CatalinaStyledSegmentController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CatalinaStyledSegmentController.swift; sourceTree = ""; }; A7D28202236C3B5D0000A9BF /* SwiftSignalKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; A7D49477235F226C003E9A25 /* SpinningProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinningProgressView.swift; sourceTree = ""; }; @@ -248,6 +252,14 @@ name = segment; sourceTree = ""; }; + A789ECFC23EAE97800AEB34A /* scrollable-segment */ = { + isa = PBXGroup; + children = ( + A789ECFD23EAE99100AEB34A /* ScrollableSegmentView.swift */, + ); + name = "scrollable-segment"; + sourceTree = ""; + }; A7C41DB72359E66800CF9402 /* catalina */ = { isa = PBXGroup; children = ( @@ -333,6 +345,7 @@ C22E062A1D7F3C2700A11C88 /* utils */ = { isa = PBXGroup; children = ( + A789ECFF23EAFDE600AEB34A /* MergeLists.swift */, C2271DEC1DAFE4D0001792B6 /* TransformImageArguments.swift */, C2CBCAC11D81593B00142EC0 /* extensions */, C22E062D1D7F3CC000A11C88 /* TGColor.swift */, @@ -465,6 +478,7 @@ C2E0DEA91D7EF51C00EF1C8D /* TGUIKit */ = { isa = PBXGroup; children = ( + A789ECFC23EAE97800AEB34A /* scrollable-segment */, D05F391E22FB377E0040F341 /* date */, 9FC76CAB20DBDD370050CE3B /* segment */, C2449A0F1F0E475200DF5650 /* thrid-party */, @@ -636,6 +650,7 @@ C234CA8F1D97DF26003023F7 /* Image.swift in Sources */, C2B1A1181DA1673300ACB1DD /* TableAnimationInterface.swift in Sources */, C2271F331DB4CEB30045E719 /* HorizontalTableView.swift in Sources */, + A789ED0023EAFDE600AEB34A /* MergeLists.swift in Sources */, C2E0DEBB1D7F05AB00EF1C8D /* View.swift in Sources */, C2271DD41DAF766A001792B6 /* WeakReference.swift in Sources */, C22E06351D804C8200A11C88 /* TableView.swift in Sources */, @@ -671,6 +686,7 @@ C230B9181DD3A6350057F596 /* ProgressModal.swift in Sources */, C21178021F17E78E00AC706D /* TimableProgressView.swift in Sources */, C2E0DEB91D7EF7F300EF1C8D /* ViewController.swift in Sources */, + A789ECFE23EAE99100AEB34A /* ScrollableSegmentView.swift in Sources */, C2303E841D9A69BD00098E12 /* TabBarView.swift in Sources */, C22E063B1D8067A000A11C88 /* TableRowView.swift in Sources */, C2303E7A1D9987FE00098E12 /* Popover.swift in Sources */, diff --git a/submodules/TGUIKit/TGUIKit/Control.swift b/submodules/TGUIKit/TGUIKit/Control.swift index 492997a9f..27f9457bb 100644 --- a/submodules/TGUIKit/TGUIKit/Control.swift +++ b/submodules/TGUIKit/TGUIKit/Control.swift @@ -67,6 +67,7 @@ open class Control: View { private(set) internal var backgroundState:[ControlState:NSColor] = [:] private var mouseMovedInside: Bool = true private var longInvoked: Bool = false + public var handleLongEvent: Bool = true open override var backgroundColor: NSColor { get{ return self.style.backgroundColor @@ -265,14 +266,19 @@ open class Control: View { updateState() send(event: .Down) let point = event.locationInWindow - let disposable = (Signal.single(Void()) |> delay(0.35, queue: Queue.mainQueue())).start(next: { [weak self] in - if let inside = self?.mouseInside(), inside, let wPoint = self?.window?.mouseLocationOutsideOfEventStream, NSPointInRect(point, NSMakeRect(wPoint.x - 2, wPoint.y - 2, 4, 4)) { - self?.longInvoked = true - self?.send(event: .LongMouseDown) - } - }) - - longHandleDisposable.set(disposable) + if handleLongEvent { + let disposable = (Signal.single(Void()) |> delay(0.35, queue: Queue.mainQueue())).start(next: { [weak self] in + if let inside = self?.mouseInside(), inside, let wPoint = self?.window?.mouseLocationOutsideOfEventStream, NSPointInRect(point, NSMakeRect(wPoint.x - 2, wPoint.y - 2, 4, 4)) { + self?.longInvoked = true + self?.send(event: .LongMouseDown) + } + }) + + longHandleDisposable.set(disposable) + } else { + longHandleDisposable.set(nil) + } + } else { super.mouseDown(with: event) diff --git a/submodules/TGUIKit/TGUIKit/Extensions.swift b/submodules/TGUIKit/TGUIKit/Extensions.swift index 912851ee8..f9fa087b1 100644 --- a/submodules/TGUIKit/TGUIKit/Extensions.swift +++ b/submodules/TGUIKit/TGUIKit/Extensions.swift @@ -1934,3 +1934,8 @@ public extension String { return result } } +extension NSEdgeInsets : Equatable { + public static func ==(lhs: NSEdgeInsets, rhs: NSEdgeInsets) -> Bool { + return lhs.left == rhs.left && lhs.right == rhs.right && lhs.bottom == rhs.bottom && lhs.top == rhs.top + } +} diff --git a/Telegram-Mac/MergeLists.swift b/submodules/TGUIKit/TGUIKit/MergeLists.swift similarity index 100% rename from Telegram-Mac/MergeLists.swift rename to submodules/TGUIKit/TGUIKit/MergeLists.swift diff --git a/submodules/TGUIKit/TGUIKit/SPopoverRowItem.swift b/submodules/TGUIKit/TGUIKit/SPopoverRowItem.swift index 60b807b49..a9003544f 100644 --- a/submodules/TGUIKit/TGUIKit/SPopoverRowItem.swift +++ b/submodules/TGUIKit/TGUIKit/SPopoverRowItem.swift @@ -157,14 +157,18 @@ private class SPopoverRowView: TableRowView { public final class SPopoverSeparatorItem : TableRowItem { + let drawBorder: Bool + override public var stableId: AnyHashable { return arc4random() } override public init(_ initialSize: NSSize) { + self.drawBorder = true super.init(initialSize) } - public init() { + public init(_ drawBorder: Bool = true) { + self.drawBorder = drawBorder super.init(NSZeroSize) } @@ -173,7 +177,7 @@ public final class SPopoverSeparatorItem : TableRowItem { } override public var height: CGFloat { - return 10 + return drawBorder ? 10 : 1 } } @@ -189,6 +193,15 @@ private final class SPopoverSeparatorView : TableRowView { separator.backgroundColor = presentation.colors.border } + override func set(item: TableRowItem, animated: Bool = false) { + super.set(item: item, animated: animated) + + guard let item = item as? SPopoverSeparatorItem else { + return + } + // separator.isHidden = !item.drawBorder + } + override func layout() { super.layout() separator.setFrameSize(NSMakeSize(frame.width, .borderSize)) diff --git a/submodules/TGUIKit/TGUIKit/SPopoverViewController.swift b/submodules/TGUIKit/TGUIKit/SPopoverViewController.swift index cab64315b..f97f922cb 100644 --- a/submodules/TGUIKit/TGUIKit/SPopoverViewController.swift +++ b/submodules/TGUIKit/TGUIKit/SPopoverViewController.swift @@ -28,9 +28,10 @@ public struct SPopoverItem : Equatable { let height: CGFloat let handler:()->Void let isSeparator: Bool + let drawSeparatorBorder: Bool let additionView: SPopoverAdditionItemView? - public init(_ title:String, _ handler:@escaping ()->Void, _ image:CGImage? = nil, _ textColor: NSColor = presentation.colors.text, height: CGFloat = 40.0, isSeparator: Bool = false, additionView: SPopoverAdditionItemView? = nil) { + public init(_ title:String, _ handler:@escaping ()->Void, _ image:CGImage? = nil, _ textColor: NSColor = presentation.colors.text, height: CGFloat = 40.0, isSeparator: Bool = false, drawSeparatorBorder: Bool = true, additionView: SPopoverAdditionItemView? = nil) { self.title = title self.image = image self.textColor = textColor @@ -38,15 +39,17 @@ public struct SPopoverItem : Equatable { self.height = height self.isSeparator = false self.additionView = additionView + self.drawSeparatorBorder = drawSeparatorBorder } - public init() { + public init(_ drawSeparatorBorder: Bool = true) { self.title = "" self.image = nil self.textColor = presentation.colors.text self.handler = {} self.height = 10 self.isSeparator = true + self.drawSeparatorBorder = drawSeparatorBorder self.additionView = nil } @@ -75,7 +78,7 @@ public class SPopoverViewController: GenericViewController { let alignAsImage = !items.filter({$0.image != nil}).isEmpty let items = items.map { item -> TableRowItem in if item.isSeparator { - return SPopoverSeparatorItem() + return SPopoverSeparatorItem(item.drawSeparatorBorder) } else { return SPopoverRowItem(NSZeroSize, height: item.height, image: item.image, alignAsImage: alignAsImage, title: item.title, textColor: item.textColor, additionView: item.additionView, clickHandler: { Queue.mainQueue().justDispatch { diff --git a/submodules/TGUIKit/TGUIKit/ScrollableSegmentController.swift b/submodules/TGUIKit/TGUIKit/ScrollableSegmentController.swift new file mode 100644 index 000000000..f552321e5 --- /dev/null +++ b/submodules/TGUIKit/TGUIKit/ScrollableSegmentController.swift @@ -0,0 +1,13 @@ +// +// ScrollableSegmentController.swift +// TGUIKit +// +// Created by Mikhail Filimonov on 05.02.2020. +// Copyright © 2020 Telegram. All rights reserved. +// + +import Cocoa + +class ScrollableSegmentView: View { + +} diff --git a/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift b/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift new file mode 100644 index 000000000..6a50f8d99 --- /dev/null +++ b/submodules/TGUIKit/TGUIKit/ScrollableSegmentView.swift @@ -0,0 +1,542 @@ +// +// ScrollableSegmentController.swift +// TGUIKit +// +// Created by Mikhail Filimonov on 05.02.2020. +// Copyright © 2020 Telegram. All rights reserved. +// + +import Cocoa + + + + +public protocol _HasCustomUIEquatableRepresentation { + func _toCustomUIEquatable() -> UIEquatable? +} + +internal protocol _UIEquatableBox { + var _typeID: ObjectIdentifier { get } + func _unbox() -> T? + + func _isEqual(to: _UIEquatableBox) -> Bool? + + var _base: Any { get } + func _downCastConditional(into result: UnsafeMutablePointer) -> Bool +} + +internal struct _ConcreteEquatableBox : _UIEquatableBox { + internal var _baseEquatable: Base + + internal init(_ base: Base) { + self._baseEquatable = base + } + + + internal var _typeID: ObjectIdentifier { + return ObjectIdentifier(type(of: self)) + } + + internal func _unbox() -> T? { + return (self as _UIEquatableBox as? _ConcreteEquatableBox)?._baseEquatable + } + + internal func _isEqual(to rhs: _UIEquatableBox) -> Bool? { + if let rhs: Base = rhs._unbox() { + return _baseEquatable == rhs + } + return nil + } + + internal var _base: Any { + return _baseEquatable + } + + internal + func _downCastConditional(into result: UnsafeMutablePointer) -> Bool { + guard let value = _baseEquatable as? T else { return false } + result.initialize(to: value) + return true + } +} + + +public struct UIEquatable { + internal var _box: _UIEquatableBox + internal var _usedCustomRepresentation: Bool + + + public init(_ base: H) { + if let customRepresentation = + (base as? _HasCustomUIEquatableRepresentation)?._toCustomUIEquatable() { + self = customRepresentation + self._usedCustomRepresentation = true + return + } + + self._box = _ConcreteEquatableBox(base) + self._usedCustomRepresentation = false + } + + internal init(_usingDefaultRepresentationOf base: H) { + self._box = _ConcreteEquatableBox(base) + self._usedCustomRepresentation = false + } + + public var base: Any { + return _box._base + } + internal + func _downCastConditional(into result: UnsafeMutablePointer) -> Bool { + // Attempt the downcast. + if _box._downCastConditional(into: result) { return true } + + + + return false + } +} + +extension UIEquatable : Equatable { + public static func == (lhs: UIEquatable, rhs: UIEquatable) -> Bool { + if let result = lhs._box._isEqual(to: rhs._box) { return result } + + return false + } +} + +extension UIEquatable : CustomStringConvertible { + public var description: String { + return String(describing: base) + } +} + +extension UIEquatable : CustomDebugStringConvertible { + public var debugDescription: String { + return "UIEquatable(" + String(reflecting: base) + ")" + } +} + +extension UIEquatable : CustomReflectable { + public var customMirror: Mirror { + return Mirror( + self, + children: ["value": base]) + } +} + +public final class ScrollableSegmentItem : Equatable, Comparable, Identifiable { + let title: String + let selected: Bool + let theme: ScrollableSegmentTheme + let insets: NSEdgeInsets + let icon: CGImage? + let equatable: UIEquatable? + public let index: Int + public let uniqueId: Int32 + + public init(title: String, index: Int, uniqueId: Int32, selected: Bool, insets: NSEdgeInsets, icon: CGImage?, theme: ScrollableSegmentTheme, equatable: UIEquatable?) { + self.title = title + self.index = index + self.uniqueId = uniqueId + self.selected = selected + self.theme = theme + self.insets = insets + self.icon = icon + self.equatable = equatable + } + + public var stableId: Int32 { + return uniqueId + } + public static func <(lhs: ScrollableSegmentItem, rhs: ScrollableSegmentItem) -> Bool { + return lhs.index < rhs.index + } + public static func ==(lhs: ScrollableSegmentItem, rhs: ScrollableSegmentItem) -> Bool { + return lhs.index == rhs.index && lhs.title == rhs.title && lhs.uniqueId == rhs.uniqueId && lhs.selected == rhs.selected && lhs.theme == rhs.theme && lhs.insets == rhs.insets && lhs.equatable == rhs.equatable + } + + fileprivate var view:SegmentItemView? +} + +private func buildText(for item: ScrollableSegmentItem) -> TextViewLayout { + let layout = TextViewLayout.init(.initialize(string: item.title, color: item.selected ? item.theme.activeText : item.theme.inactiveText, font: item.theme.textFont)) + layout.measure(width: .greatestFiniteMagnitude) + return layout +} + +private final class SegmentItemView : Control { + private(set) var item: ScrollableSegmentItem + private var textLayout: TextViewLayout + private var imageView: ImageView? + private let textView = TextView() + init(item: ScrollableSegmentItem) { + self.item = item + self.textLayout = buildText(for: item) + super.init(frame: NSZeroRect) + self.handleLongEvent = false + addSubview(textView) + textView.userInteractionEnabled = false + textView.isSelectable = false + textView.isEventLess = true + self.updateItem(item, animated: false) + + set(handler: { [weak self] _ in + if self?.item.selected == false { + self?.textView.layer?.opacity = 0.8 + self?.imageView?.layer?.opacity = 0.8 + } + }, for: .Highlight) + + set(handler: { [weak self] _ in + self?.textView.layer?.opacity = 1.0 + self?.imageView?.layer?.opacity = 1.0 + }, for: .Normal) + + set(handler: { [weak self] _ in + self?.textView.layer?.opacity = 1.0 + self?.imageView?.layer?.opacity = 1.0 + }, for: .Hover) + } + + override func scrollWheel(with event: NSEvent) { + super.scrollWheel(with: event) + } + + var size: NSSize { + var width: CGFloat = self.textLayout.layoutSize.width + item.insets.left + item.insets.right + if let imageView = imageView { + width += item.insets.left + imageView.frame.width + } + if self.textLayout.layoutSize.width == 0 { + width -= (item.insets.left * 2) + } + return NSMakeSize(width, frame.height) + } + + func updateItem(_ item: ScrollableSegmentItem, animated: Bool) { + self.item = item + self.textLayout = buildText(for: item) + textView.update(self.textLayout) + + if let image = item.icon { + if imageView == nil { + imageView = ImageView() + addSubview(imageView!) + if animated { + // imageView?.layer?.animateAlpha(from: 0, to: 1, duration: duration) + } + } + imageView?.image = image + imageView?.sizeToFit() + } else { + if animated, let imageView = imageView { + self.imageView = nil + imageView.removeFromSuperview() + +// imageView.layer?.animateAlpha(from: 1, to: 0, duration: duration, removeOnCompletion: false, completion: { [weak imageView] _ in +// imageView?.removeFromSuperview() +// }) + } else { + imageView?.removeFromSuperview() + imageView = nil + } + + } + + change(size: size, animated: animated, duration: duration) + needsLayout = true + } + + override func layout() { + super.layout() + if textView.frame.width > 0 { + textView.centerY(x: item.insets.left) + textView.setFrameOrigin(NSMakePoint(textView.frame.minX, textView.frame.minY - item.insets.bottom + item.insets.top)) + } else { + textView.centerY(x: 0) + } + if let imageView = imageView { + imageView.centerY(x: textView.frame.maxX + item.insets.left) + imageView.setFrameOrigin(NSMakePoint(imageView.frame.minX, imageView.frame.minY - item.insets.bottom + item.insets.top)) + } + + } + + required init(frame frameRect: NSRect) { + fatalError("init(coder:) has not been implemented") + } + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +private final class SelectorView : View { + required init(frame frameRect: NSRect) { + super.init(frame: frameRect) + layerContentsRedrawPolicy = .duringViewResize + } + var theme: ScrollableSegmentTheme? = nil { + didSet { + needsDisplay = true + } + } + + + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func draw(_ layer: CALayer, in ctx: CGContext) { + super.draw(layer, in: ctx) + ctx.round(frame.size, 2.0) + if let theme = self.theme { + ctx.setFillColor(theme.selector.cgColor) + ctx.fill(bounds) + } + } +} + +public struct ScrollableSegmentTheme : Equatable { + let border: NSColor + let selector: NSColor + let inactiveText: NSColor + let activeText: NSColor + let textFont: NSFont + public init(border: NSColor, selector: NSColor, inactiveText: NSColor, activeText: NSColor, textFont: NSFont) { + self.border = border + self.selector = selector + self.inactiveText = inactiveText + self.activeText = activeText + self.textFont = textFont + } +} + +private let duration: Double = 0.2 + + +private class Scroll : ScrollView { + override func scrollWheel(with event: NSEvent) { + + var scrollPoint = contentView.bounds.origin + let isInverted: Bool = System.isScrollInverted + if event.scrollingDeltaY != 0 { + if isInverted { + scrollPoint.x += -event.scrollingDeltaY + } else { + scrollPoint.x -= event.scrollingDeltaY + } + } + if event.scrollingDeltaX != 0 { + if !isInverted { + scrollPoint.x += -event.scrollingDeltaX + } else { + scrollPoint.x -= event.scrollingDeltaX + } + } + if documentView!.frame.width > frame.width { + scrollPoint.x = min(max(0, scrollPoint.x), documentView!.frame.width - frame.width) + clipView.scroll(to: scrollPoint) + } + } +} + + +public class ScrollableSegmentView: View { + private let scrollView:Scroll = Scroll() + + private let selectorView: SelectorView = SelectorView(frame: NSZeroRect) + private let borderView = View() + + private let documentView = View() + private var items: [ScrollableSegmentItem] = [] + private var selected:Int = 0 + + + + public var didChangeSelectedItem:((ScrollableSegmentItem)->Void)? + + public var theme: ScrollableSegmentTheme = ScrollableSegmentTheme(border: presentation.colors.border, selector: presentation.colors.accent, inactiveText: presentation.colors.grayText, activeText: presentation.colors.accent, textFont: .medium(.title)) + { + didSet { + if theme != oldValue { + redraw() + } + } + } + + public override func scrollWheel(with event: NSEvent) { + scrollView.scrollWheel(with: event) + } + + public required init(frame frameRect: NSRect) { + super.init(frame: frameRect) + addSubview(scrollView) + addSubview(borderView) + addSubview(selectorView) + scrollView.documentView = documentView + +// scrollView.backgroundColor = .clear +// scrollView.background = .clear +// +// documentView.backgroundColor = .clear +// + NotificationCenter.default.addObserver(forName: NSView.boundsDidChangeNotification, object: scrollView.clipView, queue: OperationQueue.main, using: { [weak self] notification in + self?.needsLayout = true + }) + layout() + redraw() + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + public override func updateLocalizationAndTheme(theme presentation: PresentationTheme) { + self.theme = ScrollableSegmentTheme(border: presentation.colors.border, selector: presentation.colors.accent, inactiveText: presentation.colors.grayText, activeText: presentation.colors.accent, textFont: .normal(.title)) + } + + private var selectorFrame: CGRect { + + let selectedItem = self.items.first(where: { $0.selected }) + + var x: CGFloat = 0 + var width: CGFloat = 20 + if let selectedItem = selectedItem, let view = selectedItem.view { + let point: NSPoint + if scrollView.clipView.isAnimateScrolling { + point = NSMakePoint(min(max(view.frame.midX - frame.width / 2, 0), max(documentView.frame.width - frame.width, 0)), 0) + } else { + point = scrollView.documentOffset + } + + + x = view.frame.minX + selectedItem.insets.left - point.x + width = view.size.width - selectedItem.insets.left - selectedItem.insets.right + } + + return CGRect(origin: NSMakePoint(x, frame.height - 6 / 2), size: CGSize(width: width, height: 6)) + } + + + private func moveSelector(_ animated: Bool = false) { + self.selectorView.change(pos: selectorFrame.origin, animated: animated) + self.selectorView.change(size: selectorFrame.size, animated: animated) + } + + public override func layout() { + super.layout() + scrollView.frame = bounds + borderView.frame = NSMakeRect(0, frame.height - .borderSize, frame.width, .borderSize) + selectorView.frame = selectorFrame + for item in self.items { + if let view = item.view { + view.setFrameSize(NSMakeSize(view.size.width, frame.height)) + } + } + layoutItems(animated: false) + } + + public func updateItems(_ items:[ScrollableSegmentItem], animated: Bool, autoscroll: Bool = true) -> Void { + assertOnMainThread() + + let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: self.items, rightList: items) + for rdx in deleteIndices.reversed() { + self.removeItem(at: rdx, animated: animated) + } + for (idx, item, _) in indicesAndItems { + self.insertItem(item, at: idx, animated: animated, callback: { [weak self] item in + self?.didChangeSelectedItem?(item) + }) + } + for (idx, item, _) in updateIndices { + self.updateItem(item, at: idx, animated: animated, callback: { [weak self] item in + self?.didChangeSelectedItem?(item) + }) + } + layoutItems(animated: animated) + + + if let selectedItem = items.first(where: { $0.selected }), let selectedView = selectedItem.view { + let point = NSMakePoint(min(max(selectedView.frame.midX - frame.width / 2, 0), max(documentView.frame.width - frame.width, 0)), 0) + if point != scrollView.documentOffset, frame != .zero { + scrollView.clipView.scroll(to: point, animated: animated) + } + } + moveSelector(animated) + } + + private func removeItem(at index: Int, animated: Bool) { + let view = self.items[index].view + self.items[index].view = nil + if animated, let view = view { + view.layer?.animateAlpha(from: 1, to: 0, duration: duration, removeOnCompletion: false, completion: { [weak view] _ in + view?.removeFromSuperview() + }) + } else { + view?.removeFromSuperview() + } + + self.items.remove(at: index) + } + private func updateItem(_ item: ScrollableSegmentItem, at index: Int, animated: Bool, callback: @escaping(ScrollableSegmentItem)->Void) { + item.view = self.items[index].view + item.view?.updateItem(item, animated: animated) + + _ = item.view?.removeLastHandler() + + item.view?.set(handler: { _ in + callback(item) + }, for: .Click) + + self.items[index] = item + } + private func insertItem(_ item: ScrollableSegmentItem, at index: Int, animated: Bool, callback: @escaping(ScrollableSegmentItem)->Void) { + let view = SegmentItemView(item: item) + view.setFrameSize(NSMakeSize(view.frame.width, frame.height)) + view.set(handler: { _ in + callback(item) + }, for: .Click) + + item.view = view + + + var subviews = self.documentView.subviews + + subviews.insert(view, at: index) + self.documentView.subviews = subviews + self.items.insert(item, at: index) + + for (i, item) in self.items.enumerated() { + if i == index - 1, let v = item.view { + view.setFrameOrigin(NSMakePoint(v.frame.maxX, 0)) + } + } + } + + + + private func layoutItems(animated: Bool) { + var x: CGFloat = 0 + for item in self.items { + if let view = item.view { + view._change(pos: NSMakePoint(x, 0), animated: animated) + x += view.size.width + } + } + documentView.change(size: NSMakeSize(x, frame.height), animated: animated) + } + + private func redraw() { + selectorView.theme = self.theme + borderView.backgroundColor = self.theme.border + backgroundColor = presentation.colors.background + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + +} diff --git a/submodules/TGUIKit/TGUIKit/TGClipView.swift b/submodules/TGUIKit/TGUIKit/TGClipView.swift index 46d97209a..cdc31591c 100644 --- a/submodules/TGUIKit/TGUIKit/TGClipView.swift +++ b/submodules/TGUIKit/TGUIKit/TGClipView.swift @@ -231,12 +231,17 @@ public class TGClipView: NSClipView,CALayerDelegate { } else { _ = destination.x - o.x let ydif = destination.y - o.y - + let xdif = destination.x - o.x + if ydif != 0 { let incY = abs(ydif) - abs(ydif + 1) o.y -= incY } + if xdif != 0 { + let incX = abs(xdif) - abs(xdif + 1) + o.x -= incX + } super.scroll(to: o) } diff --git a/submodules/TGUIKit/TGUIKit/TableStickView.swift b/submodules/TGUIKit/TGUIKit/TableStickView.swift index 14b9c801d..ad815e480 100644 --- a/submodules/TGUIKit/TGUIKit/TableStickView.swift +++ b/submodules/TGUIKit/TGUIKit/TableStickView.swift @@ -18,6 +18,10 @@ open class TableStickView: TableRowView { } } + open var isAlwaysUp: Bool { + return false + } + open func updateIsVisible(_ visible: Bool, animated: Bool) { } diff --git a/submodules/TGUIKit/TGUIKit/TableView.swift b/submodules/TGUIKit/TGUIKit/TableView.swift index 512cc094c..c342dca39 100644 --- a/submodules/TGUIKit/TGUIKit/TableView.swift +++ b/submodules/TGUIKit/TGUIKit/TableView.swift @@ -642,6 +642,8 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele public var beforeSetupItem:((TableRowView, TableRowItem)->Void)? public var afterSetupItem:((TableRowView, TableRowItem)->Void)? + + private var nextScrollEventIsAnimated: Bool = false public var emptyItem:TableRowItem? { didSet { @@ -945,8 +947,8 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele if let strongSelf = self { let reqCount = strongSelf.count / 6 - strongSelf.updateStickAfterScroll(false) - + strongSelf.updateStickAfterScroll(strongSelf.nextScrollEventIsAnimated) + strongSelf.nextScrollEventIsAnimated = false let scroll = strongSelf.scrollPosition(strongSelf.visibleRows()) if (!strongSelf.updating && !strongSelf.clipView.isAnimateScrolling) { @@ -1168,13 +1170,13 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele if stickView?.item != item { - stickView?.set(item: someItem, animated: false) - stickView?.updateIsVisible(!firstTime, animated: false) + stickView?.set(item: someItem, animated: animated) + stickView?.updateIsVisible(!firstTime, animated: animated) } if let item = stickItem { if let view = (viewNecessary(at: item.index) as? TableStickView) { - view.updateIsVisible((!firstTime || !view.header), animated: false) + view.updateIsVisible((!firstTime || !view.header), animated: animated) } } @@ -1208,7 +1210,6 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele yTopOffset = 0 } - stickView.change(pos: NSMakePoint(0, yTopOffset), animated: animated) stickView.header = abs(dif) <= item.heightValue @@ -1248,7 +1249,8 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele } if tableView.isFlipped { - stickView.isHidden = documentOffset.y <= 0 + + stickView.isHidden = documentOffset.y <= 0// && !stickView.isAlwaysUp } stickTimeoutDisposable.set((Signal.single(Void()) |> delay(2.0, queue: Queue.mainQueue())).start(next: { [weak stickView] in @@ -1262,10 +1264,17 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele } else { if index == -1 { - stickView?.removeFromSuperview() + if animated, let stickView = self.stickView { + stickView.change(pos: NSMakePoint(0, -stickView.frame.height), animated: animated, removeOnCompletion: false, completion: { [weak stickView] _ in + stickView?.removeFromSuperview() + }) + } else { + stickView?.removeFromSuperview() + } + } else { + stickView?.setFrameOrigin(0, 0) + stickView?.header = true } - stickView?.setFrameOrigin(0, 0) - stickView?.header = true self.enumerateViews(with: { view in (view as? TableStickView)?.updateIsVisible(true, animated: false) @@ -2076,6 +2085,7 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele } var view: NSView? = item.isUniqueView ? nil : self.tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: identifier), owner: self.tableView) + if(view == nil) { view = makeView(at: item.index) view?.identifier = NSUserInterfaceItemIdentifier(rawValue: identifier) @@ -2470,7 +2480,7 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele } first = false - performScrollEvent() + performScrollEvent(transition.animated) } public func updateEmpties(animated: Bool = false) { @@ -2951,7 +2961,8 @@ open class TableView: ScrollView, NSTableViewDelegate,NSTableViewDataSource,Sele } } - public func performScrollEvent() -> Void { + public func performScrollEvent(_ animated: Bool = false) -> Void { + self.nextScrollEventIsAnimated = animated self.updateScroll(visibleRows()) NotificationCenter.default.post(name: NSView.boundsDidChangeNotification, object: self.contentView) } diff --git a/submodules/TGUIKit/TGUIKit/TextView.swift b/submodules/TGUIKit/TGUIKit/TextView.swift index af53f4216..1fd3e6922 100644 --- a/submodules/TGUIKit/TGUIKit/TextView.swift +++ b/submodules/TGUIKit/TGUIKit/TextView.swift @@ -992,7 +992,12 @@ public enum CursorSelectAlignment { public struct TextSelectedRange: Equatable { - public var range:NSRange = NSMakeRange(NSNotFound, 0) + public var range:NSRange = NSMakeRange(NSNotFound, 0) { + didSet { + var bp:Int = 0 + bp += 1 + } + } public var color:NSColor = presentation.colors.selectText public var def:Bool = true @@ -1170,6 +1175,13 @@ public class TextView: Control, NSViewToolTipOwner { width = endOffset - startOffset; + + if beginLineIndex == -1 { + beginLineIndex = 0 + } else if beginLineIndex >= layout.attributedString.length { + beginLineIndex = layout.attributedString.length - 1 + } + let blockValue:CGFloat = layout.mayBlocked ? CGFloat((layout.attributedString.attribute(.preformattedPre, at: beginLineIndex, effectiveRange: nil) as? NSNumber)?.floatValue ?? 0) : 0 @@ -1430,8 +1442,12 @@ public class TextView: Control, NSViewToolTipOwner { needsDisplay = true } + private var locationInWindow:NSPoint? = nil + func _mouseDown(with event: NSEvent) -> Void { + self.locationInWindow = event.locationInWindow + if !isSelectable || !userInteractionEnabled || event.modifierFlags.contains(.shift) { super.mouseDown(with: event) return @@ -1456,6 +1472,13 @@ public class TextView: Control, NSViewToolTipOwner { if !isSelectable || !userInteractionEnabled { return } + if let locationInWindow = self.locationInWindow { + let old = (ceil(locationInWindow.x), ceil(locationInWindow.y)) + let new = (ceil(event.locationInWindow.x), round(event.locationInWindow.y)) + if abs(old.0 - new.0) <= 1 && abs(old.1 - new.1) <= 1 { + return + } + } endSelect = self.convert(event.locationInWindow, from: nil) if let layout = layout { @@ -1495,6 +1518,8 @@ public class TextView: Control, NSViewToolTipOwner { public override func mouseUp(with event: NSEvent) { + self.locationInWindow = nil + if let layout = layout, userInteractionEnabled { let point = self.convert(event.locationInWindow, from: nil) if event.clickCount == 3, isSelectable { diff --git a/submodules/telegram-ios b/submodules/telegram-ios index a8353cce2..e2b36c872 160000 --- a/submodules/telegram-ios +++ b/submodules/telegram-ios @@ -1 +1 @@ -Subproject commit a8353cce2543cea17c682cdea8548bcb40afa871 +Subproject commit e2b36c872de8140baee44c9413a4aa86018ab05d diff --git a/tools/generate-images.swift b/tools/generate-images.swift index 9e97697fa..337d2ad51 100644 --- a/tools/generate-images.swift +++ b/tools/generate-images.swift @@ -458,6 +458,18 @@ func initialize() -> [String] { array.append("poll_selected_correct_outgoing") array.append("poll_selected_incorrect_outgoing") + array.append("chat_filter_add") + array.append("chat_filter_bots") + array.append("chat_filter_channels") + array.append("chat_filter_custom") + array.append("chat_filter_groups") + array.append("chat_filter_muted") + array.append("chat_filter_private_chats") + array.append("chat_filter_read") + array.append("chat_filter_secret_chats") + array.append("chat_filter_unmuted") + array.append("chat_filter_unread") + return array }