diff --git a/Images.xcassets/Call List/OutgoingIcon.imageset/CallOutgoing@2x.png b/Images.xcassets/Call List/OutgoingIcon.imageset/CallOutgoing@2x.png index 546ee275e8..1556c45ae8 100644 Binary files a/Images.xcassets/Call List/OutgoingIcon.imageset/CallOutgoing@2x.png and b/Images.xcassets/Call List/OutgoingIcon.imageset/CallOutgoing@2x.png differ diff --git a/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@2x.png b/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@2x.png index da7ee35a3f..07403f47ec 100644 Binary files a/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@2x.png and b/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@2x.png differ diff --git a/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@3x.png b/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@3x.png index b9955b9132..62a62518d8 100644 Binary files a/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@3x.png and b/Images.xcassets/Call/CallMuteButton.imageset/CallMuteIcon@3x.png differ diff --git a/Images.xcassets/Call/CallSpeakerButton.imageset/CallSpeakerIcon@3x.png b/Images.xcassets/Call/CallSpeakerButton.imageset/CallSpeakerIcon@3x.png index 531fff536d..345c9a8f3b 100644 Binary files a/Images.xcassets/Call/CallSpeakerButton.imageset/CallSpeakerIcon@3x.png and b/Images.xcassets/Call/CallSpeakerButton.imageset/CallSpeakerIcon@3x.png differ diff --git a/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/DetailLogoBlank@2x.png b/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/DetailLogoBlank@2x.png index f0ee593041..710194f8a8 100644 Binary files a/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/DetailLogoBlank@2x.png and b/Images.xcassets/Chat List/EmptyMasterDetailIcon.imageset/DetailLogoBlank@2x.png differ diff --git a/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@2x.png b/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@2x.png index 05598ef8fb..0c0de02a23 100644 Binary files a/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@2x.png and b/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@2x.png differ diff --git a/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@3x.png b/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@3x.png index 85ea2858fb..dfb61f2827 100644 Binary files a/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@3x.png and b/Images.xcassets/Chat List/RevealActionMuteIcon.imageset/ic_unmute@3x.png differ diff --git a/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@2x.png b/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@2x.png index f250acc2ca..fb63556afc 100644 Binary files a/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@2x.png and b/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@2x.png differ diff --git a/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@3x.png b/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@3x.png index 72683b3fd2..4e7233a75d 100644 Binary files a/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@3x.png and b/Images.xcassets/Chat List/RevealActionPinIcon.imageset/ic_pin@3x.png differ diff --git a/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@2x.png b/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@2x.png index 40e2ac3691..70f1ef10c7 100644 Binary files a/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@2x.png and b/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@2x.png differ diff --git a/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@3x.png b/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@3x.png index cb83255814..634035b600 100644 Binary files a/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@3x.png and b/Images.xcassets/Chat List/RevealActionUnmuteIcon.imageset/ic_unmute@3x.png differ diff --git a/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@2x.png b/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@2x.png index 813edc9f5d..2fd961d332 100644 Binary files a/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@2x.png and b/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@2x.png differ diff --git a/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@3x.png b/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@3x.png index 0cd3e4bb5d..ed94ca9f70 100644 Binary files a/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@3x.png and b/Images.xcassets/Chat List/RevealActionUnpinIcon.imageset/ic_unpin@3x.png differ diff --git a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@2x.png b/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@2x.png deleted file mode 100644 index da6c6dd833..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@2x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@3x.png b/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@3x.png deleted file mode 100644 index 4f7340561c..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Calls@3x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Contents.json b/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Contents.json deleted file mode 100644 index 4019ae2782..0000000000 --- a/Images.xcassets/Chat List/Tabs/IconCallsHW.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "Calls@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Calls@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@2x.png b/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@2x.png deleted file mode 100644 index f33b703348..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@2x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@3x.png b/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@3x.png deleted file mode 100644 index c6253384f1..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Chats@3x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@2x.png b/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@2x.png deleted file mode 100644 index eccfc5f4f9..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@2x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@3x.png b/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@3x.png deleted file mode 100644 index 296dc60b8d..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contacts@3x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contents.json b/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contents.json deleted file mode 100644 index 2554b4ce50..0000000000 --- a/Images.xcassets/Chat List/Tabs/IconContactsHW.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "Contacts@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Contacts@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Contents.json b/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Contents.json deleted file mode 100644 index 9a15c71190..0000000000 --- a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Contents.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "Settings@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "Settings@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@2x.png b/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@2x.png deleted file mode 100644 index f1e7a1f97b..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@2x.png and /dev/null differ diff --git a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@3x.png b/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@3x.png deleted file mode 100644 index 72fbd22988..0000000000 Binary files a/Images.xcassets/Chat List/Tabs/IconSettingsHW.imageset/Settings@3x.png and /dev/null differ diff --git a/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@2x.png b/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@2x.png index 5f9f667e25..0ae8733ed8 100644 Binary files a/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@2x.png and b/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@2x.png differ diff --git a/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@3x.png b/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@3x.png index 9f1be65f30..3bcdbd637f 100644 Binary files a/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@3x.png and b/Images.xcassets/Chat/Empty Chat/Cloud.imageset/ChatCloudInfoIcon@3x.png differ diff --git a/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@2x.png b/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@2x.png index fc1df7e1b3..77e9370cb6 100644 Binary files a/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@2x.png and b/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@2x.png differ diff --git a/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@3x.png b/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@3x.png index 995cb58ef1..84d20ef01b 100644 Binary files a/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@3x.png and b/Images.xcassets/Chat/Info/CallButton.imageset/TabIconCalls@3x.png differ diff --git a/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/StickerKeyboardGifIcon@3x.png b/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/StickerKeyboardGifIcon@3x.png index d760fa4947..38c0a2480d 100644 Binary files a/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/StickerKeyboardGifIcon@3x.png and b/Images.xcassets/Chat/Input/Media/GifsTabIcon.imageset/StickerKeyboardGifIcon@3x.png differ diff --git a/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@2x.png b/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@2x.png index 774c3013a4..c398dc7fbb 100644 Binary files a/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@2x.png and b/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@2x.png differ diff --git a/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@3x.png b/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@3x.png index 17c303914e..29b8a85b5e 100644 Binary files a/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@3x.png and b/Images.xcassets/Chat/Input/Media/GridSetupIcon.imageset/StickersGroupSettings@3x.png differ diff --git a/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/StickerKeyboardRecentTab@2x.png b/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/StickerKeyboardRecentTab@2x.png index 95cc50e35f..371aa0aee9 100644 Binary files a/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/StickerKeyboardRecentTab@2x.png and b/Images.xcassets/Chat/Input/Media/RecentTabIcon.imageset/StickerKeyboardRecentTab@2x.png differ diff --git a/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@2x.png b/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@2x.png index d30bef4955..33cc76e6b3 100644 Binary files a/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@2x.png and b/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@2x.png differ diff --git a/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@3x.png b/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@3x.png index 64706d7681..908cc7c207 100644 Binary files a/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@3x.png and b/Images.xcassets/Chat/Input/Media/SavedStickersTabIcon.imageset/StickerKeyboardFavoriteTab@3x.png differ diff --git a/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@2x.png b/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@2x.png index ab8d454db0..18dc7b95f8 100644 Binary files a/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@2x.png and b/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@2x.png differ diff --git a/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@3x.png b/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@3x.png index e081b297d4..995d380cf1 100644 Binary files a/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@3x.png and b/Images.xcassets/Chat/Input/Media/SettingsIcon.imageset/StickerKeyboardSettingsIcon@3x.png differ diff --git a/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@2x.png b/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@2x.png index 62c00b234e..b21083d2e5 100644 Binary files a/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@2x.png and b/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@2x.png differ diff --git a/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@3x.png b/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@3x.png index f9e6a6bb7b..be76b2aa2c 100644 Binary files a/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@3x.png and b/Images.xcassets/Chat/Input/Media/StickersNotFoundIcon.imageset/StickersPlaceholderIcon@3x.png differ diff --git a/Images.xcassets/Chat/Intro/ChannelIntro.imageset/ChannelIntro@2x.png b/Images.xcassets/Chat/Intro/ChannelIntro.imageset/ChannelIntro@2x.png index e2cd97b8a7..af73c57f24 100644 Binary files a/Images.xcassets/Chat/Intro/ChannelIntro.imageset/ChannelIntro@2x.png and b/Images.xcassets/Chat/Intro/ChannelIntro.imageset/ChannelIntro@2x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@2x.png b/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@2x.png index 35384f6e1f..82b3e2e852 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@2x.png and b/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@2x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@3x.png b/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@3x.png index 5eeda02fa0..c866ac5e89 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@3x.png and b/Images.xcassets/Chat/Message/LocationPinBackground.imageset/LocationMessagePinBackground@3x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@2x.png b/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@2x.png index cff797ee18..33e3593656 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@2x.png and b/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@2x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@3x.png b/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@3x.png index 2c7603bb7d..1d1251539f 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@3x.png and b/Images.xcassets/Chat/Message/LocationPinForeground.imageset/LocationMessagePinIcon@3x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@2x.png b/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@2x.png index 709eb48ffe..484e04b8fc 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@2x.png and b/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@2x.png differ diff --git a/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@3x.png b/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@3x.png index 38bf099fe4..56a7488282 100644 Binary files a/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@3x.png and b/Images.xcassets/Chat/Message/LocationPinShadow.imageset/LocationMessagePinShadow@3x.png differ diff --git a/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@2x.png b/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@2x.png index 1ad8e920a9..472aedaaa5 100644 Binary files a/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@2x.png and b/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@2x.png differ diff --git a/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@3x.png b/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@3x.png index 62ad51a96b..24a1ef113e 100644 Binary files a/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@3x.png and b/Images.xcassets/Chat/Message/NavigateToMessageIcon.imageset/ConversationGoToIcon@3x.png differ diff --git a/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@2x.png b/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@2x.png index d36a000e93..451e4abcca 100644 Binary files a/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@2x.png and b/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@2x.png differ diff --git a/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@3x.png b/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@3x.png index 53a2a0e293..151c9884da 100644 Binary files a/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@3x.png and b/Images.xcassets/Chat/Message/OverlayInstantVideoShadow.imageset/VideoMessagePIPShadow@3x.png differ diff --git a/Images.xcassets/Chat/Message/OverlayPlainVideoShadow.imageset/PictureInPictureShadow@2x.png b/Images.xcassets/Chat/Message/OverlayPlainVideoShadow.imageset/PictureInPictureShadow@2x.png index 695a2278fc..565644d5e7 100644 Binary files a/Images.xcassets/Chat/Message/OverlayPlainVideoShadow.imageset/PictureInPictureShadow@2x.png and b/Images.xcassets/Chat/Message/OverlayPlainVideoShadow.imageset/PictureInPictureShadow@2x.png differ diff --git a/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@2x.png b/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@2x.png index 1da98c4002..c0f33c328b 100644 Binary files a/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@2x.png and b/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@2x.png differ diff --git a/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@3x.png b/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@3x.png index b92416cd4c..3f5823e546 100644 Binary files a/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@3x.png and b/Images.xcassets/Chat/Message/RadialProgressIconDocumentIncoming.imageset/ModernMessageDocumentIconIncoming@3x.png differ diff --git a/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@2x.png b/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@2x.png index d3d84a00ef..4f0cdacba3 100644 Binary files a/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@2x.png and b/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@2x.png differ diff --git a/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@3x.png b/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@3x.png index cc773196b2..ffba3bb567 100644 Binary files a/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@3x.png and b/Images.xcassets/Chat/Message/RadialProgressIconDocumentOutgoing.imageset/ModernMessageDocumentIconOutgoing@3x.png differ diff --git a/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@2x.png b/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@2x.png index f49e918fc7..222b36ebd0 100644 Binary files a/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@2x.png and b/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@2x.png differ diff --git a/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@3x.png b/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@3x.png index 7de2782c73..2056c65b93 100644 Binary files a/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@3x.png and b/Images.xcassets/Chat/NavigateToMentions.imageset/ic_mention@3x.png differ diff --git a/Images.xcassets/Components/Search Bar/Loupe.imageset/SearchBarIconLight@2x.png b/Images.xcassets/Components/Search Bar/Loupe.imageset/SearchBarIconLight@2x.png index 846732f3b3..b942e56d49 100644 Binary files a/Images.xcassets/Components/Search Bar/Loupe.imageset/SearchBarIconLight@2x.png and b/Images.xcassets/Components/Search Bar/Loupe.imageset/SearchBarIconLight@2x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@2x.png b/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@2x.png index 0eb8650f98..241c7d68de 100644 Binary files a/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@2x.png and b/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@2x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@3x.png b/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@3x.png index f1fb7ecd8d..588dd1fc75 100644 Binary files a/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@3x.png and b/Images.xcassets/Components/Volume/VolumeFull.imageset/vol_full@3x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@2x.png b/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@2x.png index f2ad06e761..0f740dd595 100644 Binary files a/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@2x.png and b/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@2x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@3x.png b/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@3x.png index 82df9e4888..aae43d9942 100644 Binary files a/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@3x.png and b/Images.xcassets/Components/Volume/VolumeHalf.imageset/vol_half@3x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@2x.png b/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@2x.png index 5c85f1065c..44740d8972 100644 Binary files a/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@2x.png and b/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@2x.png differ diff --git a/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@3x.png b/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@3x.png index fb01775c2f..3270c2e766 100644 Binary files a/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@3x.png and b/Images.xcassets/Components/Volume/VolumeOff.imageset/vol_off@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@2x.png b/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@2x.png index 3f0dec5b36..c1acdd64e0 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@2x.png and b/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@3x.png b/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@3x.png index bbcf8d71a3..42c7caea49 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@3x.png and b/Images.xcassets/GlobalMusicPlayer/CollapseArrow.imageset/MusicPlayerArrow@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@2x.png b/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@2x.png index 7f73b91622..4516f9ff66 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@2x.png and b/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@3x.png b/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@3x.png index facc408289..e56b9ff16d 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@3x.png and b/Images.xcassets/GlobalMusicPlayer/OrderRandom.imageset/MusicPlayerControlShuffle@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@2x.png b/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@2x.png index 17b7afeaeb..ba2550c1e6 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@2x.png and b/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@3x.png b/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@3x.png index e2006eb4f5..f49cda0bd9 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@3x.png and b/Images.xcassets/GlobalMusicPlayer/OrderReverse.imageset/MusicPlayerControlReverse@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@2x.png b/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@2x.png index d211fca050..ee87a0c74a 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@2x.png and b/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@3x.png b/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@3x.png index 26c4e50b11..9f657d9432 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@3x.png and b/Images.xcassets/GlobalMusicPlayer/Pause.imageset/MusicPlayerControlPause@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@2x.png b/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@2x.png index d7edb29921..3178bf64e8 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@2x.png and b/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@3x.png b/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@3x.png index 08f093f0fc..db259c519a 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@3x.png and b/Images.xcassets/GlobalMusicPlayer/Play.imageset/MusicPlayerControlPlay@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@2x.png b/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@2x.png index d4fbb89351..1b2acef780 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@2x.png and b/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@3x.png b/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@3x.png index 3591c6c3c2..45d82a9919 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@3x.png and b/Images.xcassets/GlobalMusicPlayer/Previous.imageset/MusicPlayerControlBack@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@2x.png b/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@2x.png index b527fa27f5..cf02cc72da 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@2x.png and b/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@3x.png b/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@3x.png index e7b4c93b63..e3c1b6c86e 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@3x.png and b/Images.xcassets/GlobalMusicPlayer/Repeat.imageset/MusicPlayerControlRepeat@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@2x.png b/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@2x.png index b4f9caa534..0a55ca28fd 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@2x.png and b/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@3x.png b/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@3x.png index 9792970b89..8aed4cde1c 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@3x.png and b/Images.xcassets/GlobalMusicPlayer/RepeatOne.imageset/MusicPlayerControlRepeatOne@3x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@2x.png b/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@2x.png index 7f73b91622..4516f9ff66 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@2x.png and b/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@2x.png differ diff --git a/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@3x.png b/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@3x.png index facc408289..c7588909e5 100644 Binary files a/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@3x.png and b/Images.xcassets/GlobalMusicPlayer/Shuffle.imageset/MusicPlayerControlShuffle@3x.png differ diff --git a/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@2x.png b/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@2x.png index 67586711db..a799d2af90 100644 Binary files a/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@2x.png and b/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@2x.png differ diff --git a/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@3x.png b/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@3x.png index ec02872bc2..8c2d06a3c1 100644 Binary files a/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@3x.png and b/Images.xcassets/Instant View/ActionIcon.imageset/ic_share@3x.png differ diff --git a/Images.xcassets/Instant View/ImageLink.imageset/Link@2x.png b/Images.xcassets/Instant View/ImageLink.imageset/Link@2x.png index 98f256628c..bdfd891eba 100644 Binary files a/Images.xcassets/Instant View/ImageLink.imageset/Link@2x.png and b/Images.xcassets/Instant View/ImageLink.imageset/Link@2x.png differ diff --git a/Images.xcassets/Instant View/ImageLink.imageset/Link@3x.png b/Images.xcassets/Instant View/ImageLink.imageset/Link@3x.png index 0d13e6dba1..44e488e84d 100644 Binary files a/Images.xcassets/Instant View/ImageLink.imageset/Link@3x.png and b/Images.xcassets/Instant View/ImageLink.imageset/Link@3x.png differ diff --git a/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@2x.png b/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@2x.png index 50abf7379f..ba17a59d61 100644 Binary files a/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@2x.png and b/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@2x.png differ diff --git a/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@3x.png b/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@3x.png index 25deb49345..4d80862c0b 100644 Binary files a/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@3x.png and b/Images.xcassets/Instant View/SettingsArrow.imageset/InstantViewRightCorner@3x.png differ diff --git a/Images.xcassets/Instant View/SettingsBrightnessMaxIcon.imageset/InstantViewBrightnessMaxIcon@3x.png b/Images.xcassets/Instant View/SettingsBrightnessMaxIcon.imageset/InstantViewBrightnessMaxIcon@3x.png index ac0611dd1c..66e83982f9 100644 Binary files a/Images.xcassets/Instant View/SettingsBrightnessMaxIcon.imageset/InstantViewBrightnessMaxIcon@3x.png and b/Images.xcassets/Instant View/SettingsBrightnessMaxIcon.imageset/InstantViewBrightnessMaxIcon@3x.png differ diff --git a/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@2x.png b/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@2x.png index e7e04a6c54..7fd6bbc381 100644 Binary files a/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@2x.png and b/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@2x.png differ diff --git a/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@3x.png b/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@3x.png index 3df9b2762c..478317dd02 100644 Binary files a/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@3x.png and b/Images.xcassets/Item List/AddExceptionIcon.imageset/plus@3x.png differ diff --git a/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png index 51b2f82727..653fcd2a25 100644 Binary files a/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png and b/Images.xcassets/Item List/SearchIcon.imageset/ic_search@3x.png differ diff --git a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Contents.json b/Images.xcassets/Media Grid/Giphy.imageset/Contents.json similarity index 79% rename from Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Contents.json rename to Images.xcassets/Media Grid/Giphy.imageset/Contents.json index fcc01c2388..3faa37d35f 100644 --- a/Images.xcassets/Chat List/Tabs/IconChatsHW.imageset/Contents.json +++ b/Images.xcassets/Media Grid/Giphy.imageset/Contents.json @@ -6,12 +6,12 @@ }, { "idiom" : "universal", - "filename" : "Chats@2x.png", + "filename" : "Giphy@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "Chats@3x.png", + "filename" : "Giphy@3x.png", "scale" : "3x" } ], diff --git a/Images.xcassets/Media Grid/Giphy.imageset/Giphy@2x.png b/Images.xcassets/Media Grid/Giphy.imageset/Giphy@2x.png new file mode 100644 index 0000000000..f0d0ed388a Binary files /dev/null and b/Images.xcassets/Media Grid/Giphy.imageset/Giphy@2x.png differ diff --git a/Images.xcassets/Media Grid/Giphy.imageset/Giphy@3x.png b/Images.xcassets/Media Grid/Giphy.imageset/Giphy@3x.png new file mode 100644 index 0000000000..012ad8ade2 Binary files /dev/null and b/Images.xcassets/Media Grid/Giphy.imageset/Giphy@3x.png differ diff --git a/Images.xcassets/Peek/Arrow.imageset/PreviewUpArrow@2x.png b/Images.xcassets/Peek/Arrow.imageset/PreviewUpArrow@2x.png index eb133303b0..237889a6d9 100644 Binary files a/Images.xcassets/Peek/Arrow.imageset/PreviewUpArrow@2x.png and b/Images.xcassets/Peek/Arrow.imageset/PreviewUpArrow@2x.png differ diff --git a/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@2x.png b/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@2x.png index 7dc666fc30..a381174e37 100644 Binary files a/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@2x.png and b/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@2x.png differ diff --git a/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@3x.png b/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@3x.png index 825ff31209..21d03c9dd1 100644 Binary files a/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@3x.png and b/Images.xcassets/Peer Info/GroupStickerPackNotFound.imageset/StickerPackNotFoundIcon@3x.png differ diff --git a/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@2x.png b/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@2x.png index 260b39677a..2069911a76 100644 Binary files a/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@2x.png and b/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@2x.png differ diff --git a/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@3x.png b/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@3x.png index f5aa5bc941..813b146b3e 100644 Binary files a/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@3x.png and b/Images.xcassets/Secure ID/DocumentInputBackSide.imageset/reverse@3x.png differ diff --git a/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@2x.png b/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@2x.png index b679ff8dd6..e17986bedf 100644 Binary files a/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@2x.png and b/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@2x.png differ diff --git a/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@3x.png b/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@3x.png index 25507a4706..a367008092 100644 Binary files a/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@3x.png and b/Images.xcassets/Secure ID/DocumentInputSelfie.imageset/selfie@3x.png differ diff --git a/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@2x.png b/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@2x.png index e9d34a44fe..791bc305a8 100644 Binary files a/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@2x.png and b/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@2x.png differ diff --git a/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@3x.png b/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@3x.png index c4634dfe42..98db8f00b4 100644 Binary files a/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@3x.png and b/Images.xcassets/Secure ID/DriversLicenseInputFrontSide.imageset/driver@3x.png differ diff --git a/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@2x.png b/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@2x.png index 2a7c5c90aa..751e800416 100644 Binary files a/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@2x.png and b/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@2x.png differ diff --git a/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@3x.png b/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@3x.png index 24b152d0c6..d677a6de24 100644 Binary files a/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@3x.png and b/Images.xcassets/Secure ID/IdCardInputFrontSide.imageset/idcard@3x.png differ diff --git a/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@2x.png b/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@2x.png index 889004beb1..174d0e43b7 100644 Binary files a/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@2x.png and b/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@2x.png differ diff --git a/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@3x.png b/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@3x.png index 9a8bc05055..91f3138922 100644 Binary files a/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@3x.png and b/Images.xcassets/Secure ID/PassportInputFrontSide.imageset/passport@3x.png differ diff --git a/Images.xcassets/Secure ID/ViewPassportIcon.imageset/PassportSettingsLogo@2x.png b/Images.xcassets/Secure ID/ViewPassportIcon.imageset/PassportSettingsLogo@2x.png index 42c6e76ef7..bc8c076bdd 100644 Binary files a/Images.xcassets/Secure ID/ViewPassportIcon.imageset/PassportSettingsLogo@2x.png and b/Images.xcassets/Secure ID/ViewPassportIcon.imageset/PassportSettingsLogo@2x.png differ diff --git a/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@2x.png b/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@2x.png index 9af43ef97c..a1a1882f39 100644 Binary files a/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@2x.png and b/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@2x.png differ diff --git a/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@3x.png b/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@3x.png index d070dd777a..4451d54f87 100644 Binary files a/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@3x.png and b/Images.xcassets/Settings/ChangePhoneIntroIcon.imageset/ChangePhoneHelpIcon@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@2x.png b/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@2x.png index 4132369e5c..18e3a76771 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@2x.png and b/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@3x.png b/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@3x.png index 73ed287bed..4f857e19c7 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@3x.png and b/Images.xcassets/Settings/MenuIcons/Appearance.imageset/ic_theme@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@2x.png b/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@2x.png index e80173af04..449c62e246 100644 Binary files a/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@2x.png and b/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@3x.png b/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@3x.png index 66d9c308d6..43a3ecb2a1 100644 Binary files a/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@3x.png and b/Images.xcassets/Settings/MenuIcons/DataAndStorage.imageset/ic_data@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@2x.png b/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@2x.png index 795f5b6edf..28217de6a1 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@2x.png and b/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@3x.png b/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@3x.png index 9aa0ed26cf..f90c992067 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@3x.png and b/Images.xcassets/Settings/MenuIcons/Faq.imageset/ic_faq@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@2x.png b/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@2x.png index 171bee5563..aca34cd0df 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@2x.png and b/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@3x.png b/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@3x.png index d9283f4f9e..9fdff2227f 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@3x.png and b/Images.xcassets/Settings/MenuIcons/Language.imageset/ic_language@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@2x.png b/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@2x.png index 2393036ea6..4c1d76c452 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@2x.png and b/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@3x.png b/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@3x.png index e37163f477..85cc9c0fd6 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@3x.png and b/Images.xcassets/Settings/MenuIcons/Notifications.imageset/ic_notifications@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Passport.imageset/SettingsPassportIcon@3x.png b/Images.xcassets/Settings/MenuIcons/Passport.imageset/SettingsPassportIcon@3x.png index 3a657c20ec..25db6e87ec 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Passport.imageset/SettingsPassportIcon@3x.png and b/Images.xcassets/Settings/MenuIcons/Passport.imageset/SettingsPassportIcon@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@2x.png b/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@2x.png index bda0b2552d..8493a8f7ee 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@2x.png and b/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@3x.png b/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@3x.png index c4e69569ae..f3d5e26a61 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@3x.png and b/Images.xcassets/Settings/MenuIcons/Proxy.imageset/SettingsProxyIcon@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@2x.png b/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@2x.png index c3d98063d2..0c56ae7230 100644 Binary files a/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@2x.png and b/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@3x.png b/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@3x.png index 50694ef7b9..355419e66f 100644 Binary files a/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@3x.png and b/Images.xcassets/Settings/MenuIcons/RecentCalls.imageset/ic_recentcalls@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@2x.png b/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@2x.png index d3a840e68e..78a18cf38d 100644 Binary files a/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@2x.png and b/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@3x.png b/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@3x.png index d79f6680bd..0c626ebc50 100644 Binary files a/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@3x.png and b/Images.xcassets/Settings/MenuIcons/SavedMessages.imageset/ic_savedmessages@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@2x.png b/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@2x.png index 6a2520959a..a6c505f8b3 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@2x.png and b/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@3x.png b/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@3x.png index 76d4f8ac8d..d5a35c8bf0 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@3x.png and b/Images.xcassets/Settings/MenuIcons/Security.imageset/ic_security@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@2x.png b/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@2x.png index d91a6ee87a..3bdb82266b 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@2x.png and b/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@3x.png b/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@3x.png index e267f02a27..0cbfb19f07 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@3x.png and b/Images.xcassets/Settings/MenuIcons/Stickers.imageset/ic_stickers@3x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@2x.png b/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@2x.png index fc07b165c2..658de16291 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@2x.png and b/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@2x.png differ diff --git a/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@3x.png b/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@3x.png index 642a5cfdf6..65408ca2ac 100644 Binary files a/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@3x.png and b/Images.xcassets/Settings/MenuIcons/Support.imageset/ic_ask@3x.png differ diff --git a/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@2x.png b/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@2x.png index ba96424b48..78eef8de85 100644 Binary files a/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@2x.png and b/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@2x.png differ diff --git a/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@3x.png b/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@3x.png index 5c79ce661c..4e1a72b5bf 100644 Binary files a/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@3x.png and b/Images.xcassets/Settings/Permissions/CellularData.imageset/Data@3x.png differ diff --git a/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@2x.png b/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@2x.png index 5432e81d85..08d2c27321 100644 Binary files a/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@2x.png and b/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@2x.png differ diff --git a/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@3x.png b/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@3x.png index 017e91ca43..ff5730e8c8 100644 Binary files a/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@3x.png and b/Images.xcassets/Settings/Permissions/Contacts.imageset/Contacts@3x.png differ diff --git a/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@2x.png b/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@2x.png index 6939d96b16..73e31ebf60 100644 Binary files a/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@2x.png and b/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@2x.png differ diff --git a/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@3x.png b/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@3x.png index b5f90c32a6..3d23a06a62 100644 Binary files a/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@3x.png and b/Images.xcassets/Settings/Permissions/Notifications.imageset/Notifications@3x.png differ diff --git a/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@2x.png b/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@2x.png index bdf9d3ac20..c67f2c1c30 100644 Binary files a/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@2x.png and b/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@2x.png differ diff --git a/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@3x.png b/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@3x.png index a4875386c3..e9bf9db62e 100644 Binary files a/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@3x.png and b/Images.xcassets/Settings/Permissions/Siri.imageset/Siri@3x.png differ diff --git a/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@2x.png b/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@2x.png index f6e8e626d1..021fb8cdda 100644 Binary files a/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@2x.png and b/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@2x.png differ diff --git a/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@3x.png b/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@3x.png index ccf7c8a148..89a173c9c9 100644 Binary files a/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@3x.png and b/Images.xcassets/Share/SearchBarSearchIcon.imageset/SearchBarIconLightLarge@3x.png differ diff --git a/Images.xcassets/Share/SearchIcon.imageset/ShareSearchIcon@2x.png b/Images.xcassets/Share/SearchIcon.imageset/ShareSearchIcon@2x.png index 289227ed05..71b3e09c0b 100644 Binary files a/Images.xcassets/Share/SearchIcon.imageset/ShareSearchIcon@2x.png and b/Images.xcassets/Share/SearchIcon.imageset/ShareSearchIcon@2x.png differ diff --git a/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@2x.png b/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@2x.png index 40b4f3ac54..8a273425fb 100644 Binary files a/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@2x.png and b/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@2x.png differ diff --git a/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@3x.png b/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@3x.png index 04096fb79c..274144916e 100644 Binary files a/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@3x.png and b/Images.xcassets/Share/ShareIcon.imageset/ShareExternalIcon@3x.png differ diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index e6e67fb452..584f90aff9 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -45,6 +45,9 @@ 0962E67321B622BE00245FD9 /* PermissionSplitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67221B622BE00245FD9 /* PermissionSplitTest.swift */; }; 0962E67721B673AF00245FD9 /* Permission.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67621B673AF00245FD9 /* Permission.swift */; }; 0962E67921B67A9800245FD9 /* ChatMessageAnimatedStickerItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67821B67A9800245FD9 /* ChatMessageAnimatedStickerItemNode.swift */; }; + 0962E67B21BA00C900245FD9 /* WebSearchInterfaceState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67A21BA00C900245FD9 /* WebSearchInterfaceState.swift */; }; + 0962E67D21BA048D00245FD9 /* WebSearchSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67C21BA048D00245FD9 /* WebSearchSettings.swift */; }; + 0962E67F21BA786A00245FD9 /* WebSearchItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0962E67E21BA786A00245FD9 /* WebSearchItem.swift */; }; 096C98BA21787A5C00C211FF /* LegacyBridgeAudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 096C98B921787A5C00C211FF /* LegacyBridgeAudio.swift */; }; 096C98BF21787C6700C211FF /* TGBridgeAudioEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 096C98BB21787C6600C211FF /* TGBridgeAudioEncoder.m */; }; 096C98C021787C6700C211FF /* TGBridgeAudioEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */; }; @@ -81,6 +84,8 @@ 09C9EA3821A044B500E90146 /* StringForDuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09C9EA3721A044B500E90146 /* StringForDuration.swift */; }; 09D304152173C0E900C00567 /* WatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304142173C0E900C00567 /* WatchManager.swift */; }; 09D304182173C15700C00567 /* WatchSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D304172173C15700C00567 /* WatchSettingsController.swift */; }; + 09DD88E721BAE11B000766BC /* WebSearchRecentQueriesNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09DD88E621BAE11B000766BC /* WebSearchRecentQueriesNode.swift */; }; + 09DD88E921BAF65E000766BC /* ItemListAddressItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09DD88E821BAF65E000766BC /* ItemListAddressItem.swift */; }; 09FE756D2153F5F900A3120F /* CallRouteActionSheetItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */; }; 9F06830921A404AB001D8EDB /* NotificationExceptionControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */; }; 9F06830B21A404C4001D8EDB /* NotificationExcetionSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */; }; @@ -1126,6 +1131,9 @@ 0962E67221B622BE00245FD9 /* PermissionSplitTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionSplitTest.swift; sourceTree = ""; }; 0962E67621B673AF00245FD9 /* Permission.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permission.swift; sourceTree = ""; }; 0962E67821B67A9800245FD9 /* ChatMessageAnimatedStickerItemNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatMessageAnimatedStickerItemNode.swift; sourceTree = ""; }; + 0962E67A21BA00C900245FD9 /* WebSearchInterfaceState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchInterfaceState.swift; sourceTree = ""; }; + 0962E67C21BA048D00245FD9 /* WebSearchSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchSettings.swift; sourceTree = ""; }; + 0962E67E21BA786A00245FD9 /* WebSearchItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchItem.swift; sourceTree = ""; }; 096C98B921787A5C00C211FF /* LegacyBridgeAudio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyBridgeAudio.swift; sourceTree = ""; }; 096C98BB21787C6600C211FF /* TGBridgeAudioEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGBridgeAudioEncoder.m; sourceTree = ""; }; 096C98BC21787C6600C211FF /* TGBridgeAudioEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGBridgeAudioEncoder.h; sourceTree = ""; }; @@ -1166,6 +1174,8 @@ 09C9EA3721A044B500E90146 /* StringForDuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringForDuration.swift; sourceTree = ""; }; 09D304142173C0E900C00567 /* WatchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchManager.swift; sourceTree = ""; }; 09D304172173C15700C00567 /* WatchSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchSettingsController.swift; sourceTree = ""; }; + 09DD88E621BAE11B000766BC /* WebSearchRecentQueriesNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebSearchRecentQueriesNode.swift; sourceTree = ""; }; + 09DD88E821BAF65E000766BC /* ItemListAddressItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemListAddressItem.swift; sourceTree = ""; }; 09FE756C2153F5F900A3120F /* CallRouteActionSheetItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CallRouteActionSheetItem.swift; sourceTree = ""; }; 9F06830821A404AB001D8EDB /* NotificationExceptionControllerNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExceptionControllerNode.swift; sourceTree = ""; }; 9F06830A21A404C4001D8EDB /* NotificationExcetionSettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationExcetionSettingsController.swift; sourceTree = ""; }; @@ -2348,6 +2358,9 @@ 0962E66021B3512500245FD9 /* WebSearchController.swift */, 0962E66221B3513100245FD9 /* WebSearchControllerNode.swift */, 0962E66421B3631100245FD9 /* WebSearchNavigationContentNode.swift */, + 0962E67A21BA00C900245FD9 /* WebSearchInterfaceState.swift */, + 0962E67E21BA786A00245FD9 /* WebSearchItem.swift */, + 09DD88E621BAE11B000766BC /* WebSearchRecentQueriesNode.swift */, ); name = "Web Search"; sourceTree = ""; @@ -3256,6 +3269,7 @@ D06ECFCA20B8448E00C576C2 /* ContactSynchronizationSettings.swift */, D08A10BA211DF7A80077488B /* StickerSettings.swift */, 0952D1762177FB5400194860 /* WatchPresetSettings.swift */, + 0962E67C21BA048D00245FD9 /* WebSearchSettings.swift */, ); name = Settings; sourceTree = ""; @@ -4050,6 +4064,7 @@ D0F19F6120E5694D00EEC860 /* GroupStickerPackCurrentItem.swift */, D0F4B019211073C500912B92 /* DeviceContactInfoController.swift */, 092F368F2157AB46001A9F49 /* ItemListCallListItem.swift */, + 09DD88E821BAF65E000766BC /* ItemListAddressItem.swift */, ); name = "Peer Info"; sourceTree = ""; @@ -5262,6 +5277,7 @@ D0EC6D3A1EB9F58800EBF1C3 /* AudioWaveformNode.swift in Sources */, D0105D682182680E007C04A7 /* IsMediaStreamable.swift in Sources */, D0EB41F71F30D4A800838FE6 /* LegacyMediaLocations.swift in Sources */, + 09DD88E721BAE11B000766BC /* WebSearchRecentQueriesNode.swift in Sources */, D0EC6D3B1EB9F58800EBF1C3 /* EditableTokenListNode.swift in Sources */, D0EC6D3C1EB9F58800EBF1C3 /* PhoneInputNode.swift in Sources */, D0147BAB206EA6C100E40378 /* SecureIdDocumentImageGalleryItem.swift in Sources */, @@ -5483,6 +5499,7 @@ D00FF2091F4E2414006FA332 /* InstantPageSettingsNode.swift in Sources */, D0BE3037206139F500FBE6D8 /* ImageCompression.swift in Sources */, 09AE3823214C110900850BFD /* LegacySecureIdScanController.swift in Sources */, + 0962E67D21BA048D00245FD9 /* WebSearchSettings.swift in Sources */, D0EC6DAB1EB9F58900EBF1C3 /* ChatInterfaceStateAccessoryPanels.swift in Sources */, D0EC6DAC1EB9F58900EBF1C3 /* ChatInterfaceStateInputPanels.swift in Sources */, D056CD761FF2A30900880D28 /* ChatSwipeToReplyRecognizer.swift in Sources */, @@ -5587,6 +5604,7 @@ D0EC6DDF1EB9F58900EBF1C3 /* ChatTextInputAudioRecordingTimeNode.swift in Sources */, D0BFAE5B20AB35D200793CF2 /* IconSwitchNode.swift in Sources */, D0EC6DE01EB9F58900EBF1C3 /* ChatTextInputAudioRecordingCancelIndicator.swift in Sources */, + 0962E67F21BA786A00245FD9 /* WebSearchItem.swift in Sources */, D09D88711F86D36700BEB4C9 /* CountryList.swift in Sources */, D0EC6DE11EB9F58900EBF1C3 /* ChatMessageSelectionInputPanelNode.swift in Sources */, D04281FA200E5CDC009DDE36 /* ChatRecentActionsControllerState.swift in Sources */, @@ -5773,6 +5791,7 @@ D0B37C5C1F8D22AE004252DF /* ThemeSettingsController.swift in Sources */, D05D8B412192FC8A0064586F /* LocalizationListItem.swift in Sources */, D0383ED4207CFBB900C45548 /* GalleryThumbnailContainerNode.swift in Sources */, + 0962E67B21BA00C900245FD9 /* WebSearchInterfaceState.swift in Sources */, D0EC6E4B1EB9F58900EBF1C3 /* ItemListControllerSegmentedTitleView.swift in Sources */, D0EC6E4D1EB9F58900EBF1C3 /* PeerInfoController.swift in Sources */, D0EC6E4E1EB9F58900EBF1C3 /* GroupInfoController.swift in Sources */, @@ -5871,6 +5890,7 @@ 0952D1752176DEB500194860 /* NotificationMuteSettingsController.swift in Sources */, D0EC6E821EB9F58900EBF1C3 /* NotificationContainerControllerNode.swift in Sources */, D0EC6E831EB9F58900EBF1C3 /* NotificationItemContainerNode.swift in Sources */, + 09DD88E921BAF65E000766BC /* ItemListAddressItem.swift in Sources */, D0CB27D220C17A7F001ACF93 /* TermsOfServiceControllerNode.swift in Sources */, D0EC6E841EB9F58900EBF1C3 /* NotificationItem.swift in Sources */, D0EC6E851EB9F58900EBF1C3 /* ChatMessageNotificationItem.swift in Sources */, diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index 0ebd6493c6..b189b0fa45 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -3625,6 +3625,8 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal } }, openFileGallery: { self?.presentFileMediaPickerOptions(editingMessage: editMediaOptions != nil) + }, openWebSearch: { + self?.presentWebSearch(editingMessage : editMediaOptions != nil) }, openMap: { self?.presentMapPicker(editingMessage: editMediaOptions != nil) }, openContacts: { @@ -3765,6 +3767,41 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal }) } + private func presentWebSearch(editingMessage: Bool) { + guard let _ = self.presentationInterfaceState.renderedPeer?.peer else { + return + } + + let _ = (self.account.postbox.transaction { transaction -> SearchBotsConfiguration in + if let entry = transaction.getPreferencesEntry(key: PreferencesKeys.searchBotsConfiguration) as? SearchBotsConfiguration { + return entry + } else { + return SearchBotsConfiguration.defaultValue + } + } + |> deliverOnMainQueue).start(next: { [weak self] configuration in + if let strongSelf = self { + let controller = WebSearchController(account: strongSelf.account, chatLocation: strongSelf.chatLocation, configuration: configuration, sendSelected: { [weak self] ids, collection in + if let strongSelf = self { + for id in ids { + var result: ChatContextResult? + for r in collection.results { + if r.id == id { + result = r + break + } + } + if let result = result { + strongSelf.enqueueChatContextResult(collection, result, includeViaBot: false) + } + } + } + }) + strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + } + }) + } + private func presentMapPicker(editingMessage: Bool) { guard let peer = self.presentationInterfaceState.renderedPeer?.peer else { return @@ -4024,11 +4061,11 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal })) } - private func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult) { + private func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, includeViaBot: Bool = true) { guard case let .peer(peerId) = self.chatLocation else { return } - if let message = outgoingMessageWithChatContextResult(to: peerId, results: results, result: result), canSendMessagesToChat(self.presentationInterfaceState) { + if let message = outgoingMessageWithChatContextResult(to: peerId, results: results, result: result, includeViaBot: includeViaBot), canSendMessagesToChat(self.presentationInterfaceState) { let replyMessageId = self.presentationInterfaceState.interfaceState.replyMessageId self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in if let strongSelf = self { diff --git a/TelegramUI/ChatHistoryGridNode.swift b/TelegramUI/ChatHistoryGridNode.swift index 36a48ef6e0..7a826ab103 100644 --- a/TelegramUI/ChatHistoryGridNode.swift +++ b/TelegramUI/ChatHistoryGridNode.swift @@ -7,7 +7,6 @@ import TelegramCore private class ChatGridLiveSelectorRecognizer: UIPanGestureRecognizer { - private let selectionGestureActivationThreshold: CGFloat = 2.0 private let selectionGestureVerticalFailureThreshold: CGFloat = 5.0 @@ -42,25 +41,22 @@ private class ChatGridLiveSelectorRecognizer: UIPanGestureRecognizer { override func touchesMoved(_ touches: Set, with event: UIEvent) { let location = touches.first!.location(in: self.view) - let translation = CGPoint(x: location.x - firstLocation.x, y: location.y - firstLocation.y) + let translation = CGPoint(x: location.x - self.firstLocation.x, y: location.y - self.firstLocation.y) - if validatedGesture == nil { - if (fabs(translation.y) >= selectionGestureVerticalFailureThreshold) - { - validatedGesture = false + if self.validatedGesture == nil { + if (fabs(translation.y) >= selectionGestureVerticalFailureThreshold) { + self.validatedGesture = false } else if (fabs(translation.x) >= selectionGestureActivationThreshold) { - validatedGesture = true + self.validatedGesture = true } } - if let validatedGesture = validatedGesture { + if let validatedGesture = self.validatedGesture { if validatedGesture { super.touchesMoved(touches, with: event) } } - - } } @@ -197,8 +193,6 @@ private func mappedChatHistoryViewListTransition(account: Account, peerId: PeerI private func gridNodeLayoutForContainerLayout(size: CGSize) -> GridNodeLayoutType { let side = floorToScreenPixels((size.width - 3.0) / 4.0) - //let side = floor(size.width / 4.0) - //return CGSize(width: side, height: side) return .fixed(itemSize: CGSize(width: side, height: side), fillWidth: true, lineSpacing: 1.0, itemSpacing: 1.0) } diff --git a/TelegramUI/ChatMessageInstantVideoItemNode.swift b/TelegramUI/ChatMessageInstantVideoItemNode.swift index 58d5bd0916..8d5b78536d 100644 --- a/TelegramUI/ChatMessageInstantVideoItemNode.swift +++ b/TelegramUI/ChatMessageInstantVideoItemNode.swift @@ -151,7 +151,6 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView { let graphics = PresentationResourcesChat.additionalGraphics(item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) replyBackgroundImage = graphics.chatServiceBubbleFillImage - break } else if let attribute = attribute as? InlineBotMessageAttribute { if let peerId = attribute.peerId, let bot = item.message.peers[peerId] as? TelegramUser { inlineBotNameString = bot.username diff --git a/TelegramUI/ChatMessageStickerItemNode.swift b/TelegramUI/ChatMessageStickerItemNode.swift index 5de41092ce..3ef0d713ee 100644 --- a/TelegramUI/ChatMessageStickerItemNode.swift +++ b/TelegramUI/ChatMessageStickerItemNode.swift @@ -23,6 +23,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView { private var replyInfoNode: ChatMessageReplyInfoNode? private var replyBackgroundNode: ASImageNode? + private var actionButtonsNode: ChatMessageActionButtonsNode? + private var highlightedState: Bool = false private var currentSwipeToReplyTranslation: CGFloat = 0.0 @@ -97,6 +99,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { let layoutConstants = self.layoutConstants let imageLayout = self.imageNode.asyncLayout() let makeDateAndStatusLayout = self.dateAndStatusNode.asyncLayout() + let actionButtonsLayout = ChatMessageActionButtonsNode.asyncLayout(self.actionButtonsNode) let makeReplyInfoLayout = ChatMessageReplyInfoNode.asyncLayout(self.replyInfoNode) let currentReplyBackgroundNode = self.replyBackgroundNode @@ -231,6 +234,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView { var replyInfoApply: (CGSize, () -> ChatMessageReplyInfoNode)? var updatedReplyBackgroundNode: ASImageNode? var replyBackgroundImage: UIImage? + var replyMarkup: ReplyMarkupMessageAttribute? + for attribute in item.message.attributes { if let replyAttribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[replyAttribute.messageId] { let availableWidth = max(60.0, params.width - params.leftInset - params.rightInset - imageSize.width - 20.0 - layoutConstants.bubble.edgeInset * 2.0 - avatarInset - layoutConstants.bubble.contentInsets.left) @@ -244,7 +249,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView { let graphics = PresentationResourcesChat.additionalGraphics(item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper) replyBackgroundImage = graphics.chatFreeformContentAdditionalInfoBackgroundImage - break + } else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty { + replyMarkup = attribute } } @@ -277,8 +283,25 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } let contentHeight = max(imageSize.height, layoutConstants.image.minDimensions.height) + var maxContentWidth = imageSize.width + var actionButtonsFinalize: ((CGFloat) -> (CGSize, (_ animated: Bool) -> ChatMessageActionButtonsNode))? + if let replyMarkup = replyMarkup { + let (minWidth, buttonsLayout) = actionButtonsLayout(item.account, item.presentationData.theme, item.presentationData.strings, replyMarkup, item.message, maxContentWidth) + maxContentWidth = max(maxContentWidth, minWidth) + actionButtonsFinalize = buttonsLayout + } - return (ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: contentHeight), insets: layoutInsets), { [weak self] animation, _ in + var actionButtonsSizeAndApply: (CGSize, (Bool) -> ChatMessageActionButtonsNode)? + if let actionButtonsFinalize = actionButtonsFinalize { + actionButtonsSizeAndApply = actionButtonsFinalize(maxContentWidth) + } + + var layoutSize = CGSize(width: params.width, height: contentHeight) + if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { + layoutSize.height += actionButtonsSizeAndApply.0.height + } + + return (ListViewItemNodeLayout(contentSize: layoutSize, insets: layoutInsets), { [weak self] animation, _ in if let strongSelf = self { let updatedImageFrame = imageFrame.offsetBy(dx: 0.0, dy: floor((contentHeight - imageSize.height) / 2.0)) @@ -334,6 +357,35 @@ class ChatMessageStickerItemNode: ChatMessageItemView { replyInfoNode.removeFromSupernode() strongSelf.replyInfoNode = nil } + + if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { + var animated = false + if let _ = strongSelf.actionButtonsNode { + if case .System = animation { + animated = true + } + } + let actionButtonsNode = actionButtonsSizeAndApply.1(animated) + let previousFrame = actionButtonsNode.frame + let actionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY), size: actionButtonsSizeAndApply.0) + actionButtonsNode.frame = actionButtonsFrame + if actionButtonsNode !== strongSelf.actionButtonsNode { + strongSelf.actionButtonsNode = actionButtonsNode + actionButtonsNode.buttonPressed = { button in + if let strongSelf = self { + strongSelf.performMessageButtonAction(button: button) + } + } + strongSelf.addSubnode(actionButtonsNode) + } else { + if case let .System(duration) = animation { + actionButtonsNode.layer.animateFrame(from: previousFrame, to: actionButtonsFrame, duration: duration, timingFunction: kCAMediaTimingFunctionSpring) + } + } + } else if let actionButtonsNode = strongSelf.actionButtonsNode { + actionButtonsNode.removeFromSupernode() + strongSelf.actionButtonsNode = nil + } } }) } diff --git a/TelegramUI/DeclareEncodables.swift b/TelegramUI/DeclareEncodables.swift index ef779935b5..7f67a1b63e 100644 --- a/TelegramUI/DeclareEncodables.swift +++ b/TelegramUI/DeclareEncodables.swift @@ -29,6 +29,7 @@ private var telegramUIDeclaredEncodables: Void = { declareEncodable(InstantPageStoredState.self, f: { InstantPageStoredState(decoder: $0) }) declareEncodable(InstantPageStoredDetailsState.self, f: { InstantPageStoredDetailsState(decoder: $0) }) declareEncodable(WatchPresetSettings.self, f: { WatchPresetSettings(decoder: $0) }) + declareEncodable(WebSearchSettings.self, f: { WebSearchSettings(decoder: $0) }) return }() diff --git a/TelegramUI/DeviceContactInfoController.swift b/TelegramUI/DeviceContactInfoController.swift index 07cd709682..518b6b1bf8 100644 --- a/TelegramUI/DeviceContactInfoController.swift +++ b/TelegramUI/DeviceContactInfoController.swift @@ -107,7 +107,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { case addPhoneNumber(Int, PresentationTheme, String) case email(Int, Int, PresentationTheme, String, String, String, Bool?) case url(Int, Int, PresentationTheme, String, String, String, Bool?) - case address(Int, Int, PresentationTheme, String, DeviceContactAddressData, Bool?) + case address(Int, Int, PresentationTheme, String, DeviceContactAddressData, Signal<(TransformImageArguments) -> DrawingContext?, NoError>?, Bool?) case birthday(Int, PresentationTheme, String, Date, String, Bool?) case socialProfile(Int, Int, PresentationTheme, String, DeviceContactSocialProfileData, String, Bool?) case instantMessenger(Int, Int, PresentationTheme, String, DeviceContactInstantMessagingProfileData, String, Bool?) @@ -149,7 +149,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { return .email(catIndex) case let .url(_, catIndex, _, _, _, _, _): return .url(catIndex) - case let .address(_, catIndex, _, _, _, _): + case let .address(_, catIndex, _, _, _, _, _): return .address(catIndex) case .birthday: return .constant(.birthday) @@ -249,8 +249,8 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { } else { return false } - case let .address(lhsIndex, lhsCatIndex, lhsTheme, lhsTitle, lhsValue, lhsSelected): - if case let .address(rhsIndex, rhsCatIndex, rhsTheme, rhsTitle, rhsValue, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsCatIndex == rhsCatIndex, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue, lhsSelected == rhsSelected { + case let .address(lhsIndex, lhsCatIndex, lhsTheme, lhsTitle, lhsValue, lhsImageSignal, lhsSelected): + if case let .address(rhsIndex, rhsCatIndex, rhsTheme, rhsTitle, rhsValue, rhsImageSignal, rhsSelected) = rhs, lhsIndex == rhsIndex, lhsCatIndex == rhsCatIndex, lhsTheme === rhsTheme, lhsTitle == rhsTitle, lhsValue == rhsValue, lhsSelected == rhsSelected { return true } else { return false @@ -300,7 +300,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { return index case let .url(index, _, _, _, _, _, _): return index - case let .address(index, _, _, _, _, _): + case let .address(index, _, _, _, _, _, _): return index case let .birthday(index, _, _, _, _, _): return index @@ -391,7 +391,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { arguments.displayCopyContextMenu(.info(index), value) } }, tag: DeviceContactInfoEntryTag.info(index)) - case let .address(_, index, theme, title, value, selected): + case let .address(_, index, theme, title, value, imageSignal, selected): var string = "" func combineComponent(string: inout String, component: String) { if !component.isEmpty { @@ -407,7 +407,7 @@ private enum DeviceContactInfoEntry: ItemListNodeEntry { combineComponent(string: &string, component: value.city) combineComponent(string: &string, component: value.country) combineComponent(string: &string, component: value.postcode) - return ItemListTextWithLabelItem(theme: theme, label: title, text: string, textColor: .primary, enabledEntitiyTypes: [], multiline: true, selected: selected, sectionId: self.section, action: { + return ItemListAddressItem(theme: theme, label: title, text: string, imageSignal: imageSignal, selected: selected, sectionId: self.section, action: { if selected != nil { arguments.toggleSelection(.address(value)) } else { @@ -597,7 +597,7 @@ private func deviceContactInfoEntries(account: Account, presentationData: Presen var addressIndex = 0 for address in contactData.addresses { - entries.append(.address(entries.count, addressIndex, presentationData.theme, localizedGenericContactFieldLabel(label: address.label, strings: presentationData.strings), address, selecting ? !state.excludedComponents.contains(.address(address)) : nil)) + entries.append(.address(entries.count, addressIndex, presentationData.theme, localizedGenericContactFieldLabel(label: address.label, strings: presentationData.strings), address, nil, selecting ? !state.excludedComponents.contains(.address(address)) : nil)) addressIndex += 1 } diff --git a/TelegramUI/GalleryControllerNode.swift b/TelegramUI/GalleryControllerNode.swift index d1bb30a2bd..1efa905816 100644 --- a/TelegramUI/GalleryControllerNode.swift +++ b/TelegramUI/GalleryControllerNode.swift @@ -139,6 +139,7 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog } else { node = strongSelf.currentThumbnailContainerNode } + node?.alpha = strongSelf.areControlsHidden ? 0.0 : 1.0 node?.updateItems(items, indexes: indexes, centralIndex: convertedIndex, progress: progress) node?.itemChanged = { [weak self] index in if let strongSelf = self { @@ -159,10 +160,12 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog fromLeft = true } if let current = strongSelf.currentThumbnailContainerNode { - current.animateOut(toRight: fromLeft) - current.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak current] _ in - current?.removeFromSupernode() - }) + if !strongSelf.areControlsHidden { + current.animateOut(toRight: fromLeft) + current.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak current] _ in + current?.removeFromSupernode() + }) + } } strongSelf.currentThumbnailContainerNode = node if let node = node { diff --git a/TelegramUI/GridMessageSelectionNode.swift b/TelegramUI/GridMessageSelectionNode.swift index 0082ce09c3..23974e4cbd 100644 --- a/TelegramUI/GridMessageSelectionNode.swift +++ b/TelegramUI/GridMessageSelectionNode.swift @@ -53,6 +53,6 @@ final class GridMessageSelectionNode: ASDisplayNode { super.layout() let checkSize = CGSize(width: 32.0, height: 32.0) - self.checkNode.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width - 4.0, y: 4.0), size: checkSize) + self.checkNode.frame = CGRect(origin: CGPoint(x: self.bounds.size.width - checkSize.width, y: 0.0), size: checkSize) } } diff --git a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift index a4be920a85..c49119a419 100644 --- a/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift +++ b/TelegramUI/HorizontalListContextResultsChatInputPanelItem.swift @@ -87,7 +87,6 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode private var statusDisposable = MetaDisposable() private let statusNode: RadialStatusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) - override var visibility: ListViewItemNodeVisibility { didSet { switch visibility { @@ -170,7 +169,7 @@ final class HorizontalListContextResultsChatInputPanelItemNode: ListViewItemNode displayLink.isPaused = true displayLink.invalidate() } - statusDisposable.dispose() + self.statusDisposable.dispose() } override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) { diff --git a/TelegramUI/ItemListAddressItem.swift b/TelegramUI/ItemListAddressItem.swift new file mode 100644 index 0000000000..c8a0235ff8 --- /dev/null +++ b/TelegramUI/ItemListAddressItem.swift @@ -0,0 +1,319 @@ +import Foundation +import Display +import AsyncDisplayKit +import SwiftSignalKit + +final class ItemListAddressItem: ListViewItem, ItemListItem { + let theme: PresentationTheme + let label: String + let text: String + let imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? + let selected: Bool? + let sectionId: ItemListSectionId + let action: (() -> Void)? + let longTapAction: (() -> Void)? + let linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? + + let tag: Any? + + init(theme: PresentationTheme, label: String, text: String, imageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?, selected: Bool? = nil, sectionId: ItemListSectionId, action: (() -> Void)?, longTapAction: (() -> Void)? = nil, linkItemAction: ((TextLinkItemActionType, TextLinkItem) -> Void)? = nil, tag: Any? = nil) { + self.theme = theme + self.label = label + self.text = text + self.imageSignal = imageSignal + self.selected = selected + self.sectionId = sectionId + self.action = action + self.longTapAction = longTapAction + self.linkItemAction = linkItemAction + self.tag = tag + } + + func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal?, (ListViewItemApply) -> Void)) -> Void) { + async { + let node = ItemListAddressItemNode() + let (layout, apply) = node.asyncLayout()(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + + node.contentSize = layout.contentSize + node.insets = layout.insets + + Queue.mainQueue().async { + completion(node, { + return (nil, { _ in apply(.None) }) + }) + } + } + } + + func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) { + Queue.mainQueue().async { + if let nodeValue = node() as? ItemListAddressItemNode { + let makeLayout = nodeValue.asyncLayout() + + async { + let (layout, apply) = makeLayout(self, params, itemListNeighbors(item: self, topItem: previousItem as? ItemListItem, bottomItem: nextItem as? ItemListItem)) + Queue.mainQueue().async { + completion(layout, { _ in + apply(animation) + }) + } + } + } + } + } + + var selectable: Bool { + return self.action != nil + } + + func selected(listView: ListView) { + listView.clearHighlightAnimated(true) + self.action?() + } +} + +private let labelFont = Font.regular(14.0) +private let textFont = Font.regular(17.0) +private let textBoldFont = Font.medium(17.0) +private let textItalicFont = Font.italic(17.0) +private let textFixedFont = Font.regular(17.0) + +class ItemListAddressItemNode: ListViewItemNode { + let labelNode: TextNode + let textNode: TextNode + + private let backgroundNode: ASDisplayNode + private let topStripeNode: ASDisplayNode + private let bottomStripeNode: ASDisplayNode + private let highlightedBackgroundNode: ASDisplayNode + private let imageNode: TransformImageNode + private var selectionNode: ItemListSelectableControlNode? + + var item: ItemListAddressItem? + + override var canBeLongTapped: Bool { + return true + } + + init() { + self.backgroundNode = ASDisplayNode() + self.backgroundNode.isLayerBacked = true + + self.topStripeNode = ASDisplayNode() + self.topStripeNode.isLayerBacked = true + + self.bottomStripeNode = ASDisplayNode() + self.bottomStripeNode.isLayerBacked = true + + self.highlightedBackgroundNode = ASDisplayNode() + self.highlightedBackgroundNode.isLayerBacked = true + + self.labelNode = TextNode() + self.labelNode.isUserInteractionEnabled = false + self.labelNode.contentMode = .left + self.labelNode.contentsScale = UIScreen.main.scale + + self.textNode = TextNode() + self.textNode.isUserInteractionEnabled = false + self.textNode.contentMode = .left + self.textNode.contentsScale = UIScreen.main.scale + + self.imageNode = TransformImageNode() + + super.init(layerBacked: false, dynamicBounce: false) + + self.addSubnode(self.labelNode) + self.addSubnode(self.textNode) + self.addSubnode(self.imageNode) + } + + func asyncLayout() -> (_ item: ItemListAddressItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation) -> Void) { + let makeLabelLayout = TextNode.asyncLayout(self.labelNode) + let makeTextLayout = TextNode.asyncLayout(self.textNode) + + let currentItem = self.item + + let selectionNodeLayout = ItemListSelectableControlNode.asyncLayout(self.selectionNode) + + return { item, params, neighbors in + var updatedTheme: PresentationTheme? + if currentItem?.theme !== item.theme { + updatedTheme = item.theme + } + + let insets = itemListNeighborsPlainInsets(neighbors) + let leftInset: CGFloat = 16.0 + params.leftInset + let rightInset: CGFloat = 8.0 + params.rightInset + let separatorHeight = UIScreenPixel + + var leftOffset: CGFloat = 0.0 + var selectionNodeWidthAndApply: (CGFloat, (CGSize, Bool) -> ItemListSelectableControlNode)? + if let selected = item.selected { + let (selectionWidth, selectionApply) = selectionNodeLayout(item.theme.list.itemCheckColors.strokeColor, item.theme.list.itemCheckColors.fillColor, item.theme.list.itemCheckColors.foregroundColor, selected, false) + selectionNodeWidthAndApply = (selectionWidth, selectionApply) + leftOffset += selectionWidth - 8.0 + } + + let labelColor = item.theme.list.itemPrimaryTextColor + let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor: labelColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - leftOffset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + + let baseColor = item.theme.list.itemPrimaryTextColor + let string = stringWithAppliedEntities(item.text, entities: [], baseColor: baseColor, linkColor: item.theme.list.itemAccentColor, baseFont: textFont, linkFont: textFont, boldFont: textBoldFont, italicFont: textItalicFont, fixedFont: textFixedFont) + + let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: string, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - leftOffset - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) + let contentSize = CGSize(width: params.width, height: textLayout.size.height + 39.0) + let nodeLayout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets) + return (nodeLayout, { [weak self] animation in + if let strongSelf = self { + let transition: ContainedViewLayoutTransition + if animation.isAnimated { + transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) + } else { + transition = .immediate + } + + strongSelf.item = item + + if let _ = updatedTheme { + strongSelf.topStripeNode.backgroundColor = item.theme.list.itemPlainSeparatorColor + strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemPlainSeparatorColor + strongSelf.backgroundNode.backgroundColor = item.theme.list.plainBackgroundColor + strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor + } + + let _ = labelApply() + let _ = textApply() + + if let (selectionWidth, selectionApply) = selectionNodeWidthAndApply { + let selectionFrame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: selectionWidth, height: nodeLayout.contentSize.height)) + let selectionNode = selectionApply(selectionFrame.size, transition.isAnimated) + if selectionNode !== strongSelf.selectionNode { + strongSelf.selectionNode?.removeFromSupernode() + strongSelf.selectionNode = selectionNode + strongSelf.addSubnode(selectionNode) + selectionNode.frame = selectionFrame + transition.animatePosition(node: selectionNode, from: CGPoint(x: -selectionFrame.size.width / 2.0, y: selectionFrame.midY)) + } else { + transition.updateFrame(node: selectionNode, frame: selectionFrame) + } + } else if let selectionNode = strongSelf.selectionNode { + strongSelf.selectionNode = nil + let selectionFrame = selectionNode.frame + transition.updatePosition(node: selectionNode, position: CGPoint(x: -selectionFrame.size.width / 2.0, y: selectionFrame.midY), completion: { [weak selectionNode] _ in + selectionNode?.removeFromSupernode() + }) + } + + strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 11.0), size: labelLayout.size) + strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 31.0), size: textLayout.size) + + let leftInset: CGFloat + let style = ItemListStyle.plain + switch style { + case .plain: + leftInset = 16.0 + params.leftInset + leftOffset + + if strongSelf.backgroundNode.supernode != nil { + strongSelf.backgroundNode.removeFromSupernode() + } + if strongSelf.topStripeNode.supernode != nil { + strongSelf.topStripeNode.removeFromSupernode() + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 0) + } + + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: leftInset, y: contentSize.height - separatorHeight), size: CGSize(width: params.width - leftInset, height: separatorHeight)) + case .blocks: + leftInset = 16.0 + params.leftInset + + if strongSelf.backgroundNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0) + } + if strongSelf.topStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.topStripeNode, at: 1) + } + if strongSelf.bottomStripeNode.supernode == nil { + strongSelf.insertSubnode(strongSelf.bottomStripeNode, at: 2) + } + switch neighbors.top { + case .sameSection(false): + strongSelf.topStripeNode.isHidden = true + default: + strongSelf.topStripeNode.isHidden = false + } + let bottomStripeInset: CGFloat + let bottomStripeOffset: CGFloat + switch neighbors.bottom { + case .sameSection(false): + bottomStripeInset = 16.0 + params.leftInset + bottomStripeOffset = -separatorHeight + default: + bottomStripeInset = 0.0 + bottomStripeOffset = 0.0 + } + strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight))) + strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: separatorHeight)) + strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: params.width - bottomStripeInset, height: separatorHeight)) + } + + strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: contentSize.height + UIScreenPixel + UIScreenPixel)) + } + }) + } + } + + override func setHighlighted(_ highlighted: Bool, at point: CGPoint, animated: Bool) { + super.setHighlighted(highlighted, at: point, animated: animated) + + if highlighted && self.selectionNode == nil { + self.highlightedBackgroundNode.alpha = 1.0 + if self.highlightedBackgroundNode.supernode == nil { + var anchorNode: ASDisplayNode? + if self.bottomStripeNode.supernode != nil { + anchorNode = self.bottomStripeNode + } else if self.topStripeNode.supernode != nil { + anchorNode = self.topStripeNode + } else if self.backgroundNode.supernode != nil { + anchorNode = self.backgroundNode + } + if let anchorNode = anchorNode { + self.insertSubnode(self.highlightedBackgroundNode, aboveSubnode: anchorNode) + } else { + self.addSubnode(self.highlightedBackgroundNode) + } + } + } else { + if self.highlightedBackgroundNode.supernode != nil { + if animated { + self.highlightedBackgroundNode.layer.animateAlpha(from: self.highlightedBackgroundNode.alpha, to: 0.0, duration: 0.4, completion: { [weak self] completed in + if let strongSelf = self { + if completed { + strongSelf.highlightedBackgroundNode.removeFromSupernode() + } + } + }) + self.highlightedBackgroundNode.alpha = 0.0 + } else { + self.highlightedBackgroundNode.removeFromSupernode() + } + } + } + } + + override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) { + self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4) + } + + override func animateRemoved(_ currentTimestamp: Double, duration: Double) { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false) + } + + override func longTapped() { + self.item?.longTapAction?() + } + + var tag: Any? { + return self.item?.tag + } +} diff --git a/TelegramUI/LegacyAttachmentMenu.swift b/TelegramUI/LegacyAttachmentMenu.swift index acc5c81832..eb767e9d13 100644 --- a/TelegramUI/LegacyAttachmentMenu.swift +++ b/TelegramUI/LegacyAttachmentMenu.swift @@ -6,7 +6,7 @@ import SwiftSignalKit import Postbox import TelegramCore -func legacyAttachmentMenu(account: Account, peer: Peer, editMediaOptions: MessageMediaEditingOptions?, saveEditedPhotos: Bool, allowGrouping: Bool, theme: PresentationTheme, strings: PresentationStrings, parentController: LegacyController, recentlyUsedInlineBots: [Peer], openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, sendMessagesWithSignals: @escaping ([Any]?) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void) -> TGMenuSheetController { +func legacyAttachmentMenu(account: Account, peer: Peer, editMediaOptions: MessageMediaEditingOptions?, saveEditedPhotos: Bool, allowGrouping: Bool, theme: PresentationTheme, strings: PresentationStrings, parentController: LegacyController, recentlyUsedInlineBots: [Peer], openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, sendMessagesWithSignals: @escaping ([Any]?) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void) -> TGMenuSheetController { let isSecretChat = peer.id.namespace == Namespaces.Peer.SecretChat let controller = TGMenuSheetController(context: parentController.context, dark: false)! @@ -64,6 +64,14 @@ func legacyAttachmentMenu(account: Account, peer: Peer, editMediaOptions: Messag controller?.dismiss(animated: true) openGallery() })! + if !editing { + galleryItem.longPressAction = { [weak controller] in + if let controller = controller { + controller.dismiss(animated: true) + } + openWebSearch() + } + } itemViews.append(galleryItem) underlyingViews.append(galleryItem) @@ -145,9 +153,10 @@ func legacyPasteMenu(account: Account, peer: Peer, saveEditedPhotos: Bool, allow } let recipientName = peer.displayTitle + legacyController.enableSizeClassSignal = true legacyController.presentationCompleted = { [weak legacyController, weak baseController] in if let strongLegacyController = legacyController, let baseController = baseController { - TGClipboardMenu.present(inParentController: baseController, context: strongLegacyController.context, images: images, hasCaption: true, hasTimer: hasTimer, recipientName: recipientName, completed: { selectionContext, editingContext, currentItem in + let controller = TGClipboardMenu.present(inParentController: baseController, context: strongLegacyController.context, images: images, hasCaption: true, hasTimer: hasTimer, recipientName: recipientName, completed: { selectionContext, editingContext, currentItem in let signals = TGClipboardMenu.resultSignals(for: selectionContext, editingContext: editingContext, currentItem: currentItem, descriptionGenerator: legacyAssetPickerItemGenerator()) sendMessagesWithSignals(signals) }, dismissed: { @@ -155,7 +164,11 @@ func legacyPasteMenu(account: Account, peer: Peer, saveEditedPhotos: Bool, allow strongLegacyController.dismiss() } }, sourceView: baseController.view, sourceRect: nil) + controller?.customRemoveFromParentViewController = { [weak legacyController] in + legacyController?.dismiss() + } } } + return legacyController } diff --git a/TelegramUI/PeerMediaCollectionController.swift b/TelegramUI/PeerMediaCollectionController.swift index a49c844348..7d4cb151dc 100644 --- a/TelegramUI/PeerMediaCollectionController.swift +++ b/TelegramUI/PeerMediaCollectionController.swift @@ -529,7 +529,6 @@ public class PeerMediaCollectionController: TelegramController { func updateInterfaceState(animated: Bool = true, _ f: (PeerMediaCollectionInterfaceState) -> PeerMediaCollectionInterfaceState) { let updatedInterfaceState = f(self.interfaceState) - if self.isNodeLoaded { self.mediaCollectionDisplayNode.updateMediaCollectionInterfaceState(updatedInterfaceState, animated: animated) } diff --git a/TelegramUI/PreferencesKeys.swift b/TelegramUI/PreferencesKeys.swift index e0b37fd774..7848ab2b62 100644 --- a/TelegramUI/PreferencesKeys.swift +++ b/TelegramUI/PreferencesKeys.swift @@ -18,6 +18,7 @@ private enum ApplicationSpecificPreferencesKeyValues: Int32 { case contactSynchronizationSettings = 12 case stickerSettings = 13 case watchPresetSettings = 14 + case webSearchSettings = 15 } public struct ApplicationSpecificPreferencesKeys { @@ -36,4 +37,5 @@ public struct ApplicationSpecificPreferencesKeys { public static let contactSynchronizationSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.contactSynchronizationSettings.rawValue) public static let stickerSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.stickerSettings.rawValue) public static let watchPresetSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.watchPresetSettings.rawValue) + public static let webSearchSettings = applicationSpecificPreferencesKey(ApplicationSpecificPreferencesKeyValues.webSearchSettings.rawValue) } diff --git a/TelegramUI/PresentationData.swift b/TelegramUI/PresentationData.swift index 5d088c5556..e48f742712 100644 --- a/TelegramUI/PresentationData.swift +++ b/TelegramUI/PresentationData.swift @@ -11,6 +11,16 @@ public struct PresentationDateTimeFormat: Equatable { let dateSeparator: String } +public struct PresentationVolumeControlStatusBarIcons: Equatable { + let offIcon: UIImage + let halfIcon: UIImage + let fullIcon: UIImage + + public var images: (UIImage, UIImage, UIImage) { + return (self.offIcon, self.halfIcon, self.fullIcon) + } +} + public enum PresentationTimeFormat { case regular case military @@ -42,14 +52,14 @@ public final class PresentationData: Equatable { public let strings: PresentationStrings public let theme: PresentationTheme public let chatWallpaper: TelegramWallpaper - public let volumeControlStatusBarIcons: (UIImage, UIImage, UIImage) + public let volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons public let fontSize: PresentationFontSize public let dateTimeFormat: PresentationDateTimeFormat public let nameDisplayOrder: PresentationPersonNameOrder public let nameSortOrder: PresentationPersonNameOrder public let disableAnimations: Bool - public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, volumeControlStatusBarIcons: (UIImage, UIImage, UIImage), fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool) { + public init(strings: PresentationStrings, theme: PresentationTheme, chatWallpaper: TelegramWallpaper, volumeControlStatusBarIcons: PresentationVolumeControlStatusBarIcons, fontSize: PresentationFontSize, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, nameSortOrder: PresentationPersonNameOrder, disableAnimations: Bool) { self.strings = strings self.theme = theme self.chatWallpaper = chatWallpaper @@ -94,8 +104,8 @@ func dictFromLocalization(_ value: Localization) -> [String: String] { return dict } -private func volumeControlStatusBarIcons() -> (UIImage, UIImage, UIImage) { - return (UIImage(bundleImageName: "Components/Volume/VolumeOff")!, UIImage(bundleImageName: "Components/Volume/VolumeHalf")!, UIImage(bundleImageName: "Components/Volume/VolumeFull")!) +private func volumeControlStatusBarIcons() -> PresentationVolumeControlStatusBarIcons { + return PresentationVolumeControlStatusBarIcons(offIcon: UIImage(bundleImageName: "Components/Volume/VolumeOff")!, halfIcon: UIImage(bundleImageName: "Components/Volume/VolumeHalf")!, fullIcon: UIImage(bundleImageName: "Components/Volume/VolumeFull")!) } private func currentDateTimeFormat() -> PresentationDateTimeFormat { diff --git a/TelegramUI/Resources/Stripe/stp_card_amex@2x.png b/TelegramUI/Resources/Stripe/stp_card_amex@2x.png index 04feb23eeb..a0704ff63a 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_amex@2x.png and b/TelegramUI/Resources/Stripe/stp_card_amex@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_amex@3x.png b/TelegramUI/Resources/Stripe/stp_card_amex@3x.png index a2a34960d2..9f6a91488d 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_amex@3x.png and b/TelegramUI/Resources/Stripe/stp_card_amex@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_amex_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_amex_template@2x.png index 64eb765a5b..d169e4daa9 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_amex_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_amex_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_amex_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_amex_template@3x.png index b07fcf2e4f..7e2500fef1 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_amex_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_amex_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_applepay@2x.png b/TelegramUI/Resources/Stripe/stp_card_applepay@2x.png index 4ff86964c7..4df4ef55cd 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_applepay@2x.png and b/TelegramUI/Resources/Stripe/stp_card_applepay@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_applepay@3x.png b/TelegramUI/Resources/Stripe/stp_card_applepay@3x.png index 35e7caffa1..59247418a0 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_applepay@3x.png and b/TelegramUI/Resources/Stripe/stp_card_applepay@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_applepay_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_applepay_template@2x.png index fc1b0efea6..c202fb00cd 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_applepay_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_applepay_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_applepay_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_applepay_template@3x.png index 950928f5a4..a5ea4be7a4 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_applepay_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_applepay_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_cvc@2x.png b/TelegramUI/Resources/Stripe/stp_card_cvc@2x.png index 7f47afe7d7..33ce353a0e 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_cvc@2x.png and b/TelegramUI/Resources/Stripe/stp_card_cvc@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_cvc@3x.png b/TelegramUI/Resources/Stripe/stp_card_cvc@3x.png index a0bb31dea9..55acddf299 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_cvc@3x.png and b/TelegramUI/Resources/Stripe/stp_card_cvc@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_cvc_amex@2x.png b/TelegramUI/Resources/Stripe/stp_card_cvc_amex@2x.png index 68bee40cce..820426ff9a 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_cvc_amex@2x.png and b/TelegramUI/Resources/Stripe/stp_card_cvc_amex@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_cvc_amex@3x.png b/TelegramUI/Resources/Stripe/stp_card_cvc_amex@3x.png index 961108d8f4..f167ef9d4e 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_cvc_amex@3x.png and b/TelegramUI/Resources/Stripe/stp_card_cvc_amex@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_diners@2x.png b/TelegramUI/Resources/Stripe/stp_card_diners@2x.png index 6733bcc687..3558f64609 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_diners@2x.png and b/TelegramUI/Resources/Stripe/stp_card_diners@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_diners@3x.png b/TelegramUI/Resources/Stripe/stp_card_diners@3x.png index c24a15233e..f551a33e3b 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_diners@3x.png and b/TelegramUI/Resources/Stripe/stp_card_diners@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_diners_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_diners_template@2x.png index 9dd1c08d7f..e8cb329473 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_diners_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_diners_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_diners_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_diners_template@3x.png index 99725e154e..4d8d16dd83 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_diners_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_diners_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_discover@2x.png b/TelegramUI/Resources/Stripe/stp_card_discover@2x.png index 1fd9d2a1f8..8c2748f8fd 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_discover@2x.png and b/TelegramUI/Resources/Stripe/stp_card_discover@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_discover@3x.png b/TelegramUI/Resources/Stripe/stp_card_discover@3x.png index b32cc8fa23..199e03cf34 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_discover@3x.png and b/TelegramUI/Resources/Stripe/stp_card_discover@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_discover_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_discover_template@2x.png index 2861f32022..63b79012da 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_discover_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_discover_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_discover_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_discover_template@3x.png index c0770f4f57..f8538acfbd 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_discover_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_discover_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_form_applepay@2x.png b/TelegramUI/Resources/Stripe/stp_card_form_applepay@2x.png index 705d93bc7e..01da57b3f3 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_form_applepay@2x.png and b/TelegramUI/Resources/Stripe/stp_card_form_applepay@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_form_applepay@3x.png b/TelegramUI/Resources/Stripe/stp_card_form_applepay@3x.png index 23716436e3..d7fa0f198c 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_form_applepay@3x.png and b/TelegramUI/Resources/Stripe/stp_card_form_applepay@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_form_back@2x.png b/TelegramUI/Resources/Stripe/stp_card_form_back@2x.png index cf9adcaaad..7ead641d27 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_form_back@2x.png and b/TelegramUI/Resources/Stripe/stp_card_form_back@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_form_back@3x.png b/TelegramUI/Resources/Stripe/stp_card_form_back@3x.png index 9aa39e3c2f..00b054591f 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_form_back@3x.png and b/TelegramUI/Resources/Stripe/stp_card_form_back@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_form_front@2x.png b/TelegramUI/Resources/Stripe/stp_card_form_front@2x.png index 69af8e63c1..e5a9048780 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_form_front@2x.png and b/TelegramUI/Resources/Stripe/stp_card_form_front@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_jcb@2x.png b/TelegramUI/Resources/Stripe/stp_card_jcb@2x.png index 7f0a74b771..90e5908d16 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_jcb@2x.png and b/TelegramUI/Resources/Stripe/stp_card_jcb@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_jcb@3x.png b/TelegramUI/Resources/Stripe/stp_card_jcb@3x.png index dab7a5fbdf..0f74728392 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_jcb@3x.png and b/TelegramUI/Resources/Stripe/stp_card_jcb@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_jcb_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_jcb_template@2x.png index 5504c9733f..a7326e02f8 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_jcb_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_jcb_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_jcb_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_jcb_template@3x.png index 92f1b706a4..ded9de569d 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_jcb_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_jcb_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_mastercard@2x.png b/TelegramUI/Resources/Stripe/stp_card_mastercard@2x.png index 137c3d7c12..e2f915a166 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_mastercard@2x.png and b/TelegramUI/Resources/Stripe/stp_card_mastercard@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_mastercard@3x.png b/TelegramUI/Resources/Stripe/stp_card_mastercard@3x.png index 4a699ba532..8564aa2662 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_mastercard@3x.png and b/TelegramUI/Resources/Stripe/stp_card_mastercard@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_mastercard_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_mastercard_template@2x.png index ac4b140af4..edae0d55e4 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_mastercard_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_mastercard_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_mastercard_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_mastercard_template@3x.png index b879eea2bf..e1129569d6 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_mastercard_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_mastercard_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_placeholder_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_placeholder_template@2x.png index 2b55b1f521..0fe21a041b 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_placeholder_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_placeholder_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_placeholder_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_placeholder_template@3x.png index c84d9299d8..3150cdab08 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_placeholder_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_placeholder_template@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_visa@2x.png b/TelegramUI/Resources/Stripe/stp_card_visa@2x.png index a5c3eeb02f..bc0f0d1d93 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_visa@2x.png and b/TelegramUI/Resources/Stripe/stp_card_visa@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_visa@3x.png b/TelegramUI/Resources/Stripe/stp_card_visa@3x.png index 6b75ed884b..23bcda3c92 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_visa@3x.png and b/TelegramUI/Resources/Stripe/stp_card_visa@3x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_visa_template@2x.png b/TelegramUI/Resources/Stripe/stp_card_visa_template@2x.png index 12ef2ce182..e634ef9c29 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_visa_template@2x.png and b/TelegramUI/Resources/Stripe/stp_card_visa_template@2x.png differ diff --git a/TelegramUI/Resources/Stripe/stp_card_visa_template@3x.png b/TelegramUI/Resources/Stripe/stp_card_visa_template@3x.png index e95c9a5e34..cb6ea246e6 100755 Binary files a/TelegramUI/Resources/Stripe/stp_card_visa_template@3x.png and b/TelegramUI/Resources/Stripe/stp_card_visa_template@3x.png differ diff --git a/TelegramUI/SearchBarNode.swift b/TelegramUI/SearchBarNode.swift index 7faad911b9..97878e26ef 100644 --- a/TelegramUI/SearchBarNode.swift +++ b/TelegramUI/SearchBarNode.swift @@ -129,7 +129,7 @@ final class SearchBarNodeTheme { init(theme: PresentationTheme, active: Bool = true) { self.background = active ? theme.rootController.activeNavigationSearchBar.backgroundColor : theme.rootController.navigationBar.backgroundColor - self.separator = theme.rootController.navigationBar.separatorColor + self.separator = active ? theme.rootController.navigationBar.separatorColor : theme.rootController.navigationBar.backgroundColor self.inputFill = theme.rootController.activeNavigationSearchBar.inputFillColor self.placeholder = theme.rootController.activeNavigationSearchBar.inputPlaceholderTextColor self.primaryText = theme.rootController.activeNavigationSearchBar.inputTextColor @@ -143,6 +143,7 @@ final class SearchBarNodeTheme { class SearchBarNode: ASDisplayNode, UITextFieldDelegate { var cancel: (() -> Void)? var textUpdated: ((String) -> Void)? + var textReturned: ((String) -> Void)? var clearPrefix: (() -> Void)? private let backgroundNode: ASDisplayNode @@ -213,6 +214,15 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate { } } + var hasCancelButton: Bool = true { + didSet { + self.cancelButton.isHidden = !self.hasCancelButton + if let (boundingSize, leftInset, rightInset) = self.validLayout { + self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate) + } + } + } + private var validLayout: (CGSize, CGFloat, CGFloat)? private var theme: SearchBarNodeTheme @@ -244,7 +254,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate { self.textField = SearchBarTextField() self.textField.autocorrectionType = .no - self.textField.returnKeyType = .done + self.textField.returnKeyType = .search self.textField.font = Font.regular(14.0) self.textField.textColor = theme.primaryText @@ -318,7 +328,7 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate { let cancelButtonSize = self.cancelButton.measure(CGSize(width: 100.0, height: CGFloat.infinity)) transition.updateFrame(node: self.cancelButton, frame: CGRect(origin: CGPoint(x: contentFrame.maxX - 8.0 - cancelButtonSize.width, y: verticalOffset + 31.0), size: cancelButtonSize)) - let textBackgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX + 8.0, y: verticalOffset + 28.0), size: CGSize(width: contentFrame.width - 16.0 - cancelButtonSize.width - 11.0, height: 28.0)) + let textBackgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX + 8.0, y: verticalOffset + 28.0), size: CGSize(width: contentFrame.width - 16.0 - (self.hasCancelButton ? cancelButtonSize.width + 11.0 : 0.0), height: 28.0)) transition.updateFrame(node: self.textBackgroundNode, frame: textBackgroundFrame) let textFrame = CGRect(origin: CGPoint(x: textBackgroundFrame.minX + 23.0, y: textBackgroundFrame.minY), size: CGSize(width: max(1.0, textBackgroundFrame.size.width - 23.0 - 20.0), height: textBackgroundFrame.size.height)) @@ -470,6 +480,9 @@ class SearchBarNode: ASDisplayNode, UITextFieldDelegate { func textFieldShouldReturn(_ textField: UITextField) -> Bool { self.textField.resignFirstResponder() + if let textReturned = self.textReturned { + textReturned(textField.text ?? "") + } return false } diff --git a/TelegramUI/WebSearchController.swift b/TelegramUI/WebSearchController.swift index dc1eb99ede..8a116e359f 100644 --- a/TelegramUI/WebSearchController.swift +++ b/TelegramUI/WebSearchController.swift @@ -5,11 +5,46 @@ import Display import AsyncDisplayKit import TelegramCore -final class WebSearchController: ViewController { - private let account: Account +private func requestContextResults(account: Account, botId: PeerId, query: String, peerId: PeerId, offset: String = "", existingResults: ChatContextResultCollection? = nil, limit: Int = 30) -> Signal { + return requestChatContextResults(account: account, botId: botId, peerId: peerId, query: query, offset: offset) + |> mapToSignal { results -> Signal in + var collection = existingResults + if let existingResults = existingResults, let results = results { + var newResults: [ChatContextResult] = [] + newResults.append(contentsOf: existingResults.results) + newResults.append(contentsOf: results.results) + collection = ChatContextResultCollection(botId: existingResults.botId, peerId: existingResults.peerId, query: existingResults.query, geoPoint: existingResults.geoPoint, queryId: results.queryId, nextOffset: results.nextOffset, presentation: existingResults.presentation, switchPeer: existingResults.switchPeer, results: newResults, cacheTimeout: existingResults.cacheTimeout) + } else { + collection = results + } + if let collection = collection, collection.results.count < limit, let nextOffset = collection.nextOffset { + return requestContextResults(account: account, botId: botId, query: query, peerId: peerId, offset: nextOffset, existingResults: collection) + } else { + return .single(collection) + } + } +} + +final class WebSearchControllerInteraction { + let openResult: (ChatContextResult) -> Void + let toggleSelection: ([String], Bool) -> Void + let sendSelected: (ChatContextResultCollection) -> Void + var selectionState: WebSearchSelectionState? + init(openResult: @escaping (ChatContextResult) -> Void, toggleSelection: @escaping ([String], Bool) -> Void, sendSelected: @escaping (ChatContextResultCollection) -> Void) { + self.openResult = openResult + self.toggleSelection = toggleSelection + self.sendSelected = sendSelected + } +} + +final class WebSearchController: ViewController { private var validLayout: ContainerViewLayout? + private let account: Account + private let chatLocation: ChatLocation + private let configuration: SearchBotsConfiguration + private var controllerNode: WebSearchControllerNode { return self.displayNode as! WebSearchControllerNode } @@ -19,44 +54,76 @@ final class WebSearchController: ViewController { return self._ready } - private var presentationData: PresentationData - private var presentationDataDisposable: Disposable? + private var didPlayPresentationAnimation = false + + private var controllerInteraction: WebSearchControllerInteraction? + private var interfaceState: WebSearchInterfaceState + private let interfaceStatePromise = ValuePromise() + + private var disposable: Disposable? + private let resultsDisposable = MetaDisposable() private var navigationContentNode: WebSearchNavigationContentNode? - init(account: Account) { + init(account: Account, chatLocation: ChatLocation, configuration: SearchBotsConfiguration, sendSelected: @escaping ([String], ChatContextResultCollection) -> Void) { self.account = account - self.presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + self.chatLocation = chatLocation + self.configuration = configuration - super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme).withUpdatedSeparatorColor(self.presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings))) + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + self.interfaceState = WebSearchInterfaceState(presentationData: presentationData) + + super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme).withUpdatedSeparatorColor(presentationData.theme.rootController.navigationBar.backgroundColor), strings: NavigationBarStrings(presentationStrings: presentationData.strings))) + self.statusBar.statusBarStyle = presentationData.theme.rootController.statusBar.style.style - self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBar.style.style - - self.presentationDataDisposable = (account.telegramApplicationContext.presentationData - |> deliverOnMainQueue).start(next: { [weak self] presentationData in - if let strongSelf = self { - let previousTheme = strongSelf.presentationData.theme - let previousStrings = strongSelf.presentationData.strings - - strongSelf.presentationData = presentationData - - if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings { - //strongSelf.updateThemeAndStrings() + let settings = self.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.webSearchSettings]) + |> take(1) + |> map { view -> WebSearchSettings in + if let current = view.values[ApplicationSpecificPreferencesKeys.webSearchSettings] as? WebSearchSettings { + return current + } else { + return WebSearchSettings.defaultSettings + } + } + + self.disposable = ((combineLatest(settings, account.telegramApplicationContext.presentationData)) + |> deliverOnMainQueue).start(next: { [weak self] settings, presentationData in + guard let strongSelf = self else { + return + } + strongSelf.updateInterfaceState { current -> WebSearchInterfaceState in + var updated = current + if current.state?.mode != settings.mode { + updated = updated.withUpdatedMode(settings.mode) } + if current.presentationData !== presentationData { + updated = updated.withUpdatedPresentationData(presentationData) + } + return updated } }) - let navigationContentNode = WebSearchNavigationContentNode(theme: self.presentationData.theme, strings: self.presentationData.strings, cancel: { [weak self] in - - }) + let navigationContentNode = WebSearchNavigationContentNode(theme: presentationData.theme, strings: presentationData.strings) self.navigationContentNode = navigationContentNode navigationContentNode.setQueryUpdated { [weak self] query in guard let strongSelf = self, strongSelf.isNodeLoaded else { return } - //strongSelf.controllerNode.updateSearchQuery(query) + strongSelf.updateSearchQuery(query) } self.navigationBar?.setContentNode(navigationContentNode, animated: false) + + self.controllerInteraction = WebSearchControllerInteraction(openResult: { result in + + }, toggleSelection: { [weak self] ids, value in + if let strongSelf = self { + strongSelf.updateInterfaceState { $0.withToggledSelectedMessages(ids, value: value) } + } + }, sendSelected: { [weak self] collection in + if let strongSelf = self, let state = strongSelf.interfaceState.state, !state.selectionState.selectedIds.isEmpty { + sendSelected(Array(state.selectionState.selectedIds), collection) + } + }) } required public init(coder aDecoder: NSCoder) { @@ -64,16 +131,184 @@ final class WebSearchController: ViewController { } deinit { - self.presentationDataDisposable?.dispose() + self.disposable?.dispose() + } + + public override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + if let presentationArguments = self.presentationArguments as? ViewControllerPresentationArguments, !self.didPlayPresentationAnimation { + self.didPlayPresentationAnimation = true + if case .modalSheet = presentationArguments.presentationAnimation { + self.controllerNode.animateIn() + } + } } override public func loadDisplayNode() { - self.displayNode = WebSearchControllerNode(account: self.account, theme: self.presentationData.theme, strings: self.presentationData.strings) - self._ready.set(.single(true)) + self.displayNode = WebSearchControllerNode(account: self.account, theme: self.interfaceState.presentationData.theme, strings: interfaceState.presentationData.strings, controllerInteraction: self.controllerInteraction!) + self.controllerNode.requestUpdateInterfaceState = { [weak self] animated, f in + if let strongSelf = self { + strongSelf.updateInterfaceState(f) + } + } + self.controllerNode.cancel = { [weak self] in + if let strongSelf = self { + strongSelf.dismiss() + } + } + self.controllerNode.updateInterfaceState(self.interfaceState, animated: false) + self._ready.set(.single(true)) self.displayNodeDidLoad() } + func updateInterfaceState(animated: Bool = true, _ f: (WebSearchInterfaceState) -> WebSearchInterfaceState) { + let previousInterfaceState = self.interfaceState + let previousTheme = self.interfaceState.presentationData.theme + let previousStrings = self.interfaceState.presentationData.theme + + let updatedInterfaceState = f(self.interfaceState) + self.interfaceState = updatedInterfaceState + self.interfaceStatePromise.set(updatedInterfaceState) + + self.controllerInteraction?.selectionState = updatedInterfaceState.state?.selectionState + + if self.isNodeLoaded { + if previousTheme !== updatedInterfaceState.presentationData.theme || previousStrings !== updatedInterfaceState.presentationData.strings { + self.controllerNode.updatePresentationData(theme: updatedInterfaceState.presentationData.theme, strings: updatedInterfaceState.presentationData.strings) + } + if previousInterfaceState != self.interfaceState { + self.controllerNode.updateInterfaceState(self.interfaceState, animated: animated) + } + } + } + + private func updateSearchQuery(_ query: String) { + let mode = self.interfaceStatePromise.get() + |> map { state -> WebSearchMode? in + return state.state?.mode + } + |> distinctUntilChanged + + var results = mode + |> mapToSignal { mode -> (Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError>) in + if let mode = mode { + return self.signalForQuery(query, mode: mode) + |> deliverOnMainQueue + |> beforeStarted { [weak self] in + if let strongSelf = self { + strongSelf.navigationContentNode?.setActivity(true) + } + } + |> afterCompleted { [weak self] in + if let strongSelf = self { + strongSelf.navigationContentNode?.setActivity(false) + } + } + } else { + return .complete() + } + } + + if query.isEmpty { + results = .single({ _ in return nil}) + self.navigationContentNode?.setActivity(false) + } + + self.resultsDisposable.set((results + |> deliverOnMainQueue).start(next: { [weak self] result in + if let strongSelf = self { + if let result = result(nil), case let .contextRequestResult(_, results) = result { + if let results = results { + strongSelf.controllerNode.updateResults(results) + } + } + } + })) + } + + private func signalForQuery(_ query: String, mode: WebSearchMode) -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> { + var delayRequest = true + var signal: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> = .complete() +// if let previousQuery = previousQuery { +// switch previousQuery { +// case let .contextRequest(currentAddressName, currentContextQuery) where currentAddressName == addressName: +// if query.isEmpty && !currentContextQuery.isEmpty { +// delayRequest = false +// } +// default: +// delayRequest = false +// signal = .single({ _ in return .contextRequestResult(nil, nil) }) +// } +// } else { + signal = .single({ _ in return .contextRequestResult(nil, nil) }) +// } + + guard case let .peer(peerId) = self.chatLocation else { + return .single({ _ in return .contextRequestResult(nil, nil) }) + } + + let botName: String? + switch mode { + case .images: + botName = self.configuration.imageBotUsername + case .gifs: + botName = self.configuration.gifBotUsername + } + guard let name = botName else { + return .single({ _ in return .contextRequestResult(nil, nil) }) + } + + let account = self.account + let contextBot = resolvePeerByName(account: account, name: name) + |> mapToSignal { peerId -> Signal in + if let peerId = peerId { + return account.postbox.loadedPeerWithId(peerId) + |> map { peer -> Peer? in + return peer + } + |> take(1) + } else { + return .single(nil) + } + } + |> mapToSignal { peer -> Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> in + if let user = peer as? TelegramUser, let botInfo = user.botInfo, let _ = botInfo.inlinePlaceholder { + let results = requestContextResults(account: account, botId: user.id, query: query, peerId: peerId, limit: 64) + |> map { results -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in + return { _ in + return .contextRequestResult(user, results) + } + } + + let botResult: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> = .single({ previousResult in + var passthroughPreviousResult: ChatContextResultCollection? + if let previousResult = previousResult { + if case let .contextRequestResult(previousUser, previousResults) = previousResult { + if previousUser?.id == user.id { + passthroughPreviousResult = previousResults + } + } + } + return .contextRequestResult(nil, passthroughPreviousResult) + }) + + let maybeDelayedContextResults: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, NoError> + if delayRequest { + maybeDelayedContextResults = results |> delay(0.4, queue: Queue.concurrentDefaultQueue()) + } else { + maybeDelayedContextResults = results + } + + return botResult |> then(maybeDelayedContextResults) + } else { + return .single({ _ in return nil }) + } + } + return signal |> then(contextBot) + } + override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, transition: transition) @@ -81,4 +316,11 @@ final class WebSearchController: ViewController { self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition) } + + override public func dismiss(completion: (() -> Void)? = nil) { + self.controllerNode.animateOut(completion: { [weak self] in + self?.presentingViewController?.dismiss(animated: false, completion: nil) + completion?() + }) + } } diff --git a/TelegramUI/WebSearchControllerNode.swift b/TelegramUI/WebSearchControllerNode.swift index abf53f5d55..cc48837af9 100644 --- a/TelegramUI/WebSearchControllerNode.swift +++ b/TelegramUI/WebSearchControllerNode.swift @@ -5,7 +5,80 @@ import SwiftSignalKit import Display import TelegramCore +private struct WebSearchContextResultStableId: Hashable { + let result: ChatContextResult + + var hashValue: Int { + return result.id.hashValue + } + + static func ==(lhs: WebSearchContextResultStableId, rhs: WebSearchContextResultStableId) -> Bool { + return lhs.result == rhs.result + } +} + +private struct WebSearchEntry: Comparable, Identifiable { + let index: Int + let result: ChatContextResult + + var stableId: WebSearchContextResultStableId { + return WebSearchContextResultStableId(result: self.result) + } + + static func ==(lhs: WebSearchEntry, rhs: WebSearchEntry) -> Bool { + return lhs.index == rhs.index && lhs.result == rhs.result + } + + static func <(lhs: WebSearchEntry, rhs: WebSearchEntry) -> Bool { + return lhs.index < rhs.index + } + + func item(account: Account, theme: PresentationTheme, interfaceState: WebSearchInterfaceState, controllerInteraction: WebSearchControllerInteraction) -> GridItem { + return WebSearchItem(account: account, theme: theme, interfaceState: interfaceState, result: self.result, controllerInteraction: controllerInteraction) + } +} + +private struct WebSearchTransition { + let deleteItems: [Int] + let insertItems: [GridNodeInsertItem] + let updateItems: [GridNodeUpdateItem] + let entryCount: Int + let hasMore: Bool +} + +private final class HorizontalListContextResultsOpaqueState { + let entryCount: Int + let hasMore: Bool + + init(entryCount: Int, hasMore: Bool) { + self.entryCount = entryCount + self.hasMore = hasMore + } +} + +private func preparedTransition(from fromEntries: [WebSearchEntry], to toEntries: [WebSearchEntry], hasMore: Bool, account: Account, theme: PresentationTheme, interfaceState: WebSearchInterfaceState, controllerInteraction: WebSearchControllerInteraction) -> WebSearchTransition { + let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) + + let insertions = indicesAndItems.map { GridNodeInsertItem(index: $0.0, item: $0.1.item(account: account, theme: theme, interfaceState: interfaceState, controllerInteraction: controllerInteraction), previousIndex: $0.2) } + let updates = updateIndices.map { GridNodeUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(account: account, theme: theme, interfaceState: interfaceState, controllerInteraction: controllerInteraction)) } + + return WebSearchTransition(deleteItems: deleteIndices, insertItems: insertions, updateItems: updates, entryCount: toEntries.count, hasMore: hasMore) +} + +private func gridNodeLayoutForContainerLayout(size: CGSize) -> GridNodeLayoutType { + let side = floorToScreenPixels((size.width - 3.0) / 4.0) + return .fixed(itemSize: CGSize(width: side, height: side), fillWidth: true, lineSpacing: 1.0, itemSpacing: 1.0) +} + class WebSearchControllerNode: ASDisplayNode { + private let account: Account + private var theme: PresentationTheme + private var strings: PresentationStrings + + private let controllerInteraction: WebSearchControllerInteraction + private var webSearchInterfaceState: WebSearchInterfaceState + private let webSearchInterfaceStatePromise: ValuePromise + private let segmentedBackgroundNode: ASDisplayNode private let segmentedSeparatorNode: ASDisplayNode private let segmentedControl: UISegmentedControl @@ -14,54 +87,135 @@ class WebSearchControllerNode: ASDisplayNode { private let toolbarSeparatorNode: ASDisplayNode private let cancelButton: HighlightableButtonNode private let sendButton: HighlightableButtonNode + private let attributionNode: ASImageNode - private let account: Account + private let gridNode: GridNode + private var enqueuedTransitions: [(WebSearchTransition, Bool)] = [] + private var dequeuedInitialTransitionOnLayout = false + + private var currentExternalResults: ChatContextResultCollection? + private var currentProcessedResults: ChatContextResultCollection? + private var currentEntries: [WebSearchEntry]? + private var isLoadingMore = false + + private let results = ValuePromise(ignoreRepeated: true) + + + private let disposable = MetaDisposable() + private let loadMoreDisposable = MetaDisposable() private var containerLayout: (ContainerViewLayout, CGFloat)? - init(account: Account, theme: PresentationTheme, strings: PresentationStrings) { + var requestUpdateInterfaceState: (Bool, (WebSearchInterfaceState) -> WebSearchInterfaceState) -> Void = { _, _ in } + var cancel: (() -> Void)? + + init(account: Account, theme: PresentationTheme, strings: PresentationStrings, controllerInteraction: WebSearchControllerInteraction) { self.account = account + self.theme = theme + self.strings = strings + self.controllerInteraction = controllerInteraction + + self.webSearchInterfaceState = WebSearchInterfaceState(presentationData: account.telegramApplicationContext.currentPresentationData.with { $0 }) + self.webSearchInterfaceStatePromise = ValuePromise(self.webSearchInterfaceState, ignoreRepeated: true) self.segmentedBackgroundNode = ASDisplayNode() - self.segmentedBackgroundNode.backgroundColor = theme.rootController.navigationBar.backgroundColor - self.segmentedSeparatorNode = ASDisplayNode() - self.segmentedSeparatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor - self.segmentedControl = UISegmentedControl(items: [strings.WebSearch_Images, strings.WebSearch_GIFs, strings.WebSearch_RecentSectionTitle]) - self.segmentedControl.tintColor = theme.rootController.navigationBar.accentTextColor + self.segmentedControl = UISegmentedControl(items: [strings.WebSearch_Images, strings.WebSearch_GIFs]) self.segmentedControl.selectedSegmentIndex = 0 self.toolbarBackgroundNode = ASDisplayNode() - self.toolbarBackgroundNode.backgroundColor = theme.rootController.navigationBar.backgroundColor - self.toolbarSeparatorNode = ASDisplayNode() - self.toolbarSeparatorNode.backgroundColor = theme.rootController.navigationBar.separatorColor self.attributionNode = ASImageNode() self.cancelButton = HighlightableButtonNode() - self.cancelButton.setTitle(strings.Common_Cancel, with: Font.regular(17.0), with: theme.rootController.navigationBar.accentTextColor, for: .normal) self.sendButton = HighlightableButtonNode() + self.gridNode = GridNode() + self.gridNode.backgroundColor = theme.list.plainBackgroundColor + super.init() self.setViewBlock({ return UITracingLayerView() }) - self.backgroundColor = theme.chatList.backgroundColor - + self.addSubnode(self.gridNode) self.addSubnode(self.segmentedBackgroundNode) self.addSubnode(self.segmentedSeparatorNode) self.view.addSubview(self.segmentedControl) - self.segmentedControl.addTarget(self, action: #selector(self.indexChanged), for: .valueChanged) - self.addSubnode(self.toolbarBackgroundNode) self.addSubnode(self.toolbarSeparatorNode) self.addSubnode(self.cancelButton) self.addSubnode(self.sendButton) + self.addSubnode(self.attributionNode) + + self.segmentedControl.addTarget(self, action: #selector(self.indexChanged), for: .valueChanged) + self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside) + self.sendButton.addTarget(self, action: #selector(self.sendPressed), forControlEvents: .touchUpInside) + + self.applyPresentationData() + + self.disposable.set((combineLatest(self.results.get(), self.webSearchInterfaceStatePromise.get()) + |> deliverOnMainQueue).start(next: { [weak self] results, interfaceState in + if let strongSelf = self { + strongSelf.updateInternalResults(results, interfaceState: interfaceState) + } + })) + + self.gridNode.visibleItemsUpdated = { [weak self] visibleItems in + //state.hasMore && + //if visibleItems.bottom.0 <= state.entryCount - 10 { + // strongSelf.loadMore() + //} + } + +// let selectorRecogizner = ChatGridLiveSelectorRecognizer(target: self, action: #selector(self.panGesture(_:))) +// selectorRecogizner.shouldBegin = { [weak controllerInteraction] in +// return controllerInteraction?.selectionState != nil +// } +// self.view.addGestureRecognizer(selectorRecogizner) + } + + deinit { + self.loadMoreDisposable.dispose() + } + + func updatePresentationData(theme: PresentationTheme, strings: PresentationStrings) { + let themeUpdated = theme !== self.theme + self.theme = theme + self.strings = strings + + self.applyPresentationData(themeUpdated: themeUpdated) + } + + func applyPresentationData(themeUpdated: Bool = true) { + self.cancelButton.setTitle(self.strings.Common_Cancel, with: Font.regular(17.0), with: self.theme.rootController.navigationBar.accentTextColor, for: .normal) + self.sendButton.setTitle(self.strings.MediaPicker_Send, with: Font.medium(17.0), with: self.theme.rootController.navigationBar.accentTextColor, for: .normal) + + if themeUpdated { + self.backgroundColor = self.theme.chatList.backgroundColor + + self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor + self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor + self.segmentedControl.tintColor = self.theme.rootController.navigationBar.accentTextColor + self.toolbarBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor + self.toolbarSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor + + self.attributionNode.image = generateTintedImage(image: UIImage(bundleImageName: "Media Grid/Giphy"), color: self.theme.list.itemSecondaryTextColor) + } + } + + func animateIn(completion: (() -> Void)? = nil) { + self.layer.animatePosition(from: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), to: self.layer.position, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + } + + func animateOut(completion: (() -> Void)? = nil) { + self.layer.animatePosition(from: self.layer.position, to: CGPoint(x: self.layer.position.x, y: self.layer.position.y + self.layer.bounds.size.height), duration: 0.2, timingFunction: kCAMediaTimingFunctionEaseInEaseOut, removeOnCompletion: false, completion: { _ in + completion?() + }) } func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { @@ -77,18 +231,151 @@ class WebSearchControllerNode: ASDisplayNode { transition.updateFrame(node: self.segmentedSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelY + segmentedHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel))) var controlSize = self.segmentedControl.sizeThatFits(layout.size) - controlSize.width = layout.size.width - 8.0 * 2.0 + controlSize.width = layout.size.width - layout.safeInsets.left - layout.safeInsets.right - 8.0 * 2.0 - transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - controlSize.width) / 2.0), y: panelY + floor((segmentedHeight - controlSize.height) / 2.0)), size: controlSize)) + transition.updateFrame(view: self.segmentedControl, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + floor((layout.size.width - layout.safeInsets.left - layout.safeInsets.right - controlSize.width) / 2.0), y: panelY + floor((segmentedHeight - controlSize.height) / 2.0)), size: controlSize)) + + let toolbarHeight: CGFloat = 44.0 + let toolbarY = layout.size.height - toolbarHeight - insets.bottom + transition.updateFrame(node: self.toolbarBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: toolbarY), size: CGSize(width: layout.size.width, height: toolbarHeight + insets.bottom))) + transition.updateFrame(node: self.toolbarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: toolbarY), size: CGSize(width: layout.size.width, height: UIScreenPixel))) + + if let image = self.attributionNode.image { + transition.updateFrame(node: self.attributionNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - image.size.width) / 2.0), y: toolbarY + floor((toolbarHeight - image.size.height) / 2.0)), size: image.size)) + transition.updateAlpha(node: self.attributionNode, alpha: self.webSearchInterfaceState.state?.mode == .gifs ? 1.0 : 0.0) + } + + let toolbarPadding: CGFloat = 15.0 + let cancelSize = self.cancelButton.measure(CGSize(width: layout.size.width, height: toolbarHeight)) + transition.updateFrame(node: self.cancelButton, frame: CGRect(origin: CGPoint(x: toolbarPadding + layout.safeInsets.left, y: toolbarY), size: CGSize(width: cancelSize.width, height: toolbarHeight))) + + let sendSize = self.sendButton.measure(CGSize(width: layout.size.width, height: toolbarHeight)) + transition.updateFrame(node: self.sendButton, frame: CGRect(origin: CGPoint(x: layout.size.width - toolbarPadding - layout.safeInsets.right - sendSize.width, y: toolbarY), size: CGSize(width: sendSize.width, height: toolbarHeight))) + + let previousBounds = self.gridNode.bounds + self.gridNode.bounds = CGRect(x: previousBounds.origin.x, y: previousBounds.origin.y, width: layout.size.width, height: layout.size.height) + self.gridNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0) + + insets.top += segmentedHeight + insets.bottom += toolbarHeight + self.gridNode.transaction(GridNodeTransaction(deleteItems: [], insertItems: [], updateItems: [], scrollToItem: nil, updateLayout: GridNodeUpdateLayout(layout: GridNodeLayout(size: layout.size, insets: insets, preloadSize: 400.0, type: gridNodeLayoutForContainerLayout(size: layout.size)), transition: .immediate), itemTransition: .immediate, stationaryItems: .none,updateFirstIndexInSectionOffset: nil), completion: { _ in }) + + if !self.dequeuedInitialTransitionOnLayout { + self.dequeuedInitialTransitionOnLayout = true + self.dequeueTransition() + } + } + + func updateInterfaceState(_ interfaceState: WebSearchInterfaceState, animated: Bool) { + self.webSearchInterfaceState = interfaceState + self.webSearchInterfaceStatePromise.set(self.webSearchInterfaceState) + + if let state = interfaceState.state { + self.segmentedControl.selectedSegmentIndex = Int(state.mode.rawValue) + } + + if let validLayout = self.containerLayout { + self.containerLayoutUpdated(validLayout.0, navigationBarHeight: validLayout.1, transition: animated ? .animated(duration: 0.4, curve: .spring) : .immediate) + } + } + + func updateResults(_ results: ChatContextResultCollection) { + if self.currentExternalResults == results { + return + } + self.currentExternalResults = results + self.currentProcessedResults = results + + self.isLoadingMore = false + self.loadMoreDisposable.set(nil) + self.results.set(results) + } + + private func loadMore() { + guard !self.isLoadingMore, let currentProcessedResults = self.currentProcessedResults, let nextOffset = currentProcessedResults.nextOffset else { + return + } + self.isLoadingMore = true + self.loadMoreDisposable.set((requestChatContextResults(account: self.account, botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, location: .single(currentProcessedResults.geoPoint), offset: nextOffset) + |> deliverOnMainQueue).start(next: { [weak self] nextResults in + guard let strongSelf = self, let nextResults = nextResults else { + return + } + strongSelf.isLoadingMore = false + var results: [ChatContextResult] = [] + for result in currentProcessedResults.results { + results.append(result) + } + for result in nextResults.results { + results.append(result) + } + let mergedResults = ChatContextResultCollection(botId: currentProcessedResults.botId, peerId: currentProcessedResults.peerId, query: currentProcessedResults.query, geoPoint: currentProcessedResults.geoPoint, queryId: nextResults.queryId, nextOffset: nextResults.nextOffset, presentation: currentProcessedResults.presentation, switchPeer: currentProcessedResults.switchPeer, results: results, cacheTimeout: currentProcessedResults.cacheTimeout) + strongSelf.currentProcessedResults = mergedResults + strongSelf.results.set(mergedResults) + })) + } + + private func updateInternalResults(_ results: ChatContextResultCollection, interfaceState: WebSearchInterfaceState) { + var entries: [WebSearchEntry] = [] + var index = 0 + var resultIds = Set() + for result in results.results { + let entry = WebSearchEntry(index: index, result: result) + if resultIds.contains(entry.stableId) { + continue + } else { + resultIds.insert(entry.stableId) + } + entries.append(entry) + index += 1 + } + + let firstTime = self.currentEntries == nil + let transition = preparedTransition(from: self.currentEntries ?? [], to: entries, hasMore: results.nextOffset != nil, account: self.account, theme: interfaceState.presentationData.theme, interfaceState: interfaceState, controllerInteraction: self.controllerInteraction) + self.currentEntries = entries + self.enqueueTransition(transition, firstTime: firstTime) + } + + private func enqueueTransition(_ transition: WebSearchTransition, firstTime: Bool) { + self.enqueuedTransitions.append((transition, firstTime)) + + if self.containerLayout != nil { + while !self.enqueuedTransitions.isEmpty { + self.dequeueTransition() + } + } + } + + private func dequeueTransition() { + if let (transition, firstTime) = self.enqueuedTransitions.first { + self.enqueuedTransitions.remove(at: 0) + + let completion: (GridNodeDisplayedItemRange) -> Void = { [weak self] visibleRange in + if let strongSelf = self { + } + } + + self.gridNode.transaction(GridNodeTransaction(deleteItems: transition.deleteItems, insertItems: transition.insertItems, updateItems: transition.updateItems, scrollToItem: nil, updateLayout: nil, itemTransition: .immediate, stationaryItems: .none, updateFirstIndexInSectionOffset: nil), completion: completion) + } } @objc private func indexChanged() { -// if self.segmentedControl.selectedSegmentIndex == 0 { -// self.chatController?.displayNode.isHidden = false -// self.listNode.isHidden = true -// } else { -// self.chatController?.displayNode.isHidden = true -// self.listNode.isHidden = false -// } + self.requestUpdateInterfaceState(true) { current in + if let mode = WebSearchMode(rawValue: Int32(self.segmentedControl.selectedSegmentIndex)) { + return current.withUpdatedMode(mode) + } + return current + } + } + + @objc private func cancelPressed() { + self.cancel?() + } + + @objc private func sendPressed() { + if let results = self.currentProcessedResults { + self.controllerInteraction.sendSelected(results) + } + self.cancel?() } } diff --git a/TelegramUI/WebSearchInterfaceState.swift b/TelegramUI/WebSearchInterfaceState.swift new file mode 100644 index 0000000000..8e769a0982 --- /dev/null +++ b/TelegramUI/WebSearchInterfaceState.swift @@ -0,0 +1,65 @@ +import Foundation + +struct WebSearchSelectionState: Equatable { + let selectedIds: Set + + static func ==(lhs: WebSearchSelectionState, rhs: WebSearchSelectionState) -> Bool { + return lhs.selectedIds == rhs.selectedIds + } + + init(selectedIds: Set) { + self.selectedIds = selectedIds + } +} + +enum WebSearchMode: Int32 { + case images + case gifs +} + +struct WebSearchInterfaceInnerState: Equatable { + let mode: WebSearchMode + let selectionState: WebSearchSelectionState +} + +struct WebSearchInterfaceState: Equatable { + let state: WebSearchInterfaceInnerState? + let presentationData: PresentationData + + init (presentationData: PresentationData) { + self.state = nil + self.presentationData = presentationData + } + + init(state: WebSearchInterfaceInnerState?, presentationData: PresentationData) { + self.state = state + self.presentationData = presentationData + } + + func withUpdatedMode(_ mode: WebSearchMode) -> WebSearchInterfaceState { + return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(mode: mode, selectionState: self.state?.selectionState ?? WebSearchSelectionState(selectedIds: [])), presentationData: self.presentationData) + } + + func withUpdatedSelectionState(_ selectionState: WebSearchSelectionState) -> WebSearchInterfaceState { + return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(mode: self.state?.mode ?? .images, selectionState: selectionState), presentationData: self.presentationData) + } + + func withToggledSelectedMessages(_ ids: [String], value: Bool) -> WebSearchInterfaceState { + var selectedIds = Set() + if let selectionState = self.state?.selectionState { + selectedIds.formUnion(selectionState.selectedIds) + } + for id in ids { + if value { + selectedIds.insert(id) + } else { + selectedIds.remove(id) + } + } + return WebSearchInterfaceState(state: WebSearchInterfaceInnerState(mode: self.state?.mode ?? .images, selectionState: WebSearchSelectionState(selectedIds: selectedIds)), presentationData: self.presentationData) + } + + func withUpdatedPresentationData(_ presentationData: PresentationData) -> WebSearchInterfaceState { + return WebSearchInterfaceState(state: self.state, presentationData: presentationData) + } +} diff --git a/TelegramUI/WebSearchItem.swift b/TelegramUI/WebSearchItem.swift new file mode 100644 index 0000000000..57c54b1732 --- /dev/null +++ b/TelegramUI/WebSearchItem.swift @@ -0,0 +1,242 @@ +import Foundation +import AsyncDisplayKit +import Display +import TelegramCore +import SwiftSignalKit +import Postbox + +final class WebSearchItem: GridItem { + var section: GridSection? + + let account: Account + let theme: PresentationTheme + let interfaceState: WebSearchInterfaceState + let result: ChatContextResult + let controllerInteraction: WebSearchControllerInteraction + + public init(account: Account, theme: PresentationTheme, interfaceState: WebSearchInterfaceState, result: ChatContextResult, controllerInteraction: WebSearchControllerInteraction) { + self.account = account + self.theme = theme + self.result = result + self.interfaceState = interfaceState + self.controllerInteraction = controllerInteraction + } + + func node(layout: GridNodeLayout, synchronousLoad: Bool) -> GridItemNode { + let node = WebSearchItemNode() + node.setup(item: self) + return node + } + + func update(node: GridItemNode) { + guard let node = node as? WebSearchItemNode else { + assertionFailure() + return + } + node.setup(item: self) + } +} + +final class WebSearchItemNode: GridItemNode { + private let imageNodeBackground: ASDisplayNode + private let imageNode: TransformImageNode + private var selectionNode: GridMessageSelectionNode? + + private var currentImageResource: TelegramMediaResource? + private var currentVideoFile: TelegramMediaFile? + private var currentDimensions: CGSize? + + private(set) var item: WebSearchItem? + + private let fetchStatusDisposable = MetaDisposable() + private let fetchDisposable = MetaDisposable() + private var resourceStatus: MediaResourceStatus? + + private let statusNode: RadialStatusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.5)) + + override init() { + self.imageNodeBackground = ASDisplayNode() + self.imageNodeBackground.isLayerBacked = true + + self.imageNode = TransformImageNode() + self.imageNode.contentAnimations = [.subsequentUpdates] + self.imageNode.displaysAsynchronously = false + + super.init() + + self.addSubnode(self.imageNodeBackground) + self.addSubnode(self.imageNode) + } + + deinit { + self.fetchStatusDisposable.dispose() + self.fetchDisposable.dispose() + } + + override func didLoad() { + super.didLoad() + + let recognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.tapLongTapOrDoubleTapGesture(_:))) + recognizer.tapActionAtPoint = { _ in + return .waitForSingleTap + } + self.imageNode.view.addGestureRecognizer(recognizer) + } + + func setup(item: WebSearchItem) { + if self.item !== item { + var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? + var updatedStatusSignal: Signal? + + var imageResource: TelegramMediaResource? + var stickerFile: TelegramMediaFile? + var videoFile: TelegramMediaFile? + var imageDimensions: CGSize? + switch item.result { + case let .externalReference(_, _, type, title, _, url, content, thumbnail, _): + if let content = content { + imageResource = content.resource + } else if let thumbnail = thumbnail { + imageResource = thumbnail.resource + } + imageDimensions = content?.dimensions + if type == "gif", let thumbnailResource = imageResource, let content = content, let dimensions = content.dimensions { + videoFile = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: 0), partialReference: nil, resource: content.resource, previewRepresentations: [TelegramMediaImageRepresentation(dimensions: dimensions, resource: thumbnailResource)], mimeType: "video/mp4", size: nil, attributes: [.Animated, .Video(duration: 0, size: dimensions, flags: [])]) + imageResource = nil + } + + if let file = videoFile { + updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource) + } else if let imageResource = imageResource { + updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource) + } + case let .internalReference(_, _, _, title, _, image, file, _): + if let image = image { + if let largestRepresentation = largestImageRepresentation(image.representations) { + imageDimensions = largestRepresentation.dimensions + } + imageResource = imageRepresentationLargerThan(image.representations, size: CGSize(width: 200.0, height: 100.0))?.resource + } else if let file = file { + if let dimensions = file.dimensions { + imageDimensions = dimensions + } else if let largestRepresentation = largestImageRepresentation(file.previewRepresentations) { + imageDimensions = largestRepresentation.dimensions + } + imageResource = smallestImageRepresentation(file.previewRepresentations)?.resource + } + + // if let file = file { + // if file.isVideo && file.isAnimated { + // videoFile = file + // imageResource = nil + // updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(file.resource) + // } else if let imageResource = imageResource { + // updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource) + // } + // } else if let imageResource = imageResource { + // updatedStatusSignal = item.account.postbox.mediaBox.resourceStatus(imageResource) + // } + } + + if let imageResource = imageResource, let imageDimensions = imageDimensions { + let tmpRepresentation = TelegramMediaImageRepresentation(dimensions: imageDimensions, resource: imageResource) + let tmpImage = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [tmpRepresentation], reference: nil, partialReference: nil) + updateImageSignal = mediaGridMessagePhoto(account: item.account, photoReference: .standalone(media: tmpImage)) + } else { + updateImageSignal = .complete() + } + + if let updateImageSignal = updateImageSignal { + self.imageNode.setSignal(updateImageSignal) + } + + self.currentImageResource = imageResource + self.currentVideoFile = videoFile + self.currentDimensions = imageDimensions + if let _ = imageDimensions { + self.setNeedsLayout() + } + } + + self.item = item + self.updateSelectionState(animated: false) + } + + func updateSelectionState(animated: Bool) { + if self.selectionNode == nil, let item = self.item { + let selectionNode = GridMessageSelectionNode(theme: item.theme, toggle: { [weak self] value in + if let strongSelf = self, let item = strongSelf.item { + item.controllerInteraction.toggleSelection([item.result.id], value) + strongSelf.updateSelectionState(animated: true) + } + }) + + selectionNode.frame = CGRect(origin: CGPoint(), size: self.bounds.size) + self.addSubnode(selectionNode) + self.selectionNode = selectionNode + } + + if let item = self.item { + if let selectionState = item.controllerInteraction.selectionState { + let selected = selectionState.selectedIds.contains(item.result.id) + self.selectionNode?.updateSelected(selected, animated: animated) + } + } + } + + override func layout() { + super.layout() + + let imageFrame = self.bounds + self.imageNode.frame = imageFrame + + if let item = self.item, let dimensions = self.currentDimensions { + let imageSize = dimensions.aspectFilled(imageFrame.size) + self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageFrame.size, intrinsicInsets: UIEdgeInsets(), emptyColor: item.theme.list.mediaPlaceholderColor))() + } + + self.selectionNode?.frame = CGRect(origin: CGPoint(), size: self.bounds.size) + let progressDiameter: CGFloat = 40.0 + self.statusNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - progressDiameter) / 2.0), y: floor((imageFrame.size.height - progressDiameter) / 2.0)), size: CGSize(width: progressDiameter, height: progressDiameter)) + + //self.videoAccessoryNode.frame = CGRect(origin: CGPoint(x: imageFrame.maxX - self.videoAccessoryNode.contentSize.width - 5, y: imageFrame.maxY - self.videoAccessoryNode.contentSize.height - 5), size: self.videoAccessoryNode.contentSize) + } + + @objc func tapLongTapOrDoubleTapGesture(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) { +// guard let controllerInteraction = self.controllerInteraction, let message = self.item?.message else { +// return +// } +// +// switch recognizer.state { +// case .ended: +// if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation { +// switch gesture { +// case .tap: +// if let (account, media, _) = self.currentState { +// if let file = media as? TelegramMediaFile { +// if let resourceStatus = self.resourceStatus { +// switch resourceStatus { +// case .Fetching: +// messageMediaFileCancelInteractiveFetch(account: account, messageId: message.id, file: file) +// case .Local: +// let _ = controllerInteraction.openMessage(message, .default) +// case .Remote: +// self.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: true).start()) +// } +// } +// } else { +// let _ = controllerInteraction.openMessage(message, .default) +// } +// } +// case .longTap: +// controllerInteraction.openMessageContextMenu(message, false, self, self.bounds) +// default: +// break +// } +// } +// default: +// break +// } + } +} + diff --git a/TelegramUI/WebSearchNavigationContentNode.swift b/TelegramUI/WebSearchNavigationContentNode.swift index a298ceab06..b0b7b3b43f 100644 --- a/TelegramUI/WebSearchNavigationContentNode.swift +++ b/TelegramUI/WebSearchNavigationContentNode.swift @@ -10,40 +10,40 @@ final class WebSearchNavigationContentNode: NavigationBarContentNode { private let theme: PresentationTheme private let strings: PresentationStrings - private let cancel: () -> Void - private let searchBar: SearchBarNode private var queryUpdated: ((String) -> Void)? - init(theme: PresentationTheme, strings: PresentationStrings, cancel: @escaping () -> Void) { + init(theme: PresentationTheme, strings: PresentationStrings) { self.theme = theme self.strings = strings - self.cancel = cancel - self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, active: false), strings: strings) - let placeholderText = strings.Common_Search - self.searchBar.placeholderString = NSAttributedString(string: placeholderText, font: searchBarFont, textColor: theme.rootController.activeNavigationSearchBar.inputPlaceholderTextColor) + self.searchBar.hasCancelButton = false + self.searchBar.placeholderString = NSAttributedString(string: strings.Common_Search, font: searchBarFont, textColor: theme.rootController.activeNavigationSearchBar.inputPlaceholderTextColor) super.init() self.addSubnode(self.searchBar) - self.searchBar.cancel = { [weak self] in - self?.searchBar.deactivate(clear: false) - self?.cancel() - } - - self.searchBar.textUpdated = { [weak self] query in + self.searchBar.textReturned = { [weak self] query in self?.queryUpdated?(query) } + self.searchBar.textUpdated = { [weak self] query in + if query.isEmpty { + self?.queryUpdated?(query) + } + } } func setQueryUpdated(_ f: @escaping (String) -> Void) { self.queryUpdated = f } + func setActivity(_ activity: Bool) { + self.searchBar.activity = activity + } + override func layout() { super.layout() diff --git a/TelegramUI/WebSearchRecentQueriesNode.swift b/TelegramUI/WebSearchRecentQueriesNode.swift new file mode 100644 index 0000000000..81f72fba9a --- /dev/null +++ b/TelegramUI/WebSearchRecentQueriesNode.swift @@ -0,0 +1,5 @@ +import UIKit + +class WebSearchRecentQueriesNode: NSObject { + +} diff --git a/TelegramUI/WebSearchSettings.swift b/TelegramUI/WebSearchSettings.swift new file mode 100644 index 0000000000..b35fdd0e27 --- /dev/null +++ b/TelegramUI/WebSearchSettings.swift @@ -0,0 +1,45 @@ +import Foundation +import Postbox +import SwiftSignalKit + +struct WebSearchSettings: Equatable, PreferencesEntry { + var mode: WebSearchMode + + static var defaultSettings: WebSearchSettings { + return WebSearchSettings(mode: .images) + } + + init(mode: WebSearchMode) { + self.mode = mode + } + + init(decoder: PostboxDecoder) { + self.mode = WebSearchMode(rawValue: decoder.decodeInt32ForKey("mode", orElse: 0)) ?? .images + } + + func encode(_ encoder: PostboxEncoder) { + encoder.encodeInt32(self.mode.rawValue, forKey: "mode") + } + + func isEqual(to: PreferencesEntry) -> Bool { + if let to = to as? WebSearchSettings { + return self == to + } else { + return false + } + } +} + +func updateWebSearchSettingsInteractively(postbox: Postbox, _ f: @escaping (WebSearchSettings) -> WebSearchSettings) -> Signal { + return postbox.transaction { transaction -> Void in + transaction.updatePreferencesEntry(key: ApplicationSpecificPreferencesKeys.webSearchSettings, { entry in + let currentSettings: WebSearchSettings + if let entry = entry as? WebSearchSettings { + currentSettings = entry + } else { + currentSettings = .defaultSettings + } + return f(currentSettings) + }) + } +}