mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-01 07:57:01 +00:00
Merge commit '2984ca1bfe0ce9c95055d007a906ece0f872195b'
This commit is contained in:
commit
2a39e417bd
@ -10,5 +10,5 @@ public protocol ChatListController: ViewController {
|
||||
func activateSearch()
|
||||
func deactivateSearch(animated: Bool)
|
||||
func activateCompose()
|
||||
func maybeAskForPeerChatRemoval(peer: RenderedPeer, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void)
|
||||
func maybeAskForPeerChatRemoval(peer: RenderedPeer, joined: Bool, deleteGloballyIfPossible: Bool, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void)
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ enum ChatContextMenuSource {
|
||||
case search(ChatListSearchContextActionSource)
|
||||
}
|
||||
|
||||
func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: ChatListNodeEntryPromoInfo?, source: ChatContextMenuSource, chatListController: ChatListControllerImpl?) -> Signal<[ContextMenuItem], NoError> {
|
||||
func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: ChatListNodeEntryPromoInfo?, source: ChatContextMenuSource, chatListController: ChatListControllerImpl?, joined: Bool) -> Signal<[ContextMenuItem], NoError> {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with({ $0 })
|
||||
let strings = presentationData.strings
|
||||
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in
|
||||
@ -233,7 +233,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { c, _ in
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController))
|
||||
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined))
|
||||
})))
|
||||
|
||||
return updatedItems
|
||||
@ -379,7 +379,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
|
||||
if case .chatList = source, groupAndIndex != nil {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Delete, textColor: .destructive, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor) }, action: { _, f in
|
||||
if let chatListController = chatListController {
|
||||
chatListController.deletePeerChat(peerId: peerId)
|
||||
chatListController.deletePeerChat(peerId: peerId, joined: joined)
|
||||
}
|
||||
f(.default)
|
||||
})))
|
||||
|
@ -575,11 +575,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
strongSelf.hidePsa(peerId)
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.containerNode.deletePeerChat = { [weak self] peerId in
|
||||
self.chatListDisplayNode.containerNode.deletePeerChat = { [weak self] peerId, joined in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.deletePeerChat(peerId: peerId)
|
||||
strongSelf.deletePeerChat(peerId: peerId, joined: joined)
|
||||
}
|
||||
|
||||
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, promoInfo in
|
||||
@ -801,6 +801,16 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
gesture?.cancel()
|
||||
return
|
||||
}
|
||||
|
||||
var joined = false
|
||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||
joined = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch item.content {
|
||||
case let .groupReference(groupReference):
|
||||
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupReference.groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false)
|
||||
@ -810,7 +820,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
case let .peer(_, peer, _, _, _, _, _, _, promoInfo, _, _, _):
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.peerId), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter), chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.peerId, promoInfo: promoInfo, source: .chatList(filter: strongSelf.chatListDisplayNode.containerNode.currentItemNode.chatListFilter), chatListController: strongSelf, joined: joined), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
}
|
||||
@ -823,7 +833,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(peer.id), subject: nil, botStart: nil, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf), reactionItems: [], gesture: gesture)
|
||||
let contextController = ContextController(account: strongSelf.context.account, presentationData: strongSelf.presentationData, source: .controller(ContextControllerContentSourceImpl(controller: chatController, sourceNode: node, navigationController: strongSelf.navigationController as? NavigationController)), items: chatContextMenuItems(context: strongSelf.context, peerId: peer.id, promoInfo: nil, source: .search(source), chatListController: strongSelf, joined: false), reactionItems: [], gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
|
||||
@ -2069,7 +2079,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
let _ = hideAccountPromoInfoChat(account: self.context.account, peerId: id).start()
|
||||
}
|
||||
|
||||
func deletePeerChat(peerId: PeerId) {
|
||||
func deletePeerChat(peerId: PeerId, joined: Bool) {
|
||||
let _ = (self.context.account.postbox.transaction { transaction -> RenderedPeer? in
|
||||
guard let peer = transaction.getPeer(peerId) else {
|
||||
return nil
|
||||
@ -2099,7 +2109,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
}
|
||||
|
||||
if let user = chatPeer as? TelegramUser, user.botInfo == nil, canRemoveGlobally {
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, completion: { _ in }, removed: {})
|
||||
strongSelf.maybeAskForPeerChatRemoval(peer: peer, joined: joined, completion: { _ in }, removed: {})
|
||||
} else {
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
@ -2189,16 +2199,24 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
if canRemoveGlobally {
|
||||
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forLocalPeer)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
|
||||
if joined || mainPeer.isDeleted {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.Common_Delete, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
} else {
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forEveryone)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak actionSheet] in
|
||||
beginClear(.forLocalPeer)
|
||||
actionSheet?.dismissAnimated()
|
||||
}))
|
||||
}
|
||||
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
@ -2258,7 +2276,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
})
|
||||
}
|
||||
|
||||
public func maybeAskForPeerChatRemoval(peer: RenderedPeer, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) {
|
||||
public func maybeAskForPeerChatRemoval(peer: RenderedPeer, joined: Bool = false, deleteGloballyIfPossible: Bool = false, completion: @escaping (Bool) -> Void, removed: @escaping () -> Void) {
|
||||
guard let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
|
||||
completion(false)
|
||||
return
|
||||
@ -2279,31 +2297,41 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
|
||||
var items: [ActionSheetItem] = []
|
||||
|
||||
items.append(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
completion(false)
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forEveryone, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forLocalPeer, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
}))
|
||||
|
||||
if joined || mainPeer.isDeleted {
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.Common_Delete, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forEveryone, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
}))
|
||||
} else {
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
|
||||
completion(false)
|
||||
}),
|
||||
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteForEveryoneConfirmationAction, action: {
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forEveryone, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
})
|
||||
], parseMarkdown: true), in: .window(.root))
|
||||
}))
|
||||
items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForCurrentUser, color: .destructive, action: { [weak self, weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
self?.schedulePeerChatRemoval(peer: peer, type: .forLocalPeer, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: {
|
||||
removed()
|
||||
})
|
||||
completion(true)
|
||||
}))
|
||||
}
|
||||
actionSheet.setItemGroups([
|
||||
ActionSheetItemGroup(items: items),
|
||||
ActionSheetItemGroup(items: [
|
||||
|
@ -195,7 +195,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
|
||||
let timestamp1: Int32 = 100000
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in }, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
||||
@ -478,8 +478,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
itemNode.listNode.hidePsa = { [weak self] peerId in
|
||||
self?.hidePsa?(peerId)
|
||||
}
|
||||
itemNode.listNode.deletePeerChat = { [weak self] peerId in
|
||||
self?.deletePeerChat?(peerId)
|
||||
itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
|
||||
self?.deletePeerChat?(peerId, joined)
|
||||
}
|
||||
itemNode.listNode.peerSelected = { [weak self] peerId, a, b in
|
||||
self?.peerSelected?(peerId, a, b)
|
||||
@ -527,7 +527,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
||||
var present: ((ViewController) -> Void)?
|
||||
var toggleArchivedFolderHiddenByDefault: (() -> Void)?
|
||||
var hidePsa: ((PeerId) -> Void)?
|
||||
var deletePeerChat: ((PeerId) -> Void)?
|
||||
var deletePeerChat: ((PeerId, Bool) -> Void)?
|
||||
var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||
var groupSelected: ((PeerGroupId) -> Void)?
|
||||
var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
||||
|
@ -1028,7 +1028,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
||||
}
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, deletePeer: { _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
}, togglePeerMarkedUnread: { _, _ in
|
||||
}, toggleArchivedFolderHiddenByDefault: {
|
||||
|
@ -1946,7 +1946,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
item.interaction.setPeerMuted(item.index.messageIndex.id.peerId, false)
|
||||
close = false
|
||||
case RevealOptionKey.delete.rawValue:
|
||||
item.interaction.deletePeer(item.index.messageIndex.id.peerId)
|
||||
var joined = false
|
||||
if case let .peer(messages, _, _, _, _, _, _, _, _, _, _, _) = item.content, let message = messages.first {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction, action.action == .peerJoined {
|
||||
joined = true
|
||||
}
|
||||
}
|
||||
}
|
||||
item.interaction.deletePeer(item.index.messageIndex.id.peerId, joined)
|
||||
case RevealOptionKey.archive.rawValue:
|
||||
item.interaction.updatePeerGrouping(item.index.messageIndex.id.peerId, true)
|
||||
close = false
|
||||
|
@ -59,7 +59,7 @@ public final class ChatListNodeInteraction {
|
||||
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
|
||||
let setItemPinned: (PinnedItemId, Bool) -> Void
|
||||
let setPeerMuted: (PeerId, Bool) -> Void
|
||||
let deletePeer: (PeerId) -> Void
|
||||
let deletePeer: (PeerId, Bool) -> Void
|
||||
let updatePeerGrouping: (PeerId, Bool) -> Void
|
||||
let togglePeerMarkedUnread: (PeerId, Bool) -> Void
|
||||
let toggleArchivedFolderHiddenByDefault: () -> Void
|
||||
@ -70,7 +70,7 @@ public final class ChatListNodeInteraction {
|
||||
public var searchTextHighightState: String?
|
||||
var highlightedChatLocation: ChatListHighlightedLocation?
|
||||
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
public init(activateSearch: @escaping () -> Void, peerSelected: @escaping (Peer, ChatListNodeEntryPromoInfo?) -> Void, disabledPeerSelected: @escaping (Peer) -> Void, togglePeerSelected: @escaping (PeerId) -> Void, additionalCategorySelected: @escaping (Int) -> Void, messageSelected: @escaping (Peer, Message, ChatListNodeEntryPromoInfo?) -> Void, groupSelected: @escaping (PeerGroupId) -> Void, addContact: @escaping (String) -> Void, setPeerIdWithRevealedOptions: @escaping (PeerId?, PeerId?) -> Void, setItemPinned: @escaping (PinnedItemId, Bool) -> Void, setPeerMuted: @escaping (PeerId, Bool) -> Void, deletePeer: @escaping (PeerId, Bool) -> Void, updatePeerGrouping: @escaping (PeerId, Bool) -> Void, togglePeerMarkedUnread: @escaping (PeerId, Bool) -> Void, toggleArchivedFolderHiddenByDefault: @escaping () -> Void, hidePsa: @escaping (PeerId) -> Void, activateChatPreview: @escaping (ChatListItem, ASDisplayNode, ContextGesture?) -> Void, present: @escaping (ViewController) -> Void) {
|
||||
self.activateSearch = activateSearch
|
||||
self.peerSelected = peerSelected
|
||||
self.disabledPeerSelected = disabledPeerSelected
|
||||
@ -430,7 +430,7 @@ public final class ChatListNode: ListView {
|
||||
public var groupSelected: ((PeerGroupId) -> Void)?
|
||||
public var addContact: ((String) -> Void)?
|
||||
public var activateSearch: (() -> Void)?
|
||||
public var deletePeerChat: ((PeerId) -> Void)?
|
||||
public var deletePeerChat: ((PeerId, Bool) -> Void)?
|
||||
public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
|
||||
public var presentAlert: ((String) -> Void)?
|
||||
public var present: ((ViewController) -> Void)?
|
||||
@ -628,8 +628,8 @@ public final class ChatListNode: ListView {
|
||||
}
|
||||
self?.setCurrentRemovingPeerId(nil)
|
||||
})
|
||||
}, deletePeer: { [weak self] peerId in
|
||||
self?.deletePeerChat?(peerId)
|
||||
}, deletePeer: { [weak self] peerId, joined in
|
||||
self?.deletePeerChat?(peerId, joined)
|
||||
}, updatePeerGrouping: { [weak self] peerId, group in
|
||||
self?.updatePeerGrouping?(peerId, group)
|
||||
}, togglePeerMarkedUnread: { [weak self, weak context] peerId, animated in
|
||||
|
@ -184,6 +184,8 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
|
||||
public final var keepMinimalScrollHeightWithTopInset: CGFloat?
|
||||
|
||||
public final var itemNodeHitTest: ((CGPoint) -> Bool)?
|
||||
|
||||
public final var stackFromBottom: Bool = false
|
||||
public final var stackFromBottomInsetItemFactor: CGFloat = 0.0
|
||||
public final var limitHitTestToNodes: Bool = false
|
||||
@ -3876,67 +3878,73 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
|
||||
}
|
||||
|
||||
self.touchesPosition = touchesPosition
|
||||
self.selectionTouchLocation = touches.first!.location(in: self.view)
|
||||
|
||||
self.selectionTouchDelayTimer?.invalidate()
|
||||
self.selectionLongTapDelayTimer?.invalidate()
|
||||
self.selectionLongTapDelayTimer = nil
|
||||
let timer = Timer(timeInterval: 0.08, target: ListViewTimerProxy { [weak self] in
|
||||
if let strongSelf = self, strongSelf.selectionTouchLocation != nil {
|
||||
strongSelf.clearHighlightAnimated(false)
|
||||
|
||||
if let index = strongSelf.itemIndexAtPoint(strongSelf.touchesPosition) {
|
||||
var canBeSelectedOrLongTapped = false
|
||||
for itemNode in strongSelf.itemNodes {
|
||||
if itemNode.index == index && (strongSelf.items[index].selectable && itemNode.canBeSelected) || itemNode.canBeLongTapped {
|
||||
canBeSelectedOrLongTapped = true
|
||||
}
|
||||
}
|
||||
var processSelection = true
|
||||
if let itemNodeHitTest = self.itemNodeHitTest, !itemNodeHitTest(touchesPosition) {
|
||||
processSelection = false
|
||||
}
|
||||
|
||||
if processSelection {
|
||||
self.selectionTouchLocation = touches.first!.location(in: self.view)
|
||||
self.selectionTouchDelayTimer?.invalidate()
|
||||
self.selectionLongTapDelayTimer?.invalidate()
|
||||
self.selectionLongTapDelayTimer = nil
|
||||
let timer = Timer(timeInterval: 0.08, target: ListViewTimerProxy { [weak self] in
|
||||
if let strongSelf = self, strongSelf.selectionTouchLocation != nil {
|
||||
strongSelf.clearHighlightAnimated(false)
|
||||
|
||||
if canBeSelectedOrLongTapped {
|
||||
strongSelf.highlightedItemIndex = index
|
||||
if let index = strongSelf.itemIndexAtPoint(strongSelf.touchesPosition) {
|
||||
var canBeSelectedOrLongTapped = false
|
||||
for itemNode in strongSelf.itemNodes {
|
||||
if itemNode.index == index && itemNode.canBeSelected {
|
||||
if true {
|
||||
if !itemNode.isLayerBacked {
|
||||
strongSelf.reorderItemNodeToFront(itemNode)
|
||||
for (_, headerNode) in strongSelf.itemHeaderNodes {
|
||||
strongSelf.reorderHeaderNodeToFront(headerNode)
|
||||
if itemNode.index == index && (strongSelf.items[index].selectable && itemNode.canBeSelected) || itemNode.canBeLongTapped {
|
||||
canBeSelectedOrLongTapped = true
|
||||
}
|
||||
}
|
||||
|
||||
if canBeSelectedOrLongTapped {
|
||||
strongSelf.highlightedItemIndex = index
|
||||
for itemNode in strongSelf.itemNodes {
|
||||
if itemNode.index == index && itemNode.canBeSelected {
|
||||
if true {
|
||||
if !itemNode.isLayerBacked {
|
||||
strongSelf.reorderItemNodeToFront(itemNode)
|
||||
for (_, headerNode) in strongSelf.itemHeaderNodes {
|
||||
strongSelf.reorderHeaderNodeToFront(headerNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
let itemNodeFrame = itemNode.frame
|
||||
let itemNodeBounds = itemNode.bounds
|
||||
if strongSelf.items[index].selectable {
|
||||
itemNode.setHighlighted(true, at: strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY), animated: false)
|
||||
}
|
||||
|
||||
if itemNode.canBeLongTapped {
|
||||
let timer = Timer(timeInterval: 0.3, target: ListViewTimerProxy {
|
||||
if let strongSelf = self, strongSelf.highlightedItemIndex == index {
|
||||
for itemNode in strongSelf.itemNodes {
|
||||
if itemNode.index == index && itemNode.canBeLongTapped {
|
||||
itemNode.longTapped()
|
||||
strongSelf.clearHighlightAnimated(true)
|
||||
strongSelf.selectionTouchLocation = nil
|
||||
break
|
||||
let itemNodeFrame = itemNode.frame
|
||||
let itemNodeBounds = itemNode.bounds
|
||||
if strongSelf.items[index].selectable {
|
||||
itemNode.setHighlighted(true, at: strongSelf.touchesPosition.offsetBy(dx: -itemNodeFrame.minX + itemNodeBounds.minX, dy: -itemNodeFrame.minY + itemNodeBounds.minY), animated: false)
|
||||
}
|
||||
|
||||
if itemNode.canBeLongTapped {
|
||||
let timer = Timer(timeInterval: 0.3, target: ListViewTimerProxy {
|
||||
if let strongSelf = self, strongSelf.highlightedItemIndex == index {
|
||||
for itemNode in strongSelf.itemNodes {
|
||||
if itemNode.index == index && itemNode.canBeLongTapped {
|
||||
itemNode.longTapped()
|
||||
strongSelf.clearHighlightAnimated(true)
|
||||
strongSelf.selectionTouchLocation = nil
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
|
||||
strongSelf.selectionLongTapDelayTimer = timer
|
||||
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
|
||||
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
|
||||
strongSelf.selectionLongTapDelayTimer = timer
|
||||
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
|
||||
self.selectionTouchDelayTimer = timer
|
||||
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
|
||||
|
||||
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
|
||||
self.selectionTouchDelayTimer = timer
|
||||
RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
|
||||
}
|
||||
super.touchesBegan(touches, with: event)
|
||||
|
||||
self.updateScroller(transition: .immediate)
|
||||
|
@ -579,6 +579,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
var previousModalContainer: NavigationModalContainer?
|
||||
var visibleModalCount = 0
|
||||
var topModalIsFlat = false
|
||||
var isLandscape = layout.orientation == .landscape
|
||||
var hasVisibleStandaloneModal = false
|
||||
var topModalDismissProgress: CGFloat = 0.0
|
||||
|
||||
@ -784,7 +785,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
let visibleRootModalDismissProgress: CGFloat
|
||||
var additionalModalFrameProgress: CGFloat
|
||||
if visibleModalCount == 1 {
|
||||
effectiveRootModalDismissProgress = topModalIsFlat ? 1.0 : topModalDismissProgress
|
||||
effectiveRootModalDismissProgress = (topModalIsFlat || isLandscape) ? 1.0 : topModalDismissProgress
|
||||
visibleRootModalDismissProgress = effectiveRootModalDismissProgress
|
||||
additionalModalFrameProgress = 0.0
|
||||
} else if visibleModalCount >= 2 {
|
||||
@ -851,7 +852,7 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
}
|
||||
let maxScale: CGFloat
|
||||
let maxOffset: CGFloat
|
||||
if topModalIsFlat {
|
||||
if topModalIsFlat || isLandscape {
|
||||
maxScale = 1.0
|
||||
maxOffset = 0.0
|
||||
} else if visibleModalCount <= 1 {
|
||||
|
@ -328,6 +328,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
|
||||
self.scrollNode.view.isScrollEnabled = !isStandaloneModal
|
||||
|
||||
let isLandscape = layout.orientation == .landscape
|
||||
let containerLayout: ContainerViewLayout
|
||||
let containerFrame: CGRect
|
||||
let containerScale: CGFloat
|
||||
@ -336,7 +337,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
self.panRecognizer?.isEnabled = true
|
||||
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
|
||||
self.container.clipsToBounds = true
|
||||
if isStandaloneModal {
|
||||
if isStandaloneModal || isLandscape {
|
||||
self.container.cornerRadius = 0.0
|
||||
} else {
|
||||
self.container.cornerRadius = 10.0
|
||||
@ -351,7 +352,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
|
||||
}
|
||||
|
||||
var topInset: CGFloat
|
||||
if isStandaloneModal {
|
||||
if isStandaloneModal || isLandscape {
|
||||
topInset = 0.0
|
||||
containerLayout = layout
|
||||
|
||||
|
@ -62,6 +62,16 @@ final class GameControllerNode: ViewControllerTracingNode {
|
||||
}, name: "performAction")
|
||||
|
||||
configuration.userContentController = userController
|
||||
|
||||
configuration.allowsInlineMediaPlayback = true
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
configuration.mediaTypesRequiringUserActionForPlayback = []
|
||||
} else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
configuration.requiresUserActionForMediaPlayback = false
|
||||
} else {
|
||||
configuration.mediaPlaybackRequiresUserAction = false
|
||||
}
|
||||
|
||||
let webView = WKWebView(frame: CGRect(), configuration: configuration)
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
webView.allowsLinkPreview = false
|
||||
|
@ -66,7 +66,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, deletePeer: { _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
}, togglePeerMarkedUnread: { _, _ in
|
||||
}, toggleArchivedFolderHiddenByDefault: {
|
||||
|
@ -238,7 +238,9 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
self.listNode = ListView()
|
||||
self.leftOverlayNode = ASDisplayNode()
|
||||
self.leftOverlayNode.isUserInteractionEnabled = false
|
||||
self.rightOverlayNode = ASDisplayNode()
|
||||
self.rightOverlayNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init()
|
||||
|
||||
@ -302,6 +304,14 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
let _ = strongSelf.contentScrollingEnded?(strongSelf.listNode)
|
||||
}
|
||||
}
|
||||
|
||||
self.listNode.itemNodeHitTest = { [weak self] point in
|
||||
if let strongSelf = self {
|
||||
return point.x > strongSelf.leftOverlayNode.frame.maxX && point.x < strongSelf.rightOverlayNode.frame.minX
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
let previousState = Atomic<ItemListNodeState?>(value: nil)
|
||||
self.transitionDisposable.set(((state
|
||||
|
@ -71,6 +71,8 @@
|
||||
bool _throttle;
|
||||
TGLocationPinAnnotationView *_ownLiveLocationView;
|
||||
__weak MKAnnotationView *_userLocationView;
|
||||
|
||||
UIImageView *_headingArrowView;
|
||||
}
|
||||
@end
|
||||
|
||||
@ -162,6 +164,8 @@
|
||||
[_liveLocationsDisposable dispose];
|
||||
[_reloadDisposable dispose];
|
||||
[_frequentUpdatesDisposable dispose];
|
||||
|
||||
[_locationManager stopUpdatingHeading];
|
||||
}
|
||||
|
||||
- (void)tg_setRightBarButtonItem:(UIBarButtonItem *)barButtonItem action:(bool)action animated:(bool)animated {
|
||||
@ -438,6 +442,36 @@
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
static UIImage *headingArrowImage = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
|
||||
dispatch_once(&onceToken, ^
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(28.0f, 28.0f), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
|
||||
CGContextClearRect(context, CGRectMake(0, 0, 28, 28));
|
||||
|
||||
CGContextSetFillColorWithColor(context, UIColorRGB(0x3393fe).CGColor);
|
||||
|
||||
CGContextMoveToPoint(context, 14, 0);
|
||||
CGContextAddLineToPoint(context, 19, 7);
|
||||
CGContextAddLineToPoint(context, 9, 7);
|
||||
CGContextClosePath(context);
|
||||
CGContextFillPath(context);
|
||||
|
||||
CGContextSetBlendMode(context, kCGBlendModeClear);
|
||||
CGContextFillEllipseInRect(context, CGRectMake(5.0, 5.0, 18.0, 18.0));
|
||||
|
||||
headingArrowImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
});
|
||||
|
||||
_headingArrowView = [[UIImageView alloc] init];
|
||||
_headingArrowView.hidden = true;
|
||||
_headingArrowView.frame = CGRectMake(0.0, 0.0, 28.0, 28.0);
|
||||
_headingArrowView.image = headingArrowImage;
|
||||
|
||||
_tableView.scrollsToTop = false;
|
||||
_mapView.tapEnabled = false;
|
||||
|
||||
@ -495,6 +529,8 @@
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
[_locationManager startUpdatingHeading];
|
||||
|
||||
if (self.previewMode && !animated)
|
||||
{
|
||||
UIView *contentView = [[_mapView subviews] firstObject];
|
||||
@ -950,6 +986,9 @@
|
||||
{
|
||||
_userLocationView = view;
|
||||
|
||||
[_userLocationView addSubview:_headingArrowView];
|
||||
_headingArrowView.center = CGPointMake(view.frame.size.width / 2.0, view.frame.size.height / 2.0);
|
||||
|
||||
if (_ownLiveLocationView != nil)
|
||||
{
|
||||
[_userLocationView addSubview:_ownLiveLocationView];
|
||||
@ -982,6 +1021,14 @@
|
||||
return CLLocationCoordinate2DMake(_locationAttachment.latitude, _locationAttachment.longitude);
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
|
||||
{
|
||||
if (newHeading != nil) {
|
||||
_headingArrowView.hidden = false;
|
||||
_headingArrowView.transform = CGAffineTransformMakeRotation(newHeading.magneticHeading / 180.0 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
|
@ -86,7 +86,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
{
|
||||
localizationPlaceholderText = TGLocalized(@"MediaPicker.AddCaption");
|
||||
NSString *placeholderText = TGLocalized(@"MediaPicker.AddCaption");
|
||||
UIFont *placeholderFont = TGSystemFontOfSize(16);
|
||||
UIFont *placeholderFont = TGSystemFontOfSize(17);
|
||||
CGSize placeholderSize = [placeholderText sizeWithFont:placeholderFont];
|
||||
placeholderSize.width += 2.0f;
|
||||
placeholderSize.height += 2.0f;
|
||||
@ -121,7 +121,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
_placeholderLabel = [[UILabel alloc] init];
|
||||
_placeholderLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
|
||||
_placeholderLabel.backgroundColor = [UIColor clearColor];
|
||||
_placeholderLabel.font = TGSystemFontOfSize(16);
|
||||
_placeholderLabel.font = TGSystemFontOfSize(17);
|
||||
_placeholderLabel.textColor = UIColorRGB(0x7f7f7f);
|
||||
_placeholderLabel.text = TGLocalized(@"MediaPicker.AddCaption");
|
||||
_placeholderLabel.userInteractionEnabled = true;
|
||||
@ -130,7 +130,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
|
||||
_inputFieldOnelineLabel = [[UILabel alloc] init];
|
||||
_inputFieldOnelineLabel.backgroundColor = [UIColor clearColor];
|
||||
_inputFieldOnelineLabel.font = TGSystemFontOfSize(16);
|
||||
_inputFieldOnelineLabel.font = TGSystemFontOfSize(17);
|
||||
_inputFieldOnelineLabel.hidden = true;
|
||||
_inputFieldOnelineLabel.numberOfLines = 1;
|
||||
_inputFieldOnelineLabel.textColor = [UIColor whiteColor];
|
||||
@ -169,7 +169,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
_inputField.textColor = [UIColor whiteColor];
|
||||
_inputField.disableFormatting = !_allowEntities;
|
||||
_inputField.placeholderView = _placeholderLabel;
|
||||
_inputField.font = TGSystemFontOfSize(16);
|
||||
_inputField.font = TGSystemFontOfSize(17);
|
||||
_inputField.accentColor = UIColorRGB(0x78b1f9);
|
||||
_inputField.clipsToBounds = true;
|
||||
_inputField.backgroundColor = nil;
|
||||
@ -188,7 +188,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
|
||||
_inputField.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(-inputFieldInternalEdgeInsets.top, 0, 5 - TGRetinaPixel, 0);
|
||||
|
||||
[_inputField setAttributedText:[TGMediaPickerCaptionInputPanel attributedStringForText:_caption entities:_entities fontSize:16.0f] keepFormatting:true animated:false];
|
||||
[_inputField setAttributedText:[TGMediaPickerCaptionInputPanel attributedStringForText:_caption entities:_entities fontSize:17.0f] keepFormatting:true animated:false];
|
||||
|
||||
[_inputFieldClippingContainer addSubview:_inputField];
|
||||
}
|
||||
@ -439,7 +439,7 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
_fieldBackground.alpha = _placeholderLabel.hidden ? 1.0f : 0.0f;
|
||||
}
|
||||
|
||||
[self.inputField setAttributedText:[TGMediaPickerCaptionInputPanel attributedStringForText:_caption entities:_entities fontSize:16.0f] keepFormatting:true animated:false];
|
||||
[self.inputField setAttributedText:[TGMediaPickerCaptionInputPanel attributedStringForText:_caption entities:_entities fontSize:17.0f] keepFormatting:true animated:false];
|
||||
}
|
||||
|
||||
+ (NSAttributedString *)attributedStringForText:(NSString *)text entities:(NSArray *)entities fontSize:(CGFloat)fontSize {
|
||||
@ -777,14 +777,14 @@ static void setViewFrame(UIView *view, CGRect frame)
|
||||
if (text == nil)
|
||||
return nil;
|
||||
|
||||
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithAttributedString:[TGMediaPickerCaptionInputPanel attributedStringForText:text entities:entities fontSize:16.0f]];
|
||||
NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithAttributedString:[TGMediaPickerCaptionInputPanel attributedStringForText:text entities:entities fontSize:17.0f]];
|
||||
|
||||
for (NSUInteger i = 0; i < string.length; i++)
|
||||
{
|
||||
unichar c = [text characterAtIndex:i];
|
||||
if (c == '\t' || c == '\n')
|
||||
{
|
||||
[string insertAttributedString:[[NSAttributedString alloc] initWithString:tokenString attributes:@{NSFontAttributeName:TGSystemFontOfSize(16.0f)}] atIndex:i];
|
||||
[string insertAttributedString:[[NSAttributedString alloc] initWithString:tokenString attributes:@{NSFontAttributeName:TGSystemFontOfSize(17.0f)}] atIndex:i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -167,13 +167,14 @@
|
||||
if (recipientName.length > 0)
|
||||
{
|
||||
_arrowView = [[UIImageView alloc] initWithImage: TGComponentsImageNamed(@"PhotoPickerArrow")];
|
||||
_arrowView.alpha = 0.45f;
|
||||
_arrowView.alpha = 0.6f;
|
||||
[_wrapperView addSubview:_arrowView];
|
||||
|
||||
_recipientLabel = [[UILabel alloc] init];
|
||||
_recipientLabel.alpha = 0.6;
|
||||
_recipientLabel.backgroundColor = [UIColor clearColor];
|
||||
_recipientLabel.font = TGBoldSystemFontOfSize(13.0f);
|
||||
_recipientLabel.textColor = UIColorRGBA(0xffffff, 0.45f);
|
||||
_recipientLabel.textColor = UIColorRGB(0xffffff);
|
||||
_recipientLabel.text = recipientName;
|
||||
_recipientLabel.userInteractionEnabled = false;
|
||||
[_recipientLabel sizeToFit];
|
||||
@ -510,13 +511,7 @@
|
||||
UIEdgeInsets screenEdges = [self screenEdges];
|
||||
|
||||
__weak TGMediaPickerGalleryInterfaceView *weakSelf = self;
|
||||
|
||||
if ([itemView.headerView isKindOfClass:[TGMediaPickerScrubberHeaderView class]])
|
||||
{
|
||||
TGMediaPickerScrubberHeaderView *headerView = (TGMediaPickerScrubberHeaderView *)itemView.headerView;
|
||||
[headerView.scrubberView setRecipientName:_recipientLabel.text];
|
||||
}
|
||||
|
||||
|
||||
[self _layoutRecipientLabelForOrientation:[self interfaceOrientation] screenEdges:screenEdges hasHeaderView:(itemView.headerView != nil)];
|
||||
|
||||
if (_selectionContext != nil)
|
||||
@ -1039,8 +1034,8 @@
|
||||
{
|
||||
_checkButton.alpha = alpha;
|
||||
_muteButton.alpha = alpha;
|
||||
_arrowView.alpha = alpha * 0.45f;
|
||||
_recipientLabel.alpha = alpha;
|
||||
_arrowView.alpha = alpha * 0.6f;
|
||||
_recipientLabel.alpha = alpha * 0.6;
|
||||
} completion:^(BOOL finished)
|
||||
{
|
||||
if (finished)
|
||||
@ -1070,8 +1065,8 @@
|
||||
_muteButton.alpha = alpha;
|
||||
_muteButton.userInteractionEnabled = !hidden;
|
||||
|
||||
_arrowView.alpha = alpha * 0.45f;
|
||||
_recipientLabel.alpha = alpha;
|
||||
_arrowView.alpha = alpha * 0.6f;
|
||||
_recipientLabel.alpha = alpha * 0.6;
|
||||
}
|
||||
|
||||
if (hidden)
|
||||
@ -1095,7 +1090,7 @@
|
||||
{
|
||||
_checkButton.alpha = alpha;
|
||||
_muteButton.alpha = alpha;
|
||||
_arrowView.alpha = alpha * 0.45f;
|
||||
_arrowView.alpha = alpha * 0.6;
|
||||
_recipientLabel.alpha = alpha;
|
||||
_portraitToolbarView.alpha = alpha;
|
||||
_landscapeToolbarView.alpha = alpha;
|
||||
@ -1132,7 +1127,7 @@
|
||||
_muteButton.alpha = alpha;
|
||||
_muteButton.userInteractionEnabled = !hidden;
|
||||
|
||||
_arrowView.alpha = alpha * 0.45f;
|
||||
_arrowView.alpha = alpha * 0.6;
|
||||
_recipientLabel.alpha = alpha;
|
||||
|
||||
_portraitToolbarView.alpha = alpha;
|
||||
@ -1391,6 +1386,8 @@
|
||||
screenEdges.left += _safeAreaInset.left;
|
||||
screenEdges.right -= _safeAreaInset.right;
|
||||
|
||||
CGFloat panelInset = 0.0f;
|
||||
|
||||
switch (orientation)
|
||||
{
|
||||
case UIInterfaceOrientationLandscapeLeft:
|
||||
@ -1402,13 +1399,10 @@
|
||||
break;
|
||||
|
||||
default:
|
||||
frame = CGRectMake(screenEdges.left + 5, screenEdges.top + 6, _muteButton.frame.size.width, _muteButton.frame.size.height);
|
||||
frame = CGRectMake(screenEdges.left + 5, screenEdges.bottom - TGPhotoEditorToolbarSize - [_captionMixin.inputPanel baseHeight] - 45 - _safeAreaInset.bottom - panelInset - (hasHeaderView ? 64.0 : 0.0), _muteButton.frame.size.width, _muteButton.frame.size.height);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasHeaderView)
|
||||
frame.origin.y += 64;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
@ -1462,9 +1456,6 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasHeaderView)
|
||||
frame.origin.y += 64;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
@ -1526,9 +1517,6 @@
|
||||
|
||||
_arrowView.frame = frame;
|
||||
_recipientLabel.frame = CGRectMake(CGRectGetMaxX(_arrowView.frame) + 6.0f, _arrowView.frame.origin.y - 2.0f, recipientWidth, _recipientLabel.frame.size.height);
|
||||
|
||||
_arrowView.hidden = hasHeaderView;
|
||||
_recipientLabel.hidden = hasHeaderView;
|
||||
}
|
||||
|
||||
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)__unused duration
|
||||
@ -1670,15 +1658,14 @@
|
||||
{
|
||||
[UIView performWithoutAnimation:^
|
||||
{
|
||||
_photoCounterButton.frame = CGRectMake(screenEdges.right - 56 - _safeAreaInset.right, screenEdges.bottom - TGPhotoEditorToolbarSize - [_captionMixin.inputPanel baseHeight] - 40 - _safeAreaInset.bottom, 64, 38);
|
||||
_photoCounterButton.frame = CGRectMake(screenEdges.right - 56 - _safeAreaInset.right, screenEdges.bottom - TGPhotoEditorToolbarSize - [_captionMixin.inputPanel baseHeight] - 40 - _safeAreaInset.bottom - (hasHeaderView ? 64.0 : 0.0), 64, 38);
|
||||
|
||||
_selectedPhotosView.frame = CGRectMake(screenEdges.left + 4, screenEdges.bottom - TGPhotoEditorToolbarSize - [_captionMixin.inputPanel baseHeight] - photosViewSize - 54 - _safeAreaInset.bottom, self.frame.size.width - 4 * 2 - _safeAreaInset.right, photosViewSize);
|
||||
_selectedPhotosView.frame = CGRectMake(screenEdges.left + 4, screenEdges.bottom - TGPhotoEditorToolbarSize - [_captionMixin.inputPanel baseHeight] - photosViewSize - 54 - _safeAreaInset.bottom - (hasHeaderView ? 64.0 : 0.0), self.frame.size.width - 4 * 2 - _safeAreaInset.right, photosViewSize);
|
||||
}];
|
||||
|
||||
_landscapeToolbarView.frame = CGRectMake(_landscapeToolbarView.frame.origin.x, screenEdges.top, TGPhotoEditorToolbarSize, self.frame.size.height);
|
||||
|
||||
CGFloat topInset = _safeAreaInset.top > FLT_EPSILON ? _safeAreaInset.top - 14.0 : 0.0f;
|
||||
_headerWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.top + topInset, self.frame.size.width, 64);
|
||||
_headerWrapperView.frame = CGRectMake(screenEdges.left, _portraitToolbarView.frame.origin.y - 64.0 - [_captionMixin.inputPanel baseHeight], self.frame.size.width, 64.0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -71,6 +71,8 @@
|
||||
bool _scrubbingPanelPresented;
|
||||
bool _scrubbingPanelLocked;
|
||||
bool _shouldResetScrubber;
|
||||
NSArray *_cachedThumbnails;
|
||||
UIImage *_immediateThumbnail;
|
||||
|
||||
UILabel *_fileInfoLabel;
|
||||
|
||||
@ -215,13 +217,12 @@
|
||||
_headerView = headerView;
|
||||
_headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
|
||||
_scrubberPanelView = [[UIView alloc] initWithFrame:CGRectMake(0, -64, _headerView.frame.size.width, 64)];
|
||||
_scrubberPanelView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _headerView.frame.size.width, 64)];
|
||||
_scrubberPanelView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
_scrubberPanelView.hidden = true;
|
||||
headerView.panelView = _scrubberPanelView;
|
||||
[_headerView addSubview:_scrubberPanelView];
|
||||
|
||||
UIView *scrubberBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, -100.0f, _headerView.frame.size.width, 164.0f)];
|
||||
UIView *scrubberBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, _headerView.frame.size.width, 64.0f)];
|
||||
scrubberBackgroundView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
scrubberBackgroundView.backgroundColor = [TGPhotoEditorInterfaceAssets toolbarTransparentBackgroundColor];
|
||||
[_scrubberPanelView addSubview:scrubberBackgroundView];
|
||||
@ -301,7 +302,6 @@
|
||||
|
||||
_appeared = false;
|
||||
[self setScrubbingPanelApperanceLocked:false];
|
||||
[self setScrubbingPanelHidden:true animated:false];
|
||||
|
||||
[_positionTimer invalidate];
|
||||
_positionTimer = nil;
|
||||
@ -386,9 +386,14 @@
|
||||
- (void)setItem:(TGMediaPickerGalleryVideoItem *)item synchronously:(bool)synchronously
|
||||
{
|
||||
bool itemChanged = ![item isEqual:self.item];
|
||||
bool itemIdChanged = item.uniqueId != self.item.uniqueId;
|
||||
|
||||
[super setItem:item synchronously:synchronously];
|
||||
|
||||
if (itemIdChanged) {
|
||||
_immediateThumbnail = item.immediateThumbnailImage;
|
||||
}
|
||||
|
||||
if (itemChanged) {
|
||||
[self _playerCleanup];
|
||||
|
||||
@ -618,17 +623,15 @@
|
||||
|
||||
void (^changeBlock)(void) = ^
|
||||
{
|
||||
_scrubberPanelView.frame = CGRectMake(0.0f, -64.0f - _safeAreaInset.top, _scrubberPanelView.frame.size.width, _scrubberPanelView.frame.size.height);
|
||||
_scrubberPanelView.alpha = 0.0f;
|
||||
};
|
||||
void (^completionBlock)(BOOL) = ^(BOOL finished)
|
||||
{
|
||||
if (finished)
|
||||
_scrubberPanelView.hidden = true;
|
||||
};
|
||||
|
||||
if (animated)
|
||||
{
|
||||
[UIView animateWithDuration:0.3f delay:0.0f options:(7 << 16) animations:changeBlock completion:completionBlock];
|
||||
[UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:changeBlock completion:completionBlock];
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -642,18 +645,17 @@
|
||||
return;
|
||||
|
||||
_scrubbingPanelPresented = true;
|
||||
|
||||
_scrubberPanelView.hidden = false;
|
||||
|
||||
[_scrubberPanelView layoutSubviews];
|
||||
[_scrubberView layoutSubviews];
|
||||
|
||||
void (^changeBlock)(void) = ^
|
||||
{
|
||||
_scrubberPanelView.frame = CGRectMake(0.0f, 0.0f, _scrubberPanelView.frame.size.width, _scrubberPanelView.frame.size.height);
|
||||
_scrubberPanelView.alpha = 1.0f;
|
||||
};
|
||||
|
||||
if (animated)
|
||||
[UIView animateWithDuration:0.3f delay:0.0f options:(7 << 16) animations:changeBlock completion:nil];
|
||||
[UIView animateWithDuration:0.2f delay:0.0f options:UIViewAnimationOptionCurveLinear animations:changeBlock completion:nil];
|
||||
else
|
||||
changeBlock();
|
||||
}
|
||||
@ -708,7 +710,6 @@
|
||||
{
|
||||
[_scrubberView resetThumbnails];
|
||||
|
||||
[self setScrubbingPanelHidden:true animated:false];
|
||||
[_scrubberPanelView setNeedsLayout];
|
||||
[_scrubberPanelView layoutIfNeeded];
|
||||
|
||||
@ -722,11 +723,14 @@
|
||||
if (_containerView == nil)
|
||||
return;
|
||||
|
||||
_containerView.frame = self.bounds;
|
||||
if (self.bounds.size.width > self.bounds.size.height)
|
||||
_containerView.frame = self.bounds;
|
||||
else
|
||||
_containerView.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height - 44.0);
|
||||
|
||||
[self _layoutPlayerView];
|
||||
|
||||
_videoContentView.frame = (CGRect){CGPointZero, frame.size};
|
||||
_videoContentView.frame = (CGRect){CGPointZero, _containerView.frame.size};
|
||||
|
||||
if (_tooltipContainerView != nil && frame.size.width > frame.size.height)
|
||||
{
|
||||
@ -753,8 +757,6 @@
|
||||
mirrored = adjustments.cropMirrored;
|
||||
}
|
||||
|
||||
// _scrubberView.maximumLength = adjustments.sendAsGif ? TGVideoEditMaximumGifDuration : 0.0;
|
||||
|
||||
[self _layoutPlayerViewWithCropRect:cropRect videoFrameSize:videoFrameSize orientation:orientation mirrored:mirrored];
|
||||
}
|
||||
|
||||
@ -1440,40 +1442,8 @@
|
||||
trimEndValue = adjustments.trimEndValue;
|
||||
}
|
||||
}
|
||||
// NSTimeInterval trimDuration = trimEndValue - trimStartValue;
|
||||
|
||||
bool sendAsGif = !adjustments.sendAsGif;
|
||||
// if (sendAsGif && _scrubberView.allowsTrimming)
|
||||
// {
|
||||
// if (trimDuration > TGVideoEditMaximumGifDuration)
|
||||
// {
|
||||
// trimEndValue = trimStartValue + TGVideoEditMaximumGifDuration;
|
||||
//
|
||||
// if (_scrubberView.value > trimEndValue)
|
||||
// {
|
||||
// [self stop];
|
||||
// [_scrubberView setValue:_scrubberView.trimStartValue resetPosition:true];
|
||||
// [self _seekToPosition:_scrubberView.value manual:true];
|
||||
// }
|
||||
//
|
||||
// _scrubberView.trimStartValue = trimStartValue;
|
||||
// _scrubberView.trimEndValue = trimEndValue;
|
||||
// [_scrubberView setTrimApplied:true];
|
||||
// [self updatePlayerRange:trimEndValue];
|
||||
// }
|
||||
// }
|
||||
// else if (_shouldResetScrubber)
|
||||
// {
|
||||
// trimStartValue = 0.0;
|
||||
// trimEndValue = _videoDuration;
|
||||
//
|
||||
// _scrubberView.trimStartValue = trimStartValue;
|
||||
// _scrubberView.trimEndValue = trimEndValue;
|
||||
//
|
||||
// [_scrubberView setTrimApplied:false];
|
||||
// [self updatePlayerRange:trimEndValue];
|
||||
// }
|
||||
|
||||
TGVideoEditAdjustments *updatedAdjustments = [TGVideoEditAdjustments editAdjustmentsWithOriginalSize:_videoDimensions cropRect:cropRect cropOrientation:adjustments.cropOrientation cropRotation:adjustments.cropRotation cropLockedAspectRatio:adjustments.cropLockedAspectRatio cropMirrored:adjustments.cropMirrored trimStartValue:trimStartValue trimEndValue:trimEndValue toolValues:adjustments.toolValues paintingData:adjustments.paintingData sendAsGif:sendAsGif preset:adjustments.preset];
|
||||
[self.item.editingContext setAdjustments:updatedAdjustments forItem:self.item.editableMediaItem];
|
||||
|
||||
@ -1596,6 +1566,23 @@
|
||||
return timestamps;
|
||||
}
|
||||
|
||||
- (SSignal *)_placeholderThumbnails:(NSArray *)timestamps {
|
||||
NSMutableArray *thumbnails = [[NSMutableArray alloc] init];
|
||||
|
||||
UIImage *image = _immediateThumbnail;
|
||||
if (image == nil)
|
||||
return [SSignal complete];
|
||||
|
||||
UIImage *blurredImage = TGBlurredRectangularImage(image, true, image.size, image.size, NULL, nil);
|
||||
for (__unused NSNumber *value in timestamps) {
|
||||
if (thumbnails.count == 0)
|
||||
[thumbnails addObject:image];
|
||||
else
|
||||
[thumbnails addObject:blurredImage];
|
||||
}
|
||||
return [SSignal single:thumbnails];
|
||||
}
|
||||
|
||||
- (void)videoScrubber:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber requestThumbnailImagesForTimestamps:(NSArray *)timestamps size:(CGSize)size isSummaryThumbnails:(bool)isSummaryThumbnails
|
||||
{
|
||||
if (timestamps.count == 0)
|
||||
@ -1605,17 +1592,42 @@
|
||||
TGMediaEditingContext *editingContext = self.item.editingContext;
|
||||
id<TGMediaEditableItem> editableItem = self.editableMediaItem;
|
||||
|
||||
SSignal *thumbnailsSignal = nil;
|
||||
if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto])
|
||||
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:self.item.asset size:size timestamps:timestamps];
|
||||
else if (avAsset != nil)
|
||||
thumbnailsSignal = [avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
|
||||
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
|
||||
}];
|
||||
// SSignal *thumbnailsSignal = nil;
|
||||
// if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto])
|
||||
// thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:self.item.asset size:size timestamps:timestamps];
|
||||
// else if (avAsset != nil)
|
||||
// thumbnailsSignal = [avAsset mapToSignal:^SSignal *(AVAsset *avAsset) {
|
||||
// return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps];
|
||||
// }];
|
||||
|
||||
__strong TGMediaPickerGalleryVideoItemView *weakSelf = self;
|
||||
SSignal *thumbnailsSignal = nil;
|
||||
if (_cachedThumbnails != nil) {
|
||||
thumbnailsSignal = [SSignal single:_cachedThumbnails];
|
||||
} else if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto]) {
|
||||
thumbnailsSignal = [[self _placeholderThumbnails:timestamps] then:[[TGMediaAssetImageSignals videoThumbnailsForAsset:(TGMediaAsset *)self.item.asset size:size timestamps:timestamps] onNext:^(NSArray *images) {
|
||||
__strong TGMediaPickerGalleryVideoItemView *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf->_cachedThumbnails == nil)
|
||||
strongSelf->_cachedThumbnails = images;
|
||||
}]];
|
||||
} else if ([self.item.asset isKindOfClass:[TGCameraCapturedVideo class]]) {
|
||||
thumbnailsSignal = [[((TGCameraCapturedVideo *)self.item.asset).avAsset takeLast] mapToSignal:^SSignal *(AVAsset *avAsset) {
|
||||
return [[self _placeholderThumbnails:timestamps] then:[[TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps] onNext:^(NSArray *images) {
|
||||
__strong TGMediaPickerGalleryVideoItemView *strongSelf = weakSelf;
|
||||
if (strongSelf == nil)
|
||||
return;
|
||||
|
||||
if (strongSelf->_cachedThumbnails == nil)
|
||||
strongSelf->_cachedThumbnails = images;
|
||||
}]];
|
||||
}];
|
||||
}
|
||||
|
||||
_requestingThumbnails = true;
|
||||
|
||||
__weak TGMediaPickerGalleryVideoItemView *weakSelf = self;
|
||||
[_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) {
|
||||
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:editableItem];
|
||||
if (adjustments.toolsApplied) {
|
||||
|
@ -45,8 +45,6 @@
|
||||
|
||||
- (void)setThumbnailImage:(UIImage *)image forTimestamp:(NSTimeInterval)timestamp index:(NSInteger)index isSummaryThubmnail:(bool)isSummaryThumbnail;
|
||||
|
||||
- (void)setRecipientName:(NSString *)recipientName;
|
||||
|
||||
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position;
|
||||
|
||||
- (void)_updateScrubberAnimationsAndResetCurrentPosition:(bool)resetCurrentPosition;
|
||||
|
@ -81,9 +81,6 @@ typedef enum
|
||||
NSInteger _zoomedPivotTimestampIndex;
|
||||
NSArray *_zoomedTimestamps;
|
||||
NSMutableArray *_zoomedThumbnailViews;
|
||||
|
||||
UIImageView *_arrowView;
|
||||
UILabel *_recipientLabel;
|
||||
}
|
||||
@end
|
||||
|
||||
@ -417,33 +414,10 @@ typedef enum
|
||||
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
|
||||
_tapGestureRecognizer.enabled = false;
|
||||
[_trimView addGestureRecognizer:_tapGestureRecognizer];
|
||||
|
||||
_arrowView = [[UIImageView alloc] initWithImage:TGComponentsImageNamed(@"PhotoPickerArrow")];
|
||||
_arrowView.alpha = 0.45f;
|
||||
_arrowView.hidden = true;
|
||||
[self addSubview:_arrowView];
|
||||
|
||||
_recipientLabel = [[UILabel alloc] init];
|
||||
_recipientLabel.backgroundColor = [UIColor clearColor];
|
||||
_recipientLabel.font = TGBoldSystemFontOfSize(13.0f);
|
||||
_recipientLabel.textColor = UIColorRGBA(0xffffff, 0.45f);
|
||||
_recipientLabel.hidden = true;
|
||||
[self addSubview:_recipientLabel];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setRecipientName:(NSString *)recipientName
|
||||
{
|
||||
_recipientLabel.text = recipientName;
|
||||
_recipientLabel.hidden = recipientName.length == 0;
|
||||
_arrowView.hidden = _recipientLabel.hidden;
|
||||
|
||||
[_recipientLabel sizeToFit];
|
||||
|
||||
[self _layoutRecipientLabel];
|
||||
}
|
||||
|
||||
- (void)setHasDotPicker:(bool)hasDotPicker {
|
||||
_hasDotPicker = hasDotPicker;
|
||||
_tapGestureRecognizer.enabled = hasDotPicker;
|
||||
@ -1052,11 +1026,9 @@ typedef enum
|
||||
|
||||
- (void)_updateTimeLabels
|
||||
{
|
||||
_currentTimeLabel.text = @"";
|
||||
_currentTimeLabel.text = self.disableTimeDisplay ? @"" : [TGMediaPickerGalleryVideoScrubber _stringFromTotalSeconds:(NSInteger)self.value];
|
||||
|
||||
NSString *text = [NSString stringWithFormat:@"%@ / %@", [TGMediaPickerGalleryVideoScrubber _stringFromTotalSeconds:(NSInteger)self.value], [TGMediaPickerGalleryVideoScrubber _stringFromTotalSeconds:(NSInteger)self.duration]];
|
||||
|
||||
_inverseTimeLabel.text = self.disableTimeDisplay ? @"" : text;
|
||||
_inverseTimeLabel.text = self.disableTimeDisplay ? @"" : [TGMediaPickerGalleryVideoScrubber _stringFromTotalSeconds:(NSInteger)self.duration];
|
||||
}
|
||||
|
||||
#pragma mark - Scrubber Handle
|
||||
@ -1466,18 +1438,6 @@ typedef enum
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_layoutRecipientLabel
|
||||
{
|
||||
if (self.frame.size.width < FLT_EPSILON)
|
||||
return;
|
||||
|
||||
CGFloat screenWidth = MAX(self.frame.size.width, self.frame.size.height);
|
||||
CGFloat recipientWidth = MIN(_recipientLabel.frame.size.width, screenWidth - 100.0f);
|
||||
|
||||
_arrowView.frame = CGRectMake(14.0f, 6.0f, _arrowView.frame.size.width, _arrowView.frame.size.height);
|
||||
_recipientLabel.frame = CGRectMake(CGRectGetMaxX(_arrowView.frame) + 6.0f, _arrowView.frame.origin.y - 2.0f, recipientWidth, _recipientLabel.frame.size.height);
|
||||
}
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
if (isnan(frame.origin.x) || isnan(frame.origin.y) || isnan(frame.size.width) || isnan(frame.size.height))
|
||||
@ -1501,8 +1461,6 @@ typedef enum
|
||||
_zoomedThumbnailWrapperView.frame = _summaryThumbnailWrapperView.frame;
|
||||
|
||||
[self _updateScrubberAnimationsAndResetCurrentPosition:true];
|
||||
|
||||
[self _layoutRecipientLabel];
|
||||
}
|
||||
|
||||
+ (NSString *)_stringFromTotalSeconds:(NSInteger)totalSeconds
|
||||
|
@ -48,7 +48,7 @@ const CGFloat TGPhotoCounterButtonMaskFade = 18;
|
||||
{
|
||||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(38.0f, 38.0f), false, 0.0f);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.7f).CGColor);
|
||||
CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.3f).CGColor);
|
||||
|
||||
CGContextFillEllipseInRect(context, CGRectMake(3.5f, 1.0f, 31.0f, 31.0f));
|
||||
|
||||
|
@ -126,7 +126,7 @@
|
||||
CGRect rect = CGRectMake(0, 0, 39.0f, 39.0f);
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.6f).CGColor);
|
||||
CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.3f).CGColor);
|
||||
CGContextFillEllipseInRect(context, CGRectInset(rect, 3, 3));
|
||||
|
||||
muteBackground = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
@ -1216,7 +1216,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
|
||||
if (![editorController isKindOfClass:[TGPhotoEditorController class]])
|
||||
return;
|
||||
|
||||
if (hasStickers) {
|
||||
if (!hasStickers) {
|
||||
[editorController setMinimalVideoDuration:duration];
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,18 @@ import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import AppBundle
|
||||
|
||||
enum LocationAttribution: Equatable {
|
||||
case foursquare
|
||||
case google
|
||||
}
|
||||
|
||||
class LocationAttributionItem: ListViewItem {
|
||||
let presentationData: ItemListPresentationData
|
||||
let attribution: LocationAttribution
|
||||
|
||||
public init(presentationData: ItemListPresentationData) {
|
||||
public init(presentationData: ItemListPresentationData, attribution: LocationAttribution) {
|
||||
self.presentationData = presentationData
|
||||
self.attribution = attribution
|
||||
}
|
||||
|
||||
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
@ -93,11 +100,20 @@ private class LocationAttributionItemNode: ListViewItemNode {
|
||||
strongSelf.layoutParams = params
|
||||
|
||||
if let _ = updatedTheme {
|
||||
strongSelf.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/FoursquareAttribution"), color: item.presentationData.theme.list.itemSecondaryTextColor)
|
||||
switch item.attribution {
|
||||
case .foursquare:
|
||||
strongSelf.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/FoursquareAttribution"), color: item.presentationData.theme.list.itemSecondaryTextColor)
|
||||
case .google:
|
||||
if item.presentationData.theme.overallDarkAppearance {
|
||||
strongSelf.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/GoogleAttribution"), color: item.presentationData.theme.list.itemSecondaryTextColor)
|
||||
} else {
|
||||
strongSelf.imageNode.image = UIImage(bundleImageName: "Location/GoogleAttribution")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let image = strongSelf.imageNode.image {
|
||||
strongSelf.imageNode.frame = CGRect(x: floor((params.width - image.size.width) / 2.0), y: 0.0, width: image.size.width, height: image.size.height)
|
||||
strongSelf.imageNode.frame = CGRect(x: floor((params.width - image.size.width) / 2.0), y: floor((contentSize.height - image.size.height) / 2.0), width: image.size.width, height: image.size.height)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -68,11 +68,30 @@ private class LocationMapView: MKMapView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private func generateHeadingArrowImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 28.0, height: 28.0)) { size, context in
|
||||
let bounds = CGRect(origin: CGPoint(), size: size)
|
||||
context.clear(bounds)
|
||||
|
||||
context.setFillColor(UIColor(rgb: 0x3393fe).cgColor)
|
||||
|
||||
context.move(to: CGPoint(x: 14.0, y: 0.0))
|
||||
context.addLine(to: CGPoint(x: 19.0, y: 7.0))
|
||||
context.addLine(to: CGPoint(x: 9.0, y: 7.0))
|
||||
context.closePath()
|
||||
context.fillPath()
|
||||
|
||||
context.setBlendMode(.clear)
|
||||
context.fillEllipse(in: bounds.insetBy(dx: 5.0, dy: 5.0))
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
private let locationPromise = Promise<CLLocation?>(nil)
|
||||
|
||||
private let pickerAnnotationContainerView: PickerAnnotationContainerView
|
||||
private weak var userLocationAnnotationView: MKAnnotationView?
|
||||
private var headingArrowView: UIImageView?
|
||||
|
||||
private let pinDisposable = MetaDisposable()
|
||||
|
||||
@ -103,6 +122,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.headingArrowView = UIImageView()
|
||||
self.headingArrowView?.frame = CGRect(origin: CGPoint(), size: CGSize(width: 28.0, height: 28.0))
|
||||
self.headingArrowView?.image = generateHeadingArrowImage()
|
||||
|
||||
self.mapView?.interactiveTransitionGestureRecognizerTest = { p in
|
||||
if p.x > 44.0 {
|
||||
return true
|
||||
@ -232,6 +255,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
for view in views {
|
||||
if view.annotation is MKUserLocation {
|
||||
self.userLocationAnnotationView = view
|
||||
if let headingArrowView = self.headingArrowView {
|
||||
view.addSubview(headingArrowView)
|
||||
headingArrowView.center = CGPoint(x: view.frame.width / 2.0, y: view.frame.height / 2.0)
|
||||
}
|
||||
if let annotationView = self.customUserLocationAnnotationView {
|
||||
view.addSubview(annotationView)
|
||||
}
|
||||
@ -347,6 +374,18 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
var userHeading: CGFloat? = nil {
|
||||
didSet {
|
||||
if let heading = self.userHeading {
|
||||
self.headingArrowView?.isHidden = false
|
||||
self.headingArrowView?.transform = CGAffineTransform(rotationAngle: CGFloat(heading / 180.0 * CGFloat.pi))
|
||||
} else {
|
||||
self.headingArrowView?.isHidden = true
|
||||
self.headingArrowView?.transform = CGAffineTransform.identity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var annotations: [LocationPinAnnotation] = [] {
|
||||
didSet {
|
||||
guard let mapView = self.mapView else {
|
||||
|
@ -289,7 +289,7 @@ public final class LocationPickerController: ViewController {
|
||||
return
|
||||
}
|
||||
|
||||
self.displayNode = LocationPickerControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction)
|
||||
self.displayNode = LocationPickerControllerNode(context: self.context, presentationData: self.presentationData, mode: self.mode, interaction: interaction, locationManager: self.locationManager)
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.permissionDisposable = (DeviceAccess.authorizationStatus(subject: .location(.send))
|
||||
|
@ -17,6 +17,7 @@ import AppBundle
|
||||
import CoreLocation
|
||||
import Geocoding
|
||||
import PhoneNumberFormat
|
||||
import DeviceAccess
|
||||
|
||||
private struct LocationPickerTransaction {
|
||||
let deletions: [ListViewDeleteItem]
|
||||
@ -40,7 +41,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
case liveLocation(PresentationTheme, String, String, CLLocationCoordinate2D?)
|
||||
case header(PresentationTheme, String)
|
||||
case venue(PresentationTheme, TelegramMediaMap, Int)
|
||||
case attribution(PresentationTheme)
|
||||
case attribution(PresentationTheme, LocationAttribution)
|
||||
|
||||
var stableId: LocationPickerEntryId {
|
||||
switch self {
|
||||
@ -83,8 +84,8 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .attribution(lhsTheme):
|
||||
if case let .attribution(rhsTheme) = rhs, lhsTheme === rhsTheme {
|
||||
case let .attribution(lhsTheme, lhsAttribution):
|
||||
if case let .attribution(rhsTheme, rhsAttribution) = rhs, lhsTheme === rhsTheme, lhsAttribution == rhsAttribution {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@ -131,7 +132,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
|
||||
func item(account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> ListViewItem {
|
||||
switch self {
|
||||
case let .location(theme, title, subtitle, venue, coordinate):
|
||||
case let .location(_, title, subtitle, venue, coordinate):
|
||||
let icon: LocationActionListItemIcon
|
||||
if let venue = venue {
|
||||
icon = .venue(venue)
|
||||
@ -147,23 +148,23 @@ private enum LocationPickerEntry: Comparable, Identifiable {
|
||||
}, highlighted: { highlighted in
|
||||
interaction?.updateSendActionHighlight(highlighted)
|
||||
})
|
||||
case let .liveLocation(theme, title, subtitle, coordinate):
|
||||
case let .liveLocation(_, title, subtitle, coordinate):
|
||||
return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: account, title: title, subtitle: subtitle, icon: .liveLocation, action: {
|
||||
if let coordinate = coordinate {
|
||||
interaction?.sendLiveLocation(coordinate)
|
||||
}
|
||||
})
|
||||
case let .header(theme, title):
|
||||
case let .header(_, title):
|
||||
return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title)
|
||||
case let .venue(theme, venue, _):
|
||||
case let .venue(_, venue, _):
|
||||
let venueType = venue.venue?.type ?? ""
|
||||
return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), account: account, venue: venue, style: .plain, action: {
|
||||
interaction?.sendVenue(venue)
|
||||
}, infoAction: ["home", "work"].contains(venueType) ? {
|
||||
interaction?.openHomeWorkInfo()
|
||||
} : nil)
|
||||
case let .attribution(theme):
|
||||
return LocationAttributionItem(presentationData: ItemListPresentationData(presentationData))
|
||||
case let .attribution(_, attribution):
|
||||
return LocationAttributionItem(presentationData: ItemListPresentationData(presentationData), attribution: attribution)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -240,12 +241,13 @@ struct LocationPickerState {
|
||||
}
|
||||
}
|
||||
|
||||
final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationManagerDelegate {
|
||||
private let context: AccountContext
|
||||
private var presentationData: PresentationData
|
||||
private let presentationDataPromise: Promise<PresentationData>
|
||||
private let mode: LocationPickerMode
|
||||
private let interaction: LocationPickerInteraction
|
||||
private let locationManager: LocationManager
|
||||
|
||||
private let listNode: ListView
|
||||
private let emptyResultsTextNode: ImmediateTextNode
|
||||
@ -269,12 +271,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
|
||||
private var listOffset: CGFloat?
|
||||
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction) {
|
||||
init(context: AccountContext, presentationData: PresentationData, mode: LocationPickerMode, interaction: LocationPickerInteraction, locationManager: LocationManager) {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.presentationDataPromise = Promise(presentationData)
|
||||
self.mode = mode
|
||||
self.interaction = interaction
|
||||
self.locationManager = locationManager
|
||||
|
||||
self.state = LocationPickerState()
|
||||
self.statePromise = Promise(self.state)
|
||||
@ -496,15 +499,21 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|
||||
entries.append(.header(presentationData.theme, presentationData.strings.Map_ChooseAPlace.uppercased()))
|
||||
|
||||
var displayedVenues = foundVenues != nil || state.searchingVenuesAround ? foundVenues : venues
|
||||
let displayedVenues = foundVenues != nil || state.searchingVenuesAround ? foundVenues : venues
|
||||
if let venues = displayedVenues {
|
||||
var index: Int = 0
|
||||
var attribution: LocationAttribution?
|
||||
for venue in venues {
|
||||
if venue.venue?.provider == "foursquare" {
|
||||
attribution = .foursquare
|
||||
} else if venue.venue?.provider == "gplaces" {
|
||||
attribution = .google
|
||||
}
|
||||
entries.append(.venue(presentationData.theme, venue, index))
|
||||
index += 1
|
||||
}
|
||||
if !venues.isEmpty {
|
||||
entries.append(.attribution(presentationData.theme))
|
||||
if let attribution = attribution {
|
||||
entries.append(.attribution(presentationData.theme, attribution))
|
||||
}
|
||||
}
|
||||
let previousEntries = previousEntries.swap(entries)
|
||||
@ -533,7 +542,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
switch previousState.selectedLocation {
|
||||
case .none, .venue:
|
||||
updateMap = true
|
||||
case let .location(previousCoordinate, address):
|
||||
case let .location(previousCoordinate, _):
|
||||
if previousCoordinate != coordinate {
|
||||
updateMap = true
|
||||
}
|
||||
@ -574,7 +583,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
|
||||
if let (layout, navigationBarHeight) = strongSelf.validLayout {
|
||||
var updateLayout = false
|
||||
var transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring)
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.45, curve: .spring)
|
||||
|
||||
if previousState.displayingMapModeOptions != state.displayingMapModeOptions {
|
||||
updateLayout = true
|
||||
@ -685,11 +694,20 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
strongSelf.goToUserLocation()
|
||||
}
|
||||
}
|
||||
|
||||
self.locationManager.manager.startUpdatingHeading()
|
||||
self.locationManager.manager.delegate = self
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
self.geocodingDisposable.dispose()
|
||||
|
||||
self.locationManager.manager.stopUpdatingHeading()
|
||||
}
|
||||
|
||||
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
|
||||
self.headerNode.mapNode.userHeading = CGFloat(newHeading.magneticHeading)
|
||||
}
|
||||
|
||||
func updatePresentationData(_ presentationData: PresentationData) {
|
||||
@ -721,7 +739,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
|
||||
}
|
||||
|
||||
private func dequeueTransition() {
|
||||
guard let layout = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
guard let _ = self.validLayout, let transition = self.enqueuedTransitions.first else {
|
||||
return
|
||||
}
|
||||
self.enqueuedTransitions.remove(at: 0)
|
||||
|
@ -181,7 +181,11 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
|
||||
if withDirections {
|
||||
return .openUrl(url: "comgooglemaps-x-callback://?daddr=\(coordinates)&directionsmode=driving&x-success=telegram://?resume=true&x-source=Telegram")
|
||||
} else {
|
||||
return .openUrl(url: "comgooglemaps-x-callback://?center=\(coordinates)&q=\(coordinates)&x-success=telegram://?resume=true&x-source=Telegram")
|
||||
if let venue = location.venue, let venueId = venue.id, let provider = venue.provider, provider == "gplaces" {
|
||||
return .openUrl(url: "https://www.google.com/maps/search/?api=1&query=\(venue.address ?? "")&query_place_id=\(venueId)")
|
||||
} else {
|
||||
return .openUrl(url: "comgooglemaps-x-callback://?center=\(coordinates)&q=\(coordinates)&x-success=telegram://?resume=true&x-source=Telegram")
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
|
@ -1076,8 +1076,8 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
|
||||
}
|
||||
for childController in tabController.controllers {
|
||||
if let chatListController = childController as? ChatListController {
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] deleted in
|
||||
if deleted {
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), joined: false, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] removed in
|
||||
if removed {
|
||||
navigationController?.popToRoot(animated: true)
|
||||
}
|
||||
}, removed: {
|
||||
|
@ -2439,7 +2439,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
|
||||
}
|
||||
for childController in tabController.controllers {
|
||||
if let chatListController = childController as? ChatListController {
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] removed in
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), joined: false, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] removed in
|
||||
if removed {
|
||||
navigationController?.popToRoot(animated: true)
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in })
|
||||
|
@ -767,7 +767,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in
|
||||
|
@ -351,7 +351,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
var items: [ChatListItem] = []
|
||||
|
||||
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, messageSelected: { _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, deletePeer: { _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, hidePsa: { _ in
|
||||
}, activateChatPreview: { _, _, gesture in
|
||||
gesture?.cancel()
|
||||
}, present: { _ in
|
||||
|
@ -173,7 +173,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
||||
let leftInset = 16.0 + params.leftInset
|
||||
let rightInset = 16.0 + params.rightInset
|
||||
var totalLeftInset = leftInset
|
||||
let additionalRightInset: CGFloat = 93.0
|
||||
let additionalRightInset: CGFloat = 128.0
|
||||
|
||||
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize)
|
||||
|
||||
@ -229,9 +229,9 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
|
||||
|
||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: label, font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - totalLeftInset - rightInset - additionalRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let (viewsLayout, viewsApply) = makeViewsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageViews(item.views), font: labelFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (viewsLayout, viewsApply) = makeViewsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageViews(item.views), font: labelFont, textColor: item.presentationData.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let (forwardsLayout, forwardsApply) = makeForwardsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageForwards(item.forwards), font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 100.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (forwardsLayout, forwardsApply) = makeForwardsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Stats_MessageForwards(item.forwards), font: labelFont, textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: 128.0, height: CGFloat.greatestFiniteMagnitude), alignment: .right, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let verticalInset: CGFloat = 11.0
|
||||
let titleSpacing: CGFloat = 3.0
|
||||
|
@ -30,8 +30,8 @@ public enum StatsGraph: Equatable {
|
||||
switch self {
|
||||
case .Empty:
|
||||
return true
|
||||
case let .Failed(error):
|
||||
return error.lowercased().contains("not enough data")
|
||||
case .Failed:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
22
submodules/TelegramUI/Images.xcassets/Location/GoogleAttribution.imageset/Contents.json
vendored
Normal file
22
submodules/TelegramUI/Images.xcassets/Location/GoogleAttribution.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "powered_by_google_on_white@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "powered_by_google_on_white@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
@ -570,6 +570,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
if strongSelf.presentationInterfaceState.interfaceState.selectionState != nil {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.dismissAllTooltips()
|
||||
|
||||
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
|
||||
if let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) {
|
||||
@ -1985,7 +1988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
})
|
||||
}, displaySwipeToReplyHint: { [weak self] in
|
||||
if let strongSelf = self, let validLayout = strongSelf.validLayout, min(validLayout.size.width, validLayout.size.height) > 320.0 {
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .swipeToReply(title: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintTitle, text: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintText), elevatedLayout: true, action: { _ in return false }), in: .window(.root))
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .swipeToReply(title: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintTitle, text: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintText), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
}, dismissReplyMarkupMessage: { [weak self] message in
|
||||
guard let strongSelf = self, strongSelf.presentationInterfaceState.keyboardButtonsMessage?.id == message.id else {
|
||||
@ -2044,6 +2047,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
if strongSelf.presentationInterfaceState.interfaceState.selectionState != nil {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.dismissAllTooltips()
|
||||
|
||||
let context = strongSelf.context
|
||||
let _ = (context.account.postbox.transaction { transaction -> Peer? in
|
||||
return transaction.getPeer(peer.id)
|
||||
@ -5228,18 +5238,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
self.dismissAllTooltips()
|
||||
|
||||
self.window?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
})
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss()
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
self.sendMessageActionsController?.dismiss()
|
||||
|
||||
if let _ = self.peekData {
|
||||
@ -6077,7 +6075,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
disposable.set((signal
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
if let strongSelf = self, let _ = strongSelf.validLayout {
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: true, action: { _ in return false }), in: .current)
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), in: .current)
|
||||
}
|
||||
}))
|
||||
|
||||
@ -7118,12 +7116,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
if let value = value {
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: canSendMessagesToChat(self.presentationInterfaceState) ? self.presentationData.strings.Conversation_SendDice : nil), elevatedLayout: true, action: { [weak self] action in
|
||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: canSendMessagesToChat(self.presentationInterfaceState) ? self.presentationData.strings.Conversation_SendDice : nil), elevatedLayout: false, action: { [weak self] action in
|
||||
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState), action == .undo {
|
||||
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil)])
|
||||
}
|
||||
return false
|
||||
}), in: .window(.root))
|
||||
}), in: .current)
|
||||
}
|
||||
}
|
||||
|
||||
@ -9179,6 +9177,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.silentPostTooltipController?.dismiss()
|
||||
self.mediaRecordingModeTooltipController?.dismiss()
|
||||
self.mediaRestrictedTooltipController?.dismiss()
|
||||
|
||||
self.window?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
})
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss()
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
private func commitPurposefulAction() {
|
||||
|
@ -974,10 +974,14 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
optionsMap[id]!.insert(.deleteLocally)
|
||||
} else if let peer = transaction.getPeer(id.peerId) {
|
||||
var isAction = false
|
||||
var isDice = false
|
||||
for media in message.media {
|
||||
if media is TelegramMediaAction || media is TelegramMediaExpiredContent {
|
||||
isAction = true
|
||||
}
|
||||
if media is TelegramMediaDice {
|
||||
isDice = true
|
||||
}
|
||||
}
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if message.flags.contains(.Incoming) {
|
||||
@ -1064,6 +1068,11 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
} else if limitsConfiguration.canRemoveIncomingMessagesInPrivateChats {
|
||||
canDeleteGlobally = true
|
||||
}
|
||||
|
||||
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
|
||||
if isDice && Int64(message.timestamp) + 60 * 60 * 24 > Int64(timestamp) {
|
||||
canDeleteGlobally = false
|
||||
}
|
||||
if message.flags.contains(.Incoming) {
|
||||
hadPersonalIncoming = true
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
|
||||
}, setPeerIdWithRevealedOptions: { _, _ in
|
||||
}, setItemPinned: { _, _ in
|
||||
}, setPeerMuted: { _, _ in
|
||||
}, deletePeer: { _ in
|
||||
}, deletePeer: { _, _ in
|
||||
}, updatePeerGrouping: { _, _ in
|
||||
}, togglePeerMarkedUnread: { _, _ in
|
||||
}, toggleArchivedFolderHiddenByDefault: {
|
||||
|
@ -3837,7 +3837,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
|
||||
}
|
||||
for childController in tabController.controllers {
|
||||
if let chatListController = childController as? ChatListController {
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: globally, completion: { [weak navigationController] deleted in
|
||||
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), joined: false, deleteGloballyIfPossible: globally, completion: { [weak navigationController] deleted in
|
||||
if deleted {
|
||||
navigationController?.popToRoot(animated: true)
|
||||
}
|
||||
|
@ -88,24 +88,24 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
|
||||
let userContentController = WKUserContentController()
|
||||
userContentController.addUserScript(WKUserScript(source: "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta)", injectionTime: .atDocumentEnd, forMainFrameOnly: true))
|
||||
|
||||
let config = WKWebViewConfiguration()
|
||||
config.allowsInlineMediaPlayback = true
|
||||
config.userContentController = userContentController
|
||||
let configuration = WKWebViewConfiguration()
|
||||
configuration.allowsInlineMediaPlayback = true
|
||||
configuration.userContentController = userContentController
|
||||
|
||||
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
|
||||
config.mediaTypesRequiringUserActionForPlayback = []
|
||||
configuration.mediaTypesRequiringUserActionForPlayback = []
|
||||
} else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
config.requiresUserActionForMediaPlayback = false
|
||||
configuration.requiresUserActionForMediaPlayback = false
|
||||
} else {
|
||||
config.mediaPlaybackRequiresUserAction = false
|
||||
configuration.mediaPlaybackRequiresUserAction = false
|
||||
}
|
||||
|
||||
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
|
||||
config.allowsPictureInPictureMediaPlayback = false
|
||||
configuration.allowsPictureInPictureMediaPlayback = false
|
||||
}
|
||||
|
||||
let frame = CGRect(origin: CGPoint.zero, size: intrinsicDimensions)
|
||||
self.webView = WKWebView(frame: frame, configuration: config)
|
||||
self.webView = WKWebView(frame: frame, configuration: configuration)
|
||||
|
||||
super.init()
|
||||
self.frame = frame
|
||||
|
Loading…
x
Reference in New Issue
Block a user