mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'master' into experiments/group-video-calls
This commit is contained in:
commit
ca8901bd7d
@ -46,13 +46,15 @@ public final class ContactMultiselectionControllerParams {
|
||||
public let options: [ContactListAdditionalOption]
|
||||
public let filters: [ContactListFilter]
|
||||
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.mode = mode
|
||||
self.options = options
|
||||
self.filters = filters
|
||||
self.alwaysEnabled = alwaysEnabled
|
||||
self.limit = limit
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
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
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
let _ = togglePeerUnreadMarkInteractively(postbox: context.account.postbox, viewTracker: context.account.viewTracker, peerId: peerId).start()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
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
|
||||
if let filter = filter {
|
||||
location = .filter(filter.id)
|
||||
var chatListFilter: ChatListFilter?
|
||||
if case let .chatList(filter) = source, let chatFilter = filter {
|
||||
chatListFilter = chatFilter
|
||||
location = .filter(chatFilter.id)
|
||||
} else {
|
||||
location = .group(group)
|
||||
}
|
||||
|
||||
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
|
||||
let _ = (toggleItemPinned(postbox: context.account.postbox, location: location, itemId: .peer(peerId))
|
||||
|> 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 {
|
||||
var isMuted = false
|
||||
|
@ -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
|
||||
let _ = (controller.result
|
||||
|> take(1)
|
||||
@ -680,7 +680,7 @@ private func internalChatListFilterExcludeChatsController(context: AccountContex
|
||||
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
|
||||
let _ = (controller.result
|
||||
|> take(1)
|
||||
|
@ -306,16 +306,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
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())
|
||||
|> mapToSignal { peers, dates, selectedFilter, searchQuery -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?), NoError> in
|
||||
self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get(), accountPeer)
|
||||
|> mapToSignal { peers, dates, selectedFilter, searchQuery, accountPeer -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?, String?, Peer?), NoError> in
|
||||
if searchQuery?.isEmpty ?? true {
|
||||
return .single((peers, dates, selectedFilter))
|
||||
return .single((peers, dates, selectedFilter, searchQuery, accountPeer))
|
||||
} else {
|
||||
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] = []
|
||||
if !dates.isEmpty {
|
||||
let formatter = DateFormatter()
|
||||
@ -327,8 +330,18 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
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) {
|
||||
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 {
|
||||
if existingPeerIds.contains(peer.id) {
|
||||
continue
|
||||
}
|
||||
let isGroup: Bool
|
||||
if peer.id.namespace == Namespaces.Peer.SecretChat {
|
||||
continue
|
||||
@ -339,8 +352,15 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
} else {
|
||||
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
|
||||
|
@ -441,6 +441,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
|
||||
if origin == nil {
|
||||
self.editButton.isHidden = true
|
||||
self.deleteButton.isHidden = true
|
||||
}
|
||||
}
|
||||
@ -516,9 +517,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
}
|
||||
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 {
|
||||
self.currentMessageText = messageText
|
||||
|
||||
|
@ -753,8 +753,8 @@ func layoutTextItemWithString(_ string: NSAttributedString, boundingWidth: CGFlo
|
||||
let cfRunRange = CTRunGetStringRange(run)
|
||||
let runRange = NSMakeRange(cfRunRange.location == kCFNotFound ? NSNotFound : cfRunRange.location, cfRunRange.length)
|
||||
string.enumerateAttributes(in: runRange, options: []) { attributes, range, _ in
|
||||
if let id = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaIdAttribute)] as? Int64, let dimensions = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaDimensionsAttribute)] as? CGSize {
|
||||
var imageFrame = CGRect(origin: CGPoint(), size: dimensions)
|
||||
if let id = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaIdAttribute)] as? Int64, let dimensions = attributes[NSAttributedString.Key.init(rawValue: InstantPageMediaDimensionsAttribute)] as? PixelDimensions {
|
||||
var imageFrame = CGRect(origin: CGPoint(), size: dimensions.cgSize)
|
||||
|
||||
let xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, nil)
|
||||
let yOffset = fontLineHeight.isZero ? 0.0 : floorToScreenPixels((fontLineHeight - imageFrame.size.height) / 2.0)
|
||||
|
@ -56,6 +56,7 @@ final class InstantPageWebEmbedNode: ASDisplayNode, InstantPageNode {
|
||||
configuration.userContentController = userController
|
||||
|
||||
let webView = WKWebView(frame: CGRect(origin: CGPoint(), size: frame.size), configuration: configuration)
|
||||
webView.allowsBackForwardNavigationGestures = false
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
webView.allowsLinkPreview = false
|
||||
}
|
||||
|
@ -309,8 +309,13 @@
|
||||
return false;
|
||||
|
||||
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)
|
||||
{
|
||||
onlyGroupableMedia = false;
|
||||
|
@ -236,7 +236,12 @@
|
||||
|
||||
- (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)
|
||||
return assetSignal;
|
||||
|
||||
|
@ -504,8 +504,13 @@
|
||||
if (_attributesDisposable == nil)
|
||||
_attributesDisposable = [[SMetaDisposable alloc] init];
|
||||
|
||||
TGMediaAsset *asset = item.asset;
|
||||
if ([asset isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
asset = [(TGCameraCapturedVideo *)asset originalAsset];
|
||||
}
|
||||
|
||||
_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;
|
||||
if (strongSelf == nil)
|
||||
|
@ -4,6 +4,16 @@ import Display
|
||||
import TelegramPresentationData
|
||||
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 {
|
||||
let completion: ([URL]) -> Void
|
||||
|
||||
@ -52,7 +62,10 @@ public func legacyICloudFilePicker(theme: PresentationTheme, mode: LegacyICloudF
|
||||
})
|
||||
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
|
||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *), case .default = mode {
|
||||
controller.allowsMultipleSelection = true
|
||||
|
@ -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 {
|
||||
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] = []
|
||||
fileAttributes.append(.FileName(fileName: fileName))
|
||||
if asAnimation {
|
||||
@ -478,6 +488,9 @@ public func legacyAssetPickerEnqueueMessages(account: Account, signals: [Any]) -
|
||||
}
|
||||
}
|
||||
}
|
||||
if estimatedSize > 5 * 1024 * 1024 {
|
||||
fileAttributes.append(.hintFileIsLarge)
|
||||
}
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
|
||||
|
@ -384,7 +384,7 @@ private func stringForSelectiveSettings(strings: PresentationStrings, settings:
|
||||
}
|
||||
case let .enableContacts(enableFor, disableFor):
|
||||
if !enableFor.isEmpty && !disableFor.isEmpty {
|
||||
return strings.PrivacySettings_LastSeenContactsMinusPlus("\(countForSelectivePeers(enableFor))", "\(countForSelectivePeers(disableFor))").0
|
||||
return strings.PrivacySettings_LastSeenContactsMinusPlus("\(countForSelectivePeers(disableFor))", "\(countForSelectivePeers(enableFor))").0
|
||||
} else if !enableFor.isEmpty {
|
||||
return strings.PrivacySettings_LastSeenContactsPlus("\(countForSelectivePeers(enableFor))").0
|
||||
} else if !disableFor.isEmpty {
|
||||
|
@ -110,7 +110,9 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
|
||||
}
|
||||
}
|
||||
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?
|
||||
if let adjustments = adjustments {
|
||||
@ -123,8 +125,10 @@ private func preparedShareItem(account: Account, to peerId: PeerId, value: [Stri
|
||||
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)
|
||||
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
|
||||
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]) {
|
||||
let fileName = url.lastPathComponent
|
||||
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 artist = value["artist"] as? String
|
||||
|
||||
@ -357,21 +361,23 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], items: [Prepa
|
||||
var messages: [EnqueueMessage] = []
|
||||
var groupingKey: Int64?
|
||||
var mediaTypes: (photo: Bool, video: Bool, music: Bool, other: Bool) = (false, false, false, false)
|
||||
for item in items {
|
||||
if case let .media(result) = item, case let .media(media) = result {
|
||||
if media.media is TelegramMediaImage {
|
||||
mediaTypes.photo = true
|
||||
} else if let media = media.media as? TelegramMediaFile {
|
||||
if media.isVideo {
|
||||
mediaTypes.video = true
|
||||
} else if let fileName = media.fileName, fileName.hasPrefix("mp3") || fileName.hasPrefix("m4a") {
|
||||
mediaTypes.music = true
|
||||
if items.count > 1 {
|
||||
for item in items {
|
||||
if case let .media(result) = item, case let .media(media) = result {
|
||||
if media.media is TelegramMediaImage {
|
||||
mediaTypes.photo = true
|
||||
} else if let media = media.media as? TelegramMediaFile {
|
||||
if media.isVideo {
|
||||
mediaTypes.video = true
|
||||
} else if let fileName = media.fileName, fileName.hasPrefix("mp3") || fileName.hasPrefix("m4a") {
|
||||
mediaTypes.music = true
|
||||
} else {
|
||||
mediaTypes.other = true
|
||||
}
|
||||
} else {
|
||||
mediaTypes.other = true
|
||||
mediaTypes = (false, false, false, false)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
mediaTypes = (false, false, false, false)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -604,16 +604,15 @@ private func uploadedMediaFileContent(network: Network, postbox: Postbox, auxili
|
||||
hintSize = Int(size)
|
||||
}
|
||||
|
||||
loop: for attr in file.attributes {
|
||||
switch attr {
|
||||
case .hintFileIsLarge:
|
||||
hintFileIsLarge = true
|
||||
break loop
|
||||
default:
|
||||
break loop
|
||||
loop: for attribute in file.attributes {
|
||||
switch attribute {
|
||||
case .hintFileIsLarge:
|
||||
hintFileIsLarge = true
|
||||
break loop
|
||||
default:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let fileReference: AnyMediaReference
|
||||
if let partialReference = file.partialReference {
|
||||
|
@ -1,5 +1,5 @@
|
||||
function initialize() {
|
||||
var controls = document.getElementsByClassName("controls")[0];
|
||||
var controls = document.getElementsByClassName("vp-controls-wrapper")[0];
|
||||
if (controls != null) {
|
||||
controls.style.display = "none";
|
||||
}
|
||||
|
@ -457,12 +457,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return true
|
||||
}
|
||||
if let _ = strongSelf.presentationInterfaceState.inputTextPanelState.mediaRecordingState {
|
||||
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))
|
||||
|
||||
if strongSelf.presentVoiceMessageDiscardAlert(action: action) {
|
||||
return false
|
||||
}
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
|
||||
strongSelf.commitPurposefulAction()
|
||||
strongSelf.dismissAllTooltips()
|
||||
|
||||
@ -7785,13 +7781,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
var groupingKey: Int64?
|
||||
var fileTypes: (music: Bool, other: Bool) = (false, false)
|
||||
for item in results {
|
||||
if let item = item {
|
||||
let pathExtension = (item.fileName as NSString).pathExtension.lowercased()
|
||||
if ["mp3", "m4a"].contains(pathExtension) {
|
||||
fileTypes.music = true
|
||||
} else {
|
||||
fileTypes.other = true
|
||||
if results.count > 1 {
|
||||
for item in results {
|
||||
if let item = item {
|
||||
let pathExtension = (item.fileName as NSString).pathExtension.lowercased()
|
||||
if ["mp3", "m4a"].contains(pathExtension) {
|
||||
fileTypes.music = true
|
||||
} else {
|
||||
fileTypes.other = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -11205,6 +11203,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
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? {
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
return navigationController
|
||||
|
@ -640,8 +640,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
self.refreshMediaProcessingManager.process = { [weak context] messageIds in
|
||||
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
|
||||
|
@ -1035,7 +1035,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
|
||||
badgeContent = .text(inset: 0.0, backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, text: string)
|
||||
}
|
||||
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)
|
||||
} else if var fetchStatus = self.fetchStatus {
|
||||
var playerPosition: Int32?
|
||||
|
@ -160,7 +160,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
peer = RenderedPeer(peer: channelPeer)
|
||||
}
|
||||
}
|
||||
entries.append(.message(message, peer, nil, presentationData))
|
||||
entries.append(.message(message, peer, searchResult.readStates[peer.peerId], presentationData))
|
||||
}
|
||||
|
||||
return entries
|
||||
|
@ -78,6 +78,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
private var initialPeersDisposable: Disposable?
|
||||
private let options: [ContactListAdditionalOption]
|
||||
private let filters: [ContactListFilter]
|
||||
private let limit: Int32?
|
||||
|
||||
init(_ params: ContactMultiselectionControllerParams) {
|
||||
self.params = params
|
||||
@ -85,6 +86,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
self.mode = params.mode
|
||||
self.options = params.options
|
||||
self.filters = params.filters
|
||||
self.limit = params.limit
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
self.titleView = CounterContollerTitleView(theme: self.presentationData.theme)
|
||||
@ -228,6 +230,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let limit = self.limit
|
||||
self.contactsNode.openPeer = { [weak self] peer in
|
||||
if let strongSelf = self, case let .peer(peer, _, _) = peer {
|
||||
var updatedCount: Int?
|
||||
@ -261,8 +264,8 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
}
|
||||
}
|
||||
case let .chats(chatsNode):
|
||||
chatsNode.updateState { state in
|
||||
var state = state
|
||||
chatsNode.updateState { initialState in
|
||||
var state = initialState
|
||||
if state.selectedPeerIds.contains(peer.id) {
|
||||
state.selectedPeerIds.remove(peer.id)
|
||||
removedTokenId = peer.id
|
||||
@ -271,6 +274,12 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
|
||||
state.selectedPeerIds.insert(peer.id)
|
||||
}
|
||||
updatedCount = state.selectedPeerIds.count
|
||||
if let limit = limit, let count = updatedCount, count > limit {
|
||||
updatedCount = nil
|
||||
removedTokenId = nil
|
||||
addedToken = nil
|
||||
return initialState
|
||||
}
|
||||
var updatedState = ContactListNodeGroupSelectionState()
|
||||
for peerId in state.selectedPeerIds {
|
||||
updatedState = updatedState.withToggledPeerId(.peer(peerId))
|
||||
|
@ -179,90 +179,21 @@ class StickerShimmerEffectNode: ASDisplayNode {
|
||||
|
||||
context.setFillColor(UIColor.black.cgColor)
|
||||
}
|
||||
|
||||
|
||||
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 segments = reader.read()
|
||||
|
||||
var currentX: Double = 0.0
|
||||
var currentY: Double = 0.0
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
let scale = size.width / 512.0
|
||||
context.scaleBy(x: scale, y: scale)
|
||||
renderPath(segments, context: context)
|
||||
} else {
|
||||
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: size), byRoundingCorners: [.topLeft, .topRight, .bottomLeft, .bottomRight], cornerRadii: CGSize(width: 10.0, height: 10.0))
|
||||
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 let input: String
|
||||
private var current: UnicodeScalar?
|
||||
|
@ -224,6 +224,11 @@ final class VimeoEmbedImplementation: WebEmbedImplementation {
|
||||
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)
|
||||
updateStatus(self.status)
|
||||
}
|
||||
|
@ -136,6 +136,10 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
|
||||
}
|
||||
|
||||
deinit {
|
||||
let webView = self.webView
|
||||
Queue.mainQueue().after(1.0) {
|
||||
print(webView.debugDescription)
|
||||
}
|
||||
func disableGestures(view: UIView) {
|
||||
if let recognizers = view.gestureRecognizers {
|
||||
for recognizer in recognizers {
|
||||
@ -167,7 +171,6 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||||
print("w")
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user