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 activateSearch()
func deactivateSearch(animated: Bool) func deactivateSearch(animated: Bool)
func activateCompose() 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) 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 presentationData = context.sharedContext.currentPresentationData.with({ $0 })
let strings = presentationData.strings let strings = presentationData.strings
return context.account.postbox.transaction { [weak chatListController] transaction -> [ContextMenuItem] in 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 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) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in }, 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 return updatedItems
@ -379,7 +379,7 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
if case .chatList = source, groupAndIndex != nil { 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 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 { if let chatListController = chatListController {
chatListController.deletePeerChat(peerId: peerId) chatListController.deletePeerChat(peerId: peerId, joined: joined)
} }
f(.default) f(.default)
}))) })))

View File

@ -575,11 +575,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
strongSelf.hidePsa(peerId) 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 { guard let strongSelf = self else {
return return
} }
strongSelf.deletePeerChat(peerId: peerId) strongSelf.deletePeerChat(peerId: peerId, joined: joined)
} }
self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, promoInfo in self.chatListDisplayNode.containerNode.peerSelected = { [weak self] peer, animated, promoInfo in
@ -801,6 +801,16 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
gesture?.cancel() gesture?.cancel()
return 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 { switch item.content {
case let .groupReference(groupReference): case let .groupReference(groupReference):
let chatListController = ChatListControllerImpl(context: strongSelf.context, groupId: groupReference.groupId, controlsHistoryPreload: false, hideNetworkActivityStatus: true, previewing: true, enableDebugActions: false) 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, _, _, _): 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)) 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) 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) 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)) 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) 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) strongSelf.presentInGlobalOverlay(contextController)
} }
@ -2069,7 +2079,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
let _ = hideAccountPromoInfoChat(account: self.context.account, peerId: id).start() 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 let _ = (self.context.account.postbox.transaction { transaction -> RenderedPeer? in
guard let peer = transaction.getPeer(peerId) else { guard let peer = transaction.getPeer(peerId) else {
return nil return nil
@ -2099,7 +2109,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
} }
if let user = chatPeer as? TelegramUser, user.botInfo == nil, canRemoveGlobally { 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 { } else {
let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData) let actionSheet = ActionSheetController(presentationData: strongSelf.presentationData)
var items: [ActionSheetItem] = [] var items: [ActionSheetItem] = []
@ -2191,6 +2201,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
var items: [ActionSheetItem] = [] 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(DeleteChatPeerActionSheetItem(context: strongSelf.context, peer: mainPeer, chatPeer: chatPeer, action: .clearHistory, strings: strongSelf.presentationData.strings, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder))
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 items.append(ActionSheetButtonItem(title: strongSelf.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak actionSheet] in
beginClear(.forEveryone) beginClear(.forEveryone)
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
@ -2199,6 +2216,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
beginClear(.forLocalPeer) beginClear(.forLocalPeer)
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
})) }))
}
actionSheet.setItemGroups([ actionSheet.setItemGroups([
ActionSheetItemGroup(items: items), 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 { guard let chatPeer = peer.peers[peer.peerId], let mainPeer = peer.chatMainPeer else {
completion(false) completion(false)
return return
@ -2279,6 +2297,16 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
var items: [ActionSheetItem] = [] 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(DeleteChatPeerActionSheetItem(context: self.context, peer: mainPeer, chatPeer: chatPeer, action: .delete, strings: self.presentationData.strings, nameDisplayOrder: self.presentationData.nameDisplayOrder))
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 items.append(ActionSheetButtonItem(title: self.presentationData.strings.ChatList_DeleteForEveryone(mainPeer.compactDisplayTitle).0, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
guard let strongSelf = self else { guard let strongSelf = self else {
@ -2303,7 +2331,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController,
}) })
completion(true) completion(true)
})) }))
}
actionSheet.setItemGroups([ actionSheet.setItemGroups([
ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: items),
ActionSheetItemGroup(items: [ ActionSheetItemGroup(items: [

View File

@ -195,7 +195,7 @@ private final class ChatListShimmerNode: ASDisplayNode {
let timestamp1: Int32 = 100000 let timestamp1: Int32 = 100000
let peers = SimpleDictionary<PeerId, Peer>() let peers = SimpleDictionary<PeerId, Peer>()
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in 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() gesture?.cancel()
}, present: { _ in }) }, present: { _ in })
@ -478,8 +478,8 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
itemNode.listNode.hidePsa = { [weak self] peerId in itemNode.listNode.hidePsa = { [weak self] peerId in
self?.hidePsa?(peerId) self?.hidePsa?(peerId)
} }
itemNode.listNode.deletePeerChat = { [weak self] peerId in itemNode.listNode.deletePeerChat = { [weak self] peerId, joined in
self?.deletePeerChat?(peerId) self?.deletePeerChat?(peerId, joined)
} }
itemNode.listNode.peerSelected = { [weak self] peerId, a, b in itemNode.listNode.peerSelected = { [weak self] peerId, a, b in
self?.peerSelected?(peerId, a, b) self?.peerSelected?(peerId, a, b)
@ -527,7 +527,7 @@ final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDelegate {
var present: ((ViewController) -> Void)? var present: ((ViewController) -> Void)?
var toggleArchivedFolderHiddenByDefault: (() -> Void)? var toggleArchivedFolderHiddenByDefault: (() -> Void)?
var hidePsa: ((PeerId) -> Void)? var hidePsa: ((PeerId) -> Void)?
var deletePeerChat: ((PeerId) -> Void)? var deletePeerChat: ((PeerId, Bool) -> Void)?
var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)? var peerSelected: ((Peer, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
var groupSelected: ((PeerGroupId) -> Void)? var groupSelected: ((PeerGroupId) -> Void)?
var updatePeerGrouping: ((PeerId, Bool) -> Void)? var updatePeerGrouping: ((PeerId, Bool) -> Void)?

View File

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

View File

@ -1946,7 +1946,15 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
item.interaction.setPeerMuted(item.index.messageIndex.id.peerId, false) item.interaction.setPeerMuted(item.index.messageIndex.id.peerId, false)
close = false close = false
case RevealOptionKey.delete.rawValue: 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: case RevealOptionKey.archive.rawValue:
item.interaction.updatePeerGrouping(item.index.messageIndex.id.peerId, true) item.interaction.updatePeerGrouping(item.index.messageIndex.id.peerId, true)
close = false close = false

View File

@ -59,7 +59,7 @@ public final class ChatListNodeInteraction {
let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void let setPeerIdWithRevealedOptions: (PeerId?, PeerId?) -> Void
let setItemPinned: (PinnedItemId, Bool) -> Void let setItemPinned: (PinnedItemId, Bool) -> Void
let setPeerMuted: (PeerId, Bool) -> Void let setPeerMuted: (PeerId, Bool) -> Void
let deletePeer: (PeerId) -> Void let deletePeer: (PeerId, Bool) -> Void
let updatePeerGrouping: (PeerId, Bool) -> Void let updatePeerGrouping: (PeerId, Bool) -> Void
let togglePeerMarkedUnread: (PeerId, Bool) -> Void let togglePeerMarkedUnread: (PeerId, Bool) -> Void
let toggleArchivedFolderHiddenByDefault: () -> Void let toggleArchivedFolderHiddenByDefault: () -> Void
@ -70,7 +70,7 @@ public final class ChatListNodeInteraction {
public var searchTextHighightState: String? public var searchTextHighightState: String?
var highlightedChatLocation: ChatListHighlightedLocation? 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.activateSearch = activateSearch
self.peerSelected = peerSelected self.peerSelected = peerSelected
self.disabledPeerSelected = disabledPeerSelected self.disabledPeerSelected = disabledPeerSelected
@ -430,7 +430,7 @@ public final class ChatListNode: ListView {
public var groupSelected: ((PeerGroupId) -> Void)? public var groupSelected: ((PeerGroupId) -> Void)?
public var addContact: ((String) -> Void)? public var addContact: ((String) -> Void)?
public var activateSearch: (() -> Void)? public var activateSearch: (() -> Void)?
public var deletePeerChat: ((PeerId) -> Void)? public var deletePeerChat: ((PeerId, Bool) -> Void)?
public var updatePeerGrouping: ((PeerId, Bool) -> Void)? public var updatePeerGrouping: ((PeerId, Bool) -> Void)?
public var presentAlert: ((String) -> Void)? public var presentAlert: ((String) -> Void)?
public var present: ((ViewController) -> Void)? public var present: ((ViewController) -> Void)?
@ -628,8 +628,8 @@ public final class ChatListNode: ListView {
} }
self?.setCurrentRemovingPeerId(nil) self?.setCurrentRemovingPeerId(nil)
}) })
}, deletePeer: { [weak self] peerId in }, deletePeer: { [weak self] peerId, joined in
self?.deletePeerChat?(peerId) self?.deletePeerChat?(peerId, joined)
}, updatePeerGrouping: { [weak self] peerId, group in }, updatePeerGrouping: { [weak self] peerId, group in
self?.updatePeerGrouping?(peerId, group) self?.updatePeerGrouping?(peerId, group)
}, togglePeerMarkedUnread: { [weak self, weak context] peerId, animated in }, 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 keepMinimalScrollHeightWithTopInset: CGFloat?
public final var itemNodeHitTest: ((CGPoint) -> Bool)?
public final var stackFromBottom: Bool = false public final var stackFromBottom: Bool = false
public final var stackFromBottomInsetItemFactor: CGFloat = 0.0 public final var stackFromBottomInsetItemFactor: CGFloat = 0.0
public final var limitHitTestToNodes: Bool = false public final var limitHitTestToNodes: Bool = false
@ -3876,8 +3878,14 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
} }
self.touchesPosition = touchesPosition self.touchesPosition = touchesPosition
self.selectionTouchLocation = touches.first!.location(in: self.view)
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.selectionTouchDelayTimer?.invalidate()
self.selectionLongTapDelayTimer?.invalidate() self.selectionLongTapDelayTimer?.invalidate()
self.selectionLongTapDelayTimer = nil self.selectionLongTapDelayTimer = nil
@ -3936,7 +3944,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false) }, selector: #selector(ListViewTimerProxy.timerEvent), userInfo: nil, repeats: false)
self.selectionTouchDelayTimer = timer self.selectionTouchDelayTimer = timer
RunLoop.main.add(timer, forMode: RunLoop.Mode.common) RunLoop.main.add(timer, forMode: RunLoop.Mode.common)
}
super.touchesBegan(touches, with: event) super.touchesBegan(touches, with: event)
self.updateScroller(transition: .immediate) self.updateScroller(transition: .immediate)

View File

@ -579,6 +579,7 @@ open class NavigationController: UINavigationController, ContainableController,
var previousModalContainer: NavigationModalContainer? var previousModalContainer: NavigationModalContainer?
var visibleModalCount = 0 var visibleModalCount = 0
var topModalIsFlat = false var topModalIsFlat = false
var isLandscape = layout.orientation == .landscape
var hasVisibleStandaloneModal = false var hasVisibleStandaloneModal = false
var topModalDismissProgress: CGFloat = 0.0 var topModalDismissProgress: CGFloat = 0.0
@ -784,7 +785,7 @@ open class NavigationController: UINavigationController, ContainableController,
let visibleRootModalDismissProgress: CGFloat let visibleRootModalDismissProgress: CGFloat
var additionalModalFrameProgress: CGFloat var additionalModalFrameProgress: CGFloat
if visibleModalCount == 1 { if visibleModalCount == 1 {
effectiveRootModalDismissProgress = topModalIsFlat ? 1.0 : topModalDismissProgress effectiveRootModalDismissProgress = (topModalIsFlat || isLandscape) ? 1.0 : topModalDismissProgress
visibleRootModalDismissProgress = effectiveRootModalDismissProgress visibleRootModalDismissProgress = effectiveRootModalDismissProgress
additionalModalFrameProgress = 0.0 additionalModalFrameProgress = 0.0
} else if visibleModalCount >= 2 { } else if visibleModalCount >= 2 {
@ -851,7 +852,7 @@ open class NavigationController: UINavigationController, ContainableController,
} }
let maxScale: CGFloat let maxScale: CGFloat
let maxOffset: CGFloat let maxOffset: CGFloat
if topModalIsFlat { if topModalIsFlat || isLandscape {
maxScale = 1.0 maxScale = 1.0
maxOffset = 0.0 maxOffset = 0.0
} else if visibleModalCount <= 1 { } else if visibleModalCount <= 1 {

View File

@ -328,6 +328,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
self.scrollNode.view.isScrollEnabled = !isStandaloneModal self.scrollNode.view.isScrollEnabled = !isStandaloneModal
let isLandscape = layout.orientation == .landscape
let containerLayout: ContainerViewLayout let containerLayout: ContainerViewLayout
let containerFrame: CGRect let containerFrame: CGRect
let containerScale: CGFloat let containerScale: CGFloat
@ -336,7 +337,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
self.panRecognizer?.isEnabled = true self.panRecognizer?.isEnabled = true
self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25) self.dim.backgroundColor = UIColor(white: 0.0, alpha: 0.25)
self.container.clipsToBounds = true self.container.clipsToBounds = true
if isStandaloneModal { if isStandaloneModal || isLandscape {
self.container.cornerRadius = 0.0 self.container.cornerRadius = 0.0
} else { } else {
self.container.cornerRadius = 10.0 self.container.cornerRadius = 10.0
@ -351,7 +352,7 @@ final class NavigationModalContainer: ASDisplayNode, UIScrollViewDelegate, UIGes
} }
var topInset: CGFloat var topInset: CGFloat
if isStandaloneModal { if isStandaloneModal || isLandscape {
topInset = 0.0 topInset = 0.0
containerLayout = layout containerLayout = layout

View File

@ -62,6 +62,16 @@ final class GameControllerNode: ViewControllerTracingNode {
}, name: "performAction") }, name: "performAction")
configuration.userContentController = userController 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) let webView = WKWebView(frame: CGRect(), configuration: configuration)
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
webView.allowsLinkPreview = false webView.allowsLinkPreview = false

View File

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

View File

@ -238,7 +238,9 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.listNode = ListView() self.listNode = ListView()
self.leftOverlayNode = ASDisplayNode() self.leftOverlayNode = ASDisplayNode()
self.leftOverlayNode.isUserInteractionEnabled = false
self.rightOverlayNode = ASDisplayNode() self.rightOverlayNode = ASDisplayNode()
self.rightOverlayNode.isUserInteractionEnabled = false
super.init() super.init()
@ -303,6 +305,14 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
} }
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) let previousState = Atomic<ItemListNodeState?>(value: nil)
self.transitionDisposable.set(((state self.transitionDisposable.set(((state
|> map { presentationData, stateAndArguments -> ItemListNodeTransition in |> map { presentationData, stateAndArguments -> ItemListNodeTransition in

View File

@ -71,6 +71,8 @@
bool _throttle; bool _throttle;
TGLocationPinAnnotationView *_ownLiveLocationView; TGLocationPinAnnotationView *_ownLiveLocationView;
__weak MKAnnotationView *_userLocationView; __weak MKAnnotationView *_userLocationView;
UIImageView *_headingArrowView;
} }
@end @end
@ -162,6 +164,8 @@
[_liveLocationsDisposable dispose]; [_liveLocationsDisposable dispose];
[_reloadDisposable dispose]; [_reloadDisposable dispose];
[_frequentUpdatesDisposable dispose]; [_frequentUpdatesDisposable dispose];
[_locationManager stopUpdatingHeading];
} }
- (void)tg_setRightBarButtonItem:(UIBarButtonItem *)barButtonItem action:(bool)action animated:(bool)animated { - (void)tg_setRightBarButtonItem:(UIBarButtonItem *)barButtonItem action:(bool)action animated:(bool)animated {
@ -438,6 +442,36 @@
{ {
[super loadView]; [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; _tableView.scrollsToTop = false;
_mapView.tapEnabled = false; _mapView.tapEnabled = false;
@ -495,6 +529,8 @@
{ {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
[_locationManager startUpdatingHeading];
if (self.previewMode && !animated) if (self.previewMode && !animated)
{ {
UIView *contentView = [[_mapView subviews] firstObject]; UIView *contentView = [[_mapView subviews] firstObject];
@ -950,6 +986,9 @@
{ {
_userLocationView = view; _userLocationView = view;
[_userLocationView addSubview:_headingArrowView];
_headingArrowView.center = CGPointMake(view.frame.size.width / 2.0, view.frame.size.height / 2.0);
if (_ownLiveLocationView != nil) if (_ownLiveLocationView != nil)
{ {
[_userLocationView addSubview:_ownLiveLocationView]; [_userLocationView addSubview:_ownLiveLocationView];
@ -982,6 +1021,14 @@
return CLLocationCoordinate2DMake(_locationAttachment.latitude, _locationAttachment.longitude); 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 - #pragma mark -
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

View File

@ -86,7 +86,7 @@ static void setViewFrame(UIView *view, CGRect frame)
{ {
localizationPlaceholderText = TGLocalized(@"MediaPicker.AddCaption"); localizationPlaceholderText = TGLocalized(@"MediaPicker.AddCaption");
NSString *placeholderText = TGLocalized(@"MediaPicker.AddCaption"); NSString *placeholderText = TGLocalized(@"MediaPicker.AddCaption");
UIFont *placeholderFont = TGSystemFontOfSize(16); UIFont *placeholderFont = TGSystemFontOfSize(17);
CGSize placeholderSize = [placeholderText sizeWithFont:placeholderFont]; CGSize placeholderSize = [placeholderText sizeWithFont:placeholderFont];
placeholderSize.width += 2.0f; placeholderSize.width += 2.0f;
placeholderSize.height += 2.0f; placeholderSize.height += 2.0f;
@ -121,7 +121,7 @@ static void setViewFrame(UIView *view, CGRect frame)
_placeholderLabel = [[UILabel alloc] init]; _placeholderLabel = [[UILabel alloc] init];
_placeholderLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin; _placeholderLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
_placeholderLabel.backgroundColor = [UIColor clearColor]; _placeholderLabel.backgroundColor = [UIColor clearColor];
_placeholderLabel.font = TGSystemFontOfSize(16); _placeholderLabel.font = TGSystemFontOfSize(17);
_placeholderLabel.textColor = UIColorRGB(0x7f7f7f); _placeholderLabel.textColor = UIColorRGB(0x7f7f7f);
_placeholderLabel.text = TGLocalized(@"MediaPicker.AddCaption"); _placeholderLabel.text = TGLocalized(@"MediaPicker.AddCaption");
_placeholderLabel.userInteractionEnabled = true; _placeholderLabel.userInteractionEnabled = true;
@ -130,7 +130,7 @@ static void setViewFrame(UIView *view, CGRect frame)
_inputFieldOnelineLabel = [[UILabel alloc] init]; _inputFieldOnelineLabel = [[UILabel alloc] init];
_inputFieldOnelineLabel.backgroundColor = [UIColor clearColor]; _inputFieldOnelineLabel.backgroundColor = [UIColor clearColor];
_inputFieldOnelineLabel.font = TGSystemFontOfSize(16); _inputFieldOnelineLabel.font = TGSystemFontOfSize(17);
_inputFieldOnelineLabel.hidden = true; _inputFieldOnelineLabel.hidden = true;
_inputFieldOnelineLabel.numberOfLines = 1; _inputFieldOnelineLabel.numberOfLines = 1;
_inputFieldOnelineLabel.textColor = [UIColor whiteColor]; _inputFieldOnelineLabel.textColor = [UIColor whiteColor];
@ -169,7 +169,7 @@ static void setViewFrame(UIView *view, CGRect frame)
_inputField.textColor = [UIColor whiteColor]; _inputField.textColor = [UIColor whiteColor];
_inputField.disableFormatting = !_allowEntities; _inputField.disableFormatting = !_allowEntities;
_inputField.placeholderView = _placeholderLabel; _inputField.placeholderView = _placeholderLabel;
_inputField.font = TGSystemFontOfSize(16); _inputField.font = TGSystemFontOfSize(17);
_inputField.accentColor = UIColorRGB(0x78b1f9); _inputField.accentColor = UIColorRGB(0x78b1f9);
_inputField.clipsToBounds = true; _inputField.clipsToBounds = true;
_inputField.backgroundColor = nil; _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.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]; [_inputFieldClippingContainer addSubview:_inputField];
} }
@ -439,7 +439,7 @@ static void setViewFrame(UIView *view, CGRect frame)
_fieldBackground.alpha = _placeholderLabel.hidden ? 1.0f : 0.0f; _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 { + (NSAttributedString *)attributedStringForText:(NSString *)text entities:(NSArray *)entities fontSize:(CGFloat)fontSize {
@ -777,14 +777,14 @@ static void setViewFrame(UIView *view, CGRect frame)
if (text == nil) if (text == nil)
return 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++) for (NSUInteger i = 0; i < string.length; i++)
{ {
unichar c = [text characterAtIndex:i]; unichar c = [text characterAtIndex:i];
if (c == '\t' || c == '\n') 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; break;
} }
} }

View File

@ -167,13 +167,14 @@
if (recipientName.length > 0) if (recipientName.length > 0)
{ {
_arrowView = [[UIImageView alloc] initWithImage: TGComponentsImageNamed(@"PhotoPickerArrow")]; _arrowView = [[UIImageView alloc] initWithImage: TGComponentsImageNamed(@"PhotoPickerArrow")];
_arrowView.alpha = 0.45f; _arrowView.alpha = 0.6f;
[_wrapperView addSubview:_arrowView]; [_wrapperView addSubview:_arrowView];
_recipientLabel = [[UILabel alloc] init]; _recipientLabel = [[UILabel alloc] init];
_recipientLabel.alpha = 0.6;
_recipientLabel.backgroundColor = [UIColor clearColor]; _recipientLabel.backgroundColor = [UIColor clearColor];
_recipientLabel.font = TGBoldSystemFontOfSize(13.0f); _recipientLabel.font = TGBoldSystemFontOfSize(13.0f);
_recipientLabel.textColor = UIColorRGBA(0xffffff, 0.45f); _recipientLabel.textColor = UIColorRGB(0xffffff);
_recipientLabel.text = recipientName; _recipientLabel.text = recipientName;
_recipientLabel.userInteractionEnabled = false; _recipientLabel.userInteractionEnabled = false;
[_recipientLabel sizeToFit]; [_recipientLabel sizeToFit];
@ -511,12 +512,6 @@
__weak TGMediaPickerGalleryInterfaceView *weakSelf = self; __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)]; [self _layoutRecipientLabelForOrientation:[self interfaceOrientation] screenEdges:screenEdges hasHeaderView:(itemView.headerView != nil)];
if (_selectionContext != nil) if (_selectionContext != nil)
@ -1039,8 +1034,8 @@
{ {
_checkButton.alpha = alpha; _checkButton.alpha = alpha;
_muteButton.alpha = alpha; _muteButton.alpha = alpha;
_arrowView.alpha = alpha * 0.45f; _arrowView.alpha = alpha * 0.6f;
_recipientLabel.alpha = alpha; _recipientLabel.alpha = alpha * 0.6;
} completion:^(BOOL finished) } completion:^(BOOL finished)
{ {
if (finished) if (finished)
@ -1070,8 +1065,8 @@
_muteButton.alpha = alpha; _muteButton.alpha = alpha;
_muteButton.userInteractionEnabled = !hidden; _muteButton.userInteractionEnabled = !hidden;
_arrowView.alpha = alpha * 0.45f; _arrowView.alpha = alpha * 0.6f;
_recipientLabel.alpha = alpha; _recipientLabel.alpha = alpha * 0.6;
} }
if (hidden) if (hidden)
@ -1095,7 +1090,7 @@
{ {
_checkButton.alpha = alpha; _checkButton.alpha = alpha;
_muteButton.alpha = alpha; _muteButton.alpha = alpha;
_arrowView.alpha = alpha * 0.45f; _arrowView.alpha = alpha * 0.6;
_recipientLabel.alpha = alpha; _recipientLabel.alpha = alpha;
_portraitToolbarView.alpha = alpha; _portraitToolbarView.alpha = alpha;
_landscapeToolbarView.alpha = alpha; _landscapeToolbarView.alpha = alpha;
@ -1132,7 +1127,7 @@
_muteButton.alpha = alpha; _muteButton.alpha = alpha;
_muteButton.userInteractionEnabled = !hidden; _muteButton.userInteractionEnabled = !hidden;
_arrowView.alpha = alpha * 0.45f; _arrowView.alpha = alpha * 0.6;
_recipientLabel.alpha = alpha; _recipientLabel.alpha = alpha;
_portraitToolbarView.alpha = alpha; _portraitToolbarView.alpha = alpha;
@ -1391,6 +1386,8 @@
screenEdges.left += _safeAreaInset.left; screenEdges.left += _safeAreaInset.left;
screenEdges.right -= _safeAreaInset.right; screenEdges.right -= _safeAreaInset.right;
CGFloat panelInset = 0.0f;
switch (orientation) switch (orientation)
{ {
case UIInterfaceOrientationLandscapeLeft: case UIInterfaceOrientationLandscapeLeft:
@ -1402,13 +1399,10 @@
break; break;
default: 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; break;
} }
if (hasHeaderView)
frame.origin.y += 64;
return frame; return frame;
} }
@ -1462,9 +1456,6 @@
break; break;
} }
if (hasHeaderView)
frame.origin.y += 64;
return frame; return frame;
} }
@ -1526,9 +1517,6 @@
_arrowView.frame = frame; _arrowView.frame = frame;
_recipientLabel.frame = CGRectMake(CGRectGetMaxX(_arrowView.frame) + 6.0f, _arrowView.frame.origin.y - 2.0f, recipientWidth, _recipientLabel.frame.size.height); _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 - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)__unused duration
@ -1670,15 +1658,14 @@
{ {
[UIView performWithoutAnimation:^ [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); _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, _portraitToolbarView.frame.origin.y - 64.0 - [_captionMixin.inputPanel baseHeight], self.frame.size.width, 64.0);
_headerWrapperView.frame = CGRectMake(screenEdges.left, screenEdges.top + topInset, self.frame.size.width, 64);
} }
break; break;
} }

View File

@ -71,6 +71,8 @@
bool _scrubbingPanelPresented; bool _scrubbingPanelPresented;
bool _scrubbingPanelLocked; bool _scrubbingPanelLocked;
bool _shouldResetScrubber; bool _shouldResetScrubber;
NSArray *_cachedThumbnails;
UIImage *_immediateThumbnail;
UILabel *_fileInfoLabel; UILabel *_fileInfoLabel;
@ -215,13 +217,12 @@
_headerView = headerView; _headerView = headerView;
_headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; _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.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_scrubberPanelView.hidden = true;
headerView.panelView = _scrubberPanelView; headerView.panelView = _scrubberPanelView;
[_headerView addSubview:_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.autoresizingMask = UIViewAutoresizingFlexibleWidth;
scrubberBackgroundView.backgroundColor = [TGPhotoEditorInterfaceAssets toolbarTransparentBackgroundColor]; scrubberBackgroundView.backgroundColor = [TGPhotoEditorInterfaceAssets toolbarTransparentBackgroundColor];
[_scrubberPanelView addSubview:scrubberBackgroundView]; [_scrubberPanelView addSubview:scrubberBackgroundView];
@ -301,7 +302,6 @@
_appeared = false; _appeared = false;
[self setScrubbingPanelApperanceLocked:false]; [self setScrubbingPanelApperanceLocked:false];
[self setScrubbingPanelHidden:true animated:false];
[_positionTimer invalidate]; [_positionTimer invalidate];
_positionTimer = nil; _positionTimer = nil;
@ -386,9 +386,14 @@
- (void)setItem:(TGMediaPickerGalleryVideoItem *)item synchronously:(bool)synchronously - (void)setItem:(TGMediaPickerGalleryVideoItem *)item synchronously:(bool)synchronously
{ {
bool itemChanged = ![item isEqual:self.item]; bool itemChanged = ![item isEqual:self.item];
bool itemIdChanged = item.uniqueId != self.item.uniqueId;
[super setItem:item synchronously:synchronously]; [super setItem:item synchronously:synchronously];
if (itemIdChanged) {
_immediateThumbnail = item.immediateThumbnailImage;
}
if (itemChanged) { if (itemChanged) {
[self _playerCleanup]; [self _playerCleanup];
@ -618,17 +623,15 @@
void (^changeBlock)(void) = ^ 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) void (^completionBlock)(BOOL) = ^(BOOL finished)
{ {
if (finished)
_scrubberPanelView.hidden = true;
}; };
if (animated) 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 else
{ {
@ -643,17 +646,16 @@
_scrubbingPanelPresented = true; _scrubbingPanelPresented = true;
_scrubberPanelView.hidden = false;
[_scrubberPanelView layoutSubviews]; [_scrubberPanelView layoutSubviews];
[_scrubberView layoutSubviews]; [_scrubberView layoutSubviews];
void (^changeBlock)(void) = ^ void (^changeBlock)(void) = ^
{ {
_scrubberPanelView.frame = CGRectMake(0.0f, 0.0f, _scrubberPanelView.frame.size.width, _scrubberPanelView.frame.size.height); _scrubberPanelView.alpha = 1.0f;
}; };
if (animated) 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 else
changeBlock(); changeBlock();
} }
@ -708,7 +710,6 @@
{ {
[_scrubberView resetThumbnails]; [_scrubberView resetThumbnails];
[self setScrubbingPanelHidden:true animated:false];
[_scrubberPanelView setNeedsLayout]; [_scrubberPanelView setNeedsLayout];
[_scrubberPanelView layoutIfNeeded]; [_scrubberPanelView layoutIfNeeded];
@ -722,11 +723,14 @@
if (_containerView == nil) if (_containerView == nil)
return; return;
if (self.bounds.size.width > self.bounds.size.height)
_containerView.frame = self.bounds; _containerView.frame = self.bounds;
else
_containerView.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height - 44.0);
[self _layoutPlayerView]; [self _layoutPlayerView];
_videoContentView.frame = (CGRect){CGPointZero, frame.size}; _videoContentView.frame = (CGRect){CGPointZero, _containerView.frame.size};
if (_tooltipContainerView != nil && frame.size.width > frame.size.height) if (_tooltipContainerView != nil && frame.size.width > frame.size.height)
{ {
@ -753,8 +757,6 @@
mirrored = adjustments.cropMirrored; mirrored = adjustments.cropMirrored;
} }
// _scrubberView.maximumLength = adjustments.sendAsGif ? TGVideoEditMaximumGifDuration : 0.0;
[self _layoutPlayerViewWithCropRect:cropRect videoFrameSize:videoFrameSize orientation:orientation mirrored:mirrored]; [self _layoutPlayerViewWithCropRect:cropRect videoFrameSize:videoFrameSize orientation:orientation mirrored:mirrored];
} }
@ -1440,40 +1442,8 @@
trimEndValue = adjustments.trimEndValue; trimEndValue = adjustments.trimEndValue;
} }
} }
// NSTimeInterval trimDuration = trimEndValue - trimStartValue;
bool sendAsGif = !adjustments.sendAsGif; 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]; 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]; [self.item.editingContext setAdjustments:updatedAdjustments forItem:self.item.editableMediaItem];
@ -1596,6 +1566,23 @@
return timestamps; 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 - (void)videoScrubber:(TGMediaPickerGalleryVideoScrubber *)__unused videoScrubber requestThumbnailImagesForTimestamps:(NSArray *)timestamps size:(CGSize)size isSummaryThumbnails:(bool)isSummaryThumbnails
{ {
if (timestamps.count == 0) if (timestamps.count == 0)
@ -1605,17 +1592,42 @@
TGMediaEditingContext *editingContext = self.item.editingContext; TGMediaEditingContext *editingContext = self.item.editingContext;
id<TGMediaEditableItem> editableItem = self.editableMediaItem; 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];
// }];
__strong TGMediaPickerGalleryVideoItemView *weakSelf = self;
SSignal *thumbnailsSignal = nil; SSignal *thumbnailsSignal = nil;
if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto]) if (_cachedThumbnails != nil) {
thumbnailsSignal = [TGMediaAssetImageSignals videoThumbnailsForAsset:self.item.asset size:size timestamps:timestamps]; thumbnailsSignal = [SSignal single:_cachedThumbnails];
else if (avAsset != nil) } else if ([self.item.asset isKindOfClass:[TGMediaAsset class]] && ![self itemIsLivePhoto]) {
thumbnailsSignal = [avAsset mapToSignal:^SSignal *(AVAsset *avAsset) { thumbnailsSignal = [[self _placeholderThumbnails:timestamps] then:[[TGMediaAssetImageSignals videoThumbnailsForAsset:(TGMediaAsset *)self.item.asset size:size timestamps:timestamps] onNext:^(NSArray *images) {
return [TGMediaAssetImageSignals videoThumbnailsForAVAsset:avAsset size:size timestamps:timestamps]; __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; _requestingThumbnails = true;
__weak TGMediaPickerGalleryVideoItemView *weakSelf = self;
[_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) { [_thumbnailsDisposable setDisposable:[[[thumbnailsSignal map:^NSArray *(NSArray *images) {
id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:editableItem]; id<TGMediaEditAdjustments> adjustments = [editingContext adjustmentsForItem:editableItem];
if (adjustments.toolsApplied) { if (adjustments.toolsApplied) {

View File

@ -45,8 +45,6 @@
- (void)setThumbnailImage:(UIImage *)image forTimestamp:(NSTimeInterval)timestamp index:(NSInteger)index isSummaryThubmnail:(bool)isSummaryThumbnail; - (void)setThumbnailImage:(UIImage *)image forTimestamp:(NSTimeInterval)timestamp index:(NSInteger)index isSummaryThubmnail:(bool)isSummaryThumbnail;
- (void)setRecipientName:(NSString *)recipientName;
- (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position; - (CGPoint)scrubberPositionForPosition:(NSTimeInterval)position;
- (void)_updateScrubberAnimationsAndResetCurrentPosition:(bool)resetCurrentPosition; - (void)_updateScrubberAnimationsAndResetCurrentPosition:(bool)resetCurrentPosition;

View File

@ -81,9 +81,6 @@ typedef enum
NSInteger _zoomedPivotTimestampIndex; NSInteger _zoomedPivotTimestampIndex;
NSArray *_zoomedTimestamps; NSArray *_zoomedTimestamps;
NSMutableArray *_zoomedThumbnailViews; NSMutableArray *_zoomedThumbnailViews;
UIImageView *_arrowView;
UILabel *_recipientLabel;
} }
@end @end
@ -417,33 +414,10 @@ typedef enum
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
_tapGestureRecognizer.enabled = false; _tapGestureRecognizer.enabled = false;
[_trimView addGestureRecognizer:_tapGestureRecognizer]; [_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; 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 { - (void)setHasDotPicker:(bool)hasDotPicker {
_hasDotPicker = hasDotPicker; _hasDotPicker = hasDotPicker;
_tapGestureRecognizer.enabled = hasDotPicker; _tapGestureRecognizer.enabled = hasDotPicker;
@ -1052,11 +1026,9 @@ typedef enum
- (void)_updateTimeLabels - (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 ? @"" : [TGMediaPickerGalleryVideoScrubber _stringFromTotalSeconds:(NSInteger)self.duration];
_inverseTimeLabel.text = self.disableTimeDisplay ? @"" : text;
} }
#pragma mark - Scrubber Handle #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 - (void)setFrame:(CGRect)frame
{ {
if (isnan(frame.origin.x) || isnan(frame.origin.y) || isnan(frame.size.width) || isnan(frame.size.height)) 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; _zoomedThumbnailWrapperView.frame = _summaryThumbnailWrapperView.frame;
[self _updateScrubberAnimationsAndResetCurrentPosition:true]; [self _updateScrubberAnimationsAndResetCurrentPosition:true];
[self _layoutRecipientLabel];
} }
+ (NSString *)_stringFromTotalSeconds:(NSInteger)totalSeconds + (NSString *)_stringFromTotalSeconds:(NSInteger)totalSeconds

View File

@ -48,7 +48,7 @@ const CGFloat TGPhotoCounterButtonMaskFade = 18;
{ {
UIGraphicsBeginImageContextWithOptions(CGSizeMake(38.0f, 38.0f), false, 0.0f); UIGraphicsBeginImageContextWithOptions(CGSizeMake(38.0f, 38.0f), false, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext(); 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)); 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); CGRect rect = CGRectMake(0, 0, 39.0f, 39.0f);
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0); UIGraphicsBeginImageContextWithOptions(rect.size, false, 0);
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.6f).CGColor); CGContextSetFillColorWithColor(context, UIColorRGBA(0x000000, 0.3f).CGColor);
CGContextFillEllipseInRect(context, CGRectInset(rect, 3, 3)); CGContextFillEllipseInRect(context, CGRectInset(rect, 3, 3));
muteBackground = UIGraphicsGetImageFromCurrentImageContext(); muteBackground = UIGraphicsGetImageFromCurrentImageContext();

View File

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

View File

@ -8,11 +8,18 @@ import TelegramPresentationData
import ItemListUI import ItemListUI
import AppBundle import AppBundle
enum LocationAttribution: Equatable {
case foursquare
case google
}
class LocationAttributionItem: ListViewItem { class LocationAttributionItem: ListViewItem {
let presentationData: ItemListPresentationData let presentationData: ItemListPresentationData
let attribution: LocationAttribution
public init(presentationData: ItemListPresentationData) { public init(presentationData: ItemListPresentationData, attribution: LocationAttribution) {
self.presentationData = presentationData 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) { 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 strongSelf.layoutParams = params
if let _ = updatedTheme { if let _ = updatedTheme {
switch item.attribution {
case .foursquare:
strongSelf.imageNode.image = generateTintedImage(image: UIImage(bundleImageName: "Location/FoursquareAttribution"), color: item.presentationData.theme.list.itemSecondaryTextColor) 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 { 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 { final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
private let locationPromise = Promise<CLLocation?>(nil) private let locationPromise = Promise<CLLocation?>(nil)
private let pickerAnnotationContainerView: PickerAnnotationContainerView private let pickerAnnotationContainerView: PickerAnnotationContainerView
private weak var userLocationAnnotationView: MKAnnotationView? private weak var userLocationAnnotationView: MKAnnotationView?
private var headingArrowView: UIImageView?
private let pinDisposable = MetaDisposable() private let pinDisposable = MetaDisposable()
@ -103,6 +122,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
override func didLoad() { override func didLoad() {
super.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 self.mapView?.interactiveTransitionGestureRecognizerTest = { p in
if p.x > 44.0 { if p.x > 44.0 {
return true return true
@ -232,6 +255,10 @@ final class LocationMapNode: ASDisplayNode, MKMapViewDelegate {
for view in views { for view in views {
if view.annotation is MKUserLocation { if view.annotation is MKUserLocation {
self.userLocationAnnotationView = view 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 { if let annotationView = self.customUserLocationAnnotationView {
view.addSubview(annotationView) 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] = [] { var annotations: [LocationPinAnnotation] = [] {
didSet { didSet {
guard let mapView = self.mapView else { guard let mapView = self.mapView else {

View File

@ -289,7 +289,7 @@ public final class LocationPickerController: ViewController {
return 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.displayNodeDidLoad()
self.permissionDisposable = (DeviceAccess.authorizationStatus(subject: .location(.send)) self.permissionDisposable = (DeviceAccess.authorizationStatus(subject: .location(.send))

View File

@ -17,6 +17,7 @@ import AppBundle
import CoreLocation import CoreLocation
import Geocoding import Geocoding
import PhoneNumberFormat import PhoneNumberFormat
import DeviceAccess
private struct LocationPickerTransaction { private struct LocationPickerTransaction {
let deletions: [ListViewDeleteItem] let deletions: [ListViewDeleteItem]
@ -40,7 +41,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
case liveLocation(PresentationTheme, String, String, CLLocationCoordinate2D?) case liveLocation(PresentationTheme, String, String, CLLocationCoordinate2D?)
case header(PresentationTheme, String) case header(PresentationTheme, String)
case venue(PresentationTheme, TelegramMediaMap, Int) case venue(PresentationTheme, TelegramMediaMap, Int)
case attribution(PresentationTheme) case attribution(PresentationTheme, LocationAttribution)
var stableId: LocationPickerEntryId { var stableId: LocationPickerEntryId {
switch self { switch self {
@ -83,8 +84,8 @@ private enum LocationPickerEntry: Comparable, Identifiable {
} else { } else {
return false return false
} }
case let .attribution(lhsTheme): case let .attribution(lhsTheme, lhsAttribution):
if case let .attribution(rhsTheme) = rhs, lhsTheme === rhsTheme { if case let .attribution(rhsTheme, rhsAttribution) = rhs, lhsTheme === rhsTheme, lhsAttribution == rhsAttribution {
return true return true
} else { } else {
return false return false
@ -131,7 +132,7 @@ private enum LocationPickerEntry: Comparable, Identifiable {
func item(account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> ListViewItem { func item(account: Account, presentationData: PresentationData, interaction: LocationPickerInteraction?) -> ListViewItem {
switch self { switch self {
case let .location(theme, title, subtitle, venue, coordinate): case let .location(_, title, subtitle, venue, coordinate):
let icon: LocationActionListItemIcon let icon: LocationActionListItemIcon
if let venue = venue { if let venue = venue {
icon = .venue(venue) icon = .venue(venue)
@ -147,23 +148,23 @@ private enum LocationPickerEntry: Comparable, Identifiable {
}, highlighted: { highlighted in }, highlighted: { highlighted in
interaction?.updateSendActionHighlight(highlighted) 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: { return LocationActionListItem(presentationData: ItemListPresentationData(presentationData), account: account, title: title, subtitle: subtitle, icon: .liveLocation, action: {
if let coordinate = coordinate { if let coordinate = coordinate {
interaction?.sendLiveLocation(coordinate) interaction?.sendLiveLocation(coordinate)
} }
}) })
case let .header(theme, title): case let .header(_, title):
return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title) return LocationSectionHeaderItem(presentationData: ItemListPresentationData(presentationData), title: title)
case let .venue(theme, venue, _): case let .venue(_, venue, _):
let venueType = venue.venue?.type ?? "" let venueType = venue.venue?.type ?? ""
return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), account: account, venue: venue, style: .plain, action: { return ItemListVenueItem(presentationData: ItemListPresentationData(presentationData), account: account, venue: venue, style: .plain, action: {
interaction?.sendVenue(venue) interaction?.sendVenue(venue)
}, infoAction: ["home", "work"].contains(venueType) ? { }, infoAction: ["home", "work"].contains(venueType) ? {
interaction?.openHomeWorkInfo() interaction?.openHomeWorkInfo()
} : nil) } : nil)
case let .attribution(theme): case let .attribution(_, attribution):
return LocationAttributionItem(presentationData: ItemListPresentationData(presentationData)) 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 let context: AccountContext
private var presentationData: PresentationData private var presentationData: PresentationData
private let presentationDataPromise: Promise<PresentationData> private let presentationDataPromise: Promise<PresentationData>
private let mode: LocationPickerMode private let mode: LocationPickerMode
private let interaction: LocationPickerInteraction private let interaction: LocationPickerInteraction
private let locationManager: LocationManager
private let listNode: ListView private let listNode: ListView
private let emptyResultsTextNode: ImmediateTextNode private let emptyResultsTextNode: ImmediateTextNode
@ -269,12 +271,13 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)? private var validLayout: (layout: ContainerViewLayout, navigationHeight: CGFloat)?
private var listOffset: 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.context = context
self.presentationData = presentationData self.presentationData = presentationData
self.presentationDataPromise = Promise(presentationData) self.presentationDataPromise = Promise(presentationData)
self.mode = mode self.mode = mode
self.interaction = interaction self.interaction = interaction
self.locationManager = locationManager
self.state = LocationPickerState() self.state = LocationPickerState()
self.statePromise = Promise(self.state) self.statePromise = Promise(self.state)
@ -496,15 +499,21 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
entries.append(.header(presentationData.theme, presentationData.strings.Map_ChooseAPlace.uppercased())) 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 { if let venues = displayedVenues {
var index: Int = 0 var index: Int = 0
var attribution: LocationAttribution?
for venue in venues { 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)) entries.append(.venue(presentationData.theme, venue, index))
index += 1 index += 1
} }
if !venues.isEmpty { if let attribution = attribution {
entries.append(.attribution(presentationData.theme)) entries.append(.attribution(presentationData.theme, attribution))
} }
} }
let previousEntries = previousEntries.swap(entries) let previousEntries = previousEntries.swap(entries)
@ -533,7 +542,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
switch previousState.selectedLocation { switch previousState.selectedLocation {
case .none, .venue: case .none, .venue:
updateMap = true updateMap = true
case let .location(previousCoordinate, address): case let .location(previousCoordinate, _):
if previousCoordinate != coordinate { if previousCoordinate != coordinate {
updateMap = true updateMap = true
} }
@ -574,7 +583,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
if let (layout, navigationBarHeight) = strongSelf.validLayout { if let (layout, navigationBarHeight) = strongSelf.validLayout {
var updateLayout = false 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 { if previousState.displayingMapModeOptions != state.displayingMapModeOptions {
updateLayout = true updateLayout = true
@ -685,11 +694,20 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
strongSelf.goToUserLocation() strongSelf.goToUserLocation()
} }
} }
self.locationManager.manager.startUpdatingHeading()
self.locationManager.manager.delegate = self
} }
deinit { deinit {
self.disposable?.dispose() self.disposable?.dispose()
self.geocodingDisposable.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) { func updatePresentationData(_ presentationData: PresentationData) {
@ -721,7 +739,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode {
} }
private func dequeueTransition() { 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 return
} }
self.enqueuedTransitions.remove(at: 0) self.enqueuedTransitions.remove(at: 0)

View File

@ -180,9 +180,13 @@ private func allOpenInOptions(context: AccountContext, item: OpenInItem) -> [Ope
let coordinates = "\(lat),\(lon)" let coordinates = "\(lat),\(lon)"
if withDirections { if withDirections {
return .openUrl(url: "comgooglemaps-x-callback://?daddr=\(coordinates)&directionsmode=driving&x-success=telegram://?resume=true&x-source=Telegram") return .openUrl(url: "comgooglemaps-x-callback://?daddr=\(coordinates)&directionsmode=driving&x-success=telegram://?resume=true&x-source=Telegram")
} else {
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 { } else {
return .openUrl(url: "comgooglemaps-x-callback://?center=\(coordinates)&q=\(coordinates)&x-success=telegram://?resume=true&x-source=Telegram") return .openUrl(url: "comgooglemaps-x-callback://?center=\(coordinates)&q=\(coordinates)&x-success=telegram://?resume=true&x-source=Telegram")
} }
}
})) }))
options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: { options.append(OpenInOption(identifier: "yandexMaps", application: .other(title: "Yandex.Maps", identifier: 313877526, scheme: "yandexmaps", store: nil), action: {

View File

@ -1076,8 +1076,8 @@ public func channelInfoController(context: AccountContext, peerId: PeerId) -> Vi
} }
for childController in tabController.controllers { for childController in tabController.controllers {
if let chatListController = childController as? ChatListController { if let chatListController = childController as? ChatListController {
chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] deleted in chatListController.maybeAskForPeerChatRemoval(peer: RenderedPeer(peer: peer), joined: false, deleteGloballyIfPossible: deleteGloballyIfPossible, completion: { [weak navigationController] removed in
if deleted { if removed {
navigationController?.popToRoot(animated: true) navigationController?.popToRoot(animated: true)
} }
}, removed: { }, removed: {

View File

@ -2439,7 +2439,7 @@ public func groupInfoController(context: AccountContext, peerId originalPeerId:
} }
for childController in tabController.controllers { for childController in tabController.controllers {
if let chatListController = childController as? ChatListController { 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 { if removed {
navigationController?.popToRoot(animated: true) navigationController?.popToRoot(animated: true)
} }

View File

@ -214,7 +214,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
var items: [ChatListItem] = [] var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in 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 }, activateChatPreview: { _, _, gesture in
gesture?.cancel() gesture?.cancel()
}, present: { _ in }) }, present: { _ in })

View File

@ -767,7 +767,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
var items: [ChatListItem] = [] var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in 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 }, activateChatPreview: { _, _, gesture in
gesture?.cancel() gesture?.cancel()
}, present: { _ in }, present: { _ in

View File

@ -351,7 +351,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
var items: [ChatListItem] = [] var items: [ChatListItem] = []
let interaction = ChatListNodeInteraction(activateSearch: {}, peerSelected: { _, _ in }, disabledPeerSelected: { _ in }, togglePeerSelected: { _ in }, additionalCategorySelected: { _ in 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 }, activateChatPreview: { _, _, gesture in
gesture?.cancel() gesture?.cancel()
}, present: { _ in }, present: { _ in

View File

@ -173,7 +173,7 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
let leftInset = 16.0 + params.leftInset let leftInset = 16.0 + params.leftInset
let rightInset = 16.0 + params.rightInset let rightInset = 16.0 + params.rightInset
var totalLeftInset = leftInset var totalLeftInset = leftInset
let additionalRightInset: CGFloat = 93.0 let additionalRightInset: CGFloat = 128.0
let titleFont = Font.regular(item.presentationData.fontSize.itemListBaseFontSize) 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 (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 verticalInset: CGFloat = 11.0
let titleSpacing: CGFloat = 3.0 let titleSpacing: CGFloat = 3.0

View File

@ -30,8 +30,8 @@ public enum StatsGraph: Equatable {
switch self { switch self {
case .Empty: case .Empty:
return true return true
case let .Failed(error): case .Failed:
return error.lowercased().contains("not enough data") return true
default: default:
return false 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 { if strongSelf.presentationInterfaceState.interfaceState.selectionState != nil {
return return
} }
strongSelf.dismissAllTooltips()
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
let gesture: ContextGesture? = anyRecognizer as? ContextGesture let gesture: ContextGesture? = anyRecognizer as? ContextGesture
if let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) { if let messages = strongSelf.chatDisplayNode.historyNode.messageGroupInCurrentHistoryView(message.id) {
@ -1985,7 +1988,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}) })
}, displaySwipeToReplyHint: { [weak self] in }, displaySwipeToReplyHint: { [weak self] in
if let strongSelf = self, let validLayout = strongSelf.validLayout, min(validLayout.size.width, validLayout.size.height) > 320.0 { 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 }, dismissReplyMarkupMessage: { [weak self] message in
guard let strongSelf = self, strongSelf.presentationInterfaceState.keyboardButtonsMessage?.id == message.id else { 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 { guard let strongSelf = self else {
return return
} }
if strongSelf.presentationInterfaceState.interfaceState.selectionState != nil {
return
}
strongSelf.dismissAllTooltips()
let context = strongSelf.context let context = strongSelf.context
let _ = (context.account.postbox.transaction { transaction -> Peer? in let _ = (context.account.postbox.transaction { transaction -> Peer? in
return transaction.getPeer(peer.id) return transaction.getPeer(peer.id)
@ -5228,18 +5238,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.dismissAllTooltips() 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() self.sendMessageActionsController?.dismiss()
if let _ = self.peekData { if let _ = self.peekData {
@ -6077,7 +6075,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
disposable.set((signal disposable.set((signal
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self, let _ = strongSelf.validLayout { 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 { 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 { 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)]) strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil)])
} }
return false return false
}), in: .window(.root)) }), in: .current)
} }
} }
@ -9179,6 +9177,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.silentPostTooltipController?.dismiss() self.silentPostTooltipController?.dismiss()
self.mediaRecordingModeTooltipController?.dismiss() self.mediaRecordingModeTooltipController?.dismiss()
self.mediaRestrictedTooltipController?.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() { private func commitPurposefulAction() {

View File

@ -974,10 +974,14 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
optionsMap[id]!.insert(.deleteLocally) optionsMap[id]!.insert(.deleteLocally)
} else if let peer = transaction.getPeer(id.peerId) { } else if let peer = transaction.getPeer(id.peerId) {
var isAction = false var isAction = false
var isDice = false
for media in message.media { for media in message.media {
if media is TelegramMediaAction || media is TelegramMediaExpiredContent { if media is TelegramMediaAction || media is TelegramMediaExpiredContent {
isAction = true isAction = true
} }
if media is TelegramMediaDice {
isDice = true
}
} }
if let channel = peer as? TelegramChannel { if let channel = peer as? TelegramChannel {
if message.flags.contains(.Incoming) { if message.flags.contains(.Incoming) {
@ -1064,6 +1068,11 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
} else if limitsConfiguration.canRemoveIncomingMessagesInPrivateChats { } else if limitsConfiguration.canRemoveIncomingMessagesInPrivateChats {
canDeleteGlobally = true canDeleteGlobally = true
} }
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
if isDice && Int64(message.timestamp) + 60 * 60 * 24 > Int64(timestamp) {
canDeleteGlobally = false
}
if message.flags.contains(.Incoming) { if message.flags.contains(.Incoming) {
hadPersonalIncoming = true hadPersonalIncoming = true
} }

View File

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

View File

@ -3837,7 +3837,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
for childController in tabController.controllers { for childController in tabController.controllers {
if let chatListController = childController as? ChatListController { 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 { if deleted {
navigationController?.popToRoot(animated: true) navigationController?.popToRoot(animated: true)
} }

View File

@ -88,24 +88,24 @@ final class WebEmbedPlayerNode: ASDisplayNode, WKNavigationDelegate {
let userContentController = WKUserContentController() 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)) 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() let configuration = WKWebViewConfiguration()
config.allowsInlineMediaPlayback = true configuration.allowsInlineMediaPlayback = true
config.userContentController = userContentController configuration.userContentController = userContentController
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
config.mediaTypesRequiringUserActionForPlayback = [] configuration.mediaTypesRequiringUserActionForPlayback = []
} else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { } else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
config.requiresUserActionForMediaPlayback = false configuration.requiresUserActionForMediaPlayback = false
} else { } else {
config.mediaPlaybackRequiresUserAction = false configuration.mediaPlaybackRequiresUserAction = false
} }
if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { if #available(iOSApplicationExtension 9.0, iOS 9.0, *) {
config.allowsPictureInPictureMediaPlayback = false configuration.allowsPictureInPictureMediaPlayback = false
} }
let frame = CGRect(origin: CGPoint.zero, size: intrinsicDimensions) let frame = CGRect(origin: CGPoint.zero, size: intrinsicDimensions)
self.webView = WKWebView(frame: frame, configuration: config) self.webView = WKWebView(frame: frame, configuration: configuration)
super.init() super.init()
self.frame = frame self.frame = frame