Various fixes

This commit is contained in:
Ilya Laktyushin 2020-11-09 00:45:44 +04:00
parent 0bdfd79289
commit 564ee0d966
22 changed files with 415 additions and 160 deletions

View File

@ -46,13 +46,15 @@ public final class ContactMultiselectionControllerParams {
public let options: [ContactListAdditionalOption] public let options: [ContactListAdditionalOption]
public let filters: [ContactListFilter] public let filters: [ContactListFilter]
public let alwaysEnabled: Bool public let alwaysEnabled: Bool
public let limit: Int32?
public init(context: AccountContext, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], alwaysEnabled: Bool = false) { public init(context: AccountContext, mode: ContactMultiselectionControllerMode, options: [ContactListAdditionalOption], filters: [ContactListFilter] = [.excludeSelf], alwaysEnabled: Bool = false, limit: Int32? = nil) {
self.context = context self.context = context
self.mode = mode self.mode = mode
self.options = options self.options = options
self.filters = filters self.filters = filters
self.alwaysEnabled = alwaysEnabled self.alwaysEnabled = alwaysEnabled
self.limit = limit
} }
} }

View File

@ -244,18 +244,18 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
}))) })))
} }
} }
}
if isUnread {
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in if isUnread {
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start() items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsRead, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsRead"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default) let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
}))) f(.default)
} else { })))
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in } else {
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start() items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_MarkAsUnread, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MarkAsUnread"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default) let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
}))) f(.default)
} })))
} }
let groupAndIndex = transaction.getPeerChatListIndex(peerId) let groupAndIndex = transaction.getPeerChatListIndex(peerId)
@ -288,17 +288,19 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
}))) })))
} }
if case let .chatList(filter) = source { // if {
let location: TogglePeerChatPinnedLocation let location: TogglePeerChatPinnedLocation
if let filter = filter { var chatListFilter: ChatListFilter?
location = .filter(filter.id) if case let .chatList(filter) = source, let chatFilter = filter {
chatListFilter = chatFilter
location = .filter(chatFilter.id)
} else { } else {
location = .group(group) location = .group(group)
} }
let isPinned = getPinnedItemIds(transaction: transaction, location: location).contains(.peer(peerId)) let isPinned = getPinnedItemIds(transaction: transaction, location: location).contains(.peer(peerId))
if isPinned || filter == nil || peerId.namespace != Namespaces.Peer.SecretChat { if isPinned || chatListFilter == nil || peerId.namespace != Namespaces.Peer.SecretChat {
items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in items.append(.action(ContextMenuActionItem(text: isPinned ? strings.ChatList_Context_Unpin : strings.ChatList_Context_Pin, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: isPinned ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { _, f in
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: .peer(peerId)) let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: .peer(peerId))
|> deliverOnMainQueue).start(next: { result in |> deliverOnMainQueue).start(next: { result in
@ -312,7 +314,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
}) })
}))) })))
} }
} // }
if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings { if !isSavedMessages, let notificationSettings = transaction.getPeerNotificationSettings(peerId) as? TelegramPeerNotificationSettings {
var isMuted = false var isMuted = false

View File

@ -593,7 +593,7 @@ private func internalChatListFilterAddChatsController(context: AccountContext, f
} }
} }
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_IncludeChatsTitle, selectedChats: Set(filter.data.includePeers.peers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories), chatListFilters: allFilters), options: [], filters: [], alwaysEnabled: true)) let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_IncludeChatsTitle, selectedChats: Set(filter.data.includePeers.peers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories), chatListFilters: allFilters), options: [], filters: [], alwaysEnabled: true, limit: 100))
controller.navigationPresentation = .modal controller.navigationPresentation = .modal
let _ = (controller.result let _ = (controller.result
|> take(1) |> take(1)
@ -680,7 +680,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
selectedCategories.insert(AdditionalExcludeCategoryId.archived.rawValue) selectedCategories.insert(AdditionalExcludeCategoryId.archived.rawValue)
} }
let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_ExcludeChatsTitle, selectedChats: Set(filter.data.excludePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories), chatListFilters: allFilters), options: [], filters: [], alwaysEnabled: true)) let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .chatSelection(title: presentationData.strings.ChatListFolder_ExcludeChatsTitle, selectedChats: Set(filter.data.excludePeers), additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: selectedCategories), chatListFilters: allFilters), options: [], filters: [], alwaysEnabled: true, limit: 100))
controller.navigationPresentation = .modal controller.navigationPresentation = .modal
let _ = (controller.result let _ = (controller.result
|> take(1) |> take(1)

View File

@ -306,16 +306,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
return .single([]) return .single([])
} }
} }
let accountPeer = self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
|> take(1)
self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get()) self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get(), accountPeer)
|> mapToSignal { peers, dates, selectedFilter, searchQuery -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?), NoError> in |> mapToSignal { peers, dates, selectedFilter, searchQuery, accountPeer -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?, String?, Peer?), NoError> in
if searchQuery?.isEmpty ?? true { if searchQuery?.isEmpty ?? true {
return .single((peers, dates, selectedFilter)) return .single((peers, dates, selectedFilter, searchQuery, accountPeer))
} else { } else {
return (.complete() |> delay(0.25, queue: Queue.mainQueue())) return (.complete() |> delay(0.25, queue: Queue.mainQueue()))
|> then(.single((peers, dates, selectedFilter))) |> then(.single((peers, dates, selectedFilter, searchQuery, accountPeer)))
} }
} |> map { peers, dates, selectedFilter -> [ChatListSearchFilter] in } |> map { peers, dates, selectedFilter, searchQuery, accountPeer -> [ChatListSearchFilter] in
var suggestedFilters: [ChatListSearchFilter] = [] var suggestedFilters: [ChatListSearchFilter] = []
if !dates.isEmpty { if !dates.isEmpty {
let formatter = DateFormatter() let formatter = DateFormatter()
@ -327,8 +330,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
suggestedFilters.append(.date(minDate.flatMap { Int32($0.timeIntervalSince1970) }, Int32(maxDate.timeIntervalSince1970), title)) suggestedFilters.append(.date(minDate.flatMap { Int32($0.timeIntervalSince1970) }, Int32(maxDate.timeIntervalSince1970), title))
} }
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) { if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) {
var existingPeerIds = Set<PeerId>()
var peers = peers
if let accountPeer = accountPeer, let lowercasedQuery = searchQuery?.lowercased(), lowercasedQuery.count > 1 && (presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery)) {
peers.insert(accountPeer, at: 0)
}
for peer in peers { for peer in peers {
if existingPeerIds.contains(peer.id) {
continue
}
let isGroup: Bool let isGroup: Bool
if peer.id.namespace == Namespaces.Peer.SecretChat { if peer.id.namespace == Namespaces.Peer.SecretChat {
continue continue
@ -339,8 +352,15 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
} else { } else {
isGroup = false isGroup = false
} }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
suggestedFilters.append(.peer(peer.id, isGroup, peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), peer.compactDisplayTitle)) var title: String = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
var compactDisplayTitle = peer.compactDisplayTitle
if peer.id == accountPeer?.id {
title = presentationData.strings.DialogList_SavedMessages
compactDisplayTitle = title
}
suggestedFilters.append(.peer(peer.id, isGroup, title, compactDisplayTitle))
existingPeerIds.insert(peer.id)
} }
} }
return suggestedFilters return suggestedFilters

View File

@ -441,6 +441,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
} }
if origin == nil { if origin == nil {
self.editButton.isHidden = true
self.deleteButton.isHidden = true self.deleteButton.isHidden = true
} }
} }
@ -516,9 +517,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
} }
messageText = galleryCaptionStringWithAppliedEntities(message.text, entities: entities) messageText = galleryCaptionStringWithAppliedEntities(message.text, entities: entities)
} }
self.editButton.isHidden = message.containsSecretMedia
if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.isHidden || canEdit != !self.editButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText { if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.isHidden || canEdit != !self.editButton.isHidden || self.currentAuthorNameText != authorNameText || self.currentDateText != dateText {
self.currentMessageText = messageText self.currentMessageText = messageText

View File

@ -56,6 +56,7 @@ final class InstantPageWebEmbedNode: ASDisplayNode, InstantPageNode {
configuration.userContentController = userController configuration.userContentController = userController
let webView = WKWebView(frame: CGRect(origin: CGPoint(), size: frame.size), configuration: configuration) let webView = WKWebView(frame: CGRect(origin: CGPoint(), size: frame.size), configuration: configuration)
webView.allowsBackForwardNavigationGestures = false
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
webView.allowsLinkPreview = false webView.allowsLinkPreview = false
} }

View File

@ -309,8 +309,13 @@
return false; return false;
bool onlyGroupableMedia = true; bool onlyGroupableMedia = true;
for (TGMediaAsset *asset in strongSelf->_selectionContext.selectedItems) for (TGMediaAsset *item in strongSelf->_selectionContext.selectedItems)
{ {
TGMediaAsset *asset = asset;
if ([asset isKindOfClass:[TGCameraCapturedVideo class]]) {
asset = [(TGCameraCapturedVideo *)item originalAsset];
}
if (asset.type == TGMediaAssetGifType) if (asset.type == TGMediaAssetGifType)
{ {
onlyGroupableMedia = false; onlyGroupableMedia = false;

View File

@ -236,7 +236,12 @@
- (SSignal *)_signalForItem:(id)item - (SSignal *)_signalForItem:(id)item
{ {
SSignal *assetSignal = [TGMediaAssetImageSignals imageForAsset:item imageType:TGMediaAssetImageTypeThumbnail size:[_layoutMetrics imageSize]]; TGMediaAsset *concreteAsset = (TGMediaAsset *)item;
if ([concreteAsset isKindOfClass:[TGCameraCapturedVideo class]]) {
concreteAsset = [(TGCameraCapturedVideo *)item originalAsset];
}
SSignal *assetSignal = [TGMediaAssetImageSignals imageForAsset:concreteAsset imageType:TGMediaAssetImageTypeThumbnail size:[_layoutMetrics imageSize]];
if (self.editingContext == nil) if (self.editingContext == nil)
return assetSignal; return assetSignal;

View File

@ -504,8 +504,13 @@
if (_attributesDisposable == nil) if (_attributesDisposable == nil)
_attributesDisposable = [[SMetaDisposable alloc] init]; _attributesDisposable = [[SMetaDisposable alloc] init];
TGMediaAsset *asset = item.asset;
if ([asset isKindOfClass:[TGCameraCapturedVideo class]]) {
asset = [(TGCameraCapturedVideo *)asset originalAsset];
}
_fileInfoLabel.text = nil; _fileInfoLabel.text = nil;
[_attributesDisposable setDisposable:[[[TGMediaAssetImageSignals fileAttributesForAsset:item.asset] deliverOn:[SQueue mainQueue]] startWithNext:^(TGMediaAssetImageFileAttributes *next) [_attributesDisposable setDisposable:[[[TGMediaAssetImageSignals fileAttributesForAsset:asset] deliverOn:[SQueue mainQueue]] startWithNext:^(TGMediaAssetImageFileAttributes *next)
{ {
__strong TGMediaPickerGalleryVideoItemView *strongSelf = weakSelf; __strong TGMediaPickerGalleryVideoItemView *strongSelf = weakSelf;
if (strongSelf == nil) if (strongSelf == nil)

View File

@ -4,6 +4,16 @@ import Display
import TelegramPresentationData import TelegramPresentationData
import LegacyUI import LegacyUI
private class DocumentPickerViewController: UIDocumentPickerViewController {
var didDisappear: (() -> Void)?
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.didDisappear?()
}
}
private final class LegacyICloudFileController: LegacyController, UIDocumentPickerDelegate { private final class LegacyICloudFileController: LegacyController, UIDocumentPickerDelegate {
let completion: ([URL]) -> Void let completion: ([URL]) -> Void
@ -52,7 +62,10 @@ public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudF
}) })
legacyController.statusBar.statusBarStyle = .Black legacyController.statusBar.statusBarStyle = .Black
let controller = UIDocumentPickerViewController(documentTypes: documentTypes, in: mode.documentPickerMode) let controller = DocumentPickerViewController(documentTypes: documentTypes, in: mode.documentPickerMode)
controller.didDisappear = {
dismissImpl?()
}
controller.delegate = legacyController controller.delegate = legacyController
if #available(iOSApplicationExtension 11.0, iOS 11.0, *), case .default = mode { if #available(iOSApplicationExtension 11.0, iOS 11.0, *), case .default = mode {
controller.allowsMultipleSelection = true controller.allowsMultipleSelection = true

View File

@ -429,6 +429,14 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
} }
} }
var preset: TGMediaVideoConversionPreset = TGMediaVideoConversionPresetCompressedMedium
if let selectedPreset = adjustments?.preset {
preset = selectedPreset
}
if asAnimation {
preset = TGMediaVideoConversionPresetAnimation
}
if !asAnimation { if !asAnimation {
finalDimensions = TGMediaVideoConverter.dimensions(for: finalDimensions, adjustments: adjustments, preset: TGMediaVideoConversionPresetCompressedMedium) finalDimensions = TGMediaVideoConverter.dimensions(for: finalDimensions, adjustments: adjustments, preset: TGMediaVideoConversionPresetCompressedMedium)
} }
@ -465,6 +473,8 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
} }
} }
let estimatedSize = TGMediaVideoConverter.estimatedSize(for: preset, duration: finalDuration, hasAudio: !asAnimation)
var fileAttributes: [TelegramMediaFileAttribute] = [] var fileAttributes: [TelegramMediaFileAttribute] = []
fileAttributes.append(.FileName(fileName: fileName)) fileAttributes.append(.FileName(fileName: fileName))
if asAnimation { if asAnimation {
@ -478,6 +488,9 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
} }
} }
} }
if estimatedSize > 5 * 1024 * 1024 {
fileAttributes.append(.hintFileIsLarge)
}
var attributes: [MessageAttribute] = [] var attributes: [MessageAttribute] = []

View File

@ -110,7 +110,9 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
} }
} }
var finalDuration: Double = CMTimeGetSeconds(asset.duration) var finalDuration: Double = CMTimeGetSeconds(asset.duration)
let finalDimensions = TGMediaVideoConverter.dimensions(for: asset.originalSize, adjustments: adjustments, preset: adjustments?.preset ?? TGMediaVideoConversionPresetCompressedMedium)
let preset = adjustments?.preset ?? TGMediaVideoConversionPresetCompressedMedium
let finalDimensions = TGMediaVideoConverter.dimensions(for: asset.originalSize, adjustments: adjustments, preset: preset)
var resourceAdjustments: VideoMediaResourceAdjustments? var resourceAdjustments: VideoMediaResourceAdjustments?
if let adjustments = adjustments { if let adjustments = adjustments {
@ -123,8 +125,10 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
resourceAdjustments = VideoMediaResourceAdjustments(data: adjustmentsData, digest: digest) resourceAdjustments = VideoMediaResourceAdjustments(data: adjustmentsData, digest: digest)
} }
let estimatedSize = TGMediaVideoConverter.estimatedSize(for: preset, duration: finalDuration, hasAudio: true)
let resource = LocalFileVideoMediaResource(randomId: arc4random64(), path: asset.url.path, adjustments: resourceAdjustments) let resource = LocalFileVideoMediaResource(randomId: arc4random64(), path: asset.url.path, adjustments: resourceAdjustments)
return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .resource(.standalone(resource: resource)), mimeType: "video/mp4", attributes: [.Video(duration: Int(finalDuration), size: PixelDimensions(width: Int32(finalDimensions.width), height: Int32(finalDimensions.height)), flags: flags)], hintFileIsLarge: finalDuration > 3.0 * 60.0) return standaloneUploadedFile(account: account, peerId: peerId, text: "", source: .resource(.standalone(resource: resource)), mimeType: "video/mp4", attributes: [.Video(duration: Int(finalDuration), size: PixelDimensions(width: Int32(finalDimensions.width), height: Int32(finalDimensions.height)), flags: flags)], hintFileIsLarge: estimatedSize > 5 * 1024 * 1024)
|> mapError { _ -> Void in |> mapError { _ -> Void in
return Void() return Void()
} }
@ -229,7 +233,7 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
if let audioData = try? Data(contentsOf: url, options: [.mappedIfSafe]) { if let audioData = try? Data(contentsOf: url, options: [.mappedIfSafe]) {
let fileName = url.lastPathComponent let fileName = url.lastPathComponent
let duration = (value["duration"] as? NSNumber)?.doubleValue ?? 0.0 let duration = (value["duration"] as? NSNumber)?.doubleValue ?? 0.0
let isVoice = ((value["isVoice"] as? NSNumber)?.boolValue ?? false) || (duration.isZero && duration < 30.0) let isVoice = ((value["isVoice"] as? NSNumber)?.boolValue ?? false)
let title = value["title"] as? String let title = value["title"] as? String
let artist = value["artist"] as? String let artist = value["artist"] as? String
@ -357,21 +361,23 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], items: [Prepa
var messages: [EnqueueMessage] = [] var messages: [EnqueueMessage] = []
var groupingKey: Int64? var groupingKey: Int64?
var mediaTypes: (photo: Bool, video: Bool, music: Bool, other: Bool) = (false, false, false, false) var mediaTypes: (photo: Bool, video: Bool, music: Bool, other: Bool) = (false, false, false, false)
for item in items { if items.count > 1 {
if case let .media(result) = item, case let .media(media) = result { for item in items {
if media.media is TelegramMediaImage { if case let .media(result) = item, case let .media(media) = result {
mediaTypes.photo = true if media.media is TelegramMediaImage {
} else if let media = media.media as? TelegramMediaFile { mediaTypes.photo = true
if media.isVideo { } else if let media = media.media as? TelegramMediaFile {
mediaTypes.video = true if media.isVideo {
} else if let fileName = media.fileName, fileName.hasPrefix("mp3") || fileName.hasPrefix("m4a") { mediaTypes.video = true
mediaTypes.music = true } else if let fileName = media.fileName, fileName.hasPrefix("mp3") || fileName.hasPrefix("m4a") {
mediaTypes.music = true
} else {
mediaTypes.other = true
}
} else { } else {
mediaTypes.other = true mediaTypes = (false, false, false, false)
break
} }
} else {
mediaTypes = (false, false, false, false)
break
} }
} }
} }

View File

@ -604,16 +604,15 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
hintSize = Int(size) hintSize = Int(size)
} }
loop: for attr in file.attributes { loop: for attribute in file.attributes {
switch attr { switch attribute {
case .hintFileIsLarge: case .hintFileIsLarge:
hintFileIsLarge = true hintFileIsLarge = true
break loop break loop
default: default:
break loop break loop
} }
} }
let fileReference: AnyMediaReference let fileReference: AnyMediaReference
if let partialReference = file.partialReference { if let partialReference = file.partialReference {

View File

@ -1,5 +1,5 @@
function initialize() { function initialize() {
var controls = document.getElementsByClassName("controls")[0]; var controls = document.getElementsByClassName("vp-controls-wrapper")[0];
if (controls != null) { if (controls != null) {
controls.style.display = "none"; controls.style.display = "none";
} }

View File

@ -457,12 +457,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return true return true
} }
if let _ = strongSelf.presentationInterfaceState.inputTextPanelState.mediaRecordingState { if strongSelf.presentVoiceMessageDiscardAlert(action: action) {
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_DiscardVoiceMessageDescription, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Conversation_DiscardVoiceMessageAction, action: {
self?.stopMediaRecorder()
action()
})]), in: .window(.root))
return false return false
} }
return true return true
@ -472,6 +467,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) else { guard let strongSelf = self, strongSelf.isNodeLoaded, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) else {
return false return false
} }
strongSelf.commitPurposefulAction() strongSelf.commitPurposefulAction()
strongSelf.dismissAllTooltips() strongSelf.dismissAllTooltips()
@ -7785,13 +7781,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var groupingKey: Int64? var groupingKey: Int64?
var fileTypes: (music: Bool, other: Bool) = (false, false) var fileTypes: (music: Bool, other: Bool) = (false, false)
for item in results { if results.count > 1 {
if let item = item { for item in results {
let pathExtension = (item.fileName as NSString).pathExtension.lowercased() if let item = item {
if ["mp3", "m4a"].contains(pathExtension) { let pathExtension = (item.fileName as NSString).pathExtension.lowercased()
fileTypes.music = true if ["mp3", "m4a"].contains(pathExtension) {
} else { fileTypes.music = true
fileTypes.other = true } else {
fileTypes.other = true
}
} }
} }
} }
@ -11205,6 +11203,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.present(controller, in: .window(.root)) self.present(controller, in: .window(.root))
} }
private func presentVoiceMessageDiscardAlert(action: @escaping () -> Void = {}) -> Bool {
if let _ = self.presentationInterfaceState.inputTextPanelState.mediaRecordingState {
self.present(textAlertController(context: self.context, title: nil, text: self.presentationData.strings.Conversation_DiscardVoiceMessageDescription, actions: [TextAlertAction(type: .genericAction, title: self.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Conversation_DiscardVoiceMessageAction, action: { [weak self] in
self?.stopMediaRecorder()
action()
})]), in: .window(.root))
return true
}
return false
}
private var effectiveNavigationController: NavigationController? { private var effectiveNavigationController: NavigationController? {
if let navigationController = self.navigationController as? NavigationController { if let navigationController = self.navigationController as? NavigationController {
return navigationController return navigationController

View File

@ -640,8 +640,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
self.refreshMediaProcessingManager.process = { [weak context] messageIds in self.refreshMediaProcessingManager.process = { [weak context] messageIds in
context?.account.viewTracker.refreshSecretMediaMediaForMessageIds(messageIds: messageIds) context?.account.viewTracker.refreshSecretMediaMediaForMessageIds(messageIds: messageIds)
} }
self.messageMentionProcessingManager.process = { [weak context] messageIds in
context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds) self.messageMentionProcessingManager.process = { [weak self, weak context] messageIds in
if let strongSelf = self {
let _ = (strongSelf.canReadHistory.get()
|> take(1)).start(next: { [weak context] canReadHistory in
if canReadHistory {
context?.account.viewTracker.updateMarkMentionsSeenForMessageIds(messageIds: messageIds)
}
})
}
} }
self.preloadPages = false self.preloadPages = false

View File

@ -1035,7 +1035,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string) badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string)
} }
var animated: Bool = animated var animated: Bool = animated
if let updatingMedia = attributes.updatingMedia { if let updatingMedia = attributes.updatingMedia, case .update = updatingMedia.media {
state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true) state = .progress(color: messageTheme.mediaOverlayControlColors.foregroundColor, lineWidth: nil, value: CGFloat(updatingMedia.progress), cancelEnabled: true)
} else if var fetchStatus = self.fetchStatus { } else if var fetchStatus = self.fetchStatus {
var playerPosition: Int32? var playerPosition: Int32?

View File

@ -160,7 +160,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
peer = RenderedPeer(peer: channelPeer) peer = RenderedPeer(peer: channelPeer)
} }
} }
entries.append(.message(message, peer, nil, presentationData)) entries.append(.message(message, peer, searchResult.readStates[peer.peerId], presentationData))
} }
return entries return entries

View File

@ -78,6 +78,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
private var initialPeersDisposable: Disposable? private var initialPeersDisposable: Disposable?
private let options: [ContactListAdditionalOption] private let options: [ContactListAdditionalOption]
private let filters: [ContactListFilter] private let filters: [ContactListFilter]
private let limit: Int32?
init(_ params: ContactMultiselectionControllerParams) { init(_ params: ContactMultiselectionControllerParams) {
self.params = params self.params = params
@ -85,6 +86,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
self.mode = params.mode self.mode = params.mode
self.options = params.options self.options = params.options
self.filters = params.filters self.filters = params.filters
self.limit = params.limit
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 } self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
self.titleView = CounterContollerTitleView(theme: self.presentationData.theme) self.titleView = CounterContollerTitleView(theme: self.presentationData.theme)
@ -228,6 +230,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
self?.presentingViewController?.dismiss(animated: true, completion: nil) self?.presentingViewController?.dismiss(animated: true, completion: nil)
} }
let limit = self.limit
self.contactsNode.openPeer = { [weak self] peer in self.contactsNode.openPeer = { [weak self] peer in
if let strongSelf = self, case let .peer(peer, _, _) = peer { if let strongSelf = self, case let .peer(peer, _, _) = peer {
var updatedCount: Int? var updatedCount: Int?
@ -261,8 +264,8 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
} }
} }
case let .chats(chatsNode): case let .chats(chatsNode):
chatsNode.updateState { state in chatsNode.updateState { initialState in
var state = state var state = initialState
if state.selectedPeerIds.contains(peer.id) { if state.selectedPeerIds.contains(peer.id) {
state.selectedPeerIds.remove(peer.id) state.selectedPeerIds.remove(peer.id)
removedTokenId = peer.id removedTokenId = peer.id
@ -271,6 +274,12 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
state.selectedPeerIds.insert(peer.id) state.selectedPeerIds.insert(peer.id)
} }
updatedCount = state.selectedPeerIds.count updatedCount = state.selectedPeerIds.count
if let limit = limit, let count = updatedCount, count > limit {
updatedCount = nil
removedTokenId = nil
addedToken = nil
return initialState
}
var updatedState = ContactListNodeGroupSelectionState() var updatedState = ContactListNodeGroupSelectionState()
for peerId in state.selectedPeerIds { for peerId in state.selectedPeerIds {
updatedState = updatedState.withToggledPeerId(.peer(peerId)) updatedState = updatedState.withToggledPeerId(.peer(peerId))

View File

@ -179,90 +179,21 @@ class StickerShimmerEffectNode: ASDisplayNode {
context.setFillColor(UIColor.black.cgColor) context.setFillColor(UIColor.black.cgColor)
} }
if let data = data, let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024), let path = String(data: unpackedData, encoding: .utf8) { if let data = data, let unpackedData = TGGUnzipData(data, 5 * 1024 * 1024), let path = String(data: unpackedData, encoding: .utf8) {
if data.count == 141 {
print()
}
var path = path
if !path.hasPrefix("z") {
path = "\(path)z"
}
let reader = PathDataReader(input: path) let reader = PathDataReader(input: path)
let segments = reader.read() let segments = reader.read()
var currentX: Double = 0.0 let scale = size.width / 512.0
var currentY: Double = 0.0 context.scaleBy(x: scale, y: scale)
renderPath(segments, context: context)
let mul: Double = Double(size.width) / 512.0
for segment in segments {
switch segment.type {
case .M, .m:
let x = segment.data[0]
let y = segment.data[1]
if segment.isAbsolute() {
currentX = x
currentY = y
} else {
currentX += x
currentY += y
}
context.move(to: CGPoint(x: currentX * mul, y: currentY * mul))
case .L, .l:
let x = segment.data[0]
let y = segment.data[1]
let effectiveX: Double
let effectiveY: Double
if segment.isAbsolute() {
effectiveX = x
effectiveY = y
} else {
effectiveX = currentX + x
effectiveY = currentY + y
}
currentX = effectiveX
currentY = effectiveY
context.addLine(to: CGPoint(x: effectiveX * mul, y: effectiveY * mul))
case .C, .c:
let x1 = segment.data[0]
let y1 = segment.data[1]
let x2 = segment.data[2]
let y2 = segment.data[3]
let x = segment.data[4]
let y = segment.data[5]
let effectiveX1: Double
let effectiveY1: Double
let effectiveX2: Double
let effectiveY2: Double
let effectiveX: Double
let effectiveY: Double
if segment.isAbsolute() {
effectiveX1 = x1
effectiveY1 = y1
effectiveX2 = x2
effectiveY2 = y2
effectiveX = x
effectiveY = y
} else {
effectiveX1 = currentX + x1
effectiveY1 = currentY + y1
effectiveX2 = currentX + x2
effectiveY2 = currentY + y2
effectiveX = currentX + x
effectiveY = currentY + y
}
currentX = effectiveX
currentY = effectiveY
context.addCurve(to: CGPoint(x: effectiveX * mul, y: effectiveY * mul), control1: CGPoint(x: effectiveX1 * mul, y: effectiveY1 * mul), control2: CGPoint(x: effectiveX2 * mul, y: effectiveY2 * mul))
case .z:
context.fillPath()
default:
break
}
}
} else { } else {
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: size), byRoundingCorners: [.topLeft, .topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0)) let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: size), byRoundingCorners: [.topLeft, .topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0))
UIGraphicsPushContext(context) UIGraphicsPushContext(context)
@ -348,6 +279,225 @@ open class PathSegment: Equatable {
} }
} }
private func renderPath(_ segments: [PathSegment], context: CGContext) {
var currentPoint: CGPoint?
var cubicPoint: CGPoint?
var quadrPoint: CGPoint?
var initialPoint: CGPoint?
func M(_ x: Double, y: Double) {
let point = CGPoint(x: CGFloat(x), y: CGFloat(y))
context.move(to: point)
setInitPoint(point)
}
func m(_ x: Double, y: Double) {
if let cur = currentPoint {
let next = CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(y) + cur.y)
context.move(to: next)
setInitPoint(next)
} else {
M(x, y: y)
}
}
func L(_ x: Double, y: Double) {
lineTo(CGPoint(x: CGFloat(x), y: CGFloat(y)))
}
func l(_ x: Double, y: Double) {
if let cur = currentPoint {
lineTo(CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(y) + cur.y))
} else {
L(x, y: y)
}
}
func H(_ x: Double) {
if let cur = currentPoint {
lineTo(CGPoint(x: CGFloat(x), y: CGFloat(cur.y)))
}
}
func h(_ x: Double) {
if let cur = currentPoint {
lineTo(CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(cur.y)))
}
}
func V(_ y: Double) {
if let cur = currentPoint {
lineTo(CGPoint(x: CGFloat(cur.x), y: CGFloat(y)))
}
}
func v(_ y: Double) {
if let cur = currentPoint {
lineTo(CGPoint(x: CGFloat(cur.x), y: CGFloat(y) + cur.y))
}
}
func lineTo(_ p: CGPoint) {
context.addLine(to: p)
setPoint(p)
}
func c(_ x1: Double, y1: Double, x2: Double, y2: Double, x: Double, y: Double) {
if let cur = currentPoint {
let endPoint = CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(y) + cur.y)
let controlPoint1 = CGPoint(x: CGFloat(x1) + cur.x, y: CGFloat(y1) + cur.y)
let controlPoint2 = CGPoint(x: CGFloat(x2) + cur.x, y: CGFloat(y2) + cur.y)
context.addCurve(to: endPoint, control1: controlPoint1, control2: controlPoint2)
setCubicPoint(endPoint, cubic: controlPoint2)
}
}
func C(_ x1: Double, y1: Double, x2: Double, y2: Double, x: Double, y: Double) {
let endPoint = CGPoint(x: CGFloat(x), y: CGFloat(y))
let controlPoint1 = CGPoint(x: CGFloat(x1), y: CGFloat(y1))
let controlPoint2 = CGPoint(x: CGFloat(x2), y: CGFloat(y2))
context.addCurve(to: endPoint, control1: controlPoint1, control2: controlPoint2)
setCubicPoint(endPoint, cubic: controlPoint2)
}
func s(_ x2: Double, y2: Double, x: Double, y: Double) {
if let cur = currentPoint {
let nextCubic = CGPoint(x: CGFloat(x2) + cur.x, y: CGFloat(y2) + cur.y)
let next = CGPoint(x: CGFloat(x) + cur.x, y: CGFloat(y) + cur.y)
let xy1: CGPoint
if let curCubicVal = cubicPoint {
xy1 = CGPoint(x: CGFloat(2 * cur.x) - curCubicVal.x, y: CGFloat(2 * cur.y) - curCubicVal.y)
} else {
xy1 = cur
}
context.addCurve(to: next, control1: xy1, control2: nextCubic)
setCubicPoint(next, cubic: nextCubic)
}
}
func S(_ x2: Double, y2: Double, x: Double, y: Double) {
if let cur = currentPoint {
let nextCubic = CGPoint(x: CGFloat(x2), y: CGFloat(y2))
let next = CGPoint(x: CGFloat(x), y: CGFloat(y))
let xy1: CGPoint
if let curCubicVal = cubicPoint {
xy1 = CGPoint(x: CGFloat(2 * cur.x) - curCubicVal.x, y: CGFloat(2 * cur.y) - curCubicVal.y)
} else {
xy1 = cur
}
context.addCurve(to: next, control1: xy1, control2: nextCubic)
setCubicPoint(next, cubic: nextCubic)
}
}
func z() {
context.fillPath()
}
func setQuadrPoint(_ p: CGPoint, quadr: CGPoint) {
currentPoint = p
quadrPoint = quadr
cubicPoint = nil
}
func setCubicPoint(_ p: CGPoint, cubic: CGPoint) {
currentPoint = p
cubicPoint = cubic
quadrPoint = nil
}
func setInitPoint(_ p: CGPoint) {
setPoint(p)
initialPoint = p
}
func setPoint(_ p: CGPoint) {
currentPoint = p
cubicPoint = nil
quadrPoint = nil
}
for segment in segments {
var data = segment.data
switch segment.type {
case .M:
M(data[0], y: data[1])
data.removeSubrange(Range(uncheckedBounds: (lower: 0, upper: 2)))
while data.count >= 2 {
L(data[0], y: data[1])
data.removeSubrange((0 ..< 2))
}
case .m:
m(data[0], y: data[1])
data.removeSubrange((0 ..< 2))
while data.count >= 2 {
l(data[0], y: data[1])
data.removeSubrange((0 ..< 2))
}
case .L:
while data.count >= 2 {
L(data[0], y: data[1])
data.removeSubrange((0 ..< 2))
}
case .l:
while data.count >= 2 {
l(data[0], y: data[1])
data.removeSubrange((0 ..< 2))
}
case .H:
H(data[0])
case .h:
h(data[0])
case .V:
V(data[0])
case .v:
v(data[0])
case .C:
while data.count >= 6 {
C(data[0], y1: data[1], x2: data[2], y2: data[3], x: data[4], y: data[5])
data.removeSubrange((0 ..< 6))
}
case .c:
while data.count >= 6 {
c(data[0], y1: data[1], x2: data[2], y2: data[3], x: data[4], y: data[5])
data.removeSubrange((0 ..< 6))
}
case .S:
while data.count >= 4 {
S(data[0], y2: data[1], x: data[2], y: data[3])
data.removeSubrange((0 ..< 4))
}
case .s:
while data.count >= 4 {
s(data[0], y2: data[1], x: data[2], y: data[3])
data.removeSubrange((0 ..< 4))
}
// case .Q:
// Q(data[0], y1: data[1], x: data[2], y: data[3])
// case .q:
// q(data[0], y1: data[1], x: data[2], y: data[3])
// case .T:
// T(data[0], y: data[1])
// case .t:
// t(data[0], y: data[1])
// case .A:
// A(data[0], ry: data[1], angle: data[2], largeArc: num2bool(data[3]), sweep: num2bool(data[4]), x: data[5], y: data[6])
// case .a:
// a(data[0], ry: data[1], angle: data[2], largeArc: num2bool(data[3]), sweep: num2bool(data[4]), x: data[5], y: data[6])
// case .E:
// E(data[0], y: data[1], w: data[2], h: data[3], startAngle: data[4], arcAngle: data[5])
// case .e:
// e(data[0], y: data[1], w: data[2], h: data[3], startAngle: data[4], arcAngle: data[5])
case .z:
z()
default:
print("unknown")
break
}
}
}
private class PathDataReader { private class PathDataReader {
private let input: String private let input: String
private var current: UnicodeScalar? private var current: UnicodeScalar?

View File

@ -224,6 +224,11 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0, display: true) playbackStatus = .buffering(initial: true, whilePlaying: false, progress: 0.0, display: true)
} }
if case .playing = playbackStatus, !self.started {
self.started = true
self.onPlaybackStarted?()
}
self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: 1.0, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true) self.status = MediaPlayerStatus(generationTimestamp: self.status.generationTimestamp, duration: Double(duration), dimensions: self.status.dimensions, timestamp: newTimestamp, baseRate: 1.0, seekId: self.status.seekId, status: playbackStatus, soundEnabled: true)
updateStatus(self.status) updateStatus(self.status)
} }

View File

@ -136,6 +136,10 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
} }
deinit { deinit {
let webView = self.webView
Queue.mainQueue().after(1.0) {
print(webView.debugDescription)
}
func disableGestures(view: UIView) { func disableGestures(view: UIView) {
if let recognizers = view.gestureRecognizers { if let recognizers = view.gestureRecognizers {
for recognizer in recognizers { for recognizer in recognizers {
@ -167,7 +171,6 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
} }
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) { func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
print("w")
} }
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {