Cherry-pick various fixes

This commit is contained in:
Ilya Laktyushin 2020-11-16 15:40:06 +04:00
parent b003339efd
commit 02e1612e7a
366 changed files with 5680 additions and 28180 deletions

View File

@ -5867,6 +5867,7 @@ Sorry for the inconvenience.";
"Chat.PinnedMessagesHiddenText" = "You will see the bar with pinned messages only if a new message is pinned.";
"OpenFile.PotentiallyDangerousContentAlert" = "Previewing this file can potentially expose your IP address to its sender. Continue?";
"OpenFile.Proceed" = "Proceed";
"Chat.PinnedListPreview.ShowAllMessages" = "Show All Messages";
"Chat.PinnedListPreview.UnpinAllMessages" = "Unpin All Messages";
@ -5887,3 +5888,5 @@ Sorry for the inconvenience.";
"Stats.Message.Views" = "Views";
"Stats.Message.PublicShares" = "Public Shares";
"Stats.Message.PrivateShares" = "Private Shares";
"Conversation.TextCopied" = "Text copied to clipboard";

View File

@ -18,8 +18,9 @@ public final class GalleryControllerActionInteraction {
public let openBotCommand: (String) -> Void
public let addContact: (String) -> Void
public let storeMediaPlaybackState: (MessageId, Double?) -> Void
public let editMedia: (MessageId) -> Void
public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void) {
public init(openUrl: @escaping (String, Bool) -> Void, openUrlIn: @escaping (String) -> Void, openPeerMention: @escaping (String) -> Void, openPeer: @escaping (PeerId) -> Void, openHashtag: @escaping (String?, String) -> Void, openBotCommand: @escaping (String) -> Void, addContact: @escaping (String) -> Void, storeMediaPlaybackState: @escaping (MessageId, Double?) -> Void, editMedia: @escaping (MessageId) -> Void) {
self.openUrl = openUrl
self.openUrlIn = openUrlIn
self.openPeerMention = openPeerMention
@ -28,5 +29,6 @@ public final class GalleryControllerActionInteraction {
self.openBotCommand = openBotCommand
self.addContact = addContact
self.storeMediaPlaybackState = storeMediaPlaybackState
self.editMedia = editMedia
}
}

View File

@ -264,6 +264,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
private(set) var emptyNode: ChatListEmptyNode?
var emptyShimmerEffectNode: ChatListShimmerNode?
private var shimmerNodeOffset: CGFloat = 0.0
let listNode: ChatListNode
private var validLayout: (CGSize, UIEdgeInsets, CGFloat)?
@ -285,8 +286,12 @@ private final class ChatListContainerItemNode: ASDisplayNode {
return
}
var needsShimmerNode = false
var shimmerNodeOffset: CGFloat = 0.0
switch isEmptyState {
case let .empty(isLoading):
case let .empty(isLoading, hasArchiveInfo):
if hasArchiveInfo {
shimmerNodeOffset = 253.0
}
if isLoading {
needsShimmerNode = true
@ -326,12 +331,13 @@ private final class ChatListContainerItemNode: ASDisplayNode {
}
}
if needsShimmerNode {
strongSelf.shimmerNodeOffset = shimmerNodeOffset
if strongSelf.emptyShimmerEffectNode == nil {
let emptyShimmerEffectNode = ChatListShimmerNode()
strongSelf.emptyShimmerEffectNode = emptyShimmerEffectNode
strongSelf.insertSubnode(emptyShimmerEffectNode, belowSubnode: strongSelf.listNode)
if let (size, insets, _) = strongSelf.validLayout, let offset = strongSelf.floatingHeaderOffset {
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: .immediate)
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: .immediate)
}
}
} else if let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode {
@ -349,7 +355,7 @@ private final class ChatListContainerItemNode: ASDisplayNode {
}
strongSelf.floatingHeaderOffset = offset
if let (size, insets, _) = strongSelf.validLayout, let emptyShimmerEffectNode = strongSelf.emptyShimmerEffectNode {
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset, transition: transition)
strongSelf.layoutEmptyShimmerEffectNode(node: emptyShimmerEffectNode, size: size, insets: insets, verticalOffset: offset + strongSelf.shimmerNodeOffset, transition: transition)
}
}
}

View File

@ -226,25 +226,23 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
self.paneContainerNode.interaction = interaction
self.paneContainerNode.currentPaneUpdated = { [weak self] key, transitionFraction, transition in
if let strongSelf = self {
var filterKey: ChatListSearchFilter?
if let key = key {
switch key {
case .chats:
filterKey = .chats
case .media:
filterKey = .media
case .links:
filterKey = .links
case .files:
filterKey = .files
case .music:
filterKey = .music
case .voice:
filterKey = .voice
}
if let strongSelf = self, let key = key {
var filterKey: ChatListSearchFilter
switch key {
case .chats:
filterKey = .chats
case .media:
filterKey = .media
case .links:
filterKey = .links
case .files:
filterKey = .files
case .music:
filterKey = .music
case .voice:
filterKey = .voice
}
strongSelf.selectedFilterKey = filterKey.flatMap { .filter($0.id) }
strongSelf.selectedFilterKey = .filter(filterKey.id)
strongSelf.selectedFilterKeyPromise.set(.single(strongSelf.selectedFilterKey))
strongSelf.transitionFraction = transitionFraction
@ -306,16 +304,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 +328,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 }
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)
}
if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) {
for peer in peers {
if existingPeerIds.contains(peer.id) {
continue
}
let isGroup: Bool
if peer.id.namespace == Namespaces.Peer.SecretChat {
continue
@ -339,8 +350,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

View File

@ -403,7 +403,7 @@ public enum ChatListNodeScrollPosition {
public enum ChatListNodeEmptyState: Equatable {
case notEmpty(containsChats: Bool)
case empty(isLoading: Bool)
case empty(isLoading: Bool, hasArchiveInfo: Bool)
}
public final class ChatListNode: ListView {
@ -1411,6 +1411,7 @@ public final class ChatListNode: ListView {
var isEmpty = false
var isLoading = false
var hasArchiveInfo = false
if transition.chatListView.filteredEntries.isEmpty {
isEmpty = true
} else {
@ -1421,6 +1422,9 @@ public final class ChatListNode: ListView {
case .GroupReferenceEntry, .HeaderEntry, .HoleEntry:
break
default:
if case .ArchiveIntro = entry {
hasArchiveInfo = true
}
isEmpty = false
break loop1
}
@ -1441,14 +1445,21 @@ public final class ChatListNode: ListView {
if !hasHoles {
isLoading = false
}
} else {
for entry in transition.chatListView.filteredEntries.reversed().prefix(2) {
if case .ArchiveIntro = entry {
hasArchiveInfo = true
break
}
}
}
}
let isEmptyState: ChatListNodeEmptyState
if transition.chatListView.isLoading {
isEmptyState = .empty(isLoading: true)
isEmptyState = .empty(isLoading: true, hasArchiveInfo: hasArchiveInfo)
} else if isEmpty {
isEmptyState = .empty(isLoading: isLoading)
isEmptyState = .empty(isLoading: isLoading, hasArchiveInfo: false)
} else {
var containsChats = false
loop: for entry in transition.chatListView.filteredEntries {

View File

@ -4,7 +4,7 @@
bool TGIsGzippedData(NSData *data) {
const UInt8 *bytes = (const UInt8 *)data.bytes;
return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
return data.length >= 2 && ((bytes[0] == 0x1f && bytes[1] == 0x8b) || (bytes[0] == 0x78 && bytes[1] == 0x9c));
}
NSData *TGGZipData(NSData *data, float level) {

View File

@ -21,6 +21,7 @@ import TextSelectionNode
private let deleteImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionTrash"), color: .white)
private let actionImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: .white)
private let editImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/Draw"), color: .white)
private let backwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/BackwardButton"), color: .white)
private let forwardImage = generateTintedImage(image: UIImage(bundleImageName: "Media Gallery/ForwardButton"), color: .white)
@ -47,7 +48,7 @@ private let dateFont = Font.regular(14.0)
enum ChatItemGalleryFooterContent: Equatable {
case info
case fetch(status: MediaResourceStatus)
case fetch(status: MediaResourceStatus, seekable: Bool)
case playback(paused: Bool, seekable: Bool)
static func ==(lhs: ChatItemGalleryFooterContent, rhs: ChatItemGalleryFooterContent) -> Bool {
@ -58,8 +59,8 @@ enum ChatItemGalleryFooterContent: Equatable {
} else {
return false
}
case let .fetch(lhsStatus):
if case let .fetch(rhsStatus) = rhs, lhsStatus == rhsStatus {
case let .fetch(lhsStatus, lhsSeekable):
if case let .fetch(rhsStatus, rhsSeekable) = rhs, lhsStatus == rhsStatus, lhsSeekable == rhsSeekable {
return true
} else {
return false
@ -116,6 +117,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
private let contentNode: ASDisplayNode
private let deleteButton: UIButton
private let actionButton: UIButton
private let editButton: UIButton
private let maskNode: ASDisplayNode
private let scrollWrapperNode: CaptionScrollWrapperNode
private let scrollNode: ASScrollNode
@ -165,11 +167,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.playbackControlButton.isHidden = true
self.statusButtonNode.isHidden = true
self.statusNode.isHidden = true
case let .fetch(status):
case let .fetch(status, seekable):
self.authorNameNode.isHidden = true
self.dateNode.isHidden = true
self.backwardButton.isHidden = true
self.forwardButton.isHidden = true
self.backwardButton.isHidden = !seekable
self.forwardButton.isHidden = !seekable
if status == .Local {
self.playbackControlButton.isHidden = false
self.playbackControlButton.setImage(playImage, for: [])
@ -217,8 +219,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
}
didSet {
if let scrubberView = self.scrubberView {
scrubberView.setCollapsed(self.visibilityAlpha < 1.0 ? true : false, animated: false)
if let scrubberView = self.scrubberView {
scrubberView.setCollapsed(self.visibilityAlpha < 1.0, animated: false)
self.view.addSubview(scrubberView)
scrubberView.updateScrubbingVisual = { [weak self] value in
guard let strongSelf = self else {
@ -253,7 +255,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
override func setVisibilityAlpha(_ alpha: CGFloat, animated: Bool) {
self.visibilityAlpha = alpha
self.contentNode.alpha = alpha
self.scrubberView?.setCollapsed(alpha < 1.0 ? true : false, animated: animated)
self.scrubberView?.setCollapsed(alpha < 1.0, animated: animated)
}
init(context: AccountContext, presentationData: PresentationData, present: @escaping (ViewController, Any?) -> Void = { _, _ in }) {
@ -268,9 +270,11 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.deleteButton = UIButton()
self.actionButton = UIButton()
self.editButton = UIButton()
self.deleteButton.setImage(deleteImage, for: [.normal])
self.actionButton.setImage(actionImage, for: [.normal])
self.editButton.setImage(editImage, for: [.normal])
self.scrollWrapperNode = CaptionScrollWrapperNode()
self.scrollWrapperNode.clipsToBounds = true
@ -340,6 +344,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.contentNode.view.addSubview(self.deleteButton)
self.contentNode.view.addSubview(self.actionButton)
// self.contentNode.view.addSubview(self.editButton)
self.contentNode.addSubnode(self.scrollWrapperNode)
self.scrollWrapperNode.addSubnode(self.scrollNode)
self.scrollNode.addSubnode(self.textNode)
@ -356,6 +361,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), for: [.touchUpInside])
self.actionButton.addTarget(self, action: #selector(self.actionButtonPressed), for: [.touchUpInside])
self.editButton.addTarget(self, action: #selector(self.editButtonPressed), for: [.touchUpInside])
self.backwardButton.addTarget(self, action: #selector(self.backwardButtonPressed), forControlEvents: .touchUpInside)
self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
@ -436,6 +442,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
if origin == nil {
self.deleteButton.isHidden = true
self.editButton.isHidden = true
}
}
@ -444,6 +451,16 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
let canDelete: Bool
var canShare = !message.containsSecretMedia && !Namespaces.Message.allScheduled.contains(message.id.namespace)
var canEdit = false
for media in message.media {
if media is TelegramMediaImage {
canEdit = true
break
}
}
canEdit = canEdit && !message.containsSecretMedia
if let peer = message.peers[message.id.peerId] {
if peer is TelegramUser || peer is TelegramSecretChat {
canDelete = true
@ -452,17 +469,21 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
} else if let channel = peer as? TelegramChannel {
if message.flags.contains(.Incoming) {
canDelete = channel.hasPermission(.deleteAllMessages)
canEdit = canEdit && channel.hasPermission(.editAllMessages)
} else {
canDelete = true
}
} else {
canDelete = false
canEdit = false
}
} else {
canDelete = false
canShare = false
canEdit = false
}
var authorNameText: String?
if let author = message.effectiveAuthor {
authorNameText = author.displayTitle(strings: self.strings, displayOrder: self.nameOrder)
@ -496,10 +517,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
messageText = galleryCaptionStringWithAppliedEntities(message.text, entities: entities)
}
self.editButton.isHidden = message.containsSecretMedia
self.actionButton.isHidden = message.containsSecretMedia || Namespaces.Message.allScheduled.contains(message.id.namespace)
if self.currentMessageText != messageText || canDelete != !self.deleteButton.isHidden || canShare != !self.actionButton.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
if messageText.length == 0 {
@ -519,6 +540,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.deleteButton.isHidden = !canDelete
self.actionButton.isHidden = !canShare
self.editButton.isHidden = !canEdit
self.requestLayout?(.immediate)
}
@ -620,20 +642,22 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
if self.textNode.isHidden || !displayCaption {
panelHeight += 8.0
} else {
scrubberY = panelHeight - bottomInset - 44.0 - 41.0
scrubberY = panelHeight - bottomInset - 44.0 - 44.0
if contentInset > 0.0 {
scrubberY -= contentInset + 3.0
scrubberY -= contentInset
}
}
let scrubberFrame = CGRect(origin: CGPoint(x: leftInset, y: scrubberY), size: CGSize(width: width - leftInset - rightInset, height: 34.0))
scrubberView.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
transition.updateFrame(layer: scrubberView.layer, frame: scrubberFrame)
transition.updateBounds(layer: scrubberView.layer, bounds: CGRect(origin: CGPoint(), size: scrubberFrame.size))
transition.updatePosition(layer: scrubberView.layer, position: CGPoint(x: scrubberFrame.midX, y: scrubberFrame.midY))
}
transition.updateAlpha(node: self.textNode, alpha: displayCaption ? 1.0 : 0.0)
self.actionButton.frame = CGRect(origin: CGPoint(x: leftInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
self.deleteButton.frame = CGRect(origin: CGPoint(x: width - 44.0 - rightInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
self.editButton.frame = CGRect(origin: CGPoint(x: width - 44.0 - 50.0 - rightInset, y: panelHeight - bottomInset - 44.0), size: CGSize(width: 44.0, height: 44.0))
if let image = self.backwardButton.image(for: .normal) {
self.backwardButton.frame = CGRect(origin: CGPoint(x: floor((width - image.size.width) / 2.0) - 66.0, y: panelHeight - bottomInset - 44.0 + 7.0), size: image.size)
@ -708,6 +732,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.authorNameNode.alpha = 1.0
self.deleteButton.alpha = 1.0
self.actionButton.alpha = 1.0
self.editButton.alpha = 1.0
self.backwardButton.alpha = 1.0
self.forwardButton.alpha = 1.0
self.statusNode.alpha = 1.0
@ -730,6 +755,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.authorNameNode.alpha = 0.0
self.deleteButton.alpha = 0.0
self.actionButton.alpha = 0.0
self.editButton.alpha = 0.0
self.backwardButton.alpha = 0.0
self.forwardButton.alpha = 0.0
self.statusNode.alpha = 0.0
@ -1049,6 +1075,13 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
}
}
@objc func editButtonPressed() {
guard let message = self.currentMessage else {
return
}
self.controllerInteraction?.editMedia(message.id)
}
@objc func playbackControlPressed() {
self.playbackControl?()
}

View File

@ -441,9 +441,9 @@ public class GalleryController: ViewController, StandalonePresentableController
namespaces = .not(Namespaces.Message.allScheduled)
}
return context.account.postbox.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(message!.index), count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, namespaces: namespaces, orderStatistics: [.combinedLocation])
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
let mapped = GalleryMessageHistoryView.view(view)
return .single(mapped)
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
let mapped = GalleryMessageHistoryView.view(view)
return .single(mapped)
}
} else {
return .single(GalleryMessageHistoryView.entries([MessageHistoryEntry(message: message!, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false))], false, false))
@ -911,6 +911,11 @@ public class GalleryController: ViewController, StandalonePresentableController
if let strongSelf = self {
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { [weak self] messageId in
if let strongSelf = self {
strongSelf.dismiss(forceAway: true)
strongSelf.actionInteraction?.editMedia(messageId)
}
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -3,16 +3,19 @@ import UIKit
import AsyncDisplayKit
import Display
import SwiftSignalKit
import Postbox
public final class GalleryControllerInteraction {
public let presentController: (ViewController, ViewControllerPresentationArguments?) -> Void
public let dismissController: () -> Void
public let replaceRootController: (ViewController, Promise<Bool>?) -> Void
public let editMedia: (MessageId) -> Void
public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void) {
public init(presentController: @escaping (ViewController, ViewControllerPresentationArguments?) -> Void, dismissController: @escaping () -> Void, replaceRootController: @escaping (ViewController, Promise<Bool>?) -> Void, editMedia: @escaping (MessageId) -> Void) {
self.presentController = presentController
self.dismissController = dismissController
self.replaceRootController = replaceRootController
self.editMedia = editMedia
}
}

View File

@ -517,7 +517,7 @@ public final class GalleryPagerNode: ASDisplayNode, UIScrollViewDelegate, UIGest
}
if self.itemNodes.isEmpty {
let node = self.makeNodeForItem(at: self.centralItemIndex ?? 0, synchronous: synchronous)
node.frame = CGRect(origin: CGPoint(), size: scrollView.bounds.size)
node.frame = CGRect(origin: CGPoint(), size: self.scrollView.bounds.size)
if let containerLayout = self.containerLayout {
node.containerLayoutUpdated(containerLayout.0, navigationBarHeight: containerLayout.1, transition: .immediate)
}

View File

@ -125,9 +125,15 @@ public final class GalleryThumbnailContainerNode: ASDisplayNode, UIScrollViewDel
self.items = items
self.itemNodes = itemNodes
}
var updatedIndexOnly = false
if let centralIndexAndProgress = self.centralIndexAndProgress, centralIndexAndProgress.0 != centralIndex, centralIndexAndProgress.1 == progress {
updatedIndexOnly = true
}
self.centralIndexAndProgress = (centralIndex, progress)
if let size = self.currentLayout {
self.updateLayout(size: size, transition: .immediate)
self.updateLayout(size: size, transition: updatedIndexOnly ? .animated(duration: 0.2, curve: .spring) : .immediate)
}
}

View File

@ -449,8 +449,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if let (previousLayout, _) = self.validLayout, self.dismissOnOrientationChange, previousLayout.size.width > previousLayout.size.height && previousLayout.size.height == layout.size.width {
dismiss = true
}
let hadLayout = self.validLayout != nil
self.validLayout = (layout, navigationBarHeight)
if !hadLayout {
self.zoomableContent = zoomableContent
}
let statusDiameter: CGFloat = 50.0
let statusFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - statusDiameter) / 2.0), y: floor((layout.size.height - statusDiameter) / 2.0)), size: CGSize(width: statusDiameter, height: statusDiameter))
transition.updateFrame(node: self.statusButtonNode, frame: statusFrame)
@ -530,7 +535,6 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
let mediaManager = item.context.sharedContext.mediaManager
let videoNode = UniversalVideoNode(postbox: item.context.account.postbox, audioSession: mediaManager.audioSession, manager: mediaManager.universalVideoManager, decoration: GalleryVideoDecoration(), content: item.content, priority: .gallery)
let videoScale: CGFloat
if item.content is WebEmbedVideoContent {
videoScale = 1.0
@ -578,6 +582,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
self.requiresDownload = true
var mediaFileStatus: Signal<MediaResourceStatus?, NoError> = .single(nil)
var hintSeekable = false
if let contentInfo = item.contentInfo, case let .message(message) = contentInfo {
if Namespaces.Message.allScheduled.contains(message.id.namespace) {
disablePictureInPicture = true
@ -611,6 +617,12 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
}
if let file = file {
for attribute in file.attributes {
if case let .Video(duration, _, _) = attribute, duration >= 30 {
hintSeekable = true
break
}
}
let status = messageMediaFileStatus(context: item.context, messageId: message.id, file: file)
if !isWebpage {
self.scrubberView.setFetchStatusSignal(status, strings: self.presentationData.strings, decimalSeparator: self.presentationData.dateTimeFormat.decimalSeparator, fileSize: file.size)
@ -634,7 +646,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
var initialBuffering = false
var playing = false
var isPaused = true
var seekable = false
var seekable = hintSeekable
var hasStarted = false
var displayProgress = true
if let value = value {
@ -682,13 +694,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if !content.enableSound {
isPaused = false
}
} else {
} else if strongSelf.actionAtEnd == .stop {
strongSelf.updateControlsVisibility(true)
strongSelf.controlsTimer?.invalidate()
strongSelf.controlsTimer = nil
}
}
seekable = value.duration >= 30.0
if !value.duration.isZero {
seekable = value.duration >= 30.0
}
}
if strongSelf.isCentral && playing && strongSelf.previousPlaying != true && !disablePlayerControls {
@ -749,7 +763,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
if hasStarted || strongSelf.didPause {
strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable)
} else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload {
strongSelf.footerContentNode.content = .fetch(status: fetchStatus)
strongSelf.footerContentNode.content = .fetch(status: fetchStatus, seekable: seekable)
}
} else {
strongSelf.footerContentNode.content = .playback(paused: false, seekable: seekable)
@ -773,11 +787,17 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
}
self._rightBarButtonItems.set(.single(barButtonItems))
videoNode.playbackCompleted = { [weak videoNode] in
videoNode.playbackCompleted = { [weak self, weak videoNode] in
Queue.mainQueue().async {
item.playbackCompleted()
if !isAnimated {
if let strongSelf = self, !isAnimated {
videoNode?.seek(0.0)
if strongSelf.actionAtEnd == .stop {
strongSelf.updateControlsVisibility(true)
strongSelf.controlsTimer?.invalidate()
strongSelf.controlsTimer = nil
}
}
}
}

View File

@ -208,6 +208,7 @@ public final class SecretMediaPreviewController: ViewController {
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { _, _ in
}, editMedia: { _ in
})
self.displayNode = SecretMediaPreviewControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -1228,7 +1228,15 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
if let map = media.media as? TelegramMediaMap {
let controller = legacyLocationController(message: nil, mapMedia: map, context: self.context, openPeer: { _ in }, sendLiveLocation: { _, _ in }, stopLiveLocation: { }, openUrl: { _ in })
let controllerParams = LocationViewParams(sendLiveLocation: { _ in
}, stopLiveLocation: { _ in
}, openUrl: { _ in }, openPeer: { _ in
}, showAll: false)
let peer = TelegramUser(id: PeerId(namespace: Namespaces.Peer.CloudUser, id: 1), accessHash: nil, firstName: "", lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [])
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer, text: "", attributes: [], media: [map], peers: SimpleDictionary(), associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let controller = LocationViewController(context: self.context, subject: message, params: controllerParams)
self.pushController(controller)
return
}

View File

@ -358,12 +358,13 @@ public class InstantPageGalleryController: ViewController, StandalonePresentable
if let strongSelf = self {
strongSelf.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
}
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { [weak self] controller, ready in
if let strongSelf = self {
strongSelf.replaceRootController(controller, ready)
}
}, dismissController: { [weak self] in
self?.dismiss(forceAway: true)
}, replaceRootController: { [weak self] controller, ready in
if let strongSelf = self {
strongSelf.replaceRootController(controller, ready)
}
}, editMedia: { _ in
})
self.displayNode = GalleryControllerNode(controllerInteraction: controllerInteraction)
self.displayNodeDidLoad()

View File

@ -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)

View File

@ -457,9 +457,9 @@ class ItemListStickerPackItemNode: ItemListRevealOptionsItemNode {
}
if let editableControlSizeAndApply = editableControlSizeAndApply {
let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: layout.size.height))
let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: layout.contentSize.height))
if strongSelf.editableControlNode == nil {
let editableControlNode = editableControlSizeAndApply.1(layout.size.height)
let editableControlNode = editableControlSizeAndApply.1(layout.contentSize.height)
editableControlNode.tapped = {
if let strongSelf = self {
strongSelf.setRevealOptionsOpened(true, animated: true)

View File

@ -136,15 +136,7 @@
#import <LegacyComponents/TGLiveUploadInterface.h>
#import <LegacyComponents/TGLocalMessageMetaMediaAttachment.h>
#import <LegacyComponents/TGLocalization.h>
#import <LegacyComponents/TGLocationLiveElapsedView.h>
#import <LegacyComponents/TGLocationLiveSessionItemView.h>
#import <LegacyComponents/TGLocationMapViewController.h>
#import <LegacyComponents/TGLocationMediaAttachment.h>
#import <LegacyComponents/TGLocationPickerController.h>
#import <LegacyComponents/TGLocationPulseView.h>
#import <LegacyComponents/TGLocationVenue.h>
#import <LegacyComponents/TGLocationViewController.h>
#import <LegacyComponents/TGLocationWavesView.h>
#import <LegacyComponents/TGMediaAsset.h>
#import <LegacyComponents/TGMediaAssetFetchResult.h>
#import <LegacyComponents/TGMediaAssetFetchResultChange.h>
@ -267,8 +259,6 @@
#import <LegacyComponents/TGRemoteImageView.h>
#import <LegacyComponents/TGReplyMarkupAttachment.h>
#import <LegacyComponents/TGReplyMessageMediaAttachment.h>
#import <LegacyComponents/TGSearchBar.h>
#import <LegacyComponents/TGSearchDisplayMixin.h>
#import <LegacyComponents/TGStaticBackdropAreaData.h>
#import <LegacyComponents/TGStaticBackdropImageData.h>
#import <LegacyComponents/TGStickerAssociation.h>
@ -294,7 +284,6 @@
#import <LegacyComponents/TGWebPageMediaAttachment.h>
#import <LegacyComponents/UICollectionView+Utils.h>
#import <LegacyComponents/UIControl+HitTestEdgeInsets.h>
#import <LegacyComponents/UIDevice+PlatformInfo.h>
#import <LegacyComponents/UIImage+TG.h>
#import <LegacyComponents/UIImage+TGMediaEditableItem.h>
#import <LegacyComponents/UIScrollView+TGHacks.h>

View File

@ -58,10 +58,6 @@ typedef enum {
- (id<LegacyComponentsAccessChecker>)accessChecker;
- (SSignal *)stickerPacksSignal;
- (SSignal *)maskStickerPacksSignal;
- (SSignal *)recentStickerMasksSignal;
- (id<SDisposable>)requestAudioSession:(TGAudioSessionType)type interrupted:(void (^)())interrupted;
- (SThreadPool *)sharedMediaImageProcessingThreadPool;
@ -71,11 +67,6 @@ typedef enum {
- (NSString *)localDocumentDirectoryForLocalDocumentId:(int64_t)localDocumentId version:(int32_t)version;
- (NSString *)localDocumentDirectoryForDocumentId:(int64_t)documentId version:(int32_t)version;
- (SSignal *)jsonForHttpLocation:(NSString *)httpLocation;
- (SSignal *)dataForHttpLocation:(NSString *)httpLocation;
- (NSOperation<LegacyHTTPRequestOperation> *)makeHTTPRequestOperationWithRequest:(NSURLRequest *)request;
- (void)pausePictureInPicturePlayback;
- (void)resumePictureInPicturePlayback;
- (void)maybeReleaseVolumeOverlay;

View File

@ -1,8 +0,0 @@
#import <UIKit/UIKit.h>
@interface TGLocationLiveElapsedView : UIView
- (void)setColor:(UIColor *)color;
- (void)setRemaining:(int32_t)remaining period:(int32_t)period;
@end

View File

@ -1,12 +0,0 @@
#import <LegacyComponents/LegacyComponents.h>
#import <LegacyComponents/TGMenuSheetButtonItemView.h>
#import <SSignalKit/SSignalKit.h>
@class TGUser;
@class TGMessage;
@interface TGLocationLiveSessionItemView : TGMenuSheetButtonItemView
- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer remaining:(SSignal *)remaining action:(void (^)(void))action;
@end

View File

@ -1,84 +0,0 @@
#import <LegacyComponents/TGViewController.h>
#import <LegacyComponents/LegacyComponentsContext.h>
#import <MapKit/MapKit.h>
#import <SSignalKit/SSignalKit.h>
@class TGLocationMapView;
@class TGLocationOptionsView;
@class TGSearchBarPallete;
@interface TGLocationPallete : NSObject
@property (nonatomic, readonly) UIColor *backgroundColor;
@property (nonatomic, readonly) UIColor *selectionColor;
@property (nonatomic, readonly) UIColor *separatorColor;
@property (nonatomic, readonly) UIColor *textColor;
@property (nonatomic, readonly) UIColor *secondaryTextColor;
@property (nonatomic, readonly) UIColor *accentColor;
@property (nonatomic, readonly) UIColor *destructiveColor;
@property (nonatomic, readonly) UIColor *locationColor;
@property (nonatomic, readonly) UIColor *liveLocationColor;
@property (nonatomic, readonly) UIColor *iconColor;
@property (nonatomic, readonly) UIColor *sectionHeaderBackgroundColor;
@property (nonatomic, readonly) UIColor *sectionHeaderTextColor;
@property (nonatomic, readonly) TGSearchBarPallete *searchBarPallete;
@property (nonatomic, readonly) UIImage *avatarPlaceholder;
+ (instancetype)palleteWithBackgroundColor:(UIColor *)backgroundColor selectionColor:(UIColor *)selectionColor separatorColor:(UIColor *)separatorColor textColor:(UIColor *)textColor secondaryTextColor:(UIColor *)secondaryTextColor accentColor:(UIColor *)accentColor destructiveColor:(UIColor *)destructiveColor locationColor:(UIColor *)locationColor liveLocationColor:(UIColor *)liveLocationColor iconColor:(UIColor *)iconColor sectionHeaderBackgroundColor:(UIColor *)sectionHeaderBackgroundColor sectionHeaderTextColor:(UIColor *)sectionHeaderTextColor searchBarPallete:(TGSearchBarPallete *)searchBarPallete avatarPlaceholder:(UIImage *)avatarPlaceholder;
@end
@interface TGLocationMapViewController : TGViewController <UITableViewDataSource, UITableViewDelegate, UIScrollViewDelegate, MKMapViewDelegate>
{
CLLocationManager *_locationManager;
bool _locationServicesDisabled;
CGFloat _tableViewTopInset;
CGFloat _tableViewBottomInset;
UITableView *_tableView;
UIActivityIndicatorView *_activityIndicator;
UILabel *_messageLabel;
UIView *_mapViewWrapper;
TGLocationMapView *_mapView;
TGLocationOptionsView *_optionsView;
UIImageView *_edgeView;
UIImageView *_edgeHighlightView;
}
@property (nonatomic, copy) void (^liveLocationStarted)(CLLocationCoordinate2D coordinate, int32_t period);
@property (nonatomic, copy) void (^liveLocationStopped)(void);
@property (nonatomic, strong) TGLocationPallete *pallete;
@property (nonatomic, readonly, strong) UIView *locationMapView;
- (void)userLocationButtonPressed;
- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate offset:(CGPoint)offset animated:(bool)animated;
- (void)setMapCenterCoordinate:(CLLocationCoordinate2D)coordinate span:(MKCoordinateSpan)span offset:(CGPoint)offset animated:(bool)animated;
- (void)updateInsets;
- (void)updateMapHeightAnimated:(bool)animated;
- (CGFloat)visibleContentHeight;
- (CGFloat)mapHeight;
- (CGFloat)safeAreaInsetBottom;
- (bool)hasUserLocation;
- (SSignal *)userLocationSignal;
- (bool)locationServicesDisabled;
- (void)updateLocationAvailability;
@property (nonatomic, strong) id receivingPeer;
- (void)_presentLiveLocationMenu:(CLLocationCoordinate2D)coordinate dismissOnCompletion:(bool)dismissOnCompletion;
- (CGRect)_liveLocationMenuSourceRect;
- (void)_willStartOwnLiveLocation;
@end
extern const CGFloat TGLocationMapInset;
extern const CGFloat TGLocationMapClipHeight;
extern const MKCoordinateSpan TGLocationDefaultSpan;

View File

@ -1,29 +0,0 @@
#import <LegacyComponents/TGLocationMapViewController.h>
#import <LegacyComponents/LegacyComponentsContext.h>
#import <CoreLocation/CoreLocation.h>
@class TGVenueAttachment;
@class TGUser;
@class TGMessage;
typedef enum {
TGLocationPickerControllerDefaultIntent,
TGLocationPickerControllerCustomLocationIntent
} TGLocationPickerControllerIntent;
@interface TGLocationPickerController : TGLocationMapViewController
@property (nonatomic, copy) void (^locationPicked)(CLLocationCoordinate2D coordinate, TGVenueAttachment *venue, NSString *address);
@property (nonatomic, copy) SSignal *(^nearbyPlacesSignal)(NSString *query, CLLocation *coordinate);
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context intent:(TGLocationPickerControllerIntent)intent;
- (void)setLiveLocationsSignal:(SSignal *)signal;
@property (nonatomic, copy) SSignal *(^remainingTimeForMessage)(TGMessage *message);
@property (nonatomic, strong) id peer;
@property (nonatomic, assign) bool allowLiveLocationSharing;
@end

View File

@ -1,8 +0,0 @@
#import <UIKit/UIKit.h>
@interface TGLocationPulseView : UIView
- (void)start;
- (void)stop;
@end

View File

@ -1,34 +0,0 @@
#import <CoreLocation/CoreLocation.h>
@class TGVenueAttachment;
@class TGLocationMediaAttachment;
@interface TGLocationVenue : NSObject
@property (nonatomic, readonly) NSString *identifier;
@property (nonatomic, readonly) NSString *name;
@property (nonatomic, readonly) NSString *displayAddress;
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, readonly) NSString *categoryName;
@property (nonatomic, readonly) NSURL *categoryIconUrl;
@property (nonatomic, readonly) NSString *provider;
@property (readonly, nonatomic) NSString *country;
@property (readonly, nonatomic) NSString *state;
@property (readonly, nonatomic) NSString *city;
@property (readonly, nonatomic) NSString *address;
@property (readonly, nonatomic) NSString *crossStreet;
@property (readonly, nonatomic) NSString *street;
- (TGVenueAttachment *)venueAttachment;
+ (TGLocationVenue *)venueWithFoursquareDictionary:(NSDictionary *)dictionary;
+ (TGLocationVenue *)venueWithGooglePlacesDictionary:(NSDictionary *)dictionary;
+ (TGLocationVenue *)venueWithLocationAttachment:(TGLocationMediaAttachment *)attachment;
@end
extern NSString *const TGLocationGooglePlacesVenueProvider;
extern NSString *const TGLocationFoursquareVenueProvider;

View File

@ -1,59 +0,0 @@
#import <LegacyComponents/LegacyComponentsContext.h>
#import <LegacyComponents/TGLocationMapViewController.h>
#import <CoreLocation/CoreLocation.h>
@class TGLocationMediaAttachment;
@class TGVenueAttachment;
@class TGMenuSheetController;
@class TGMessage;
@class TGUser;
@interface TGLiveLocation : NSObject
@property (nonatomic, strong, readonly) TGMessage *message;
@property (nonatomic, strong, readonly) id peer;
@property (nonatomic, readonly) bool hasOwnSession;
@property (nonatomic, readonly) bool isOwnLocation;
@property (nonatomic, readonly) bool isExpired;
- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer hasOwnSession:(bool)hasOwnSession isOwnLocation:(bool)isOwnLocation isExpired:(bool)isExpired;
- (instancetype)initWithMessage:(TGMessage *)message peer:(id)peer;
- (int64_t)peerId;
@end
@interface TGLocationViewController : TGLocationMapViewController;
@property (nonatomic, assign) bool modalMode;
@property (nonatomic, assign) bool previewMode;
@property (nonatomic, assign) bool allowLiveLocationSharing;
@property (nonatomic, assign) bool zoomToFitAllLocationsOnScreen;
@property (nonatomic, copy) void (^presentActionsMenu)(TGLocationMediaAttachment *, bool);
@property (nonatomic, copy) bool (^presentShareMenu)(TGMenuSheetController *, CLLocationCoordinate2D);
@property (nonatomic, copy) bool (^presentOpenInMenu)(TGLocationViewController *, TGLocationMediaAttachment *, bool, void (^)(TGMenuSheetController *));
@property (nonatomic, copy) void (^shareAction)(NSArray *peerIds, NSString *caption);
@property (nonatomic, copy) void (^openLocation)(TGMessage *message);
@property (nonatomic, copy) void (^onViewDidAppear)(void);
@property (nonatomic, copy) void (^updateRightBarItem)(UIBarButtonItem *, bool, bool);
@property (nonatomic, readonly) UIButton *directionsButton;
@property (nonatomic, copy) SSignal *(^remainingTimeForMessage)(TGMessage *message);
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context liveLocation:(TGLiveLocation *)liveLocation;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context locationAttachment:(TGLocationMediaAttachment *)locationAttachment peer:(id)peer color:(UIColor *)color;
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context message:(TGMessage *)message peer:(id)peer color:(UIColor *)color;
- (void)actionsButtonPressed;
- (void)setLiveLocationsSignal:(SSignal *)signal;
- (void)setFrequentUpdatesHandle:(id<SDisposable>)disposable;
@end

View File

@ -1,11 +0,0 @@
#import <UIKit/UIKit.h>
@interface TGLocationWavesView : UIView
@property (nonatomic, strong) UIColor *color;
- (void)invalidate;
- (void)start;
- (void)stop;
@end

View File

@ -50,4 +50,6 @@
- (instancetype)initWithContext:(id<LegacyComponentsContext>)context items:(NSArray *)items focusItem:(id<TGModernGalleryItem>)focusItem selectionContext:(TGMediaSelectionContext *)selectionContext editingContext:(TGMediaEditingContext *)editingContext hasCaptions:(bool)hasCaptions allowCaptionEntities:(bool)allowCaptionEntities hasTimer:(bool)hasTimer onlyCrop:(bool)onlyCrop inhibitDocumentCaptions:(bool)inhibitDocumentCaptions hasSelectionPanel:(bool)hasSelectionPanel hasCamera:(bool)hasCamera recipientName:(NSString *)recipientName;
- (void)presentPhotoEditorForItem:(id<TGModernGalleryEditableItem>)item tab:(TGPhotoEditorTab)tab;
@end

View File

@ -4,6 +4,6 @@
+ (void)presentWithContext:(id<LegacyComponentsContext>)context parentController:(TGViewController *)parentController image:(UIImage *)image video:(NSURL *)video didFinishWithImage:(void (^)(UIImage *image))didFinishWithImage didFinishWithVideo:(void (^)(UIImage *image, NSURL *url, TGVideoEditAdjustments *adjustments))didFinishWithVideo dismissed:(void (^)(void))dismissed;
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
+ (void)presentWithContext:(id<LegacyComponentsContext>)context controller:(TGViewController *)controller caption:(NSString *)caption entities:(NSArray *)entities withItem:(id<TGMediaEditableItem, TGMediaSelectableItem>)item paint:(bool)paint recipientName:(NSString *)recipientName stickersContext:(id<TGPhotoPaintStickersContext>)stickersContext completion:(void (^)(id<TGMediaEditableItem>, TGMediaEditingContext *))completion dismissed:(void (^)())dismissed;
@end

View File

@ -1,94 +0,0 @@
#import <UIKit/UIKit.h>
@class TGSearchBar;
typedef enum {
TGSearchBarStyleDefault = 0,
TGSearchBarStyleDark = 1,
TGSearchBarStyleLight = 2,
TGSearchBarStyleLightPlain = 3,
TGSearchBarStyleLightAlwaysPlain = 4,
TGSearchBarStyleHeader = 5,
TGSearchBarStyleKeyboard = 6
} TGSearchBarStyle;
@protocol TGSearchBarDelegate <UISearchBarDelegate>
- (void)searchBar:(TGSearchBar *)searchBar willChangeHeight:(CGFloat)newHeight;
@end
@interface TGSearchBarPallete : NSObject
@property (nonatomic, readonly) bool isDark;
@property (nonatomic, readonly) UIColor *backgroundColor;
@property (nonatomic, readonly) UIColor *highContrastBackgroundColor;
@property (nonatomic, readonly) UIColor *textColor;
@property (nonatomic, readonly) UIColor *placeholderColor;
@property (nonatomic, readonly) UIImage *clearIcon;
@property (nonatomic, readonly) UIColor *barBackgroundColor;
@property (nonatomic, readonly) UIColor *barSeparatorColor;
@property (nonatomic, readonly) UIColor *plainBackgroundColor;
@property (nonatomic, readonly) UIColor *accentColor;
@property (nonatomic, readonly) UIColor *accentContrastColor;
@property (nonatomic, readonly) UIColor *menuBackgroundColor;
@property (nonatomic, readonly) UIImage *segmentedControlBackgroundImage;
@property (nonatomic, readonly) UIImage *segmentedControlSelectedImage;
@property (nonatomic, readonly) UIImage *segmentedControlHighlightedImage;
@property (nonatomic, readonly) UIImage *segmentedControlDividerImage;
+ (instancetype)palleteWithDark:(bool)dark backgroundColor:(UIColor *)backgroundColor highContrastBackgroundColor:(UIColor *)highContrastBackgroundColor textColor:(UIColor *)textColor placeholderColor:(UIColor *)placeholderColor clearIcon:(UIImage *)clearIcon barBackgroundColor:(UIColor *)barBackgroundColor barSeparatorColor:(UIColor *)barSeparatorColor plainBackgroundColor:(UIColor *)plainBackgroundColor accentColor:(UIColor *)accentColor accentContrastColor:(UIColor *)accentContrastColor menuBackgroundColor:(UIColor *)menuBackgroundColor segmentedControlBackgroundImage:(UIImage *)segmentedControlBackgroundImage segmentedControlSelectedImage:(UIImage *)segmentedControlSelectedImage segmentedControlHighlightedImage:(UIImage *)segmentedControlHighlightedImage segmentedControlDividerImage:(UIImage *)segmentedControlDividerImage;
@end
@interface TGSearchBar : UIView
+ (CGFloat)searchBarBaseHeight;
+ (CGFloat)searchBarScopeHeight;
- (CGFloat)baseHeight;
@property (nonatomic, copy) void (^clearPrefix)(bool);
@property (nonatomic, assign) UIEdgeInsets safeAreaInset;
@property (nonatomic, weak) id<TGSearchBarDelegate> delegate;
@property (nonatomic) bool highContrast;
@property (nonatomic, strong) UITextField *customTextField;
@property (nonatomic, readonly) UITextField *maybeCustomTextField;
@property (nonatomic, strong) UIImageView *customBackgroundView;
@property (nonatomic, strong) UIImageView *customActiveBackgroundView;
@property (nonatomic, strong) NSArray *customScopeButtonTitles;
@property (nonatomic) NSInteger selectedScopeButtonIndex;
@property (nonatomic) bool showsScopeBar;
@property (nonatomic) bool scopeBarCollapsed;
@property (nonatomic) bool searchBarShouldShowScopeControl;
@property (nonatomic) bool alwaysExtended;
@property (nonatomic) bool hidesCancelButton;
@property (nonatomic, strong) UIButton *customCancelButton;
@property (nonatomic) TGSearchBarStyle style;
@property (nonatomic, strong) NSString *text;
@property (nonatomic, strong) NSString *placeholder;
@property (nonatomic, strong) NSAttributedString *prefixText;
@property (nonatomic) bool showActivity;
@property (nonatomic) bool delayActivity;
- (instancetype)initWithFrame:(CGRect)frame style:(TGSearchBarStyle)style;
- (void)setShowsCancelButton:(bool)showsCancelButton animated:(bool)animated;
- (void)setCustomScopeBarHidden:(bool)hidden;
- (void)updateClipping:(CGFloat)clippedHeight;
- (void)localizationUpdated;
- (void)setPallete:(TGSearchBarPallete *)pallete;
@end

View File

@ -1,46 +0,0 @@
#import <UIKit/UIKit.h>
@class TGSearchDisplayMixin;
@class TGSearchBar;
@protocol TGSearchDisplayMixinDelegate <NSObject>
@required
- (UITableView *)createTableViewForSearchMixin:(TGSearchDisplayMixin *)searchMixin;
- (UIView *)referenceViewForSearchResults;
- (void)searchMixin:(TGSearchDisplayMixin *)searchMixin hasChangedSearchQuery:(NSString *)searchQuery withScope:(int)scope;
@optional
- (void)searchMixinWillActivate:(bool)animated;
- (void)searchMixinWillDeactivate:(bool)animated;
@end
@interface TGSearchDisplayMixin : NSObject
@property (nonatomic, weak) id<TGSearchDisplayMixinDelegate> delegate;
@property (nonatomic, strong) TGSearchBar *searchBar;
@property (nonatomic) bool isActive;
@property (nonatomic, strong) UITableView *searchResultsTableView;
@property (nonatomic) bool alwaysShowsCancelButton;
@property (nonatomic) bool searchResultsTableViewHidden;
@property (nonatomic) bool simpleLayout;
- (void)setSearchResultsTableViewHidden:(bool)searchResultsTableViewHidden animated:(bool)animated;
- (void)setIsActive:(bool)isActive animated:(bool)animated;
- (void)controllerInsetUpdated:(UIEdgeInsets)controllerInset;
- (void)controllerLayoutUpdated:(CGSize)layoutSize;
- (void)reloadSearchResults;
- (void)resignResponderIfAny;
- (void)unload;
@end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Some files were not shown because too many files have changed in this diff Show More