mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
1e49c24614
commit
de61740a73
@ -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.";
|
||||
|
@ -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()
|
||||
|
@ -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];
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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([
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -415,6 +415,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
||||
}, performTextSelectionAction: { _, _, _ in
|
||||
}, updateMessageReaction: { _, _ in
|
||||
}, openMessageReactions: { _ in
|
||||
}, displaySwipeToReplyHint: {
|
||||
}, requestMessageUpdate: { _ in
|
||||
}, cancelInteractiveKeyboardGestures: {
|
||||
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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
Binary file not shown.
@ -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 {
|
||||
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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() {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user