Various fixes

This commit is contained in:
Ilya Laktyushin 2019-10-19 17:13:32 +04:00
parent 1e49c24614
commit de61740a73
26 changed files with 2775 additions and 2663 deletions

View File

@ -4980,3 +4980,9 @@ Any member of this group will be able to see messages in the channel.";
"ClearCache.FreeSpaceDescription" = "If you want to save space on your device, you don't need to delete anything.\n\nYou can use cache settings to remove unnecessary media — and re-download files if you need them again.";
"ClearCache.FreeSpace" = "Free Space";
"ClearCache.Success" = "**%@** freed on your phone!";
"Conversation.ScheduleMessage.SendWhenOnline" = "Send When Online";
"ScheduledMessages.ScheduledOnline" = "Scheduled until online";
"Conversation.SwipeToReplyHintTitle" = "Swipe To Reply";
"Conversation.SwipeToReplyHintText" = "Swipe left on any message to reply to it.";

View File

@ -333,7 +333,7 @@ private final class WalletContextImpl: NSObject, WalletContext, UIImagePickerCon
}
}
func pickImage(completion: @escaping (UIImage) -> Void) {
func pickImage(present: @escaping (ViewController) -> Void, completion: @escaping (UIImage) -> Void) {
self.currentImagePickerCompletion = completion
let pickerController = UIImagePickerController()

View File

@ -389,6 +389,11 @@
completionBlock();
}
- (NSArray<NSString *> *)suggestionsForResponseToActionWithIdentifier:(NSString *)identifier forNotification:(UNNotification *)notification inputLanguage:(NSString *)inputLanguage
{
return [TGInputController suggestionsForText:nil];
}
- (NSArray<NSString *> *)suggestionsForResponseToActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)localNotification inputLanguage:(NSString *)inputLanguage
{
return [TGInputController suggestionsForText:nil];

View File

@ -413,7 +413,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
self.requestLayout?(.immediate)
}
self.deleteButton.isHidden = origin == nil
if origin == nil {
self.deleteButton.isHidden = true
}
}
func setMessage(_ message: Message) {
@ -830,7 +832,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
if !ask && items.count == 1 {
let _ = deleteMessagesInteractively(postbox: strongSelf.context.account.postbox, messageIds: messages.map { $0.id }, type: .forEveryone).start()
strongSelf.controllerInteraction?.dismissController()
} else {
} else if !items.isEmpty {
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated()

View File

@ -45,29 +45,29 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
|> map { data, size, bytesPerRow in
return { arguments in
let context = DrawingContext(size: arguments.drawingSize, scale: arguments.scale ?? 0.0, clear: true)
let side = floorToScreenPixels(arguments.drawingSize.width / CGFloat(size))
let padding: CGFloat = floor((arguments.drawingSize.width - CGFloat(side * CGFloat(size))) / 2.0)
let drawingRect = arguments.drawingRect
let fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize)
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
let codeScale: CGFloat = 1.10256
let clipSide = fittedRect.width * 0.23124
let clipRect = CGRect(x: fittedRect.midX - clipSide / 2.0, y: fittedRect.midY - clipSide / 2.0, width: clipSide, height: clipSide)
let cutout: (Int, Int)?
if case .none = icon {
cutout = nil
} else {
switch size {
case 39:
cutout = (14, 24)
case 43:
cutout = (15, 27)
case 47:
cutout = (17, 29)
case 51:
cutout = (19, 31)
case 55:
cutout = (21, 33)
case 59:
cutout = (22, 36)
case 63:
cutout = (23, 39)
default:
cutout = (16, 26)
var cutoutSize = Int(ceil((clipSide + side * 2.0) / side))
if size == 39 {
cutoutSize = 11
} else if cutoutSize % 2 == 0 {
cutoutSize += 1
}
let start = (size - cutoutSize) / 2
cutout = (start, start + cutoutSize - 1)
}
func valueAt(x: Int, y: Int) -> Bool {
if x >= 0 && x < size && y >= 0 && y < size {
@ -87,9 +87,6 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
}
}
let side = floorToScreenPixels(arguments.drawingSize.width / CGFloat(size))
let padding: CGFloat = floor((arguments.drawingSize.width - CGFloat(side * CGFloat(size))) / 2.0)
let squareSize = CGSize(width: side, height: side)
let tmpContext = DrawingContext(size: CGSize(width: squareSize.width * 4.0, height: squareSize.height), scale: arguments.scale ?? 0.0, clear: true)
tmpContext.withContext { c in
@ -233,14 +230,7 @@ public func qrCode(string: String, color: UIColor, backgroundColor: UIColor? = n
c.translateBy(x: -padding, y: -padding)
let drawingRect = arguments.drawingRect
let fittedSize = arguments.imageSize.aspectFilled(arguments.boundingSize).fitted(arguments.imageSize)
let fittedRect = CGRect(origin: CGPoint(x: drawingRect.origin.x + (drawingRect.size.width - fittedSize.width) / 2.0, y: drawingRect.origin.y + (drawingRect.size.height - fittedSize.height) / 2.0), size: fittedSize)
let codeScale: CGFloat = 43.0 / 39.0
let clipSide = 56.0 * fittedRect.width / 267.0 * codeScale
let clipRect = CGRect(x: fittedRect.midX - clipSide / 2.0, y: fittedRect.midY - clipSide / 2.0, width: clipSide, height: clipSide)
switch icon {
case .proxy:
let iconScale = fittedRect.width / 420.0 * codeScale

View File

@ -193,7 +193,7 @@ public extension Message {
func effectivelyFailed(timestamp: Int32) -> Bool {
if self.flags.contains(.Failed) {
return true
} else if self.id.namespace == Namespaces.Message.ScheduledCloud {
} else if self.id.namespace == Namespaces.Message.ScheduledCloud && self.timestamp != 0x7FFFFFFE {
return timestamp > self.timestamp + 60
} else {
return false

View File

@ -1689,6 +1689,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.present(MessageReactionListController(context: strongSelf.context, messageId: message.id, initialReactions: initialReactions), in: .window(.root))
}
})
}, displaySwipeToReplyHint: { [weak self] in
if let strongSelf = self {
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .swipeToReply(title: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintTitle, text: strongSelf.presentationData.strings.Conversation_SwipeToReplyHintText), elevatedLayout: true, action: { _ in }), in: .window(.root))
}
}, requestMessageUpdate: { [weak self] id in
if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
@ -5073,8 +5077,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.dismiss()
case .clearCache:
let clearDisposable = MetaDisposable()
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) })
switch self.chatLocationInfoData {
case let .peer(peerView):
self.navigationActionDisposable.set((peerView.get()
@ -5244,13 +5247,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
clearDisposable.set(nil)
}
clearDisposable.set((signal
|> deliverOnMainQueue).start(completed: {
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0), elevatedLayout: false, action: { _ in }), in: .window(.root))
|> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self {
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0), elevatedLayout: true, action: { _ in }), in: .window(.root))
}
}))
dismissAction()
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) })
}))
controller.setItemGroups([

View File

@ -99,6 +99,7 @@ public final class ChatControllerInteraction {
let performTextSelectionAction: (UInt32, String, TextSelectionAction) -> Void
let updateMessageReaction: (MessageId, String) -> Void
let openMessageReactions: (MessageId) -> Void
let displaySwipeToReplyHint: () -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -113,7 +114,7 @@ public final class ChatControllerInteraction {
var searchTextHighightState: (String, [MessageIndex])?
var seenOneTimeAnimatedMedia = Set<MessageId>()
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String) -> Void, openMessageReactions: @escaping (MessageId) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, TapLongTapOrDoubleTapGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOption: @escaping (MessageId, Data) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage
self.openPeer = openPeer
self.openPeerMention = openPeerMention
@ -165,7 +166,8 @@ public final class ChatControllerInteraction {
self.performTextSelectionAction = performTextSelectionAction
self.updateMessageReaction = updateMessageReaction
self.openMessageReactions = openMessageReactions
self.displaySwipeToReplyHint = displaySwipeToReplyHint
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -201,6 +203,7 @@ public final class ChatControllerInteraction {
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, openMessageReactions: { _ in
}, displaySwipeToReplyHint: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -2121,6 +2121,19 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}
var forwardingToSameChat = false
if case let .peer(id) = self.chatPresentationInterfaceState.chatLocation, id.namespace == Namespaces.Peer.CloudUser, id != self.context.account.peerId, let forwardMessageIds = self.chatPresentationInterfaceState.interfaceState.forwardMessageIds {
for messageId in forwardMessageIds {
if messageId.peerId == id {
forwardingToSameChat = true
}
}
}
if !messages.isEmpty && forwardingToSameChat {
//self.controllerInteraction.displaySwipeToReplyHint()
}
if !messages.isEmpty || self.chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil {
self.setupSendActionOnViewUpdate({ [weak self] in
if let strongSelf = self, let textInputPanelNode = strongSelf.inputPanelNode as? ChatTextInputPanelNode {

View File

@ -32,7 +32,9 @@ final class ChatMessageDateHeader: ListViewItemHeader {
self.presentationData = presentationData
self.context = context
self.action = action
if timestamp == Int32.max {
if timestamp == 0x7FFFFFFE {
self.roundedTimestamp = 0x7FFFFFFE
} else if timestamp == Int32.max {
self.roundedTimestamp = timestamp / (granularity) * (granularity)
} else {
self.roundedTimestamp = ((timestamp + timezoneOffset) / (granularity)) * (granularity)
@ -151,7 +153,9 @@ final class ChatMessageDateHeaderNode: ListViewItemHeaderNode {
}
if scheduled {
if timeinfo.tm_year == timeinfoNow.tm_year && timeinfo.tm_yday == timeinfoNow.tm_yday {
if localTimestamp == 0x7FFFFFFE {
text = presentationData.strings.ScheduledMessages_ScheduledOnline
} else if timeinfo.tm_year == timeinfoNow.tm_year && timeinfo.tm_yday == timeinfoNow.tm_yday {
text = presentationData.strings.ScheduledMessages_ScheduledToday
} else {
text = presentationData.strings.ScheduledMessages_ScheduledDate(text).0

View File

@ -415,6 +415,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, openMessageReactions: { _ in
}, displaySwipeToReplyHint: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -63,7 +63,7 @@ final class ChatScheduleTimeController: ViewController {
override public func loadDisplayNode() {
self.displayNode = ChatScheduleTimeControllerNode(context: self.context, mode: self.mode, currentTime: self.currentTime, minimalTime: self.minimalTime, dismissByTapOutside: self.dismissByTapOutside)
self.controllerNode.completion = { [weak self] time in
self?.completion(time + 5)
self?.completion(time != 0x7FFFFFFE ? time + 5 : time)
self?.dismiss()
}
self.controllerNode.dismiss = { [weak self] in

View File

@ -25,6 +25,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
private let titleNode: ASTextNode
private let cancelButton: HighlightableButtonNode
private let doneButton: SolidRoundedButtonNode
private let onlineButton: HighlightableButtonNode
private var pickerView: UIDatePicker?
private let dateFormatter: DateFormatter
@ -75,6 +76,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
self.doneButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false)
self.onlineButton = HighlightableButtonNode()
self.onlineButton.setTitle(self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.dateFormatter = DateFormatter()
self.dateFormatter.timeStyle = .none
self.dateFormatter.dateStyle = .short
@ -97,6 +101,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
self.contentContainerNode.addSubnode(self.titleNode)
self.contentContainerNode.addSubnode(self.cancelButton)
self.contentContainerNode.addSubnode(self.doneButton)
//self.contentContainerNode.addSubnode(self.onlineButton)
self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside)
self.doneButton.pressed = { [weak self] in
@ -111,6 +116,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
}
}
}
self.onlineButton.addTarget(self, action: #selector(self.onlineButtonPressed), forControlEvents: .touchUpInside)
self.setupPickerView(currentTime: currentTime)
self.updateButtonTitle()
@ -130,7 +136,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
pickerView.timeZone = TimeZone.current
pickerView.minuteInterval = 1
pickerView.setValue(self.presentationData.theme.actionSheet.primaryTextColor, forKey: "textColor")
contentContainerNode.view.addSubview(pickerView)
self.contentContainerNode.view.addSubview(pickerView)
pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
self.pickerView = pickerView
@ -154,6 +160,7 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
self.doneButton.updateTheme(SolidRoundedButtonTheme(theme: self.presentationData.theme))
self.onlineButton.setTitle(self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
}
private func updateMinimumDate(currentTime: Int32? = nil) {
@ -233,6 +240,10 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
self.cancel?()
}
@objc func onlineButtonPressed() {
self.completion?(0x7FFFFFFE)
}
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if self.dismissByTapOutside, case .ended = recognizer.state {
self.cancelButtonPressed()
@ -299,10 +310,12 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
let cleanInsets = layout.insets(options: [.statusBar])
insets.top = max(10.0, insets.top)
var buttonOffset: CGFloat = 0.0 //44.0
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom
let titleHeight: CGFloat = 54.0
var contentHeight = titleHeight + bottomInset + 52.0 + 17.0
let pickerHeight: CGFloat = min(216.0, layout.size.height - contentHeight)
var contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + buttonOffset
let pickerHeight: CGFloat = min(216.0, layout.size.height - contentHeight - buttonOffset)
contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + pickerHeight
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
@ -329,7 +342,11 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
let buttonInset: CGFloat = 16.0
let buttonHeight = self.doneButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - buttonHeight - insets.bottom - 10.0, width: contentFrame.width, height: buttonHeight))
transition.updateFrame(node: self.doneButton, frame: CGRect(x: buttonInset, y: contentHeight - buttonHeight - insets.bottom - 10.0 - buttonOffset, width: contentFrame.width, height: buttonHeight))
let onlineSize = self.onlineButton.measure(CGSize(width: width, height: titleHeight))
let onlineFrame = CGRect(origin: CGPoint(x: ceil((layout.size.width - onlineSize.width) / 2.0), y: contentHeight - 36.0 - insets.bottom), size: onlineSize)
transition.updateFrame(node: self.onlineButton, frame: onlineFrame)
self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight))

View File

@ -116,6 +116,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, openMessageReactions: { _ in
}, displaySwipeToReplyHint: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -404,6 +404,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
}, performTextSelectionAction: { _, _, _ in
}, updateMessageReaction: { _, _ in
}, openMessageReactions: { _ in
}, displaySwipeToReplyHint: {
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,9 @@ func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, da
timestamp = message.timestamp
}
var dateText = stringForMessageTimestamp(timestamp: timestamp, dateTimeFormat: dateTimeFormat)
if timestamp == 0x7FFFFFFE {
dateText = " "
}
var authorTitle: String?
if let author = message.author as? TelegramUser {

View File

@ -243,11 +243,11 @@ final class WalletContextImpl: WalletContext {
})
}
func pickImage(completion: @escaping (UIImage) -> Void) {
func pickImage(present: @escaping (ViewController) -> Void, completion: @escaping (UIImage) -> Void) {
self.context.sharedContext.openImagePicker(context: self.context, completion: { image in
completion(image)
}, present: { [weak self] controller in
self?.context.sharedContext.mainWindow?.present(controller, on: .root)
present(controller)
})
}
}

View File

@ -10,6 +10,7 @@ public enum UndoOverlayContent {
case revealedArchive(title: String, text: String, undo: Bool)
case succeed(text: String)
case emoji(path: String, text: String)
case swipeToReply(title: String, text: String)
}
public final class UndoOverlayController: ViewController {

View File

@ -137,6 +137,16 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.textNode.maximumNumberOfLines = 2
displayUndo = false
self.originalRemainingSeconds = 5
case let .swipeToReply(title, text):
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = AnimationNode(animation: "anim_swipereply", colors: [:], scale: 1.0)
self.animatedStickerNode = nil
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(14.0), textColor: .white)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(14.0), textColor: .white)
self.textNode.maximumNumberOfLines = 2
displayUndo = false
self.originalRemainingSeconds = 5
}
self.remainingSeconds = self.originalRemainingSeconds
@ -168,7 +178,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
case .removedChat:
self.panelWrapperNode.addSubnode(self.timerTextNode)
self.panelWrapperNode.addSubnode(self.statusNode)
case .archivedChat, .hidArchive, .revealedArchive, .succeed, .emoji:
case .archivedChat, .hidArchive, .revealedArchive, .succeed, .emoji, .swipeToReply:
break
}
self.iconNode.flatMap(self.panelWrapperNode.addSubnode)

View File

@ -65,15 +65,20 @@ class WalletAmountItem: ListViewItem, ItemListItem {
private let integralFont = Font.medium(48.0)
private let fractionalFont = Font.medium(24.0)
private let iconSize = CGSize(width: 50.0, height: 50.0)
private let verticalOffset: CGFloat = -10.0
class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemNode, ItemListItemFocusableNode {
private let backgroundNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode
private let containerNode: ASDisplayNode
private let textNode: TextFieldNode
private let iconNode: AnimatedStickerNode
private let measureNode: TextNode
private var item: WalletAmountItem?
private var validLayout: (CGFloat, CGFloat, CGFloat)?
var tag: ItemListItemTag? {
return self.item?.tag
@ -86,6 +91,8 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
self.bottomStripeNode = ASDisplayNode()
self.bottomStripeNode.isLayerBacked = true
self.containerNode = ASDisplayNode()
self.textNode = TextFieldNode()
self.iconNode = AnimatedStickerNode()
@ -100,8 +107,9 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
self.clipsToBounds = false
self.addSubnode(self.textNode)
self.addSubnode(self.iconNode)
self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.textNode)
self.containerNode.addSubnode(self.iconNode)
}
override func didLoad() {
@ -122,9 +130,49 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
self.textNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
}
private func inputFieldAsyncLayout() -> (_ item: WalletAmountItem, _ params: ListViewItemLayoutParams) -> (NSAttributedString, NSAttributedString, () -> Void) {
let makeMeasureLayout = TextNode.asyncLayout(self.measureNode)
return { item, params in
let contentSize = CGSize(width: params.width, height: 100.0)
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: UIEdgeInsets())
let attributedPlaceholderText = NSAttributedString(string: "0", font: integralFont, textColor: item.theme.list.itemPlaceholderTextColor)
let attributedAmountText = amountAttributedString(item.amount, integralFont: integralFont, fractionalFont: fractionalFont, color: item.theme.list.itemPrimaryTextColor)
let (measureLayout, _) = makeMeasureLayout(TextNodeLayoutArguments(attributedString: item.amount.isEmpty ? attributedPlaceholderText : attributedAmountText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: CGFloat.greatestFiniteMagnitude, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
return (attributedPlaceholderText, attributedAmountText, { [weak self] in
if let strongSelf = self {
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - max(31.0, measureLayout.size.width)) / 2.0 - 28.0), y: floor((layout.contentSize.height - iconSize.height) / 2.0) - 3.0 + verticalOffset), size: iconSize)
strongSelf.iconNode.updateLayout(size: iconFrame.size)
strongSelf.iconNode.frame = iconFrame
let totalWidth = measureLayout.size.width + iconSize.width + 6.0
let paddedWidth = layout.size.width - 32.0
if totalWidth > paddedWidth {
let scale = paddedWidth / totalWidth
strongSelf.containerNode.transform = CATransform3DMakeScale(scale, scale, 1.0)
} else {
strongSelf.containerNode.transform = CATransform3DIdentity
}
}
})
}
}
private func updateInputField() {
guard let item = self.item, let validLayout = self.validLayout else {
return
}
let makeInputFieldLayout = self.inputFieldAsyncLayout()
let (_, _, inputFieldApply) = makeInputFieldLayout(item, ListViewItemLayoutParams(width: validLayout.0, leftInset: validLayout.1, rightInset: validLayout.2))
inputFieldApply()
}
func asyncLayout() -> (_ item: WalletAmountItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
let currentItem = self.item
let makeMeasureLayout = TextNode.asyncLayout(self.measureNode)
let makeInputFieldLayout = self.inputFieldAsyncLayout()
return { item, params, neighbors in
var updatedTheme: WalletTheme?
@ -143,16 +191,12 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
insets.top = 0.0
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
let layoutSize = layout.size
let attributedPlaceholderText = NSAttributedString(string: "0", font: integralFont, textColor: item.theme.list.itemPlaceholderTextColor)
let attributedAmountText = amountAttributedString(item.amount, integralFont: integralFont, fractionalFont: fractionalFont, color: item.theme.list.itemPrimaryTextColor)
let (measureLayout, _) = makeMeasureLayout(TextNodeLayoutArguments(attributedString: item.amount.isEmpty ? attributedPlaceholderText : attributedAmountText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.rightInset - leftInset * 2.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (attributedPlaceholderText, attributedAmountText, inputFieldApply) = makeInputFieldLayout(item, params)
return (layout, { [weak self] in
if let strongSelf = self {
strongSelf.item = item
strongSelf.validLayout = (params.width, params.leftInset, params.rightInset)
if let _ = updatedTheme {
strongSelf.bottomStripeNode.backgroundColor = item.theme.list.itemBlocksSeparatorColor
@ -185,10 +229,7 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
strongSelf.textNode.textField.attributedText = attributedAmountText
}
let iconSize = CGSize(width: 50.0, height: 50.0)
let verticalOffset: CGFloat = -10.0
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((layout.contentSize.height - 48.0) / 2.0) + verticalOffset), size: CGSize(width: max(1.0, params.width - (leftInset + rightInset) + iconSize.width - 5.0), height: 48.0))
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset - 67.0, y: floor((layout.contentSize.height - 48.0) / 2.0) + verticalOffset), size: CGSize(width: max(1.0, params.width + iconSize.width - 5.0 + 100.0), height: 48.0))
if strongSelf.backgroundNode.supernode == nil {
strongSelf.insertSubnode(strongSelf.backgroundNode, at: 0)
@ -207,16 +248,15 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
}
strongSelf.backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - UIScreenPixel), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height - UIScreenPixel), size: CGSize(width: layout.size.width - bottomStripeInset, height: separatorHeight))
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: contentSize)
if strongSelf.textNode.textField.attributedPlaceholder == nil || !strongSelf.textNode.textField.attributedPlaceholder!.isEqual(to: attributedPlaceholderText) {
strongSelf.textNode.textField.attributedPlaceholder = attributedPlaceholderText
strongSelf.textNode.textField.accessibilityHint = attributedPlaceholderText.string
}
let iconFrame = CGRect(origin: CGPoint(x: floor((layout.size.width - max(31.0, measureLayout.size.width)) / 2.0 - 28.0), y: floor((layout.contentSize.height - iconSize.height) / 2.0) - 3.0 + verticalOffset), size: iconSize)
strongSelf.iconNode.updateLayout(size: iconFrame.size)
strongSelf.iconNode.frame = iconFrame
inputFieldApply()
}
})
}
@ -232,6 +272,7 @@ class WalletAmountItemNode: ListViewItemNode, UITextFieldDelegate, ItemListItemN
@objc private func textFieldTextChanged(_ textField: UITextField) {
self.textUpdated(self.textNode.textField.text ?? "")
self.updateInputField()
}
@objc private func clearButtonPressed() {

View File

@ -1,6 +1,7 @@
import Foundation
import UIKit
import SwiftSignalKit
import Display
import WalletCore
public enum WalletContextGetServerSaltError {
@ -24,5 +25,5 @@ public protocol WalletContext {
func shareUrl(_ url: String)
func openPlatformSettings()
func authorizeAccessToCamera(completion: @escaping () -> Void)
func pickImage(completion: @escaping (UIImage) -> Void)
func pickImage(present: @escaping (ViewController) -> Void, completion: @escaping (UIImage) -> Void)
}

View File

@ -118,7 +118,9 @@ public final class WalletQrScanScreen: ViewController {
guard let strongSelf = self else {
return
}
strongSelf.context.pickImage(completion: { image in
strongSelf.context.pickImage(present: { c in
strongSelf.push(c)
}, completion: { image in
let detector = CIDetector(ofType: CIDetectorTypeQRCode, context: nil, options: [CIDetectorAccuracy: CIDetectorAccuracyHigh])!
if let ciImage = CIImage(image: image) {
var options: [String: Any]

View File

@ -311,6 +311,7 @@ private final class WalletTransactionInfoScreenNode: ViewControllerTracingNode,
self.navigationBackgroundNode.alpha = 0.0
self.navigationSeparatorNode = ASDisplayNode()
self.navigationSeparatorNode.backgroundColor = self.presentationData.theme.navigationBar.separatorColor
self.navigationSeparatorNode.alpha = 0.0
self.scrollNode = ASScrollNode()