diff --git a/TelegramUI/AutodownloadConnectionTypeController.swift b/TelegramUI/AutodownloadConnectionTypeController.swift index 6c7e2ab610..b53ea8f77f 100644 --- a/TelegramUI/AutodownloadConnectionTypeController.swift +++ b/TelegramUI/AutodownloadConnectionTypeController.swift @@ -311,14 +311,22 @@ func autodownloadMediaConnectionTypeController(context: AccountContext, connecti pushControllerImpl?(controller) }) - let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])) + let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])) |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, AutodownloadMediaCategoryEntry.ItemGenerationArguments)) in - let settings: MediaAutoDownloadSettings + var automaticMediaDownloadSettings: MediaAutoDownloadSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { - settings = value + automaticMediaDownloadSettings = value } else { - settings = MediaAutoDownloadSettings.defaultSettings + automaticMediaDownloadSettings = MediaAutoDownloadSettings.defaultSettings + } + + var autodownloadSettings: AutodownloadSettings + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + autodownloadSettings = value + automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) + } else { + autodownloadSettings = .defaultSettings } let title: String @@ -330,7 +338,7 @@ func autodownloadMediaConnectionTypeController(context: AccountContext, connecti } let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: autodownloadMediaConnectionTypeControllerEntries(presentationData: presentationData, connectionType: connectionType, settings: settings), style: .blocks, emptyStateItem: nil, animateChanges: false) + let listState = ItemListNodeState(entries: autodownloadMediaConnectionTypeControllerEntries(presentationData: presentationData, connectionType: connectionType, settings: automaticMediaDownloadSettings), style: .blocks, emptyStateItem: nil, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/TelegramUI/AutodownloadMediaCategoryController.swift b/TelegramUI/AutodownloadMediaCategoryController.swift index 5409e64870..bda1df504e 100644 --- a/TelegramUI/AutodownloadMediaCategoryController.swift +++ b/TelegramUI/AutodownloadMediaCategoryController.swift @@ -392,15 +392,23 @@ func autodownloadMediaCategoryController(context: AccountContext, connectionType let initialValuePromise: Promise = Promise() initialValuePromise.set(currentAutodownloadSettings()) - let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])) |> deliverOnMainQueue + let signal = combineLatest(context.sharedContext.presentationData, context.sharedContext.accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings, ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])) |> deliverOnMainQueue |> map { presentationData, sharedData -> (ItemListControllerState, (ItemListNodeState, AutodownloadMediaCategoryEntry.ItemGenerationArguments)) in - let automaticMediaDownloadSettings: MediaAutoDownloadSettings + var automaticMediaDownloadSettings: MediaAutoDownloadSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings] as? MediaAutoDownloadSettings { automaticMediaDownloadSettings = value } else { automaticMediaDownloadSettings = .defaultSettings } + var autodownloadSettings: AutodownloadSettings + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + autodownloadSettings = value + automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) + } else { + autodownloadSettings = .defaultSettings + } + let title: String switch category { case .photo: diff --git a/TelegramUI/ChatController.swift b/TelegramUI/ChatController.swift index 98dc3eaf1f..0406d9b3ea 100644 --- a/TelegramUI/ChatController.swift +++ b/TelegramUI/ChatController.swift @@ -5487,6 +5487,10 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal } func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? { + guard let view = self.chatDisplayNode.view.hitTest(location, with: nil), view.isDescendant(of: self.chatDisplayNode.historyNode.view) else { + return nil + } + let historyPoint = sourceView.convert(location, to: self.chatDisplayNode.historyNode.view) var result: (Message, ChatMessagePeekPreviewContent)? self.chatDisplayNode.historyNode.forEachItemNode { itemNode in diff --git a/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift b/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift index 6958c1ba42..ae36cf4c35 100644 --- a/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift +++ b/TelegramUI/ChatMessageInteractiveInstantVideoNode.swift @@ -34,7 +34,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { private var item: ChatMessageBubbleContentItem? private var automaticDownload: Bool? - var telegramFile: TelegramMediaFile? + var media: TelegramMediaFile? private var secretProgressIcon: UIImage? private let fetchDisposable = MetaDisposable() @@ -112,7 +112,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { } func asyncLayout() -> (_ item: ChatMessageBubbleContentItem, _ width: CGFloat, _ displaySize: CGSize, _ statusType: ChatMessageInteractiveInstantVideoNodeStatusType, _ automaticDownload: Bool) -> (ChatMessageInstantVideoItemLayoutResult, (ChatMessageInstantVideoItemLayoutData, ContainedViewLayoutTransition) -> Void) { - let previousFile = self.telegramFile + let previousFile = self.media let currentItem = self.item let previousAutomaticDownload = self.automaticDownload @@ -283,7 +283,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { strongSelf.secretVideoPlaceholderBackground.image = secretVideoPlaceholderBackgroundImage } - strongSelf.telegramFile = updatedFile + strongSelf.media = updatedFile if let infoBackgroundImage = strongSelf.infoBackgroundNode.image, let muteImage = strongSelf.muteIconNode.image { let infoWidth = muteImage.size.width @@ -603,10 +603,16 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { return } if self.infoBackgroundNode.alpha.isZero { - item.context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice) + if let status = self.status, case let .fetchStatus(fetchStatus) = status, case .Remote = fetchStatus { + item.context.sharedContext.mediaManager.playlistControl(.playback(.pause), type: .voice) + self.videoNode?.fetchControl(.fetch) + } else { + item.context.sharedContext.mediaManager.playlistControl(.playback(.togglePlayPause), type: .voice) + } } else { let _ = item.controllerInteraction.openMessage(item.message, .default) } + } override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { @@ -623,7 +629,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { } private func progressPressed() { - guard let item = self.item, let file = self.telegramFile else { + guard let item = self.item, let file = self.media else { return } if let status = self.status { diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index a910baf55c..8f4e138921 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -444,7 +444,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { if let currentFile = currentMedia as? TelegramMediaFile, currentFile.resource is EmptyMediaResource { replaceVideoNode = true } - } else { + } else if !(file.resource is LocalFileVideoMediaResource) { replaceVideoNode = true } } else { @@ -592,7 +592,11 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { let streamVideo = !updatedVideoFile.isAnimated && isMediaStreamable(message: message, media: updatedVideoFile) let videoNode = UniversalVideoNode(postbox: context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: decoration, content: NativeVideoContent(id: .message(message.id, message.stableId, updatedVideoFile.fileId), fileReference: .message(message: MessageReference(message), media: updatedVideoFile), streamVideo: streamVideo, enableSound: false, fetchAutomatically: false, onlyFullSizeThumbnail: (onlyFullSizeVideoThumbnail ?? false), continuePlayingWithoutSoundOnLostAudioSession: isInlinePlayableVideo, placeholderColor: emptyColor), priority: .embedded) videoNode.isUserInteractionEnabled = false - + videoNode.ownsContentNodeUpdated = { [weak self] owns in + if let strongSelf = self { + strongSelf.videoNode?.isHidden = !owns + } + } strongSelf.videoNode = videoNode updatedVideoNodeReadySignal = videoNode.ready diff --git a/TelegramUI/DataAndStorageSettingsController.swift b/TelegramUI/DataAndStorageSettingsController.swift index 9c9b9a8b98..a129dd5974 100644 --- a/TelegramUI/DataAndStorageSettingsController.swift +++ b/TelegramUI/DataAndStorageSettingsController.swift @@ -313,12 +313,14 @@ private struct DataAndStorageControllerState: Equatable { private struct DataAndStorageData: Equatable { let automaticMediaDownloadSettings: MediaAutoDownloadSettings + let autodownloadSettings: AutodownloadSettings let generatedMediaStoreSettings: GeneratedMediaStoreSettings let voiceCallSettings: VoiceCallSettings let proxySettings: ProxySettings? - init(automaticMediaDownloadSettings: MediaAutoDownloadSettings, generatedMediaStoreSettings: GeneratedMediaStoreSettings, voiceCallSettings: VoiceCallSettings, proxySettings: ProxySettings?) { + init(automaticMediaDownloadSettings: MediaAutoDownloadSettings, autodownloadSettings: AutodownloadSettings, generatedMediaStoreSettings: GeneratedMediaStoreSettings, voiceCallSettings: VoiceCallSettings, proxySettings: ProxySettings?) { self.automaticMediaDownloadSettings = automaticMediaDownloadSettings + self.autodownloadSettings = autodownloadSettings self.generatedMediaStoreSettings = generatedMediaStoreSettings self.voiceCallSettings = voiceCallSettings self.proxySettings = proxySettings @@ -329,14 +331,16 @@ private struct DataAndStorageData: Equatable { } } -private func stringForUseLessDataSetting(strings: PresentationStrings, settings: VoiceCallSettings) -> String { - switch settings.dataSaving { +private func stringForUseLessDataSetting(_ dataSaving: VoiceCallDataSaving, strings: PresentationStrings) -> String { + switch dataSaving { case .never: return strings.CallSettings_Never case .cellular: return strings.CallSettings_OnMobile case .always: return strings.CallSettings_Always + case .default: + return "" } } @@ -405,7 +409,8 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat entries.append(.autoplayVideos(presentationData.theme, presentationData.strings.ChatSettings_AutoPlayVideos, data.automaticMediaDownloadSettings.autoplayVideos)) entries.append(.voiceCallsHeader(presentationData.theme, presentationData.strings.Settings_CallSettings.uppercased())) - entries.append(.useLessVoiceData(presentationData.theme, presentationData.strings.CallSettings_UseLessData, stringForUseLessDataSetting(strings: presentationData.strings, settings: data.voiceCallSettings))) + let dataSaving = effectiveDataSaving(for: data.voiceCallSettings, autodownloadSettings: data.autodownloadSettings) + entries.append(.useLessVoiceData(presentationData.theme, presentationData.strings.CallSettings_UseLessData, stringForUseLessDataSetting(dataSaving, strings: presentationData.strings))) entries.append(.otherHeader(presentationData.theme, presentationData.strings.ChatSettings_Other)) entries.append(.saveIncomingPhotos(presentationData.theme, presentationData.strings.Settings_SaveIncomingPhotos)) @@ -449,8 +454,12 @@ func dataAndStorageController(context: AccountContext) -> ViewController { automaticMediaDownloadSettings = .defaultSettings } + var autodownloadSettings: AutodownloadSettings if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { - automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(value) + autodownloadSettings = value + automaticMediaDownloadSettings = automaticMediaDownloadSettings.updatedWithAutodownloadSettings(autodownloadSettings) + } else { + autodownloadSettings = .defaultSettings } let generatedMediaStoreSettings: GeneratedMediaStoreSettings @@ -472,7 +481,7 @@ func dataAndStorageController(context: AccountContext) -> ViewController { proxySettings = value } - return DataAndStorageData(automaticMediaDownloadSettings: automaticMediaDownloadSettings, generatedMediaStoreSettings: generatedMediaStoreSettings, voiceCallSettings: voiceCallSettings, proxySettings: proxySettings) + return DataAndStorageData(automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, generatedMediaStoreSettings: generatedMediaStoreSettings, voiceCallSettings: voiceCallSettings, proxySettings: proxySettings) }) let arguments = DataAndStorageControllerArguments(openStorageUsage: { diff --git a/TelegramUI/FetchVideoMediaResource.swift b/TelegramUI/FetchVideoMediaResource.swift index aea2caaab9..bcb1bdc420 100644 --- a/TelegramUI/FetchVideoMediaResource.swift +++ b/TelegramUI/FetchVideoMediaResource.swift @@ -51,8 +51,8 @@ class VideoConversionWatcher: TGMediaVideoFileWatcher { } struct VideoConversionConfiguration { - public static var defaultValue: VideoConversionConfiguration { - return VideoConversionConfiguration(remuxToFMp4: true) + static var defaultValue: VideoConversionConfiguration { + return VideoConversionConfiguration(remuxToFMp4: false) } public let remuxToFMp4: Bool diff --git a/TelegramUI/ID3Artwork.m b/TelegramUI/ID3Artwork.m index a53b5c2a77..6986b72170 100644 --- a/TelegramUI/ID3Artwork.m +++ b/TelegramUI/ID3Artwork.m @@ -16,14 +16,6 @@ const uint8_t ID3v3Artwork[4] = {0x41, 0x50, 0x49, 0x43}; const uint8_t JPGMagic[3] = {0xff, 0xd8, 0xff}; const uint8_t PNGMagic[4] = {0x89, 0x50, 0x4e, 0x47}; -uint32_t getSize(const uint8_t *bytes) { - uint32_t size = CFSwapInt32HostToBig(*(const uint32_t *)(bytes + ID3SizeOffset)); - uint32_t b1 = (size & 0x7F000000) >> 3; - uint32_t b2 = (size & 0x007F0000) >> 2; - uint32_t b3 = (size & 0x00007F00) >> 1; - uint32_t b4 = size & 0x0000007F; - return b1 + b2 + b3 + b4; -} uint32_t frameOffsetForVersion(uint8_t version) { return version == 2 ? ID3v2FrameOffset : ID3v3FrameOffset; diff --git a/TelegramUI/InstantVideoRadialStatusNode.swift b/TelegramUI/InstantVideoRadialStatusNode.swift index 09af713305..f054f1b2cc 100644 --- a/TelegramUI/InstantVideoRadialStatusNode.swift +++ b/TelegramUI/InstantVideoRadialStatusNode.swift @@ -112,10 +112,10 @@ final class InstantVideoRadialStatusNode: ASDisplayNode { if let (timestamp, duration, baseRate) = timestampAndDuration, let statusValue = self.statusValue { let progress = CGFloat(timestamp / duration) - if progress.isNaN || !progress.isFinite || statusValue.generationTimestamp.isZero { + if progress.isNaN || !progress.isFinite { self.pop_removeAnimation(forKey: "progress") self.effectiveProgress = 0.0 - } else if statusValue.status != .playing { + } else if statusValue.status != .playing || statusValue.generationTimestamp.isZero { self.pop_removeAnimation(forKey: "progress") self.effectiveProgress = progress } else { @@ -130,14 +130,11 @@ final class InstantVideoRadialStatusNode: ASDisplayNode { (node as! InstantVideoRadialStatusNode).effectiveProgress = values!.pointee } property?.threshold = 0.01 - }) as! POPAnimatableProperty + }) as? POPAnimatableProperty animation.fromValue = progress as NSNumber animation.toValue = 1.0 as NSNumber animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) animation.duration = max(0.0, duration - timestamp) / baseRate - animation.completionBlock = { [weak self] _, _ in - - } animation.beginTime = statusValue.generationTimestamp self.pop_add(animation, forKey: "progress") } diff --git a/TelegramUI/MediaAutoDownloadSettings.swift b/TelegramUI/MediaAutoDownloadSettings.swift index f59b8ab3f9..7a32f3c6f2 100644 --- a/TelegramUI/MediaAutoDownloadSettings.swift +++ b/TelegramUI/MediaAutoDownloadSettings.swift @@ -95,8 +95,8 @@ public struct MediaAutoDownloadCategories: PostboxCoding, Equatable, Comparable } public static func < (lhs: MediaAutoDownloadCategories, rhs: MediaAutoDownloadCategories) -> Bool { - let lhsSizeLimit = (isAutodownloadEnabledForAnyPeerType(category: lhs.video) ? lhs.video.sizeLimit : 0) + (isAutodownloadEnabledForAnyPeerType(category: lhs.file) ? lhs.file.sizeLimit : 0) - let rhsSizeLimit = (isAutodownloadEnabledForAnyPeerType(category: rhs.video) ? rhs.video.sizeLimit : 0) + (isAutodownloadEnabledForAnyPeerType(category: rhs.file) ? rhs.file.sizeLimit : 0) + let lhsSizeLimit: Int64 = Int64((isAutodownloadEnabledForAnyPeerType(category: lhs.video) ? lhs.video.sizeLimit : 0)) + Int64((isAutodownloadEnabledForAnyPeerType(category: lhs.file) ? lhs.file.sizeLimit : 0)) + let rhsSizeLimit: Int64 = Int64((isAutodownloadEnabledForAnyPeerType(category: rhs.video) ? rhs.video.sizeLimit : 0)) + Int64((isAutodownloadEnabledForAnyPeerType(category: rhs.file) ? rhs.file.sizeLimit : 0)) return lhsSizeLimit < rhsSizeLimit } } @@ -228,7 +228,7 @@ public struct MediaAutoDownloadSettings: PreferencesEntry, Equatable { func updatedWithAutodownloadSettings(_ autodownloadSettings: AutodownloadSettings) -> MediaAutoDownloadSettings { var settings = self settings.presets = presetsWithAutodownloadSettings(autodownloadSettings) - return self + return settings } } diff --git a/TelegramUI/OngoingCallContext.swift b/TelegramUI/OngoingCallContext.swift index 1370e6faa9..b21b7ca625 100644 --- a/TelegramUI/OngoingCallContext.swift +++ b/TelegramUI/OngoingCallContext.swift @@ -124,6 +124,8 @@ private func ongoingDataSavingForType(_ type: VoiceCallDataSaving) -> OngoingCal return .cellular case .always: return .always + default: + return .never } } diff --git a/TelegramUI/PresentationCallManager.swift b/TelegramUI/PresentationCallManager.swift index ef74307c25..726ccd17cc 100644 --- a/TelegramUI/PresentationCallManager.swift +++ b/TelegramUI/PresentationCallManager.swift @@ -33,10 +33,13 @@ public enum RequestCallResult { public final class PresentationCallManager { private let getDeviceAccessData: () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void) + + private let accountManager: AccountManager private let audioSession: ManagedAudioSession private let callKitIntegration: CallKitIntegration? private var currentCall: PresentationCall? + private var currentCallDisposable = MetaDisposable() private let removeCurrentCallDisposable = MetaDisposable() private var ringingStatesDisposable: Disposable? @@ -56,7 +59,7 @@ public final class PresentationCallManager { private var proxyServer: ProxyServerSettings? private var proxyServerDisposable: Disposable? - private var callSettings: (VoiceCallSettings, VoipConfiguration, VoipDerivedState)? + private var callSettings: VoiceCallSettings? private var callSettingsDisposable: Disposable? public static var voipMaxLayer: Int32 { @@ -65,6 +68,7 @@ public final class PresentationCallManager { public init(accountManager: AccountManager, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), audioSession: ManagedAudioSession, activeAccounts: Signal<[Account], NoError>) { self.getDeviceAccessData = getDeviceAccessData + self.accountManager = accountManager self.audioSession = audioSession var startCallImpl: ((Account, UUID, String) -> Signal)? @@ -200,37 +204,16 @@ public final class PresentationCallManager { } }) - self.callSettingsDisposable = (combineLatest(queue: .mainQueue(), accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]), Signal.single(Void())/*, postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState])*/) - |> deliverOnMainQueue).start(next: { [weak self] sharedData, preferences in - let callSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings - let configuration: VoipConfiguration = .defaultValue// = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue - let derivedState: VoipDerivedState = .default// = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default + self.callSettingsDisposable = (accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) + |> deliverOnMainQueue).start(next: { [weak self] sharedData in if let strongSelf = self { - strongSelf.callSettings = (callSettings, configuration, derivedState) - - if let legacyP2PMode = callSettings.legacyP2PMode { - _ = updateVoiceCallSettingsSettingsInteractively(accountManager: accountManager, { settings -> VoiceCallSettings in - var settings = settings - settings.legacyP2PMode = nil - return settings - }).start() - - /*let settings: SelectivePrivacySettings - switch legacyP2PMode { - case .always: - settings = .enableEveryone(disableFor: Set()) - case .contacts: - settings = .enableContacts(enableFor: Set(), disableFor: Set()) - case .never: - settings = .disableEveryone(enableFor: Set()) - } - _ = updateSelectiveAccountPrivacySettings(account: strongSelf.tempAccount, type: .voiceCallsP2P, settings: settings).start()*/ - } + strongSelf.callSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings ?? .defaultSettings } }) } deinit { + self.currentCallDisposable.dispose() self.ringingStatesDisposable?.dispose() self.removeCurrentCallDisposable.dispose() self.startCallDisposable.dispose() @@ -241,19 +224,30 @@ public final class PresentationCallManager { private func ringingStatesUpdated(_ ringingStates: [(Account, Peer, CallSessionRingingState, Bool, NetworkType)], enableCallKit: Bool) { if let firstState = ringingStates.first { if self.currentCall == nil { - let call = PresentationCall(account: firstState.0, audioSession: self.audioSession, callSessionManager: firstState.0.callSessionManager, callKitIntegration: enableCallKit ? callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings?.0) : nil, serializedData: self.callSettings?.1.serializedData, dataSaving: self.callSettings?.0.dataSaving ?? .never, derivedState: self.callSettings?.2 ?? VoipDerivedState.default, getDeviceAccessData: self.getDeviceAccessData, internalId: firstState.2.id, peerId: firstState.2.peerId, isOutgoing: false, peer: firstState.1, proxyServer: self.proxyServer, currentNetworkType: firstState.4, updatedNetworkType: firstState.0.networkType) - self.currentCall = call - self.currentCallPromise.set(.single(call)) - self.hasActiveCallsPromise.set(true) - self.removeCurrentCallDisposable.set((call.canBeRemoved - |> deliverOnMainQueue).start(next: { [weak self, weak call] value in - if value, let strongSelf = self, let call = call { - if strongSelf.currentCall === call { - strongSelf.currentCall = nil - strongSelf.currentCallPromise.set(.single(nil)) - strongSelf.hasActiveCallsPromise.set(false) - } + self.currentCallDisposable.set((combineLatest(firstState.0.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings]) |> take(1)) + |> deliverOnMainQueue).start(next: { [weak self] preferences, sharedData in + guard let strongSelf = self else { + return } + + let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue + let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default + let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings + + let call = PresentationCall(account: firstState.0, audioSession: strongSelf.audioSession, callSessionManager: firstState.0.callSessionManager, callKitIntegration: enableCallKit ? callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings) : nil, serializedData: configuration.serializedData, dataSaving: effectiveDataSaving(for: strongSelf.callSettings, autodownloadSettings: autodownloadSettings), derivedState: derivedState, getDeviceAccessData: strongSelf.getDeviceAccessData, internalId: firstState.2.id, peerId: firstState.2.peerId, isOutgoing: false, peer: firstState.1, proxyServer: strongSelf.proxyServer, currentNetworkType: firstState.4, updatedNetworkType: firstState.0.networkType) + strongSelf.currentCall = call + strongSelf.currentCallPromise.set(.single(call)) + strongSelf.hasActiveCallsPromise.set(true) + strongSelf.removeCurrentCallDisposable.set((call.canBeRemoved + |> deliverOnMainQueue).start(next: { [weak self, weak call] value in + if value, let strongSelf = self, let call = call { + if strongSelf.currentCall === call { + strongSelf.currentCall = nil + strongSelf.currentCallPromise.set(.single(nil)) + strongSelf.hasActiveCallsPromise.set(false) + } + } + })) })) } else { for (account, _, state, _, _) in ringingStates { @@ -269,7 +263,7 @@ public final class PresentationCallManager { if let call = self.currentCall, !endCurrentIfAny { return .alreadyInProgress(call.peerId) } - if let _ = callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings?.0) { + if let _ = callKitIntegrationIfEnabled(self.callKitIntegration, settings: self.callSettings) { let begin: () -> Void = { [weak self] in guard let strongSelf = self else { return @@ -350,22 +344,27 @@ public final class PresentationCallManager { |> runOn(Queue.mainQueue()) let networkType = account.networkType + let accountManager = self.accountManager return accessEnabledSignal |> mapToSignal { [weak self] accessEnabled -> Signal in if !accessEnabled { return .single(false) } - return (combineLatest(queue: .mainQueue(), account.callSessionManager.request(peerId: peerId, internalId: internalId), networkType |> take(1), account.postbox.peerView(id: peerId) |> take(1) |> map({ peerView -> Bool in + return (combineLatest(queue: .mainQueue(), account.callSessionManager.request(peerId: peerId, internalId: internalId), networkType |> take(1), account.postbox.peerView(id: peerId) |> map { peerView -> Bool in return peerView.peerIsContact - }) |> take(1)) + } |> take(1), account.postbox.preferencesView(keys: [PreferencesKeys.voipConfiguration, ApplicationSpecificPreferencesKeys.voipDerivedState]) |> take(1), accountManager.sharedData(keys: [SharedDataKeys.autodownloadSettings]) |> take(1)) |> deliverOnMainQueue - |> beforeNext { internalId, currentNetworkType, isContact in + |> beforeNext { internalId, currentNetworkType, isContact, preferences, sharedData in if let strongSelf = self, accessEnabled { if let currentCall = strongSelf.currentCall { currentCall.rejectBusy() } - let call = PresentationCall(account: account, audioSession: strongSelf.audioSession, callSessionManager: account.callSessionManager, callKitIntegration: callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings?.0), serializedData: strongSelf.callSettings?.1.serializedData, dataSaving: strongSelf.callSettings?.0.dataSaving ?? .never, derivedState: strongSelf.callSettings?.2 ?? VoipDerivedState.default, getDeviceAccessData: strongSelf.getDeviceAccessData, internalId: internalId, peerId: peerId, isOutgoing: true, peer: nil, proxyServer: strongSelf.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: account.networkType) + let configuration = preferences.values[PreferencesKeys.voipConfiguration] as? VoipConfiguration ?? .defaultValue + let derivedState = preferences.values[ApplicationSpecificPreferencesKeys.voipDerivedState] as? VoipDerivedState ?? .default + let autodownloadSettings = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings ?? .defaultSettings + + let call = PresentationCall(account: account, audioSession: strongSelf.audioSession, callSessionManager: account.callSessionManager, callKitIntegration: callKitIntegrationIfEnabled(strongSelf.callKitIntegration, settings: strongSelf.callSettings), serializedData: configuration.serializedData, dataSaving: effectiveDataSaving(for: strongSelf.callSettings, autodownloadSettings: autodownloadSettings), derivedState: derivedState, getDeviceAccessData: strongSelf.getDeviceAccessData, internalId: internalId, peerId: peerId, isOutgoing: true, peer: nil, proxyServer: strongSelf.proxyServer, currentNetworkType: currentNetworkType, updatedNetworkType: account.networkType) strongSelf.currentCall = call strongSelf.currentCallPromise.set(.single(call)) strongSelf.hasActiveCallsPromise.set(true) diff --git a/TelegramUI/SelectivePrivacySettingsController.swift b/TelegramUI/SelectivePrivacySettingsController.swift index 42ec7235b6..109ac481ca 100644 --- a/TelegramUI/SelectivePrivacySettingsController.swift +++ b/TelegramUI/SelectivePrivacySettingsController.swift @@ -692,7 +692,7 @@ func selectivePrivacySettingsController(context: AccountContext, kind: Selective return state.withUpdatedSaving(false) } if case .voiceCalls = kind, let dataSaving = state.callDataSaving, let callP2PSettings = callP2PSettings, let systemIntegrationEnabled = state.callIntegrationEnabled { - updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, p2pMode: nil, enableSystemIntegration: systemIntegrationEnabled))) + updated(settings, (callP2PSettings, VoiceCallSettings(dataSaving: dataSaving, enableSystemIntegration: systemIntegrationEnabled))) } else { updated(settings, nil) } diff --git a/TelegramUI/UniversalVideoGalleryItem.swift b/TelegramUI/UniversalVideoGalleryItem.swift index 79daca5745..15a5c0b73e 100644 --- a/TelegramUI/UniversalVideoGalleryItem.swift +++ b/TelegramUI/UniversalVideoGalleryItem.swift @@ -571,10 +571,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } else { videoNode.continuePlayingWithoutSound() } + self.updateDisplayPlaceholder(!videoNode.ownsContentNode) } else if !item.fromPlayingVideo { videoNode.canAttachContent = isVisible + self.updateDisplayPlaceholder(!videoNode.ownsContentNode) } - self.updateDisplayPlaceholder(!videoNode.ownsContentNode) if self.shouldAutoplayOnCentrality() { self.hideStatusNodeUntilCentrality = true self.statusButtonNode.isHidden = true @@ -593,6 +594,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } if isAnimated { videoNode.seek(0.0) + videoNode.play() } else { videoNode.playOnceWithSound(playAndRecord: false, actionAtEnd: .stop) } @@ -765,7 +767,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { let fromTransform: CATransform3D let toTransform: CATransform3D - if let interactiveMediaNode = node.0 as? ChatMessageInteractiveMediaNode, interactiveMediaNode.automaticPlayback ?? false { + if let interactiveMediaNode = node.0 as? ChatMessageInteractiveMediaNode, interactiveMediaNode.automaticPlayback ?? false, videoNode.hasAttachedContext { copyView.removeFromSuperview() surfaceCopyView.removeFromSuperview() diff --git a/TelegramUI/VoiceCallDataSavingController.swift b/TelegramUI/VoiceCallDataSavingController.swift index 7aec92947d..91d55c4878 100644 --- a/TelegramUI/VoiceCallDataSavingController.swift +++ b/TelegramUI/VoiceCallDataSavingController.swift @@ -100,24 +100,23 @@ private func stringForDataSavingOption(_ option: VoiceCallDataSaving, strings: P return strings.CallSettings_OnMobile case .always: return strings.CallSettings_Always + default: + return "" } } -private func voiceCallDataSavingControllerEntries(presentationData: PresentationData, settings: VoiceCallSettings) -> [VoiceCallDataSavingEntry] { +private func voiceCallDataSavingControllerEntries(presentationData: PresentationData, dataSaving: VoiceCallDataSaving) -> [VoiceCallDataSavingEntry] { var entries: [VoiceCallDataSavingEntry] = [] - - entries.append(.never(presentationData.theme, stringForDataSavingOption(.never, strings: presentationData.strings), settings.dataSaving == .never)) - entries.append(.cellular(presentationData.theme, stringForDataSavingOption(.cellular, strings: presentationData.strings), settings.dataSaving == .cellular)) - entries.append(.always(presentationData.theme, stringForDataSavingOption(.always, strings: presentationData.strings), settings.dataSaving == .always)) + entries.append(.never(presentationData.theme, stringForDataSavingOption(.never, strings: presentationData.strings), dataSaving == .never)) + entries.append(.cellular(presentationData.theme, stringForDataSavingOption(.cellular, strings: presentationData.strings), dataSaving == .cellular)) + entries.append(.always(presentationData.theme, stringForDataSavingOption(.always, strings: presentationData.strings), dataSaving == .always)) entries.append(.info(presentationData.theme, presentationData.strings.CallSettings_UseLessDataLongDescription)) - return entries } func voiceCallDataSavingController(context: AccountContext) -> ViewController { - let voiceCallSettingsPromise = Promise() - voiceCallSettingsPromise.set(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) - |> map { sharedData -> VoiceCallSettings in + let sharedSettings = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.voiceCallSettings]) + |> map { sharedData -> (VoiceCallSettings, AutodownloadSettings) in let voiceCallSettings: VoiceCallSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.voiceCallSettings] as? VoiceCallSettings { voiceCallSettings = value @@ -125,8 +124,15 @@ func voiceCallDataSavingController(context: AccountContext) -> ViewController { voiceCallSettings = VoiceCallSettings.defaultSettings } - return voiceCallSettings - }) + let autodownloadSettings: AutodownloadSettings + if let value = sharedData.entries[SharedDataKeys.autodownloadSettings] as? AutodownloadSettings { + autodownloadSettings = value + } else { + autodownloadSettings = AutodownloadSettings.defaultSettings + } + + return (voiceCallSettings, autodownloadSettings) + } let arguments = VoiceCallDataSavingControllerArguments(updateSelection: { option in let _ = updateVoiceCallSettingsSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in @@ -136,11 +142,13 @@ func voiceCallDataSavingController(context: AccountContext) -> ViewController { }).start() }) - let signal = combineLatest(context.sharedContext.presentationData, voiceCallSettingsPromise.get()) |> deliverOnMainQueue - |> map { presentationData, data -> (ItemListControllerState, (ItemListNodeState, VoiceCallDataSavingEntry.ItemGenerationArguments)) in + let signal = combineLatest(context.sharedContext.presentationData, sharedSettings) |> deliverOnMainQueue + |> map { presentationData, sharedSettings -> (ItemListControllerState, (ItemListNodeState, VoiceCallDataSavingEntry.ItemGenerationArguments)) in + + let dataSaving = effectiveDataSaving(for: sharedSettings.0, autodownloadSettings: sharedSettings.1) let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.CallSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(entries: voiceCallDataSavingControllerEntries(presentationData: presentationData, settings: data), style: .blocks, emptyStateItem: nil, animateChanges: false) + let listState = ItemListNodeState(entries: voiceCallDataSavingControllerEntries(presentationData: presentationData, dataSaving: dataSaving), style: .blocks, emptyStateItem: nil, animateChanges: false) return (controllerState, (listState, arguments)) } diff --git a/TelegramUI/VoiceCallSettings.swift b/TelegramUI/VoiceCallSettings.swift index 9eaf53d3d7..b2aabc038b 100644 --- a/TelegramUI/VoiceCallSettings.swift +++ b/TelegramUI/VoiceCallSettings.swift @@ -3,44 +3,52 @@ import Postbox import TelegramCore import SwiftSignalKit +func effectiveDataSaving(for settings: VoiceCallSettings?, autodownloadSettings: AutodownloadSettings) -> VoiceCallDataSaving { + if let settings = settings { + if case .default = settings.dataSaving { + switch (autodownloadSettings.mediumPreset.lessDataForPhoneCalls, autodownloadSettings.highPreset.lessDataForPhoneCalls) { + case (true, true): + return .always + case (true, false): + return .cellular + default: + return .never + } + } else { + return settings.dataSaving + } + } else { + return .never + } +} + public enum VoiceCallDataSaving: Int32 { case never case cellular case always + case `default` } public struct VoiceCallSettings: PreferencesEntry, Equatable { public var dataSaving: VoiceCallDataSaving - public var legacyP2PMode: VoiceCallP2PMode? public var enableSystemIntegration: Bool public static var defaultSettings: VoiceCallSettings { - return VoiceCallSettings(dataSaving: .never, p2pMode: nil, enableSystemIntegration: true) + return VoiceCallSettings(dataSaving: .default, enableSystemIntegration: true) } - init(dataSaving: VoiceCallDataSaving, p2pMode: VoiceCallP2PMode?, enableSystemIntegration: Bool) { + init(dataSaving: VoiceCallDataSaving, enableSystemIntegration: Bool) { self.dataSaving = dataSaving - self.legacyP2PMode = p2pMode self.enableSystemIntegration = enableSystemIntegration } public init(decoder: PostboxDecoder) { self.dataSaving = VoiceCallDataSaving(rawValue: decoder.decodeInt32ForKey("ds", orElse: 0))! - if let value = decoder.decodeOptionalInt32ForKey("p2pMode") { - self.legacyP2PMode = VoiceCallP2PMode(rawValue: value) - } else { - self.legacyP2PMode = nil - } self.enableSystemIntegration = decoder.decodeInt32ForKey("enableSystemIntegration", orElse: 1) != 0 } public func encode(_ encoder: PostboxEncoder) { encoder.encodeInt32(self.dataSaving.rawValue, forKey: "ds") - if let p2pMode = self.legacyP2PMode { - encoder.encodeInt32(p2pMode.rawValue, forKey: "p2pMode") - } else { - encoder.encodeNil(forKey: "p2pMode") - } encoder.encodeInt32(self.enableSystemIntegration ? 1 : 0, forKey: "enableSystemIntegration") } @@ -56,9 +64,6 @@ public struct VoiceCallSettings: PreferencesEntry, Equatable { if lhs.dataSaving != rhs.dataSaving { return false } - if lhs.legacyP2PMode != rhs.legacyP2PMode { - return false - } if lhs.enableSystemIntegration != rhs.enableSystemIntegration { return false }