Apply some fixes

This commit is contained in:
Ilya Laktyushin 2020-11-17 14:22:24 +04:00
parent 027a283c5e
commit e98fcb2b07
8 changed files with 206 additions and 108 deletions

View File

@ -279,6 +279,19 @@ public class ContactsController: ViewController {
openPeer(peer, false) openPeer(peer, false)
} }
self.contactsNode.requestAddContact = { [weak self] phoneNumber in
if let strongSelf = self {
strongSelf.view.endEditing(true)
strongSelf.context.sharedContext.openAddContact(context: strongSelf.context, firstName: "", lastName: "", phoneNumber: phoneNumber, label: defaultContactLabel, present: { [weak self] controller, arguments in
self?.present(controller, in: .window(.root), with: arguments)
}, pushController: { [weak self] controller in
(self?.navigationController as? NavigationController)?.pushViewController(controller)
}, completed: {
self?.deactivateSearch(animated: false)
})
}
}
self.contactsNode.openPeopleNearby = { [weak self] in self.contactsNode.openPeopleNearby = { [weak self] in
let _ = (DeviceAccess.authorizationStatus(subject: .location(.tracking)) let _ = (DeviceAccess.authorizationStatus(subject: .location(.tracking))
|> take(1) |> take(1)

View File

@ -55,6 +55,7 @@ final class ContactsControllerNode: ASDisplayNode {
var requestDeactivateSearch: (() -> Void)? var requestDeactivateSearch: (() -> Void)?
var requestOpenPeerFromSearch: ((ContactListPeer) -> Void)? var requestOpenPeerFromSearch: ((ContactListPeer) -> Void)?
var requestAddContact: ((String) -> Void)?
var openPeopleNearby: (() -> Void)? var openPeopleNearby: (() -> Void)?
var openInvite: (() -> Void)? var openInvite: (() -> Void)?
@ -184,7 +185,11 @@ final class ContactsControllerNode: ASDisplayNode {
return return
} }
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.cloudContacts, .global, .deviceContacts], openPeer: { [weak self] peer in self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.cloudContacts, .global, .deviceContacts], addContact: { [weak self] phoneNumber in
if let requestAddContact = self?.requestAddContact {
requestAddContact(phoneNumber)
}
}, openPeer: { [weak self] peer in
if let requestOpenPeerFromSearch = self?.requestOpenPeerFromSearch { if let requestOpenPeerFromSearch = self?.requestOpenPeerFromSearch {
requestOpenPeerFromSearch(peer) requestOpenPeerFromSearch(peer)
} }

View File

@ -23,93 +23,151 @@ private enum ContactListSearchGroup {
case deviceContacts case deviceContacts
} }
private struct ContactListSearchEntry: Identifiable, Comparable { private enum ContactListSearchEntryId: Hashable {
let index: Int case addContact
let theme: PresentationTheme case peerId(ContactListPeerId)
let strings: PresentationStrings
let peer: ContactListPeer
let presence: PeerPresence?
let group: ContactListSearchGroup
let enabled: Bool
var stableId: ContactListPeerId { static func <(lhs: ContactListSearchEntryId, rhs: ContactListSearchEntryId) -> Bool {
return self.peer.id return lhs.hashValue < rhs.hashValue
}
static func ==(lhs: ContactListSearchEntryId, rhs: ContactListSearchEntryId) -> Bool {
switch lhs {
case .addContact:
switch rhs {
case .addContact:
return true
default:
return false
}
case let .peerId(lhsId):
switch rhs {
case let .peerId(rhsId):
return lhsId == rhsId
default:
return false
}
}
}
}
private enum ContactListSearchEntry: Comparable, Identifiable {
case addContact(PresentationTheme, PresentationStrings, String)
case peer(Int, PresentationTheme, PresentationStrings, ContactListPeer, PeerPresence?, ContactListSearchGroup, Bool)
var stableId: ContactListSearchEntryId {
switch self {
case .addContact:
return .addContact
case let .peer(_, _, _, peer, _, _, _):
return .peerId(peer.id)
}
} }
static func ==(lhs: ContactListSearchEntry, rhs: ContactListSearchEntry) -> Bool { static func ==(lhs: ContactListSearchEntry, rhs: ContactListSearchEntry) -> Bool {
if lhs.index != rhs.index { switch lhs {
return false case let .addContact(lhsTheme, lhsStrings, lhsPhoneNumber):
if case let .addContact(rhsTheme, rhsStrings, rhsPhoneNumber) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsPhoneNumber == rhsPhoneNumber {
return true
} else {
return false
}
case let .peer(lhsIndex, lhsTheme, lhsStrings, lhsPeer, lhsPresence, lhsGroup, lhsEnabled):
switch rhs {
case let .peer(rhsIndex, rhsTheme, rhsStrings, rhsPeer, rhsPresence, rhsGroup, rhsEnabled):
if lhsIndex != rhsIndex {
return false
}
if lhsTheme !== rhsTheme {
return false
}
if lhsStrings !== rhsStrings {
return false
}
if lhsPeer != rhsPeer {
return false
}
if let lhsPresence = lhsPresence, let rhsPresence = rhsPresence {
if !lhsPresence.isEqual(to: rhsPresence) {
return false
}
} else if (lhsPresence != nil) != (rhsPresence != nil) {
return false
}
if lhsGroup != rhsGroup {
return false
}
if lhsEnabled != rhsEnabled {
return false
}
return true
default:
return false
}
} }
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.peer != rhs.peer {
return false
}
if let lhsPresence = lhs.presence, let rhsPresence = rhs.presence {
if !lhsPresence.isEqual(to: rhsPresence) {
return false
}
} else if (lhs.presence != nil) != (rhs.presence != nil) {
return false
}
if lhs.group != rhs.group {
return false
}
if lhs.enabled != rhs.enabled {
return false
}
return true
} }
static func <(lhs: ContactListSearchEntry, rhs: ContactListSearchEntry) -> Bool { static func <(lhs: ContactListSearchEntry, rhs: ContactListSearchEntry) -> Bool {
return lhs.index < rhs.index switch lhs {
case .addContact:
return true
case let .peer(lhsIndex, _, _, _, _, _, _):
switch rhs {
case .addContact:
return false
case let .peer(rhsIndex, _, _, _, _, _, _):
return lhsIndex < rhsIndex
}
}
} }
func item(context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, timeFormat: PresentationDateTimeFormat, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) -> ListViewItem { func item(context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, timeFormat: PresentationDateTimeFormat, addContact: ((String) -> Void)?, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) -> ListViewItem {
let header: ListViewItemHeader switch self {
let status: ContactsPeerItemStatus case let .addContact(theme, strings, phoneNumber):
switch self.group { return ContactsAddItem(theme: theme, strings: strings, phoneNumber: phoneNumber, header: ChatListSearchItemHeader(type: .phoneNumber, theme: theme, strings: strings, actionTitle: nil, action: nil), action: {
case .contacts: addContact?(phoneNumber)
header = ChatListSearchItemHeader(type: .contacts, theme: self.theme, strings: self.strings, actionTitle: nil, action: nil) })
if let presence = self.presence { case let .peer(_, theme, strings, peer, presence, group, enabled):
status = .presence(presence, timeFormat) let header: ListViewItemHeader
} else { let status: ContactsPeerItemStatus
status = .none switch group {
case .contacts:
header = ChatListSearchItemHeader(type: .contacts, theme: theme, strings: strings, actionTitle: nil, action: nil)
if let presence = presence {
status = .presence(presence, timeFormat)
} else {
status = .none
}
case .global:
header = ChatListSearchItemHeader(type: .globalPeers, theme: theme, strings: strings, actionTitle: nil, action: nil)
if case let .peer(peer, _, _) = peer, let _ = peer.addressName {
status = .addressName("")
} else {
status = .none
}
case .deviceContacts:
header = ChatListSearchItemHeader(type: .deviceContacts, theme: theme, strings: strings, actionTitle: nil, action: nil)
status = .none
} }
case .global: var nativePeer: Peer?
header = ChatListSearchItemHeader(type: .globalPeers, theme: self.theme, strings: self.strings, actionTitle: nil, action: nil) let peerItem: ContactsPeerItemPeer
if case let .peer(peer, _, _) = self.peer, let _ = peer.addressName { switch peer {
status = .addressName("") case let .peer(peer, _, _):
} else { peerItem = .peer(peer: peer, chatPeer: peer)
status = .none nativePeer = peer
case let .deviceContact(stableId, contact):
peerItem = .deviceContact(stableId: stableId, contact: contact)
} }
case .deviceContacts: return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: peerItem, status: status, enabled: enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
header = ChatListSearchItemHeader(type: .deviceContacts, theme: self.theme, strings: self.strings, actionTitle: nil, action: nil) openPeer(peer)
status = .none }, contextAction: contextAction.flatMap { contextAction in
return nativePeer.flatMap { nativePeer in
return { node, gesture in
contextAction(nativePeer, node, gesture)
}
}
})
} }
let peer = self.peer
var nativePeer: Peer?
let peerItem: ContactsPeerItemPeer
switch peer {
case let .peer(peer, _, _):
peerItem = .peer(peer: peer, chatPeer: peer)
nativePeer = peer
case let .deviceContact(stableId, contact):
peerItem = .deviceContact(stableId: stableId, contact: contact)
}
return ContactsPeerItem(presentationData: ItemListPresentationData(presentationData), sortOrder: nameSortOrder, displayOrder: nameDisplayOrder, context: context, peerMode: .peer, peer: peerItem, status: status, enabled: self.enabled, selection: .none, editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false), index: nil, header: header, action: { _ in
openPeer(peer)
}, contextAction: contextAction.flatMap { contextAction in
return nativePeer.flatMap { nativePeer in
return { node, gesture in
contextAction(nativePeer, node, gesture)
}
}
})
} }
} }
@ -120,12 +178,12 @@ struct ContactListSearchContainerTransition {
let isSearching: Bool let isSearching: Bool
} }
private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, timeFormat: PresentationDateTimeFormat, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) -> ContactListSearchContainerTransition { private func contactListSearchContainerPreparedRecentTransition(from fromEntries: [ContactListSearchEntry], to toEntries: [ContactListSearchEntry], isSearching: Bool, context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, timeFormat: PresentationDateTimeFormat, addContact: ((String) -> Void)?, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) -> ContactListSearchContainerTransition {
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, timeFormat: timeFormat, openPeer: openPeer, contextAction: contextAction), directionHint: nil) } let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, timeFormat: timeFormat, addContact: addContact, openPeer: openPeer, contextAction: contextAction), directionHint: nil) }
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, timeFormat: timeFormat, openPeer: openPeer, contextAction: contextAction), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, timeFormat: timeFormat, addContact: addContact, openPeer: openPeer, contextAction: contextAction), directionHint: nil) }
return ContactListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching) return ContactListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching)
} }
@ -144,6 +202,7 @@ public struct ContactsSearchCategories: OptionSet {
public final class ContactsSearchContainerNode: SearchDisplayControllerContentNode { public final class ContactsSearchContainerNode: SearchDisplayControllerContentNode {
private let context: AccountContext private let context: AccountContext
private let addContact: ((String) -> Void)?
private let openPeer: (ContactListPeer) -> Void private let openPeer: (ContactListPeer) -> Void
private let contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)? private let contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?
@ -163,8 +222,9 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
return true return true
} }
public init(context: AccountContext, onlyWriteable: Bool, categories: ContactsSearchCategories, filters: [ContactListFilter] = [.excludeSelf], openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) { public init(context: AccountContext, onlyWriteable: Bool, categories: ContactsSearchCategories, filters: [ContactListFilter] = [.excludeSelf], addContact: ((String) -> Void)?, openPeer: @escaping (ContactListPeer) -> Void, contextAction: ((Peer, ASDisplayNode, ContextGesture?) -> Void)?) {
self.context = context self.context = context
self.addContact = addContact
self.openPeer = openPeer self.openPeer = openPeer
self.contextAction = contextAction self.contextAction = contextAction
@ -250,7 +310,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
if onlyWriteable { if onlyWriteable {
enabled = canSendMessagesToPeer(peer) enabled = canSendMessagesToPeer(peer)
} }
entries.append(ContactListSearchEntry(index: index, theme: themeAndStrings.0, strings: themeAndStrings.1, peer: .peer(peer: peer, isGlobal: false, participantCount: nil), presence: localPeersAndPresences.1[peer.id], group: .contacts, enabled: enabled)) entries.append(.peer(index, themeAndStrings.0, themeAndStrings.1, .peer(peer: peer, isGlobal: false, participantCount: nil), localPeersAndPresences.1[peer.id], .contacts, enabled))
if searchDeviceContacts, let user = peer as? TelegramUser, let phone = user.phone { if searchDeviceContacts, let user = peer as? TelegramUser, let phone = user.phone {
existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone))) existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone)))
} }
@ -269,7 +329,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
enabled = canSendMessagesToPeer(peer.peer) enabled = canSendMessagesToPeer(peer.peer)
} }
entries.append(ContactListSearchEntry(index: index, theme: themeAndStrings.0, strings: themeAndStrings.1, peer: .peer(peer: peer.peer, isGlobal: true, participantCount: peer.subscribers), presence: nil, group: .global, enabled: enabled)) entries.append(.peer(index, themeAndStrings.0, themeAndStrings.1, .peer(peer: peer.peer, isGlobal: true, participantCount: peer.subscribers), nil, .global, enabled))
if searchDeviceContacts, let user = peer.peer as? TelegramUser, let phone = user.phone { if searchDeviceContacts, let user = peer.peer as? TelegramUser, let phone = user.phone {
existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone))) existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone)))
} }
@ -288,7 +348,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
enabled = canSendMessagesToPeer(peer.peer) enabled = canSendMessagesToPeer(peer.peer)
} }
entries.append(ContactListSearchEntry(index: index, theme: themeAndStrings.0, strings: themeAndStrings.1, peer: .peer(peer: peer.peer, isGlobal: true, participantCount: peer.subscribers), presence: nil, group: .global, enabled: enabled)) entries.append(.peer(index, themeAndStrings.0, themeAndStrings.1, .peer(peer: peer.peer, isGlobal: true, participantCount: peer.subscribers), nil, .global, enabled))
if searchDeviceContacts, let user = peer.peer as? TelegramUser, let phone = user.phone { if searchDeviceContacts, let user = peer.peer as? TelegramUser, let phone = user.phone {
existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone))) existingNormalizedPhoneNumbers.insert(DeviceContactNormalizedPhoneNumber(rawValue: formatPhoneNumber(phone)))
} }
@ -309,10 +369,15 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
continue outer continue outer
} }
} }
entries.append(ContactListSearchEntry(index: index, theme: themeAndStrings.0, strings: themeAndStrings.1, peer: .deviceContact(stableId, contact.0), presence: nil, group: .deviceContacts, enabled: true)) entries.append(.peer(index, themeAndStrings.0, themeAndStrings.1, .deviceContact(stableId, contact.0), nil, .deviceContacts, true))
index += 1 index += 1
} }
} }
if let _ = addContact, isViablePhoneNumber(query) {
entries.append(.addContact(themeAndStrings.0, themeAndStrings.1, query))
}
return entries return entries
} }
} else { } else {
@ -328,7 +393,16 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
if let strongSelf = self { if let strongSelf = self {
let previousItems = previousSearchItems.swap(items ?? []) let previousItems = previousSearchItems.swap(items ?? [])
let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, context: context, presentationData: strongSelf.presentationData, nameSortOrder: strongSelf.presentationData.nameSortOrder, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder, timeFormat: strongSelf.presentationData.dateTimeFormat, openPeer: { peer in self?.listNode.clearHighlightAnimated(true) var addContact: ((String) -> Void)?
if let originalAddContact = strongSelf.addContact {
addContact = { [weak self] phoneNumber in
self?.listNode.clearHighlightAnimated(true)
originalAddContact(phoneNumber)
}
}
let transition = contactListSearchContainerPreparedRecentTransition(from: previousItems, to: items ?? [], isSearching: items != nil, context: context, presentationData: strongSelf.presentationData, nameSortOrder: strongSelf.presentationData.nameSortOrder, nameDisplayOrder: strongSelf.presentationData.nameDisplayOrder, timeFormat: strongSelf.presentationData.dateTimeFormat, addContact: addContact, openPeer: { peer in
self?.listNode.clearHighlightAnimated(true)
self?.openPeer(peer) self?.openPeer(peer)
}, contextAction: strongSelf.contextAction) }, contextAction: strongSelf.contextAction)

View File

@ -505,7 +505,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
return return
} }
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.deviceContacts], openPeer: { [weak self] peer in self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.deviceContacts], addContact: nil, openPeer: { [weak self] peer in
if let strongSelf = self, case let .deviceContact(id, _) = peer { if let strongSelf = self, case let .deviceContact(id, _) = peer {
strongSelf.selectionState = strongSelf.selectionState.withSelectedContactId(id) strongSelf.selectionState = strongSelf.selectionState.withSelectedContactId(id)
strongSelf.requestDeactivateSearch?() strongSelf.requestDeactivateSearch?()

View File

@ -1238,6 +1238,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F499, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D] let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F499, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D]
let heart = 0x2764
let peach = 0x1F351 let peach = 0x1F351
let coffin = 0x26B0 let coffin = 0x26B0
@ -1247,7 +1248,12 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue return view.values[PreferencesKeys.appConfiguration] as? AppConfiguration ?? .defaultValue
} }
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first { if let text = self.item?.message.text, var firstScalar = text.unicodeScalars.first {
var textEmoji = text.strippedEmoji
if beatingHearts.contains(firstScalar.value) {
textEmoji = "❤️"
firstScalar = UnicodeScalar(heart)!
}
return .optionalAction({ return .optionalAction({
if shouldPlay { if shouldPlay {
let _ = (appConfiguration let _ = (appConfiguration
@ -1257,7 +1263,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
} }
let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: item.context.account) let emojiSounds = AnimatedEmojiSoundsConfiguration.with(appConfiguration: appConfiguration, account: item.context.account)
for (emoji, file) in emojiSounds.sounds { for (emoji, file) in emojiSounds.sounds {
if emoji.strippedEmoji == text.strippedEmoji { if emoji.strippedEmoji == textEmoji.strippedEmoji {
let mediaManager = item.context.sharedContext.mediaManager let mediaManager = item.context.sharedContext.mediaManager
let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true) let mediaPlayer = MediaPlayer(audioSessionManager: mediaManager.audioSession, postbox: item.context.account.postbox, resourceReference: .standalone(resource: file.resource), streamable: .none, video: false, preferSoftwareDecoding: false, enableSound: true, fetchAutomatically: true, ambient: true)
mediaPlayer.togglePlayPause() mediaPlayer.togglePlayPause()
@ -1269,24 +1275,24 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
strongSelf.mediaStatusDisposable.set((mediaPlayer.status strongSelf.mediaStatusDisposable.set((mediaPlayer.status
|> deliverOnMainQueue).start(next: { [weak self, weak animationNode] status in |> deliverOnMainQueue).start(next: { [weak self, weak animationNode] status in
if let strongSelf = self { if let strongSelf = self {
if firstScalar.value == coffin || firstScalar.value == peach {
var haptic: EmojiHaptic var haptic: EmojiHaptic?
if let current = strongSelf.haptic { if let current = strongSelf.haptic {
haptic = current haptic = current
} else { } else {
if beatingHearts.contains(firstScalar.value) { if firstScalar.value == heart {
haptic = HeartbeatHaptic() haptic = HeartbeatHaptic()
} else if firstScalar.value == coffin { } else if firstScalar.value == coffin {
haptic = CoffinHaptic() haptic = CoffinHaptic()
} else { } else if firstScalar.value == peach {
haptic = PeachHaptic() haptic = PeachHaptic()
}
haptic.enabled = true
strongSelf.haptic = haptic
}
if !haptic.active {
haptic.start(time: 0.0)
} }
haptic?.enabled = true
strongSelf.haptic = haptic
}
if let haptic = haptic, !haptic.active {
haptic.start(time: 0.0)
} }
switch status.status { switch status.status {

View File

@ -124,7 +124,7 @@ final class ComposeControllerNode: ASDisplayNode {
return return
} }
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.cloudContacts, .global], openPeer: { [weak self] peer in self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: [.cloudContacts, .global], addContact: nil, openPeer: { [weak self] peer in
if let requestOpenPeerFromSearch = self?.requestOpenPeerFromSearch, case let .peer(peer, _, _) = peer { if let requestOpenPeerFromSearch = self?.requestOpenPeerFromSearch, case let .peer(peer, _, _) = peer {
requestOpenPeerFromSearch(peer.id) requestOpenPeerFromSearch(peer.id)
} }

View File

@ -123,7 +123,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
} else { } else {
categories.insert(.global) categories.insert(.global)
} }
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: categories, openPeer: { [weak self] peer in self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: false, categories: categories, addContact: nil, openPeer: { [weak self] peer in
self?.requestOpenPeerFromSearch?(peer) self?.requestOpenPeerFromSearch?(peer)
}, contextAction: nil), cancel: { [weak self] in }, contextAction: nil), cancel: { [weak self] in
if let requestDeactivateSearch = self?.requestDeactivateSearch { if let requestDeactivateSearch = self?.requestDeactivateSearch {

View File

@ -248,7 +248,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
}, placeholder: placeholderNode) }, placeholder: placeholderNode)
} else if let contactListNode = self.contactListNode, contactListNode.supernode != nil { } else if let contactListNode = self.contactListNode, contactListNode.supernode != nil {
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: true, categories: [.cloudContacts, .global], openPeer: { [weak self] peer in self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: ContactsSearchContainerNode(context: self.context, onlyWriteable: true, categories: [.cloudContacts, .global], addContact: nil, openPeer: { [weak self] peer in
if let strongSelf = self { if let strongSelf = self {
switch peer { switch peer {
case let .peer(peer, _, _): case let .peer(peer, _, _):