diff --git a/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@2x.png b/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@2x.png index 370abd3c85..a643b384f0 100644 Binary files a/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@2x.png and b/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@2x.png differ diff --git a/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@3x.png b/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@3x.png index 9be5ef3d09..a6413e15bf 100644 Binary files a/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@3x.png and b/Images.xcassets/Avatar/EditAvatarIcon.imageset/SettingsCameraIcon@3x.png differ diff --git a/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@2x.png b/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@2x.png index de460c24ee..59ea1ee4b4 100644 Binary files a/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@2x.png and b/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@2x.png differ diff --git a/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@3x.png b/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@3x.png index 96a7dca662..6b2bcbd389 100644 Binary files a/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@3x.png and b/Images.xcassets/Avatar/SavedMessagesIcon.imageset/SavedMessagesIcon@3x.png differ diff --git a/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@2x.png b/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@2x.png index 066e8125a1..a916b243fb 100644 Binary files a/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@2x.png and b/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@2x.png differ diff --git a/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@3x.png b/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@3x.png index 3d21a4e764..78361b085a 100644 Binary files a/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@3x.png and b/Images.xcassets/Bot Payments/ApplePayLogo.imageset/Apple_Pay_Payment_Mark@3x.png differ diff --git a/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@2x.png b/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@2x.png index 27b01a0aae..f0fd40ce22 100644 Binary files a/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@2x.png and b/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@2x.png differ diff --git a/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@3x.png b/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@3x.png index b5ff3bbb36..98dbed4c06 100644 Binary files a/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@3x.png and b/Images.xcassets/Chat List/PeerPinnedIcon.imageset/ic_chatslistpin@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 d0dc89b9ff..ab8d454db0 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 54b04299e5..e081b297d4 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/Open In/Safari.imageset/Safari@2x.png b/Images.xcassets/Open In/Safari.imageset/Safari@2x.png index f287725682..0d153020a9 100644 Binary files a/Images.xcassets/Open In/Safari.imageset/Safari@2x.png and b/Images.xcassets/Open In/Safari.imageset/Safari@2x.png differ diff --git a/TelegramUI.xcodeproj/project.pbxproj b/TelegramUI.xcodeproj/project.pbxproj index 840aaf8996..9ba11c024b 100644 --- a/TelegramUI.xcodeproj/project.pbxproj +++ b/TelegramUI.xcodeproj/project.pbxproj @@ -7,7 +7,8 @@ objects = { /* Begin PBXBuildFile section */ - 09310D2B213ECC840020033A /* Lottie.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09310D2A213ECC830020033A /* Lottie.framework */; }; + 091EB4EB213F48B4005284DE /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 094981C52138D73B00A10660 /* Vision.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 091EB4F0213F4C4C005284DE /* Lottie.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 091EB4EF213F4C4C005284DE /* Lottie.framework */; }; 09310D2C213ED5FB0020033A /* anim_read.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D14213BC5DE0020033A /* anim_read.json */; }; 09310D2D213ED5FB0020033A /* anim_pin.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D15213BC5DE0020033A /* anim_pin.json */; }; 09310D2E213ED5FB0020033A /* anim_unmute.json in Resources */ = {isa = PBXBuildFile; fileRef = 09310D16213BC5DE0020033A /* anim_unmute.json */; }; @@ -20,7 +21,6 @@ 0941A9A0210B057200EBE194 /* OpenInActionSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A99F210B057200EBE194 /* OpenInActionSheetController.swift */; }; 0941A9A4210B0E2E00EBE194 /* OpenInAppIconResources.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */; }; 0941A9A6210B822D00EBE194 /* OpenInOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0941A9A5210B822D00EBE194 /* OpenInOptions.swift */; }; - 094981C62138D73B00A10660 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 094981C52138D73B00A10660 /* Vision.framework */; }; 09797873210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09797872210633CD0077D77F /* InstantPageSettingsButtonItemNode.swift */; }; 0979787C210642CB0077D77F /* WebEmbedPlayerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787B210642CB0077D77F /* WebEmbedPlayerNode.swift */; }; 0979787E210646C00077D77F /* YoutubeEmbedImplementation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0979787D210646C00077D77F /* YoutubeEmbedImplementation.swift */; }; @@ -108,7 +108,6 @@ D02D60B1206C189900FEFE1E /* SecureIdPlaintextFormController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60B0206C189900FEFE1E /* SecureIdPlaintextFormController.swift */; }; D02D60B3206C18A600FEFE1E /* SecureIdPlaintextFormControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60B2206C18A600FEFE1E /* SecureIdPlaintextFormControllerNode.swift */; }; D02D60C8206E705D00FEFE1E /* SecureIdValueFormPhoneItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02D60C7206E705D00FEFE1E /* SecureIdValueFormPhoneItem.swift */; }; - D02DADBF2138D76F00116225 /* Vision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D02DADBE2138D76F00116225 /* Vision.framework */; }; D02F4AE91FCF370B004DFBAE /* ChatMessageInteractiveMediaBadge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02F4AE81FCF370B004DFBAE /* ChatMessageInteractiveMediaBadge.swift */; }; D02F4AF01FD4C46D004DFBAE /* SystemVideoContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02F4AEF1FD4C46D004DFBAE /* SystemVideoContent.swift */; }; D0380DA9204E9C81000414AB /* SecretMediaPreviewFooterContentNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0380DA8204E9C81000414AB /* SecretMediaPreviewFooterContentNode.swift */; }; @@ -1017,6 +1016,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 091EB4E9213F475A005284DE /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 091EB4EC213F48BE005284DE /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 091EB4EF213F4C4C005284DE /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 09310D14213BC5DE0020033A /* anim_read.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_read.json; sourceTree = ""; }; 09310D15213BC5DE0020033A /* anim_pin.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_pin.json; sourceTree = ""; }; 09310D16213BC5DE0020033A /* anim_unmute.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_unmute.json; sourceTree = ""; }; @@ -1026,9 +1028,6 @@ 09310D1A213BC5DE0020033A /* anim_ungroup.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_ungroup.json; sourceTree = ""; }; 09310D1B213BC5DE0020033A /* anim_group.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_group.json; sourceTree = ""; }; 09310D1C213BC5DE0020033A /* anim_mute.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = anim_mute.json; sourceTree = ""; }; - 09310D26213BD84E0020033A /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 09310D28213BD8810020033A /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 09310D2A213ECC830020033A /* Lottie.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Lottie.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 0941A99F210B057200EBE194 /* OpenInActionSheetController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInActionSheetController.swift; sourceTree = ""; }; 0941A9A3210B0E2E00EBE194 /* OpenInAppIconResources.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInAppIconResources.swift; sourceTree = ""; }; 0941A9A5210B822D00EBE194 /* OpenInOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenInOptions.swift; sourceTree = ""; }; @@ -2120,10 +2119,10 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D02DADBF2138D76F00116225 /* Vision.framework in Frameworks */, + 091EB4F0213F4C4C005284DE /* Lottie.framework in Frameworks */, + 091EB4EB213F48B4005284DE /* Vision.framework in Frameworks */, D00ACA4B20222C280045D427 /* libtgvoip.framework in Frameworks */, D07BCBFE1F2B792300ED97AA /* LegacyComponents.framework in Frameworks */, - 094981C62138D73B00A10660 /* Vision.framework in Frameworks */, D053B4371F1A9CA000E2D58A /* WebKit.framework in Frameworks */, D09E63B21F11289A003444CD /* PassKit.framework in Frameworks */, D09E63B01F1010FE003444CD /* Contacts.framework in Frameworks */, @@ -2158,6 +2157,14 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 091EB4E8213F3D86005284DE /* Recovered References */ = { + isa = PBXGroup; + children = ( + 094981C52138D73B00A10660 /* Vision.framework */, + ); + name = "Recovered References"; + sourceTree = ""; + }; 09310D13213BC5DE0020033A /* Animations */ = { isa = PBXGroup; children = ( @@ -3003,6 +3010,9 @@ D08D45281D5E340200A7428A /* Frameworks */ = { isa = PBXGroup; children = ( + 091EB4EF213F4C4C005284DE /* Lottie.framework */, + 091EB4EC213F48BE005284DE /* Lottie.framework */, + 091EB4E9213F475A005284DE /* Lottie.framework */, D02DADBE2138D76F00116225 /* Vision.framework */, D00ACA4C20222C280045D427 /* libtgvoip.framework */, D057C5412004215B00990762 /* Lottie.framework */, @@ -4367,6 +4377,7 @@ D0FC408C1D5B8E7500261D9D /* TelegramUITests */, D0FC40801D5B8E7400261D9D /* Products */, D08D45281D5E340200A7428A /* Frameworks */, + 091EB4E8213F3D86005284DE /* Recovered References */, ); sourceTree = ""; }; diff --git a/TelegramUI/CallListController.swift b/TelegramUI/CallListController.swift index a10dc1e398..2204ae128e 100644 --- a/TelegramUI/CallListController.swift +++ b/TelegramUI/CallListController.swift @@ -26,6 +26,8 @@ public final class CallListController: ViewController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? + private let peerViewDisposable = MetaDisposable() + private let segmentedTitleView: ItemListControllerSegmentedTitleView private var isEmpty: Bool? @@ -86,6 +88,7 @@ public final class CallListController: ViewController { deinit { self.createActionDisposable.dispose() self.presentationDataDisposable?.dispose() + self.peerViewDisposable.dispose() } private func updateThemeAndStrings() { @@ -239,30 +242,45 @@ public final class CallListController: ViewController { } private func call(_ peerId: PeerId, began: (() -> Void)? = nil) { - let callResult = self.account.telegramApplicationContext.callManager?.requestCall(peerId: peerId, endCurrentIfAny: false) - if let callResult = callResult { - if case let .alreadyInProgress(currentPeerId) = callResult { - if currentPeerId == peerId { - began?() - self.account.telegramApplicationContext.navigateToCurrentCall?() - } else { - let presentationData = self.presentationData - let _ = (self.account.postbox.transaction { transaction -> (Peer?, Peer?) in - return (transaction.getPeer(peerId), transaction.getPeer(currentPeerId)) - } |> deliverOnMainQueue).start(next: { [weak self] peer, current in - if let strongSelf = self, let peer = peer, let current = current { - strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { - if let strongSelf = self { - let _ = strongSelf.account.telegramApplicationContext.callManager?.requestCall(peerId: peerId, endCurrentIfAny: true) - began?() - } - })]), in: .window(.root)) - } - }) + self.peerViewDisposable.set((self.account.viewTracker.peerView(peerId) |> take(1) |> deliverOnMainQueue).start(next: { [weak self] view in + if let strongSelf = self { + guard let peer = peerViewMainPeer(view) else { + return + } + + if let cachedUserData = view.cachedData as? CachedUserData, cachedUserData.callsPrivate { + let presentationData = strongSelf.account.telegramApplicationContext.currentPresentationData.with { $0 } + + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + return + } + + let callResult = strongSelf.account.telegramApplicationContext.callManager?.requestCall(peerId: peerId, endCurrentIfAny: false) + if let callResult = callResult { + if case let .alreadyInProgress(currentPeerId) = callResult { + if currentPeerId == peerId { + began?() + strongSelf.account.telegramApplicationContext.navigateToCurrentCall?() + } else { + let presentationData = strongSelf.presentationData + let _ = (strongSelf.account.postbox.transaction { transaction -> (Peer?, Peer?) in + return (transaction.getPeer(peerId), transaction.getPeer(currentPeerId)) + } |> deliverOnMainQueue).start(next: { [weak self] peer, current in + if let strongSelf = self, let peer = peer, let current = current { + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Call_CallInProgressTitle, text: presentationData.strings.Call_CallInProgressMessage(current.compactDisplayTitle, peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: { + if let strongSelf = self { + let _ = strongSelf.account.telegramApplicationContext.callManager?.requestCall(peerId: peerId, endCurrentIfAny: true) + began?() + } + })]), in: .window(.root)) + } + }) + } + } else { + began?() + } } - } else { - began?() } - } + })) } } diff --git a/TelegramUI/CallListControllerNode.swift b/TelegramUI/CallListControllerNode.swift index 637c2c3835..5b2141fa47 100644 --- a/TelegramUI/CallListControllerNode.swift +++ b/TelegramUI/CallListControllerNode.swift @@ -177,11 +177,15 @@ final class CallListControllerNode: ASDisplayNode { private let callListDisposable = MetaDisposable() private let listNode: ListView + private let emptyTextNode: ASTextNode private let call: (PeerId) -> Void private let openInfo: (PeerId) -> Void private let emptyStateUpdated: (Bool) -> Void + private let emptyStatePromise = Promise() + private let emptyStateDisposable = MetaDisposable() + init(account: Account, mode: CallListControllerMode, presentationData: PresentationData, call: @escaping (PeerId) -> Void, openInfo: @escaping (PeerId) -> Void, emptyStateUpdated: @escaping (Bool) -> Void) { self.account = account self.mode = mode @@ -195,6 +199,11 @@ final class CallListControllerNode: ASDisplayNode { self.listNode = ListView() + self.emptyTextNode = ASTextNode() + self.emptyTextNode.alpha = 0.0 + self.emptyTextNode.isLayerBacked = true + self.emptyTextNode.displaysAsynchronously = false + super.init() self.setViewBlock({ @@ -202,6 +211,7 @@ final class CallListControllerNode: ASDisplayNode { }) self.addSubnode(self.listNode) + self.addSubnode(self.emptyTextNode) switch self.mode { case .tab: @@ -339,10 +349,22 @@ final class CallListControllerNode: ASDisplayNode { self.callListDisposable.set(appliedTransition.start()) self.callListLocationAndType.set(self.currentLocationAndType) + + let emptySignal = self.emptyStatePromise.get() |> distinctUntilChanged + let typeSignal = self.callListLocationAndType.get() |> map { locationAndType -> CallListViewType in + return locationAndType.type + } |> distinctUntilChanged + + self.emptyStateDisposable.set((combineLatest(emptySignal, typeSignal, self.statePromise.get()) |> deliverOnMainQueue).start(next: { [weak self] isEmpty, type, state in + if let strongSelf = self { + strongSelf.updateEmptyPlaceholder(theme: state.theme, strings: state.strings, type: type, hidden: !isEmpty) + } + })) } deinit { self.callListDisposable.dispose() + self.emptyStateDisposable.dispose() } func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings) { @@ -356,12 +378,50 @@ final class CallListControllerNode: ASDisplayNode { self.listNode.backgroundColor = theme.list.blocksBackgroundColor } + self.updateEmptyPlaceholder(theme: theme, strings: strings, type: self.currentLocationAndType.type, hidden: self.emptyTextNode.isHidden) + self.updateState { return $0.withUpdatedPresentationData(theme: theme, strings: strings) } } } + private let textFont = Font.regular(16.0) + + func updateEmptyPlaceholder(theme: PresentationTheme, strings: PresentationStrings, type: CallListViewType, hidden: Bool) { + let alpha: CGFloat = hidden ? 0.0 : 1.0 + let previousAlpha = self.emptyTextNode.alpha + self.emptyTextNode.alpha = alpha + self.emptyTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2) + + if !hidden { + let type = self.currentLocationAndType.type + let string: String + if type == .missed { + string = strings.Calls_NoMissedCallsPlacehoder + } else { + string = strings.Calls_NoCallsPlaceholder + } + let color: UIColor + + switch self.mode { + case .tab: + self.backgroundColor = theme.chatList.backgroundColor + self.listNode.backgroundColor = theme.chatList.backgroundColor + color = theme.list.freeTextColor + case .navigation: + self.backgroundColor = theme.list.blocksBackgroundColor + self.listNode.backgroundColor = theme.list.blocksBackgroundColor + color = theme.list.freeTextColor + } + + self.emptyTextNode.attributedText = NSAttributedString(string: string, font: textFont, textColor: color, paragraphAlignment: .center) + if let layout = self.containerLayout { + self.updateLayout(layout.0, navigationBarHeight: layout.1, transition: .immediate) + } + } + } + func updateState(_ f: (CallListNodeState) -> CallListNodeState) { let state = f(self.currentState) if state != self.currentState { @@ -380,6 +440,7 @@ final class CallListControllerNode: ASDisplayNode { index = MessageIndex.absoluteUpperBound() } self.currentLocationAndType = CallListNodeLocationAndType(location: .changeType(index: index), type: type) + self.emptyStatePromise.set(.single(false)) self.callListLocationAndType.set(self.currentLocationAndType) } } @@ -420,7 +481,9 @@ final class CallListControllerNode: ASDisplayNode { if let strongSelf = self { strongSelf.callListView = transition.callListView - strongSelf.emptyStateUpdated(transition.callListView.filteredEntries.isEmpty) + let empty = countMeaningfulCallListEntries(transition.callListView.filteredEntries) == 0 + strongSelf.emptyStateUpdated(empty) + strongSelf.emptyStatePromise.set(.single(empty)) if !strongSelf.didSetReady { strongSelf.didSetReady = true @@ -445,6 +508,23 @@ final class CallListControllerNode: ASDisplayNode { } } + func updateLayout(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { + var insets = layout.insets(options: [.input]) + insets.top += max(navigationBarHeight, layout.insets(options: [.statusBar]).top) + insets.left += layout.safeInsets.left + insets.right += layout.safeInsets.right + if self.mode == .navigation { + insets.top += 64.0 + } + + let size = layout.size + let contentRect = CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: size.width, height: size.height - insets.top - insets.bottom)) + + + let textSize = self.emptyTextNode.measure(CGSize(width: size.width - 20.0, height: size.height)) + transition.updateFrame(node: self.emptyTextNode, frame: CGRect(origin: CGPoint(x: contentRect.minX + floor((contentRect.width - textSize.width) / 2.0), y: contentRect.minY + floor((contentRect.height - textSize.height) / 2.0)), size: textSize)) + } + func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { self.containerLayout = (layout, navigationBarHeight) @@ -456,6 +536,8 @@ final class CallListControllerNode: ASDisplayNode { self.listNode.bounds = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: layout.size.height) self.listNode.position = CGPoint(x: layout.size.width / 2.0, y: layout.size.height / 2.0) + updateLayout(layout, navigationBarHeight: navigationBarHeight, transition: transition) + var duration: Double = 0.0 var curve: UInt = 0 switch transition { diff --git a/TelegramUI/CallListNodeEntries.swift b/TelegramUI/CallListNodeEntries.swift index 149e26f058..4d3aea5dad 100644 --- a/TelegramUI/CallListNodeEntries.swift +++ b/TelegramUI/CallListNodeEntries.swift @@ -187,3 +187,13 @@ func callListNodeEntriesForView(_ view: CallListView, state: CallListNodeState, } return result } + +func countMeaningfulCallListEntries(_ entries: [CallListNodeEntry]) -> Int { + var count: Int = 0 + for entry in entries { + if case .setting = entry.stableId {} else { + count += 1 + } + } + return count +} diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index fb1757738b..13d08067d4 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -276,38 +276,38 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin } } } - return selectedNode - }, addToTransitionSurface: { view in - guard let strongSelf = self else { - return - } - strongSelf.chatDisplayNode.historyNode.view.superview?.insertSubview(view, aboveSubview: strongSelf.chatDisplayNode.historyNode.view) - }, openUrl: { url in - self?.openUrl(url, concealed: false) - }, openPeer: { peer, navigation in - self?.openPeer(peerId: peer.id, navigation: navigation, fromMessage: nil) - }, callPeer: { peerId in - self?.controllerInteraction?.callPeer(peerId) - }, enqueueMessage: { message in - self?.sendMessages([message]) - }, sendSticker: canSendMessagesToChat(strongSelf.presentationInterfaceState) ? { fileReference in - self?.controllerInteraction?.sendSticker(fileReference) - } : nil, setupTemporaryHiddenMedia: { signal, centralIndex, galleryMedia in - if let strongSelf = self { - strongSelf.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).start(next: { entry in - if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { - var messageIdAndMedia: [MessageId: [Media]] = [:] - - if let entry = entry, entry.index == centralIndex { - messageIdAndMedia[message.id] = [galleryMedia] - } - - controllerInteraction.hiddenMedia = messageIdAndMedia - - strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - itemNode.updateHiddenMedia() - } + } + return selectedNode + }, addToTransitionSurface: { view in + guard let strongSelf = self else { + return + } + strongSelf.chatDisplayNode.historyNode.view.superview?.insertSubview(view, aboveSubview: strongSelf.chatDisplayNode.historyNode.view) + }, openUrl: { url in + self?.openUrl(url, concealed: false) + }, openPeer: { peer, navigation in + self?.openPeer(peerId: peer.id, navigation: navigation, fromMessage: nil) + }, callPeer: { peerId in + self?.controllerInteraction?.callPeer(peerId) + }, enqueueMessage: { message in + self?.sendMessages([message]) + }, sendSticker: canSendMessagesToChat(strongSelf.presentationInterfaceState) ? { fileReference in + self?.controllerInteraction?.sendSticker(fileReference) + } : nil, setupTemporaryHiddenMedia: { signal, centralIndex, galleryMedia in + if let strongSelf = self { + strongSelf.temporaryHiddenGalleryMediaDisposable.set((signal |> deliverOnMainQueue).start(next: { entry in + if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction { + var messageIdAndMedia: [MessageId: [Media]] = [:] + + if let entry = entry, entry.index == centralIndex { + messageIdAndMedia[message.id] = [galleryMedia] + } + + controllerInteraction.hiddenMedia = messageIdAndMedia + + strongSelf.chatDisplayNode.historyNode.forEachItemNode { itemNode in + if let itemNode = itemNode as? ChatMessageItemView { + itemNode.updateHiddenMedia() } } } @@ -667,6 +667,13 @@ public final class ChatController: TelegramController, UIViewControllerPreviewin return } + if let cachedUserData = strongSelf.peerView?.cachedData as? CachedUserData, cachedUserData.callsPrivate { + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + + strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Call_ConnectionErrorTitle, text: presentationData.strings.Call_PrivacyErrorMessage(peer.compactDisplayTitle).0, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + return + } + let callResult = account.telegramApplicationContext.callManager?.requestCall(peerId: peer.id, endCurrentIfAny: false) if let callResult = callResult, case let .alreadyInProgress(currentPeerId) = callResult { if currentPeerId == peer.id { diff --git a/TelegramUI/ChatItemGalleryFooterContentNode.swift b/TelegramUI/ChatItemGalleryFooterContentNode.swift index 56a3a7f683..9497571774 100644 --- a/TelegramUI/ChatItemGalleryFooterContentNode.swift +++ b/TelegramUI/ChatItemGalleryFooterContentNode.swift @@ -112,7 +112,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { } } - var scrubberView: ChatVideoGalleryItemScrubberView? { + var scrubberView: ChatVideoGalleryItemScrubberView? = nil { didSet { if let scrubberView = self.scrubberView { self.view.addSubview(scrubberView) @@ -153,8 +153,6 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { self.playbackControlButton = HighlightableButtonNode() self.playbackControlButton.isHidden = true - self.scrubberView = ChatVideoGalleryItemScrubberView() - super.init() self.view.addSubview(self.deleteButton) @@ -288,7 +286,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode { if !self.textNode.isHidden { let sideInset: CGFloat = 8.0 + leftInset let topInset: CGFloat = 8.0 - let textBottomInset: CGFloat = 8.0 + contentInset + let textBottomInset: CGFloat = 8.0 let textSize = self.textNode.measure(CGSize(width: width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude)) panelHeight += textSize.height + topInset + textBottomInset self.textNode.frame = CGRect(origin: CGPoint(x: sideInset, y: topInset), size: textSize) diff --git a/TelegramUI/ChatMediaInputNode.swift b/TelegramUI/ChatMediaInputNode.swift index 35e1c18900..cce03385c0 100644 --- a/TelegramUI/ChatMediaInputNode.swift +++ b/TelegramUI/ChatMediaInputNode.swift @@ -454,11 +454,11 @@ final class ChatMediaInputNode: ChatInputNode { } else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue { strongSelf.setCurrentPane(.trending, transition: .animated(duration: 0.25, curve: .spring)) } else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.savedStickers.rawValue { - strongSelf.setCurrentPane(.stickers, transition: .animated(duration: 0.25, curve: .spring)) + strongSelf.setCurrentPane(.stickers, transition: .animated(duration: 0.25, curve: .spring), collectionIdHint: collectionId.namespace) strongSelf.currentStickerPacksCollectionPosition = .navigate(index: nil, collectionId: collectionId) strongSelf.itemCollectionsViewPosition.set(.single(.navigate(index: nil, collectionId: collectionId))) } else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.recentStickers.rawValue { - strongSelf.setCurrentPane(.stickers, transition: .animated(duration: 0.25, curve: .spring)) + strongSelf.setCurrentPane(.stickers, transition: .animated(duration: 0.25, curve: .spring), collectionIdHint: collectionId.namespace) strongSelf.currentStickerPacksCollectionPosition = .navigate(index: nil, collectionId: collectionId) strongSelf.itemCollectionsViewPosition.set(.single(.navigate(index: nil, collectionId: collectionId))) } else if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.peerSpecific.rawValue { @@ -894,7 +894,7 @@ final class ChatMediaInputNode: ChatInputNode { self.view.addGestureRecognizer(panRecognizer) } - private func setCurrentPane(_ pane: ChatMediaInputPaneType, transition: ContainedViewLayoutTransition) { + private func setCurrentPane(_ pane: ChatMediaInputPaneType, transition: ContainedViewLayoutTransition, collectionIdHint: Int32? = nil) { if let index = self.paneArrangement.panes.index(of: pane), index != self.paneArrangement.currentIndex { let previousGifPanelWasActive = self.paneArrangement.panes[self.paneArrangement.currentIndex] == .gifs self.paneArrangement = self.paneArrangement.withIndexTransition(0.0).withCurrentIndex(index) @@ -912,6 +912,8 @@ final class ChatMediaInputNode: ChatInputNode { case .stickers: if let highlightedStickerCollectionId = self.inputNodeInteraction.highlightedStickerItemCollectionId { self.setHighlightedItemCollectionId(highlightedStickerCollectionId) + } else if let collectionIdHint = collectionIdHint { + self.setHighlightedItemCollectionId(ItemCollectionId(namespace: collectionIdHint, id: 0)) } case .trending: self.setHighlightedItemCollectionId(ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.trending.rawValue, id: 0)) diff --git a/TelegramUI/GalleryThumbnailContainerNode.swift b/TelegramUI/GalleryThumbnailContainerNode.swift index 6003f76824..fcbac4e3e2 100644 --- a/TelegramUI/GalleryThumbnailContainerNode.swift +++ b/TelegramUI/GalleryThumbnailContainerNode.swift @@ -44,9 +44,9 @@ private final class GalleryThumbnailItemNode: ASDisplayNode { } } -final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDelegate { +final class GalleryThumbnailContainerNode: ASDisplayNode { let groupId: Int64 - private let scrollNode: ASScrollNode + private let contentNode: ASDisplayNode private(set) var items: [GalleryThumbnailItem] = [] private var itemNodes: [GalleryThumbnailItemNode] = [] @@ -55,13 +55,11 @@ final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDelegate { init(groupId: Int64) { self.groupId = groupId - self.scrollNode = ASScrollNode() - + self.contentNode = ASDisplayNode() + super.init() - - self.scrollNode.view.delegate = self - - self.addSubnode(self.scrollNode) + + self.addSubnode(self.contentNode) } func updateItems(_ items: [GalleryThumbnailItem], centralIndex: Int, progress: CGFloat) { @@ -88,7 +86,7 @@ final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDelegate { for itemNode in itemNodes { if itemNode.supernode == nil { - self.scrollNode.addSubnode(itemNode) + self.contentNode.addSubnode(itemNode) } } for itemNode in self.itemNodes { @@ -121,7 +119,7 @@ final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDelegate { func updateLayout(size: CGSize, centralIndex: Int, progress: CGFloat, transition: ContainedViewLayoutTransition) { self.currentLayout = size - self.scrollNode.frame = CGRect(origin: CGPoint(), size: size) + self.contentNode.frame = CGRect(origin: CGPoint(), size: size) let spacing: CGFloat = 2.0 let centralSpacing: CGFloat = 8.0 let itemHeight: CGFloat = 42.0 @@ -205,16 +203,4 @@ final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDelegate { delay += 0.01 } } - - func scrollViewDidScroll(_ scrollView: UIScrollView) { - - } - - func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { - - } - - func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { - - } } diff --git a/TelegramUI/LegacyController.swift b/TelegramUI/LegacyController.swift index 9cd028cf20..e2344f5553 100644 --- a/TelegramUI/LegacyController.swift +++ b/TelegramUI/LegacyController.swift @@ -5,6 +5,7 @@ import LegacyComponents public enum LegacyControllerPresentation { case custom case modal(animateIn: Bool) + case navigation } private func passControllerAppearanceAnimated(in: Bool, presentation: LegacyControllerPresentation) -> Bool { @@ -316,12 +317,18 @@ public class LegacyController: ViewController { return self.sizeClass.signal()! } - public init(presentation: LegacyControllerPresentation, theme: PresentationTheme?, initialLayout: ContainerViewLayout? = nil) { + public init(presentation: LegacyControllerPresentation, theme: PresentationTheme?, presentationData: PresentationData? = nil, initialLayout: ContainerViewLayout? = nil) { self.sizeClass.set(SSignal.single(UIUserInterfaceSizeClass.compact.rawValue as NSNumber)) self.presentation = presentation self.validLayout = initialLayout - super.init(navigationBarPresentationData: nil) + let navigationBarPresentationData: NavigationBarPresentationData? + if let presentationData = presentationData, case .navigation = presentation { + navigationBarPresentationData = NavigationBarPresentationData(presentationData: presentationData) + } else { + navigationBarPresentationData = nil + } + super.init(navigationBarPresentationData: navigationBarPresentationData) if let theme = theme { self.statusBar.statusBarStyle = theme.rootController.statusBar.style.style @@ -401,7 +408,7 @@ public class LegacyController: ViewController { self.presentationCompleted?() } self.legacyController.viewDidAppear(animated && animateIn) - case .custom: + case .custom, .navigation: self.legacyController.viewDidAppear(animated) self.presentationCompleted?() } @@ -429,6 +436,20 @@ public class LegacyController: ViewController { super.containerLayoutUpdated(layout, transition: transition) self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition) + if let legacyTelegramController = self.legacyController as? TGViewController { + var duration: TimeInterval = 0.0 + if case let .animated(transitionDuration, _) = transition { + duration = transitionDuration + } + + var orientation = UIInterfaceOrientation.portrait + if layout.size.width > layout.size.height { + orientation = .landscapeRight + } + + legacyTelegramController._updateInset(for: orientation, force: false, notify: true) + legacyTelegramController.layoutController(for: layout.size, duration: duration) + } let updatedSizeClass: UIUserInterfaceSizeClass if case .regular = layout.metrics.widthClass { updatedSizeClass = .regular @@ -459,6 +480,9 @@ public class LegacyController: ViewController { //controller.didDismiss() } self.presentingViewController?.dismiss(animated: false, completion: completion) + + case .navigation: + break } } diff --git a/TelegramUI/LegacyInstantVideoController.swift b/TelegramUI/LegacyInstantVideoController.swift index 620e5ac75c..cf3d280745 100644 --- a/TelegramUI/LegacyInstantVideoController.swift +++ b/TelegramUI/LegacyInstantVideoController.swift @@ -25,7 +25,7 @@ final class InstantVideoController: LegacyController { private var dismissedVideo = false - override init(presentation: LegacyControllerPresentation, theme: PresentationTheme?, initialLayout: ContainerViewLayout? = nil) { + override init(presentation: LegacyControllerPresentation, theme: PresentationTheme?, presentationData: PresentationData? = nil, initialLayout: ContainerViewLayout? = nil) { self.audioStatus = InstantVideoControllerRecordingStatus(micLevel: self.micLevelValue.get()) super.init(presentation: presentation, theme: theme, initialLayout: initialLayout) diff --git a/TelegramUI/LegacyLocationController.swift b/TelegramUI/LegacyLocationController.swift index 695a6e43e8..07ed54cfb3 100644 --- a/TelegramUI/LegacyLocationController.swift +++ b/TelegramUI/LegacyLocationController.swift @@ -114,7 +114,7 @@ private func telegramMap(for location: TGLocationMediaAttachment) -> TelegramMed return TelegramMediaMap(latitude: location.latitude, longitude: location.longitude, geoPlace: nil, venue: mapVenue, liveBroadcastingTimeout: nil) } -func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, account: Account, openPeer: @escaping (Peer) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, stopLiveLocation: @escaping () -> Void, showActions: @escaping (TelegramMediaMap, Bool) -> Void) -> ViewController { +func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, account: Account, modal: Bool, openPeer: @escaping (Peer) -> Void, sendLiveLocation: @escaping (CLLocationCoordinate2D, Int32) -> Void, stopLiveLocation: @escaping () -> Void, openUrl: @escaping (String) -> Void) -> ViewController { let legacyAuthor: AnyObject? = message.author.flatMap(makeLegacyPeer) let legacyLocation = TGLocationMediaAttachment() @@ -126,7 +126,7 @@ func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, acco let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let legacyController = LegacyController(presentation: .modal(animateIn: true), theme: presentationData.theme) + let legacyController = LegacyController(presentation: .navigation, theme: presentationData.theme, presentationData: presentationData) let legacyMessage = makeLegacyMessage(message) @@ -219,18 +219,40 @@ func legacyLocationController(message: Message, mapMedia: TelegramMediaMap, acco let searchTheme = theme.rootController.activeNavigationSearchBar controller.pallete = TGLocationPallete(backgroundColor: listTheme.plainBackgroundColor, selectionColor: listTheme.itemHighlightedBackgroundColor, separatorColor: listTheme.itemPlainSeparatorColor, textColor: listTheme.itemPrimaryTextColor, secondaryTextColor: listTheme.itemSecondaryTextColor, accentColor: listTheme.itemAccentColor, destructiveColor: listTheme.itemDestructiveColor, locationColor: UIColor(rgb: 0x008df2), liveLocationColor: UIColor(rgb: 0xff6464), iconColor: searchTheme.backgroundColor, sectionHeaderBackgroundColor: theme.chatList.sectionHeaderFillColor, sectionHeaderTextColor: theme.chatList.sectionHeaderTextColor, searchBarPallete: TGSearchBarPallete(dark: theme.overallDarkAppearance, backgroundColor: searchTheme.backgroundColor, highContrastBackgroundColor: searchTheme.backgroundColor, textColor: searchTheme.inputTextColor, placeholderColor: searchTheme.inputPlaceholderTextColor, clearIcon: generateClearIcon(color: theme.rootController.activeNavigationSearchBar.inputClearButtonColor), barBackgroundColor: searchTheme.backgroundColor, barSeparatorColor: searchTheme.separatorColor, plainBackgroundColor: searchTheme.backgroundColor, accentColor: searchTheme.accentColor, accentContrastColor: searchTheme.backgroundColor, menuBackgroundColor: searchTheme.backgroundColor, segmentedControlBackgroundImage: nil, segmentedControlSelectedImage: nil, segmentedControlHighlightedImage: nil, segmentedControlDividerImage: nil), avatarPlaceholder: nil) - controller.modalMode = true - let navigationController = TGNavigationController(controllers: [controller])! - legacyController.bind(controller: navigationController) - controller.navigation_setDismiss({ [weak legacyController] in - legacyController?.dismiss() - }, rootController: nil) - controller.presentActionsMenu = { legacyLocation, directions in - if let location = legacyLocation { + controller.modalMode = modal + controller.presentActionsMenu = { [weak legacyController] legacyLocation, directions in + if let strongLegacyController = legacyController, let location = legacyLocation { let map = telegramMap(for: location) - showActions(map, directions) + + let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } + let shareAction = OpenInControllerAction(title: presentationData.strings.Conversation_ContextMenuShare, action: { + strongLegacyController.present(ShareController(account: account, subject: .mapMedia(map), externalShare: true), in: .window(.root), with: nil) + }) + + strongLegacyController.present(OpenInActionSheetController(postbox: account.postbox, applicationContext: account.telegramApplicationContext, theme: presentationData.theme, strings: presentationData.strings, item: .location(map, withDirections: directions), additionalAction: shareAction, openUrl: openUrl), in: .window(.root), with: nil) } } + + controller.onViewDidAppear = { [weak controller] in + if let strongController = controller { + strongController.locationMapView.interactiveTransitionGestureRecognizerTest = { point -> Bool in + return point.x > 36.0 + } + } + } + + if modal { + let navigationController = TGNavigationController(controllers: [controller])! + legacyController.bind(controller: navigationController) + controller.navigation_setDismiss({ [weak legacyController] in + legacyController?.dismiss() + }, rootController: nil) + } else { + legacyController.navigationItem.title = controller.navigationItem.title + + legacyController.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationShareIcon(theme), style: .plain, target: controller, action: #selector(controller.actionsButtonPressed)) + legacyController.bind(controller: controller) + } return legacyController } diff --git a/TelegramUI/MediaPlayer.swift b/TelegramUI/MediaPlayer.swift index ed4fae85d5..138136b769 100644 --- a/TelegramUI/MediaPlayer.swift +++ b/TelegramUI/MediaPlayer.swift @@ -727,9 +727,11 @@ private final class MediaPlayerContext { f?() case .stop: self.stoppedAtEnd = true + self.seek(timestamp: 0.0, action: .pause) self.pause(lostAudioSession: false) case let .action(f): self.stoppedAtEnd = true + self.seek(timestamp: 0.0, action: .pause) self.pause(lostAudioSession: false) f() case let .loopDisablingSound(f): diff --git a/TelegramUI/OpenChatMessage.swift b/TelegramUI/OpenChatMessage.swift index e55707aab7..add38dbad3 100644 --- a/TelegramUI/OpenChatMessage.swift +++ b/TelegramUI/OpenChatMessage.swift @@ -151,7 +151,7 @@ func chatMessagePreviewControllerData(account: Account, message: Message, standa return nil } -func openChatMessage(account: Account, message: Message, standalone: Bool, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?, dismissInput: @escaping () -> Void, present: @escaping (ViewController, Any?) -> Void, transitionNode: @escaping (MessageId, Media) -> (ASDisplayNode, () -> UIView?)?, addToTransitionSurface: @escaping (UIView) -> Void, openUrl: @escaping (String) -> Void, openPeer: @escaping (Peer, ChatControllerInteractionNavigateToPeer) -> Void, callPeer: @escaping (PeerId) -> Void, enqueueMessage: @escaping (EnqueueMessage) -> Void, sendSticker: ((FileMediaReference) -> Void)?, setupTemporaryHiddenMedia: @escaping (Signal, Int, Media) -> Void) -> Bool { +func openChatMessage(account: Account, message: Message, standalone: Bool, reverseMessageGalleryOrder: Bool, navigationController: NavigationController?, modal: Bool = false, dismissInput: @escaping () -> Void, present: @escaping (ViewController, Any?) -> Void, transitionNode: @escaping (MessageId, Media) -> (ASDisplayNode, () -> UIView?)?, addToTransitionSurface: @escaping (UIView) -> Void, openUrl: @escaping (String) -> Void, openPeer: @escaping (Peer, ChatControllerInteractionNavigateToPeer) -> Void, callPeer: @escaping (PeerId) -> Void, enqueueMessage: @escaping (EnqueueMessage) -> Void, sendSticker: ((FileMediaReference) -> Void)?, setupTemporaryHiddenMedia: @escaping (Signal, Int, Media) -> Void) -> Bool { if let mediaData = chatMessageGalleryControllerData(account: account, message: message, navigationController: navigationController, standalone: standalone, reverseMessageGalleryOrder: reverseMessageGalleryOrder, synchronousLoad: false) { switch mediaData { case let .url(url): @@ -195,21 +195,21 @@ func openChatMessage(account: Account, message: Message, standalone: Bool, rever return true case let .map(mapMedia): dismissInput() - present(legacyLocationController(message: message, mapMedia: mapMedia, account: account, openPeer: { peer in + + let controller = legacyLocationController(message: message, mapMedia: mapMedia, account: account, modal: modal, openPeer: { peer in openPeer(peer, .info) }, sendLiveLocation: { coordinate, period in let outMessage: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaMap(latitude: coordinate.latitude, longitude: coordinate.longitude, geoPlace: nil, venue: nil, liveBroadcastingTimeout: period)), replyToMessageId: nil, localGroupingKey: nil) enqueueMessage(outMessage) }, stopLiveLocation: { account.telegramApplicationContext.liveLocationManager?.cancelLiveLocation(peerId: message.id.peerId) - }, showActions: { media, directions in - let presentationData = account.telegramApplicationContext.currentPresentationData.with { $0 } - let shareAction = OpenInControllerAction(title: presentationData.strings.Conversation_ContextMenuShare, action: { - present(ShareController(account: account, subject: .mapMedia(media), externalShare: true), nil) - }) - - present(OpenInActionSheetController(postbox: account.postbox, applicationContext: account.telegramApplicationContext, theme: presentationData.theme, strings: presentationData.strings, item: .location(media, withDirections: directions), additionalAction: shareAction, openUrl: openUrl), nil) - }), nil) + }, openUrl: openUrl) + + if modal { + present(controller, nil) + } else { + navigationController?.pushViewController(controller) + } return true case let .stickerPack(reference): let controller = StickerPackPreviewController(account: account, stickerPack: reference, parentNavigationController: navigationController) diff --git a/TelegramUI/PeerMediaCollectionEmptyNode.swift b/TelegramUI/PeerMediaCollectionEmptyNode.swift index ba091bdb20..2e3d2508f2 100644 --- a/TelegramUI/PeerMediaCollectionEmptyNode.swift +++ b/TelegramUI/PeerMediaCollectionEmptyNode.swift @@ -42,6 +42,7 @@ final class PeerMediaCollectionEmptyNode: ASDisplayNode { self.textNode = ASTextNode() self.textNode.isLayerBacked = true self.textNode.displaysAsynchronously = false + self.textNode.isHidden = true self.activityIndicator = ActivityIndicator(type: .custom(theme.list.itemSecondaryTextColor, 22.0, 2.0), speed: .regular) diff --git a/TelegramUI/ShareActionButtonNode.swift b/TelegramUI/ShareActionButtonNode.swift index 8b7d40c409..1bf865d4f6 100644 --- a/TelegramUI/ShareActionButtonNode.swift +++ b/TelegramUI/ShareActionButtonNode.swift @@ -57,7 +57,7 @@ final class ShareActionButtonNode: HighlightTrackingButtonNode { let _ = badgeApply() let backgroundSize = CGSize(width: max(22.0, badgeLayout.size.width + 10.0 + 1.0), height: 22.0) - let backgroundFrame = CGRect(origin: CGPoint(x: self.titleNode.frame.maxX + 6.0, y: self.bounds.size.height - 38.0), size: backgroundSize) + let backgroundFrame = CGRect(origin: CGPoint(x: self.titleNode.frame.maxX + 6.0, y: self.bounds.size.height - 39.0), size: backgroundSize) self.badgeBackground.frame = backgroundFrame self.badgeLabel.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(backgroundFrame.midX - badgeLayout.size.width / 2.0), y: backgroundFrame.minY + 3.0), size: badgeLayout.size) diff --git a/TelegramUI/ShareControllerNode.swift b/TelegramUI/ShareControllerNode.swift index 085a10e6f5..8f689a97f8 100644 --- a/TelegramUI/ShareControllerNode.swift +++ b/TelegramUI/ShareControllerNode.swift @@ -131,6 +131,12 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate self.actionSeparatorNode.displaysAsynchronously = false self.actionSeparatorNode.backgroundColor = self.presentationData.theme.actionSheet.opaqueItemSeparatorColor + if self.defaultAction == nil { + self.actionButtonNode.alpha = 0.0 + self.actionsBackgroundNode.alpha = 0.0 + self.actionSeparatorNode.alpha = 0.0 + } + super.init() self.controllerInteraction = ShareControllerInteraction(togglePeer: { [weak self] peer, search in @@ -155,17 +161,28 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate strongSelf.peersContentNode?.updateFoundPeers() } - let inputNodeAlpha: CGFloat = strongSelf.controllerInteraction!.selectedPeers.isEmpty ? 0.0 : 1.0 - if !strongSelf.inputFieldNode.alpha.isEqual(to: inputNodeAlpha) { - let previousAlpha = strongSelf.inputFieldNode.alpha - strongSelf.inputFieldNode.alpha = inputNodeAlpha - strongSelf.inputFieldNode.layer.animateAlpha(from: previousAlpha, to: inputNodeAlpha, duration: inputNodeAlpha.isZero ? 0.18 : 0.32) - - if inputNodeAlpha.isZero { - strongSelf.inputFieldNode.deactivateInput() + func updateActionNodesAlpha(_ nodes: [ASDisplayNode], alpha: CGFloat) { + for node in nodes { + if !node.alpha.isEqual(to: alpha) { + let previousAlpha = node.alpha + node.alpha = alpha + node.layer.animateAlpha(from: previousAlpha, to: alpha, duration: alpha.isZero ? 0.18 : 0.32) + + if let inputNode = node as? ShareInputFieldNode, alpha.isZero { + inputNode.deactivateInput() + } + } } } + let actionNodes: [ASDisplayNode] + if strongSelf.defaultAction == nil { + actionNodes = [strongSelf.inputFieldNode, strongSelf.actionsBackgroundNode, strongSelf.actionButtonNode, strongSelf.actionSeparatorNode] + } else { + actionNodes = [strongSelf.inputFieldNode] + } + updateActionNodesAlpha(actionNodes, alpha: strongSelf.controllerInteraction!.selectedPeers.isEmpty ? 0.0 : 1.0) + strongSelf.updateButton() strongSelf.peersContentNode?.updateSelectedPeers() @@ -197,7 +214,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate self.wrappingScrollNode.addSubnode(self.cancelButtonNode) self.cancelButtonNode.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside) - self.actionButtonNode.addTarget(self, action: #selector(self.installActionButtonPressed), forControlEvents: .touchUpInside) + self.actionButtonNode.addTarget(self, action: #selector(self.actionButtonPressed), forControlEvents: .touchUpInside) self.wrappingScrollNode.addSubnode(self.contentBackgroundNode) @@ -315,10 +332,15 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: insets.top), size: CGSize(width: width, height: maximumContentHeight)) let contentFrame = contentContainerFrame.insetBy(dx: 0.0, dy: 0.0) - var bottomGridInset = buttonHeight - + var bottomGridInset: CGFloat = 0 + + var actionButtonHeight: CGFloat = 0 + if self.defaultAction != nil || !self.controllerInteraction!.selectedPeers.isEmpty { + actionButtonHeight = buttonHeight + bottomGridInset += actionButtonHeight + } + let inputHeight = self.inputFieldNode.updateLayout(width: contentContainerFrame.size.width, transition: transition) - if !self.controllerInteraction!.selectedPeers.isEmpty { bottomGridInset += inputHeight } @@ -336,7 +358,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate transition.updateFrame(node: self.actionsBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentContainerFrame.size.height - bottomGridInset), size: CGSize(width: contentContainerFrame.size.width, height: bottomGridInset))) - transition.updateFrame(node: self.actionButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentContainerFrame.size.height - buttonHeight), size: CGSize(width: contentContainerFrame.size.width, height: buttonHeight))) + transition.updateFrame(node: self.actionButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentContainerFrame.size.height - actionButtonHeight), size: CGSize(width: contentContainerFrame.size.width, height: buttonHeight))) transition.updateFrame(node: self.inputFieldNode, frame: CGRect(origin: CGPoint(x: 0.0, y: contentContainerFrame.size.height - bottomGridInset), size: CGSize(width: contentContainerFrame.size.width, height: inputHeight))) @@ -403,7 +425,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate self.cancel?() } - @objc func installActionButtonPressed() { + @objc func actionButtonPressed() { if self.controllerInteraction!.selectedPeers.isEmpty { if let defaultAction = self.defaultAction { defaultAction.action() @@ -626,10 +648,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate if self.controllerInteraction!.selectedPeers.isEmpty { if let defaultAction = self.defaultAction { self.actionButtonNode.setTitle(defaultAction.title, with: Font.regular(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal) + self.actionButtonNode.badge = nil } else { self.actionButtonNode.setTitle(self.presentationData.strings.ShareMenu_Send, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.disabledActionTextColor, for: .normal) } - self.actionButtonNode.badge = nil } else { self.actionButtonNode.setTitle(self.presentationData.strings.ShareMenu_Send, with: Font.medium(20.0), with: self.presentationData.theme.actionSheet.standardActionTextColor, for: .normal) self.actionButtonNode.badge = "\(self.controllerInteraction!.selectedPeers.count)" diff --git a/TelegramUI/SharePeersContainerNode.swift b/TelegramUI/SharePeersContainerNode.swift index 0a61e1bda5..46259f20b8 100644 --- a/TelegramUI/SharePeersContainerNode.swift +++ b/TelegramUI/SharePeersContainerNode.swift @@ -171,6 +171,10 @@ final class SharePeersContainerNode: ASDisplayNode, ShareContentContainerNode { self.shareButtonNode.addTarget(self, action: #selector(self.sharePressed), forControlEvents: .touchUpInside) } + deinit { + self.disposable.dispose() + } + private func enqueueTransition(_ transition: ShareGridTransaction, firstTime: Bool) { self.enqueuedTransitions.append((transition, firstTime)) diff --git a/TelegramUI/TelegramController.swift b/TelegramUI/TelegramController.swift index eb6b8bac8a..cd16dcbdb6 100644 --- a/TelegramUI/TelegramController.swift +++ b/TelegramUI/TelegramController.swift @@ -16,7 +16,7 @@ private func presentLiveLocationController(account: Account, peerId: PeerId, con return transaction.getMessage(id) } |> deliverOnMainQueue).start(next: { [weak controller] message in if let message = message, let strongController = controller { - let _ = openChatMessage(account: account, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongController.navigationController as? NavigationController, dismissInput: { + let _ = openChatMessage(account: account, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongController.navigationController as? NavigationController, modal: true, dismissInput: { controller?.view.endEditing(true) }, present: { c, a in controller?.present(c, in: .window(.root), with: a) diff --git a/TelegramUI/UserInfoController.swift b/TelegramUI/UserInfoController.swift index 41808eecf9..71473057b1 100644 --- a/TelegramUI/UserInfoController.swift +++ b/TelegramUI/UserInfoController.swift @@ -942,10 +942,7 @@ public func userInfoController(account: Account, peerId: PeerId) -> ViewControll presentControllerImpl?(c, a) }), nil) }) - - let peerView = Promise() - peerView.set(account.viewTracker.peerView(peerId)) - + let deviceContacts: Signal<[(DeviceContactStableId, DeviceContactBasicData)], NoError> = peerView.get() |> map { peerView -> String in if let peer = peerView.peers[peerId] as? TelegramUser {