Merge commit '2984ca1bfe0ce9c95055d007a906ece0f872195b'

This commit is contained in:
Ali 2020-07-28 20:59:20 +04:00
commit 2a39e417bd
42 changed files with 500 additions and 311 deletions

View File

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

View File

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

View File

@ -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: [

View File

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

View File

@ -1028,7 +1028,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
}
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, deletePeer: { _ in
}, deletePeer: { _, _ in
}, updatePeerGrouping: { _, _ in
}, togglePeerMarkedUnread: { _, _ in
}, toggleArchivedFolderHiddenByDefault: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -66,7 +66,7 @@ public final class HashtagSearchController: TelegramBaseController {
}, setPeerIdWithRevealedOptions: { _, _ in
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, deletePeer: { _ in
}, deletePeer: { _, _ in
}, updatePeerGrouping: { _, _ in
}, togglePeerMarkedUnread: { _, _ in
}, toggleArchivedFolderHiddenByDefault: {

View File

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

View File

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

View File

@ -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;
}
}

View File

@ -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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1216,7 +1216,7 @@ const CGFloat TGPhotoPaintStickerKeyboardSize = 260.0f;
if (![editorController isKindOfClass:[TGPhotoEditorController class]])
return;
if (hasStickers) {
if (!hasStickers) {
[editorController setMinimalVideoDuration:duration];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

@ -183,7 +183,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
}, setPeerIdWithRevealedOptions: { _, _ in
}, setItemPinned: { _, _ in
}, setPeerMuted: { _, _ in
}, deletePeer: { _ in
}, deletePeer: { _, _ in
}, updatePeerGrouping: { _, _ in
}, togglePeerMarkedUnread: { _, _ in
}, toggleArchivedFolderHiddenByDefault: {

View File

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

View File

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