no message

This commit is contained in:
Peter
2016-11-04 01:39:54 +03:00
parent abfd19bda8
commit 2168cdd46a
13 changed files with 212 additions and 92 deletions

View File

@@ -27,6 +27,7 @@
D06879571DB8F22200424BBD /* FetchCachedRepresentations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D06879561DB8F22200424BBD /* FetchCachedRepresentations.swift */; };
D073CE631DCBBE5D007511FD /* MessageSent.caf in Resources */ = {isa = PBXBuildFile; fileRef = D073CE621DCBBE5D007511FD /* MessageSent.caf */; };
D073CE651DCBC26B007511FD /* ServiceSoundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE641DCBC26B007511FD /* ServiceSoundManager.swift */; };
D073CE711DCBF23F007511FD /* DeclareEncodables.swift in Sources */ = {isa = PBXBuildFile; fileRef = D073CE701DCBF23F007511FD /* DeclareEncodables.swift */; };
D07A7DA31D957671005BCD27 /* ListMessageSnippetItemNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07A7DA21D957671005BCD27 /* ListMessageSnippetItemNode.swift */; };
D07A7DA51D95783C005BCD27 /* ListMessageNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07A7DA41D95783C005BCD27 /* ListMessageNode.swift */; };
D07CFF741DCA207200761F81 /* PeerSelectionController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07CFF731DCA207200761F81 /* PeerSelectionController.swift */; };
@@ -256,6 +257,7 @@
D06879561DB8F22200424BBD /* FetchCachedRepresentations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchCachedRepresentations.swift; sourceTree = "<group>"; };
D073CE621DCBBE5D007511FD /* MessageSent.caf */ = {isa = PBXFileReference; lastKnownFileType = file; name = MessageSent.caf; path = TelegramUI/Sounds/MessageSent.caf; sourceTree = "<group>"; };
D073CE641DCBC26B007511FD /* ServiceSoundManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceSoundManager.swift; sourceTree = "<group>"; };
D073CE701DCBF23F007511FD /* DeclareEncodables.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeclareEncodables.swift; sourceTree = "<group>"; };
D07A7DA21D957671005BCD27 /* ListMessageSnippetItemNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListMessageSnippetItemNode.swift; sourceTree = "<group>"; };
D07A7DA41D95783C005BCD27 /* ListMessageNode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListMessageNode.swift; sourceTree = "<group>"; };
D07CFF731DCA207200761F81 /* PeerSelectionController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerSelectionController.swift; sourceTree = "<group>"; };
@@ -1106,6 +1108,7 @@
D0B844571DAC44E8005F29E1 /* PeerPresenceStatusManager.swift */,
D0ED5D4A1DC806D7007CBB15 /* ApplicationSpecificData.swift */,
D073CE641DCBC26B007511FD /* ServiceSoundManager.swift */,
D073CE701DCBF23F007511FD /* DeclareEncodables.swift */,
);
name = Utils;
sourceTree = "<group>";
@@ -1432,6 +1435,7 @@
D0F69DFF1D6B8A880046BCD6 /* ChatListController.swift in Sources */,
D0E7A1C11D8C258D00C37A6F /* ChatHistoryEntriesForView.swift in Sources */,
D0F69DF11D6B8A6C0046BCD6 /* AuthorizationController.swift in Sources */,
D073CE711DCBF23F007511FD /* DeclareEncodables.swift in Sources */,
D0E7A1BF1D8C24B900C37A6F /* ChatHistoryViewForLocation.swift in Sources */,
D0F69E891D6B8C850046BCD6 /* FastBlur.m in Sources */,
D07CFF761DCA224100761F81 /* PeerSelectionControllerNode.swift in Sources */,

View File

@@ -4,10 +4,4 @@ import AsyncDisplayKit
class AccessoryPanelNode: ASDisplayNode {
var dismiss: (() -> Void)?
var interfaceInteraction: ChatPanelInterfaceInteraction?
var insets = UIEdgeInsets() {
didSet {
self.setNeedsLayout()
}
}
}

View File

@@ -453,7 +453,8 @@ public class ChatController: ViewController {
super.viewWillDisappear(animated)
let peerId = self.peerId
let interfaceState = self.presentationInterfaceState.interfaceState
let timestamp = Int32(Date().timeIntervalSince1970)
let interfaceState = self.presentationInterfaceState.interfaceState.withUpdatedTimestamp(timestamp)
self.account.postbox.modify({ modifier -> Void in
modifier.updatePeerChatInterfaceState(peerId, update: { _ in
return interfaceState

View File

@@ -144,6 +144,10 @@ class ChatControllerNode: ASDisplayNode {
if let inputNode = self.inputNode {
previousInputHeight = inputNode.bounds.size.height
}
var previousInputPanelOrigin = CGPoint(x: 0.0, y: layout.size.height - previousInputHeight)
if let inputPanelNode = self.inputPanelNode {
previousInputPanelOrigin.y -= inputPanelNode.bounds.size.height
}
self.containerLayoutAndNavigationBarHeight = (layout, navigationBarHeight)
var dismissedInputNode: ChatInputNode?
@@ -261,7 +265,6 @@ class ChatControllerNode: ASDisplayNode {
}
immediatelyLayoutAccessoryPanelAndAnimateAppearance = true
accessoryPanelNode.insets = UIEdgeInsets(top: 0.0, left: 45.0, bottom: 0.0, right: 54.0)
}
} else if let accessoryPanelNode = self.accessoryPanelNode {
dismissedAccessoryPanelNode = self.accessoryPanelNode
@@ -322,7 +325,9 @@ class ChatControllerNode: ASDisplayNode {
if let accessoryPanelNode = self.accessoryPanelNode, let accessoryPanelFrame = accessoryPanelFrame, !accessoryPanelNode.frame.equalTo(accessoryPanelFrame) {
if immediatelyLayoutAccessoryPanelAndAnimateAppearance {
accessoryPanelNode.frame = accessoryPanelFrame.offsetBy(dx: 0.0, dy: accessoryPanelFrame.size.height)
var startAccessoryPanelFrame = accessoryPanelFrame
startAccessoryPanelFrame.origin.y = previousInputPanelOrigin.y
accessoryPanelNode.frame = startAccessoryPanelFrame
accessoryPanelNode.alpha = 0.0
}

View File

@@ -57,24 +57,59 @@ struct ChatTextInputState: Coding, Equatable {
}
}
final class ChatEmbeddedInterfaceState: PeerChatListEmbeddedInterfaceState {
let timestamp: Int32
let text: String
init(timestamp: Int32, text: String) {
self.timestamp = timestamp
self.text = text
}
init(decoder: Decoder) {
self.timestamp = decoder.decodeInt32ForKey("d")
self.text = decoder.decodeStringForKey("t")
}
func encode(_ encoder: Encoder) {
encoder.encodeInt32(self.timestamp, forKey: "d")
encoder.encodeString(self.text, forKey: "t")
}
public func isEqual(to: PeerChatListEmbeddedInterfaceState) -> Bool {
if let to = to as? ChatEmbeddedInterfaceState {
return self.timestamp == to.timestamp && self.text == to.text
} else {
return false
}
}
}
final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
let timestamp: Int32
let inputState: ChatTextInputState
let replyMessageId: MessageId?
let forwardMessageIds: [MessageId]?
let selectionState: ChatInterfaceSelectionState?
var chatListEmbeddedState: PeerChatListEmbeddedInterfaceState? {
if !self.inputState.inputText.isEmpty && self.timestamp != 0 {
return ChatEmbeddedInterfaceState(timestamp: self.timestamp, text: self.inputState.inputText)
} else {
return nil
}
}
init() {
self.timestamp = 0
self.inputState = ChatTextInputState()
self.replyMessageId = nil
self.forwardMessageIds = nil
self.selectionState = nil
}
init(inputState: ChatTextInputState, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, selectionState: ChatInterfaceSelectionState?) {
init(timestamp: Int32, inputState: ChatTextInputState, replyMessageId: MessageId?, forwardMessageIds: [MessageId]?, selectionState: ChatInterfaceSelectionState?) {
self.timestamp = timestamp
self.inputState = inputState
self.replyMessageId = replyMessageId
self.forwardMessageIds = forwardMessageIds
@@ -82,6 +117,7 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
}
init(decoder: Decoder) {
self.timestamp = decoder.decodeInt32ForKey("ts")
if let inputState = decoder.decodeObjectForKey("is", decoder: { return ChatTextInputState(decoder: $0) }) as? ChatTextInputState {
self.inputState = inputState
} else {
@@ -108,6 +144,7 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
}
func encode(_ encoder: Encoder) {
encoder.encodeInt32(self.timestamp, forKey: "ts")
encoder.encodeObject(self.inputState, forKey: "is")
if let replyMessageId = self.replyMessageId {
encoder.encodeInt64(replyMessageId.peerId.toInt64(), forKey: "r.p")
@@ -152,15 +189,15 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
}
func withUpdatedInputState(_ inputState: ChatTextInputState) -> ChatInterfaceState {
return ChatInterfaceState(inputState: inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: self.selectionState)
return ChatInterfaceState(timestamp: self.timestamp, inputState: inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: self.selectionState)
}
func withUpdatedReplyMessageId(_ replyMessageId: MessageId?) -> ChatInterfaceState {
return ChatInterfaceState(inputState: self.inputState, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: self.selectionState)
return ChatInterfaceState(timestamp: self.timestamp, inputState: self.inputState, replyMessageId: replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: self.selectionState)
}
func withUpdatedForwardMessageIds(_ forwardMessageIds: [MessageId]?) -> ChatInterfaceState {
return ChatInterfaceState(inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, selectionState: self.selectionState)
return ChatInterfaceState(timestamp: self.timestamp, inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: forwardMessageIds, selectionState: self.selectionState)
}
func withUpdatedSelectedMessage(_ messageId: MessageId) -> ChatInterfaceState {
@@ -169,7 +206,7 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
selectedIds.formUnion(selectionState.selectedIds)
}
selectedIds.insert(messageId)
return ChatInterfaceState(inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds))
return ChatInterfaceState(timestamp: self.timestamp, inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds))
}
func withToggledSelectedMessage(_ messageId: MessageId) -> ChatInterfaceState {
@@ -182,10 +219,14 @@ final class ChatInterfaceState: PeerChatInterfaceState, Equatable {
} else {
selectedIds.insert(messageId)
}
return ChatInterfaceState(inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds))
return ChatInterfaceState(timestamp: self.timestamp, inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: ChatInterfaceSelectionState(selectedIds: selectedIds))
}
func withoutSelectionState() -> ChatInterfaceState {
return ChatInterfaceState(inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: nil)
return ChatInterfaceState(timestamp: self.timestamp, inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: nil)
}
func withUpdatedTimestamp(_ timestamp: Int32) -> ChatInterfaceState {
return ChatInterfaceState(timestamp: timestamp, inputState: self.inputState, replyMessageId: self.replyMessageId, forwardMessageIds: self.forwardMessageIds, selectionState: self.selectionState)
}
}

View File

@@ -11,22 +11,24 @@ class ChatListItem: ListViewItem {
let message: Message
let combinedReadState: CombinedPeerReadState?
let notificationSettings: PeerNotificationSettings?
let embeddedState: PeerChatListEmbeddedInterfaceState?
let action: (Message) -> Void
let selectable: Bool = true
init(account: Account, message: Message, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, action: @escaping (Message) -> Void) {
init(account: Account, message: Message, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, embeddedState: PeerChatListEmbeddedInterfaceState?, action: @escaping (Message) -> Void) {
self.account = account
self.message = message
self.combinedReadState = combinedReadState
self.notificationSettings = notificationSettings
self.embeddedState = embeddedState
self.action = action
}
func nodeConfiguredForWidth(async: @escaping (@escaping () -> Void) -> Void, width: CGFloat, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> Void) -> Void) {
async {
let node = ChatListItemNode()
node.setupItem(account: self.account, message: self.message, combinedReadState: self.combinedReadState, notificationSettings: self.notificationSettings)
node.setupItem(account: self.account, message: self.message, combinedReadState: self.combinedReadState, notificationSettings: self.notificationSettings, embeddedState: self.embeddedState)
node.relativePosition = (first: previousItem == nil, last: nextItem == nil)
node.insets = ChatListItemNode.insets(first: node.relativePosition.first, last: node.relativePosition.last)
node.layoutForWidth(width, item: self, previousItem: previousItem, nextItem: nextItem)
@@ -38,7 +40,7 @@ class ChatListItem: ListViewItem {
assert(node is ChatListItemNode)
if let node = node as? ChatListItemNode {
Queue.mainQueue().async {
node.setupItem(account: self.account, message: self.message, combinedReadState: self.combinedReadState, notificationSettings: self.notificationSettings)
node.setupItem(account: self.account, message: self.message, combinedReadState: self.combinedReadState, notificationSettings: self.notificationSettings, embeddedState: self.embeddedState)
let layout = node.asyncLayout()
async {
let first = previousItem == nil
@@ -115,6 +117,7 @@ class ChatListItemNode: ListViewItemNode {
var message: Message?
var combinedReadState: CombinedPeerReadState?
var notificationSettings: PeerNotificationSettings?
var embeddedState: PeerChatListEmbeddedInterfaceState?
private let backgroundNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode
@@ -205,11 +208,12 @@ class ChatListItemNode: ListViewItemNode {
self.contentNode.addSubnode(self.mutedIconNode)
}
func setupItem(account: Account, message: Message, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?) {
func setupItem(account: Account, message: Message, combinedReadState: CombinedPeerReadState?, notificationSettings: PeerNotificationSettings?, embeddedState: PeerChatListEmbeddedInterfaceState?) {
self.account = account
self.message = message
self.combinedReadState = combinedReadState
self.notificationSettings = notificationSettings
self.embeddedState = embeddedState
let peer = message.peers[message.id.peerId]
if let peer = peer {
@@ -280,6 +284,7 @@ class ChatListItemNode: ListViewItemNode {
let message = self.message
let combinedReadState = self.combinedReadState
let notificationSettings = self.notificationSettings
let embeddedState = self.embeddedState
return { account, width, first, last in
var textAttributedString: NSAttributedString?
@@ -317,7 +322,12 @@ class ChatListItemNode: ListViewItemNode {
}
let attributedText: NSAttributedString
if let author = message.author as? TelegramUser, let peer = peer, peer as? TelegramUser == nil {
if let embeddedState = embeddedState as? ChatEmbeddedInterfaceState {
let mutableAttributedText = NSMutableAttributedString()
mutableAttributedText.append(NSAttributedString(string: "Draft: ", font: textFont, textColor: UIColor(0xdd4b39)))
mutableAttributedText.append(NSAttributedString(string: embeddedState.text, font: textFont, textColor: UIColor.black))
attributedText = mutableAttributedText;
} else if let author = message.author as? TelegramUser, let peer = peer, peer as? TelegramUser == nil {
let peerText: NSString = (author.id == account?.peerId ? "You: " : author.compactDisplayTitle + ": ") as NSString
let mutableAttributedText = NSMutableAttributedString(string: peerText.appending(messageText as String), attributes: [kCTFontAttributeName as String: textFont])

View File

@@ -37,10 +37,10 @@ private func mappedInsertEntries(account: Account, nodeInteraction: ChatListNode
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(placeholder: "Search for messages or users", activate: {
nodeInteraction.activateSearch()
}), directionHint: entry.directionHint)
case let .MessageEntry(message, combinedReadState, notificationSettings):
case let .MessageEntry(_, message, combinedReadState, notificationSettings, embeddedState):
switch mode {
case .chatList:
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(account: account, message: message, combinedReadState: combinedReadState, notificationSettings: notificationSettings, action: { _ in
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(account: account, message: message, combinedReadState: combinedReadState, notificationSettings: notificationSettings, embeddedState: embeddedState, action: { _ in
nodeInteraction.peerSelected(message.id.peerId)
}), directionHint: entry.directionHint)
case .peers:
@@ -63,10 +63,10 @@ private func mappedUpdateEntries(account: Account, nodeInteraction: ChatListNode
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(placeholder: "Search for messages or users", activate: {
nodeInteraction.activateSearch()
}), directionHint: entry.directionHint)
case let .MessageEntry(message, combinedReadState, notificationSettings):
case let .MessageEntry(_, message, combinedReadState, notificationSettings, embeddedState):
switch mode {
case .chatList:
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(account: account, message: message, combinedReadState: combinedReadState, notificationSettings: notificationSettings, action: { _ in
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListItem(account: account, message: message, combinedReadState: combinedReadState, notificationSettings: notificationSettings, embeddedState: embeddedState, action: { _ in
nodeInteraction.peerSelected(message.id.peerId)
}), directionHint: entry.directionHint)
case .peers:

View File

@@ -62,7 +62,7 @@ enum ChatListNodeEntryId: Hashable, CustomStringConvertible {
enum ChatListNodeEntry: Comparable, Identifiable {
case SearchEntry
case MessageEntry(Message, CombinedPeerReadState?, PeerNotificationSettings?)
case MessageEntry(MessageIndex, Message, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?)
case HoleEntry(ChatListHole)
case Nothing(MessageIndex)
@@ -70,8 +70,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
switch self {
case .SearchEntry:
return MessageIndex.absoluteUpperBound()
case let .MessageEntry(message, _, _):
return MessageIndex(message)
case let .MessageEntry(index, _, _, _, _):
return index
case let .HoleEntry(hole):
return hole.index
case let .Nothing(index):
@@ -83,8 +83,8 @@ enum ChatListNodeEntry: Comparable, Identifiable {
switch self {
case .SearchEntry:
return .Search
case let .MessageEntry(message, _, _):
return .PeerId(message.id.peerId.toInt64())
case let .MessageEntry(index, _, _, _, _):
return .PeerId(index.id.peerId.toInt64())
case let .HoleEntry(hole):
return .Hole(Int64(hole.index.id.id))
case let .Nothing(index):
@@ -105,9 +105,12 @@ enum ChatListNodeEntry: Comparable, Identifiable {
default:
return false
}
case let .MessageEntry(lhsMessage, lhsUnreadCount, lhsNotificationSettings):
case let .MessageEntry(lhsIndex, lhsMessage, lhsUnreadCount, lhsNotificationSettings, lhsEmbeddedState):
switch rhs {
case let .MessageEntry(rhsMessage, rhsUnreadCount, rhsNotificationSettings):
case let .MessageEntry(rhsIndex, rhsMessage, rhsUnreadCount, rhsNotificationSettings, rhsEmbeddedState):
if lhsIndex != rhsIndex {
return false
}
if lhsMessage.id != rhsMessage.id || lhsMessage.flags != rhsMessage.flags || lhsUnreadCount != rhsUnreadCount {
return false
}
@@ -118,6 +121,13 @@ enum ChatListNodeEntry: Comparable, Identifiable {
} else if (lhsNotificationSettings != nil) != (rhsNotificationSettings != nil) {
return false
}
if let lhsEmbeddedState = lhsEmbeddedState, let rhsEmbeddedState = rhsEmbeddedState {
if !lhsEmbeddedState.isEqual(to: rhsEmbeddedState) {
return false
}
} else if (lhsEmbeddedState != nil) != (rhsEmbeddedState != nil) {
return false
}
return true
default:
break
@@ -145,8 +155,8 @@ func chatListNodeEntriesForView(_ view: ChatListView) -> [ChatListNodeEntry] {
var result: [ChatListNodeEntry] = []
for entry in view.entries {
switch entry {
case let .MessageEntry(message, combinedReadState, notificationSettings):
result.append(.MessageEntry(message, combinedReadState, notificationSettings))
case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState):
result.append(.MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState))
case let .HoleEntry(hole):
result.append(.HoleEntry(hole))
case let .Nothing(index):

View File

@@ -59,7 +59,7 @@ final class ChatListSearchContainerNode: SearchDisplayControllerContentNode {
for item in items {
switch item {
case let .message(message):
listItems.append(ChatListItem(account: account, message: message, combinedReadState: nil, notificationSettings: nil, action: { [weak strongSelf] _ in
listItems.append(ChatListItem(account: account, message: message, combinedReadState: nil, notificationSettings: nil, embeddedState: nil, action: { [weak strongSelf] _ in
if let strongSelf = strongSelf, let peer = message.peers[message.id.peerId] {
strongSelf.listNode.clearHighlightAnimated(true)
strongSelf.openMessage(peer, message.id)

View File

@@ -391,19 +391,23 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if self.sendButton.alpha.isZero {
self.sendButton.alpha = 1.0
self.micButton.alpha = 0.0
if animated {
self.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.sendButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
self.micButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
}
} else {
if self.micButton.alpha.isZero {
self.micButton.alpha = 1.0
self.sendButton.alpha = 0.0
if animated {
self.micButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.micButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
self.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
}
}
let (accessoryButtonsWidth, textFieldHeight) = self.calculateTextFieldMetrics(width: self.bounds.size.width)
let panelHeight = self.panelHeight(textFieldHeight: textFieldHeight)

View File

@@ -0,0 +1,11 @@
import Postbox
private var telegramUIDeclaredEncodables: Void = {
declareEncodable(ChatInterfaceState.self, f: { ChatInterfaceState(decoder: $0) })
declareEncodable(ChatEmbeddedInterfaceState.self, f: { ChatEmbeddedInterfaceState(decoder: $0) })
return
}()
public func telegramUIDeclareEncodables() {
let _ = telegramUIDeclaredEncodables
}

View File

@@ -5,12 +5,26 @@ import Postbox
import SwiftSignalKit
import Display
private let lineImage = generateVerticallyStretchableFilledCircleImage(radius: 1.0, color: UIColor(0x007ee5))
private let closeButtonImage = generateImage(CGSize(width: 12.0, height: 12.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(UIColor(0x9099A2).cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - 1.0))
context.strokePath()
context.move(to: CGPoint(x: size.width - 1.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
final class ForwardAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable()
let messageIds: [MessageId]
let closeButton: ASButtonNode
let lineNode: ASDisplayNode
let lineNode: ASImageNode
let titleNode: ASTextNode
let textNode: ASTextNode
@@ -18,12 +32,14 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
self.messageIds = messageIds
self.closeButton = ASButtonNode()
self.closeButton.setImage(UIImage(bundleImageName: "Chat/Input/Acessory Panels/CloseButton")?.precomposed(), for: [])
self.closeButton.setImage(closeButtonImage, for: [])
self.closeButton.hitTestSlop = UIEdgeInsetsMake(-8.0, -8.0, -8.0, -8.0)
self.closeButton.displaysAsynchronously = false
self.lineNode = ASDisplayNode()
self.lineNode.backgroundColor = UIColor(0x007ee5)
self.lineNode = ASImageNode()
self.lineNode.displayWithoutProcessing = true
self.lineNode.displaysAsynchronously = false
self.lineNode.image = lineImage
self.titleNode = ASTextNode()
self.titleNode.truncationMode = .byTruncatingTail
@@ -65,8 +81,8 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
text = "\(messages.count) messages"
}
strongSelf.titleNode.attributedText = NSAttributedString(string: authors, font: Font.regular(14.5), textColor: UIColor(0x007ee5))
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.5), textColor: UIColor.black)
strongSelf.titleNode.attributedText = NSAttributedString(string: authors, font: Font.medium(15.0), textColor: UIColor(0x007ee5))
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: UIColor.black)
strongSelf.setNeedsLayout()
}
@@ -78,24 +94,28 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode {
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 40.0)
return CGSize(width: constrainedSize.width, height: 45.0)
}
override func layout() {
super.layout()
let bounds = self.bounds
let leftInset: CGFloat = 55.0
let textLineInset: CGFloat = 10.0
let rightInset: CGFloat = 55.0
let textRightInset: CGFloat = 20.0
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
self.closeButton.frame = CGRect(origin: CGPoint(x: bounds.size.width - self.insets.right - closeButtonSize.width, y: 12.0), size: closeButtonSize)
self.closeButton.frame = CGRect(origin: CGPoint(x: bounds.size.width - rightInset - closeButtonSize.width, y: 19.0), size: closeButtonSize)
self.lineNode.frame = CGRect(origin: CGPoint(x: self.insets.left, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 5.0))
self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0))
let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - 11.0 - insets.left - insets.right - 14.0, height: bounds.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: self.insets.left + 11.0, y: 7.0), size: titleSize)
let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 7.0), size: titleSize)
let textSize = self.textNode.measure(CGSize(width: bounds.size.width - 11.0 - insets.left - insets.right - 14.0, height: bounds.size.height))
self.textNode.frame = CGRect(origin: CGPoint(x: self.insets.left + 11.0, y: 25.0), size: textSize)
let textSize = self.textNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height))
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 25.0), size: textSize)
}
@objc func closePressed() {

View File

@@ -5,12 +5,26 @@ import Postbox
import SwiftSignalKit
import Display
private let lineImage = generateVerticallyStretchableFilledCircleImage(radius: 1.0, color: UIColor(0x007ee5))
private let closeButtonImage = generateImage(CGSize(width: 12.0, height: 12.0), contextGenerator: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setStrokeColor(UIColor(0x9099A2).cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.move(to: CGPoint(x: 1.0, y: 1.0))
context.addLine(to: CGPoint(x: size.width - 1.0, y: size.height - 1.0))
context.strokePath()
context.move(to: CGPoint(x: size.width - 1.0, y: 1.0))
context.addLine(to: CGPoint(x: 1.0, y: size.height - 1.0))
context.strokePath()
})
final class ReplyAccessoryPanelNode: AccessoryPanelNode {
private let messageDisposable = MetaDisposable()
let messageId: MessageId
let closeButton: ASButtonNode
let lineNode: ASDisplayNode
let lineNode: ASImageNode
let titleNode: ASTextNode
let textNode: ASTextNode
@@ -18,12 +32,14 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
self.messageId = messageId
self.closeButton = ASButtonNode()
self.closeButton.setImage(UIImage(bundleImageName: "Chat/Input/Acessory Panels/CloseButton")?.precomposed(), for: [])
self.closeButton.setImage(closeButtonImage, for: [])
self.closeButton.hitTestSlop = UIEdgeInsetsMake(-8.0, -8.0, -8.0, -8.0)
self.closeButton.displaysAsynchronously = false
self.lineNode = ASDisplayNode()
self.lineNode.backgroundColor = UIColor(0x007ee5)
self.lineNode = ASImageNode()
self.lineNode.displayWithoutProcessing = true
self.lineNode.displaysAsynchronously = false
self.lineNode.image = lineImage
self.titleNode = ASTextNode()
self.titleNode.truncationMode = .byTruncatingTail
@@ -56,8 +72,8 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
text = messageText
}
strongSelf.titleNode.attributedText = NSAttributedString(string: authorName, font: Font.regular(14.5), textColor: UIColor(0x007ee5))
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.5), textColor: UIColor.black)
strongSelf.titleNode.attributedText = NSAttributedString(string: authorName, font: Font.medium(15.0), textColor: UIColor(0x007ee5))
strongSelf.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: UIColor.black)
strongSelf.setNeedsLayout()
}
@@ -69,24 +85,28 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
}
override func calculateSizeThatFits(_ constrainedSize: CGSize) -> CGSize {
return CGSize(width: constrainedSize.width, height: 40.0)
return CGSize(width: constrainedSize.width, height: 45.0)
}
override func layout() {
super.layout()
let bounds = self.bounds
let leftInset: CGFloat = 55.0
let textLineInset: CGFloat = 10.0
let rightInset: CGFloat = 55.0
let textRightInset: CGFloat = 20.0
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
self.closeButton.frame = CGRect(origin: CGPoint(x: bounds.size.width - self.insets.right - closeButtonSize.width, y: 12.0), size: closeButtonSize)
self.closeButton.frame = CGRect(origin: CGPoint(x: bounds.size.width - rightInset - closeButtonSize.width, y: 19.0), size: closeButtonSize)
self.lineNode.frame = CGRect(origin: CGPoint(x: self.insets.left, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 5.0))
self.lineNode.frame = CGRect(origin: CGPoint(x: leftInset, y: 8.0), size: CGSize(width: 2.0, height: bounds.size.height - 10.0))
let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - 11.0 - insets.left - insets.right - 14.0, height: bounds.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: self.insets.left + 11.0, y: 7.0), size: titleSize)
let titleSize = self.titleNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height))
self.titleNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 7.0), size: titleSize)
let textSize = self.textNode.measure(CGSize(width: bounds.size.width - 11.0 - insets.left - insets.right - 14.0, height: bounds.size.height))
self.textNode.frame = CGRect(origin: CGPoint(x: self.insets.left + 11.0, y: 25.0), size: textSize)
let textSize = self.textNode.measure(CGSize(width: bounds.size.width - leftInset - textLineInset - rightInset - textRightInset, height: bounds.size.height))
self.textNode.frame = CGRect(origin: CGPoint(x: leftInset + textLineInset, y: 25.0), size: textSize)
}
@objc func closePressed() {