mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Web app improvements
This commit is contained in:
parent
3881bdff70
commit
ada47a4be5
@ -9915,7 +9915,9 @@ Sorry for the inconvenience.";
|
||||
"Gallery.ViewOnceVideoTooltip" = "This video can only be viewed once.";
|
||||
|
||||
"WebApp.DisclaimerTitle" = "Warning";
|
||||
"WebApp.DisclaimerText" = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue.\n\n**%@** shortcuts will be added in your attachment menu and Settings.";
|
||||
"WebApp.DisclaimerText" = "You are about to use a mini app operated by an independent party not affiliated with Telegram. You must agree to the Terms of Use of mini apps to continue.";
|
||||
"WebApp.DisclaimerShortcutsText" = "**%@** shortcuts will be added in your attachment menu.";
|
||||
"WebApp.DisclaimerShortcutsSettingsText" = "**%@** shortcuts will be added in your attachment menu and Settings.";
|
||||
"WebApp.DisclaimerAgree" = "I agree to the [Terms of Use]()";
|
||||
"WebApp.DisclaimerContinue" = "Continue";
|
||||
"WebApp.Disclaimer_URL" = "https://telegram.org/tos/mini-apps";
|
||||
|
@ -869,7 +869,7 @@ public protocol SharedAccountContext: AnyObject {
|
||||
func makeSetupTwoFactorAuthController(context: AccountContext) -> ViewController
|
||||
func makeStorageManagementController(context: AccountContext) -> ViewController
|
||||
func makeAttachmentFileController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, bannedSendMedia: (Int32, Bool)?, presentGallery: @escaping () -> Void, presentFiles: @escaping () -> Void, send: @escaping (AnyMediaReference) -> Void) -> AttachmentFileController
|
||||
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
||||
func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, isScheduledMessages: Bool, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject?
|
||||
func makeHashtagSearchController(context: AccountContext, peer: EnginePeer?, query: String, all: Bool) -> ViewController
|
||||
func makeMyStoriesController(context: AccountContext, isArchive: Bool) -> ViewController
|
||||
func makeArchiveSettingsController(context: AccountContext) -> ViewController
|
||||
|
@ -82,6 +82,7 @@ final class AttachmentTextInputActionButtonsNode: ASDisplayNode {
|
||||
super.didLoad()
|
||||
|
||||
let gestureRecognizer = ContextGesture(target: nil, action: nil)
|
||||
gestureRecognizer.isEnabled = self.sendButtonLongPressEnabled
|
||||
self.gestureRecognizer = gestureRecognizer
|
||||
self.sendButton.view.addGestureRecognizer(gestureRecognizer)
|
||||
gestureRecognizer.activated = { [weak self] recognizer, _ in
|
||||
|
@ -327,7 +327,7 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
|
||||
private var maxCaptionLength: Int32?
|
||||
|
||||
public init(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, isCaption: Bool = false, isAttachment: Bool = false, presentController: @escaping (ViewController) -> Void, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
|
||||
public init(context: AccountContext, presentationInterfaceState: ChatPresentationInterfaceState, isCaption: Bool = false, isAttachment: Bool = false, isScheduledMessages: Bool = false, presentController: @escaping (ViewController) -> Void, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
|
||||
self.context = context
|
||||
self.presentationInterfaceState = presentationInterfaceState
|
||||
self.isCaption = isCaption
|
||||
@ -374,8 +374,13 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
|
||||
super.init()
|
||||
|
||||
self.actionButtons.sendButtonLongPressed = { [weak self] node, gesture in
|
||||
self?.interfaceInteraction?.displaySendMessageOptions(node, gesture)
|
||||
if !isScheduledMessages {
|
||||
self.actionButtons.sendButtonLongPressed = { [weak self] node, gesture in
|
||||
self?.interfaceInteraction?.displaySendMessageOptions(node, gesture)
|
||||
}
|
||||
self.actionButtons.sendButtonLongPressEnabled = true
|
||||
} else {
|
||||
self.actionButtons.sendButtonLongPressEnabled = false
|
||||
}
|
||||
|
||||
self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside)
|
||||
@ -727,8 +732,6 @@ public class AttachmentTextInputPanelNode: ASDisplayNode, TGCaptionPanelView, AS
|
||||
}
|
||||
self.textPlaceholderNode.frame = CGRect(origin: self.textPlaceholderNode.frame.origin, size: placeholderSize)
|
||||
}
|
||||
|
||||
self.actionButtons.sendButtonLongPressEnabled = true
|
||||
}
|
||||
|
||||
let sendButtonHasApplyIcon = self.isCaption || interfaceState.interfaceState.editMessage != nil
|
||||
|
@ -179,6 +179,7 @@ public class AttachmentController: ViewController {
|
||||
private let context: AccountContext
|
||||
private let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?
|
||||
private let chatLocation: ChatLocation?
|
||||
private let isScheduledMessages: Bool
|
||||
private let buttons: [AttachmentButtonType]
|
||||
private let initialButton: AttachmentButtonType
|
||||
private let fromMenu: Bool
|
||||
@ -294,7 +295,7 @@ public class AttachmentController: ViewController {
|
||||
|
||||
self.container = AttachmentContainer()
|
||||
self.container.canHaveKeyboardFocus = true
|
||||
self.panel = AttachmentPanel(context: controller.context, chatLocation: controller.chatLocation, updatedPresentationData: controller.updatedPresentationData, makeEntityInputView: makeEntityInputView)
|
||||
self.panel = AttachmentPanel(context: controller.context, chatLocation: controller.chatLocation, isScheduledMessages: controller.isScheduledMessages, updatedPresentationData: controller.updatedPresentationData, makeEntityInputView: makeEntityInputView)
|
||||
self.panel.fromMenu = controller.fromMenu
|
||||
self.panel.isStandalone = controller.isStandalone
|
||||
|
||||
@ -907,10 +908,11 @@ public class AttachmentController: ViewController {
|
||||
|
||||
public var getSourceRect: (() -> CGRect?)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatLocation: ChatLocation?, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, chatLocation: ChatLocation?, isScheduledMessages: Bool = false, buttons: [AttachmentButtonType], initialButton: AttachmentButtonType = .gallery, fromMenu: Bool = false, hasTextInput: Bool = true, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView? = { return nil}) {
|
||||
self.context = context
|
||||
self.updatedPresentationData = updatedPresentationData
|
||||
self.chatLocation = chatLocation
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.buttons = buttons
|
||||
self.initialButton = initialButton
|
||||
self.fromMenu = fromMenu
|
||||
|
@ -725,6 +725,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode {
|
||||
|
||||
final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
private let context: AccountContext
|
||||
private let isScheduledMessages: Bool
|
||||
private var presentationData: PresentationData
|
||||
private var presentationDataDisposable: Disposable?
|
||||
|
||||
@ -775,9 +776,10 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
|
||||
var mainButtonPressed: () -> Void = { }
|
||||
|
||||
init(context: AccountContext, chatLocation: ChatLocation?, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
|
||||
init(context: AccountContext, chatLocation: ChatLocation?, isScheduledMessages: Bool, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, makeEntityInputView: @escaping () -> AttachmentTextInputPanelInputView?) {
|
||||
self.context = context
|
||||
self.presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
|
||||
self.makeEntityInputView = makeEntityInputView
|
||||
|
||||
@ -1248,7 +1250,7 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
private func loadTextNodeIfNeeded() {
|
||||
if let _ = self.textInputPanelNode {
|
||||
} else {
|
||||
let textInputPanelNode = AttachmentTextInputPanelNode(context: self.context, presentationInterfaceState: self.presentationInterfaceState, isAttachment: true, presentController: { [weak self] c in
|
||||
let textInputPanelNode = AttachmentTextInputPanelNode(context: self.context, presentationInterfaceState: self.presentationInterfaceState, isAttachment: true, isScheduledMessages: self.isScheduledMessages, presentController: { [weak self] c in
|
||||
if let strongSelf = self {
|
||||
strongSelf.present(c)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
private let context: AccountContext
|
||||
|
||||
private let peerId: EnginePeer.Id?
|
||||
private let isScheduledMessages: Bool
|
||||
private let forwardMessageIds: [EngineMessage.Id]?
|
||||
private let hasEntityKeyboard: Bool
|
||||
|
||||
@ -45,9 +46,10 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
|
||||
public var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)?
|
||||
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, canSendWhenOnline: Bool, completion: @escaping () -> Void, sendMessage: @escaping (SendMode) -> Void, schedule: @escaping () -> Void) {
|
||||
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id?, isScheduledMessages: Bool = false, forwardMessageIds: [EngineMessage.Id]?, hasEntityKeyboard: Bool, gesture: ContextGesture, sourceSendButton: ASDisplayNode, textInputNode: EditableTextNode, attachment: Bool = false, canSendWhenOnline: Bool, completion: @escaping () -> Void, sendMessage: @escaping (SendMode) -> Void, schedule: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.forwardMessageIds = forwardMessageIds
|
||||
self.hasEntityKeyboard = hasEntityKeyboard
|
||||
self.gesture = gesture
|
||||
@ -101,6 +103,9 @@ public final class ChatSendMessageActionSheetController: ViewController {
|
||||
isSecret = peerId.namespace == Namespaces.Peer.SecretChat
|
||||
canSchedule = !isSecret
|
||||
}
|
||||
if self.isScheduledMessages {
|
||||
canSchedule = false
|
||||
}
|
||||
|
||||
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, presentationData: self.presentationData, reminders: reminders, gesture: gesture, sourceSendButton: self.sourceSendButton, textInputNode: self.textInputNode, attachment: self.attachment, canSendWhenOnline: self.canSendWhenOnline, forwardedCount: forwardedCount, hasEntityKeyboard: self.hasEntityKeyboard, emojiViewProvider: self.emojiViewProvider, send: { [weak self] in
|
||||
self?.sendMessage(.generic)
|
||||
|
@ -100,7 +100,7 @@ enum LegacyMediaPickerGallerySource {
|
||||
case selection(item: TGMediaSelectableItem)
|
||||
}
|
||||
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?, @escaping () -> Void) -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, willTransitionOut: @escaping () -> Void, dismissAll: @escaping () -> Void) -> TGModernGalleryController {
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, threadTitle: String?, chatLocation: ChatLocation?, isScheduledMessages: Bool, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?, @escaping () -> Void) -> Void, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, willTransitionOut: @escaping () -> Void, dismissAll: @escaping () -> Void) -> TGModernGalleryController {
|
||||
let reminder = peer?.id == context.account.peerId
|
||||
let hasSilentPosting = hasSilentPosting && peer?.id != context.account.peerId
|
||||
|
||||
@ -224,103 +224,105 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
||||
})
|
||||
}
|
||||
}
|
||||
model.interfaceView.doneLongPressed = { [weak selectionContext, weak editingContext, weak legacyController, weak model] item in
|
||||
if let legacyController = legacyController, let item = item as? TGMediaPickerGalleryItem, let model = model, let selectionContext = selectionContext {
|
||||
var effectiveHasSchedule = hasSchedule
|
||||
if !isScheduledMessages {
|
||||
model.interfaceView.doneLongPressed = { [weak selectionContext, weak editingContext, weak legacyController, weak model] item in
|
||||
if let legacyController = legacyController, let item = item as? TGMediaPickerGalleryItem, let model = model, let selectionContext = selectionContext {
|
||||
var effectiveHasSchedule = hasSchedule
|
||||
|
||||
if let editingContext = editingContext {
|
||||
if let timer = editingContext.timer(for: item.asset)?.intValue, timer > 0 {
|
||||
effectiveHasSchedule = false
|
||||
}
|
||||
for item in selectionContext.selectedItems() {
|
||||
if let editableItem = item as? TGMediaEditableItem, let timer = editingContext.timer(for: editableItem)?.intValue, timer > 0 {
|
||||
if let editingContext = editingContext {
|
||||
if let timer = editingContext.timer(for: item.asset)?.intValue, timer > 0 {
|
||||
effectiveHasSchedule = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sendWhenOnlineAvailable: Signal<Bool, NoError>
|
||||
if let peer {
|
||||
if case .secretChat = peer {
|
||||
effectiveHasSchedule = false
|
||||
}
|
||||
sendWhenOnlineAvailable = context.account.viewTracker.peerView(peer.id)
|
||||
|> take(1)
|
||||
|> map { peerView -> Bool in
|
||||
guard let peer = peerViewMainPeer(peerView) else {
|
||||
return false
|
||||
}
|
||||
var sendWhenOnlineAvailable = false
|
||||
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case let .present(until) = presence.status {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if currentTime > until {
|
||||
sendWhenOnlineAvailable = true
|
||||
for item in selectionContext.selectedItems() {
|
||||
if let editableItem = item as? TGMediaEditableItem, let timer = editingContext.timer(for: editableItem)?.intValue, timer > 0 {
|
||||
effectiveHasSchedule = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id._internalGetInt64Value() == 777000 {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
|
||||
let sendWhenOnlineAvailable: Signal<Bool, NoError>
|
||||
if let peer {
|
||||
if case .secretChat = peer {
|
||||
effectiveHasSchedule = false
|
||||
}
|
||||
return sendWhenOnlineAvailable
|
||||
}
|
||||
} else {
|
||||
sendWhenOnlineAvailable = .single(false)
|
||||
}
|
||||
|
||||
let _ = (sendWhenOnlineAvailable
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sendWhenOnlineAvailable in
|
||||
let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
let sheetController = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSendWhenOnline: sendWhenOnlineAvailable && effectiveHasSchedule, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: false)
|
||||
let dismissImpl = { [weak model] in
|
||||
model?.dismiss(true, false)
|
||||
dismissAll()
|
||||
}
|
||||
sheetController.send = {
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.sendSilently = {
|
||||
completed(item.asset, true, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.sendWhenOnline = {
|
||||
completed(item.asset, false, scheduleWhenOnlineTimestamp, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.schedule = {
|
||||
presentSchedulePicker(true, { time in
|
||||
completed(item.asset, false, time, {
|
||||
dismissImpl()
|
||||
})
|
||||
})
|
||||
}
|
||||
sheetController.sendWithTimer = {
|
||||
presentTimerPicker { time in
|
||||
var items = selectionContext.selectedItems() ?? []
|
||||
items.append(item.asset as Any)
|
||||
|
||||
for case let item as TGMediaEditableItem in items {
|
||||
editingContext?.setTimer(time as NSNumber, for: item)
|
||||
sendWhenOnlineAvailable = context.account.viewTracker.peerView(peer.id)
|
||||
|> take(1)
|
||||
|> map { peerView -> Bool in
|
||||
guard let peer = peerViewMainPeer(peerView) else {
|
||||
return false
|
||||
}
|
||||
var sendWhenOnlineAvailable = false
|
||||
if let presence = peerView.peerPresences[peer.id] as? TelegramUserPresence, case let .present(until) = presence.status {
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
if currentTime > until {
|
||||
sendWhenOnlineAvailable = true
|
||||
}
|
||||
}
|
||||
if peer.id.namespace == Namespaces.Peer.CloudUser && peer.id.id._internalGetInt64Value() == 777000 {
|
||||
sendWhenOnlineAvailable = false
|
||||
}
|
||||
return sendWhenOnlineAvailable
|
||||
}
|
||||
} else {
|
||||
sendWhenOnlineAvailable = .single(false)
|
||||
}
|
||||
|
||||
let _ = (sendWhenOnlineAvailable
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sendWhenOnlineAvailable in
|
||||
let legacySheetController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
let sheetController = TGMediaPickerSendActionSheetController(context: legacyController.context, isDark: true, sendButtonFrame: model.interfaceView.doneButtonFrame, canSendSilently: hasSilentPosting, canSendWhenOnline: sendWhenOnlineAvailable && effectiveHasSchedule, canSchedule: effectiveHasSchedule, reminder: reminder, hasTimer: false)
|
||||
let dismissImpl = { [weak model] in
|
||||
model?.dismiss(true, false)
|
||||
dismissAll()
|
||||
}
|
||||
sheetController.send = {
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
}
|
||||
sheetController.customDismissBlock = { [weak legacySheetController] in
|
||||
legacySheetController?.dismiss()
|
||||
}
|
||||
legacySheetController.bind(controller: sheetController)
|
||||
present(legacySheetController, nil)
|
||||
sheetController.sendSilently = {
|
||||
completed(item.asset, true, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.sendWhenOnline = {
|
||||
completed(item.asset, false, scheduleWhenOnlineTimestamp, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
sheetController.schedule = {
|
||||
presentSchedulePicker(true, { time in
|
||||
completed(item.asset, false, time, {
|
||||
dismissImpl()
|
||||
})
|
||||
})
|
||||
}
|
||||
sheetController.sendWithTimer = {
|
||||
presentTimerPicker { time in
|
||||
var items = selectionContext.selectedItems() ?? []
|
||||
items.append(item.asset as Any)
|
||||
|
||||
let hapticFeedback = HapticFeedback()
|
||||
hapticFeedback.impact()
|
||||
})
|
||||
for case let item as TGMediaEditableItem in items {
|
||||
editingContext?.setTimer(time as NSNumber, for: item)
|
||||
}
|
||||
|
||||
completed(item.asset, false, nil, {
|
||||
dismissImpl()
|
||||
})
|
||||
}
|
||||
}
|
||||
sheetController.customDismissBlock = { [weak legacySheetController] in
|
||||
legacySheetController?.dismiss()
|
||||
}
|
||||
legacySheetController.bind(controller: sheetController)
|
||||
present(legacySheetController, nil)
|
||||
|
||||
let hapticFeedback = HapticFeedback()
|
||||
hapticFeedback.impact()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
model.interfaceView.setThumbnailSignalForItem { item in
|
||||
|
@ -169,6 +169,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
fileprivate var interaction: MediaPickerInteraction?
|
||||
|
||||
private let peer: EnginePeer?
|
||||
private let isScheduledMessages: Bool
|
||||
private let threadTitle: String?
|
||||
private let chatLocation: ChatLocation?
|
||||
private let bannedSendPhotos: (Int32, Bool)?
|
||||
@ -970,7 +971,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
|
||||
self.openingMedia = true
|
||||
|
||||
self.currentGalleryController = presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, threadTitle: controller.threadTitle, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .fetchResult(fetchResult: fetchResult, index: index, reversed: reversed), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: hasSchedule, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||
self.currentGalleryController = presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, threadTitle: controller.threadTitle, chatLocation: controller.chatLocation, isScheduledMessages: controller.isScheduledMessages, presentationData: self.presentationData, source: .fetchResult(fetchResult: fetchResult, index: index, reversed: reversed), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: hasSchedule, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||
self?.hiddenMediaId.set(.single(id))
|
||||
}, initialLayout: layout, transitionHostView: { [weak self] in
|
||||
return self?.gridNode.view
|
||||
@ -1009,7 +1010,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
}
|
||||
|
||||
self.openingMedia = true
|
||||
self.currentGalleryController = presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, threadTitle: controller.threadTitle, chatLocation: controller.chatLocation, presentationData: self.presentationData, source: .selection(item: item), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||
self.currentGalleryController = presentLegacyMediaPickerGallery(context: controller.context, peer: controller.peer, threadTitle: controller.threadTitle, chatLocation: controller.chatLocation, isScheduledMessages: controller.isScheduledMessages, presentationData: self.presentationData, source: .selection(item: item), immediateThumbnail: immediateThumbnail, selectionContext: interaction.selectionState, editingContext: interaction.editingState, hasSilentPosting: true, hasSchedule: true, hasTimer: hasTimer, updateHiddenMedia: { [weak self] id in
|
||||
self?.hiddenMediaId.set(.single(id))
|
||||
}, initialLayout: layout, transitionHostView: { [weak self] in
|
||||
return self?.selectionNode?.view
|
||||
@ -1524,6 +1525,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
peer: EnginePeer?,
|
||||
threadTitle: String?,
|
||||
chatLocation: ChatLocation?,
|
||||
isScheduledMessages: Bool = false,
|
||||
bannedSendPhotos: (Int32, Bool)?,
|
||||
bannedSendVideos: (Int32, Bool)?,
|
||||
subject: Subject,
|
||||
@ -1541,6 +1543,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self.peer = peer
|
||||
self.threadTitle = threadTitle
|
||||
self.chatLocation = chatLocation
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.bannedSendPhotos = bannedSendPhotos
|
||||
self.bannedSendVideos = bannedSendVideos
|
||||
self.subject = subject
|
||||
@ -2104,7 +2107,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
var updateNavigationStackImpl: ((AttachmentContainable) -> Void)?
|
||||
let groupsController = MediaGroupsScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, mediaAssetsContext: self.controllerNode.mediaAssetsContext, embedded: embedded, openGroup: { [weak self] collection in
|
||||
if let strongSelf = self {
|
||||
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection, mode), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
|
||||
let mediaPicker = MediaPickerScreen(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: strongSelf.peer, threadTitle: strongSelf.threadTitle, chatLocation: strongSelf.chatLocation, isScheduledMessages: strongSelf.isScheduledMessages, bannedSendPhotos: strongSelf.bannedSendPhotos, bannedSendVideos: strongSelf.bannedSendVideos, subject: .assets(collection, mode), editingContext: strongSelf.interaction?.editingState, selectionContext: strongSelf.interaction?.selectionState)
|
||||
|
||||
mediaPicker.presentSchedulePicker = strongSelf.presentSchedulePicker
|
||||
mediaPicker.presentTimerPicker = strongSelf.presentTimerPicker
|
||||
|
@ -191,6 +191,10 @@ public final class AttachMenuBots: Equatable, Codable {
|
||||
|
||||
try container.encode(Int32(self.flags.rawValue), forKey: .flags)
|
||||
}
|
||||
|
||||
func withUpdatedFlags(_ flags: Flags) -> Bot {
|
||||
return Bot(peerId: self.peerId, name: self.name, icons: self.icons, peerTypes: self.peerTypes, flags: flags)
|
||||
}
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
@ -442,6 +446,23 @@ func _internal_removeBotFromAttachMenu(accountPeerId: PeerId, postbox: Postbox,
|
||||
|> switchToLatest
|
||||
}
|
||||
|
||||
func _internal_acceptAttachMenuBotDisclaimer(postbox: Postbox, botId: PeerId) -> Signal<Never, NoError> {
|
||||
return postbox.transaction { transaction in
|
||||
if let attachMenuBots = cachedAttachMenuBots(transaction: transaction) {
|
||||
var updatedAttachMenuBots = attachMenuBots
|
||||
if let index = attachMenuBots.bots.firstIndex(where: { $0.peerId == botId }) {
|
||||
var updatedFlags = attachMenuBots.bots[index].flags
|
||||
updatedFlags.remove(.showInSettingsDisclaimer)
|
||||
let updatedBot = attachMenuBots.bots[index].withUpdatedFlags(updatedFlags)
|
||||
var updatedBots = attachMenuBots.bots
|
||||
updatedBots[index] = updatedBot
|
||||
updatedAttachMenuBots = AttachMenuBots(hash: attachMenuBots.hash, bots: updatedBots)
|
||||
}
|
||||
setCachedAttachMenuBots(transaction: transaction, attachMenuBots: updatedAttachMenuBots)
|
||||
}
|
||||
} |> ignoreValues
|
||||
}
|
||||
|
||||
public struct AttachMenuBot {
|
||||
public let peer: EnginePeer
|
||||
public let shortName: String
|
||||
@ -449,7 +470,7 @@ public struct AttachMenuBot {
|
||||
public let peerTypes: AttachMenuBots.Bot.PeerFlags
|
||||
public let flags: AttachMenuBots.Bot.Flags
|
||||
|
||||
init(peer: EnginePeer, shortName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], peerTypes: AttachMenuBots.Bot.PeerFlags, flags: AttachMenuBots.Bot.Flags) {
|
||||
public init(peer: EnginePeer, shortName: String, icons: [AttachMenuBots.Bot.IconName: TelegramMediaFile], peerTypes: AttachMenuBots.Bot.PeerFlags, flags: AttachMenuBots.Bot.Flags) {
|
||||
self.peer = peer
|
||||
self.shortName = shortName
|
||||
self.icons = icons
|
||||
|
@ -531,6 +531,10 @@ public extension TelegramEngine {
|
||||
return _internal_removeBotFromAttachMenu(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, botId: botId)
|
||||
}
|
||||
|
||||
public func acceptAttachMenuBotDisclaimer(botId: PeerId) -> Signal<Never, NoError> {
|
||||
return _internal_acceptAttachMenuBotDisclaimer(postbox: self.account.postbox, botId: botId)
|
||||
}
|
||||
|
||||
public func getAttachMenuBot(botId: PeerId, cached: Bool = false) -> Signal<AttachMenuBot, GetAttachMenuBotError> {
|
||||
return _internal_getAttachMenuBot(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, botId: botId, cached: cached)
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import TooltipUI
|
||||
public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||
private let context: AccountContext
|
||||
private let chatLocation: ChatLocation
|
||||
private let isScheduledMessages: Bool
|
||||
private let present: (ViewController) -> Void
|
||||
private let presentInGlobalOverlay: (ViewController) -> Void
|
||||
|
||||
@ -35,11 +36,13 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
chatLocation: ChatLocation,
|
||||
isScheduledMessages: Bool,
|
||||
present: @escaping (ViewController) -> Void,
|
||||
presentInGlobalOverlay: @escaping (ViewController) -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.chatLocation = chatLocation
|
||||
self.isScheduledMessages = isScheduledMessages
|
||||
self.present = present
|
||||
self.presentInGlobalOverlay = presentInGlobalOverlay
|
||||
|
||||
@ -164,7 +167,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||
strings: presentationData.strings,
|
||||
style: .media,
|
||||
placeholder: .plain(presentationData.strings.MediaPicker_AddCaption),
|
||||
maxLength: 1024,
|
||||
maxLength: Int(self.context.userLimits.maxCaptionLength),
|
||||
queryTypes: [.mention],
|
||||
alwaysDarkWhenHasText: false,
|
||||
resetInputContents: resetInputContents,
|
||||
@ -191,7 +194,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||
likeAction: nil,
|
||||
likeOptionsAction: nil,
|
||||
inputModeAction: nil,
|
||||
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser ? { [weak self] sourceView, gesture in
|
||||
timeoutAction: self.chatLocation.peerId?.namespace == Namespaces.Peer.CloudUser && !self.isScheduledMessages ? { [weak self] sourceView, gesture in
|
||||
if let self {
|
||||
self.presentTimeoutSetup(sourceView: sourceView, gesture: gesture)
|
||||
}
|
||||
|
@ -2301,7 +2301,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
return nil
|
||||
}
|
||||
//TODO:self.presentationInterfaceState.customEmojiAvailable
|
||||
return component.context.sharedContext.makeGalleryCaptionPanelView(context: component.context, chatLocation: .peer(id: peer.id), customEmojiAvailable: true, present: { [weak view] c in
|
||||
return component.context.sharedContext.makeGalleryCaptionPanelView(context: component.context, chatLocation: .peer(id: peer.id), isScheduledMessages: false, customEmojiAvailable: true, present: { [weak view] c in
|
||||
guard let view else {
|
||||
return
|
||||
}
|
||||
|
@ -13012,7 +13012,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
|
||||
private func getCaptionPanelView() -> TGCaptionPanelView? {
|
||||
return self.context.sharedContext.makeGalleryCaptionPanelView(context: self.context, chatLocation: self.presentationInterfaceState.chatLocation, customEmojiAvailable: self.presentationInterfaceState.customEmojiAvailable, present: { [weak self] c in
|
||||
var isScheduledMessages = false
|
||||
if case .scheduledMessages = self.presentationInterfaceState.subject {
|
||||
isScheduledMessages = true
|
||||
}
|
||||
return self.context.sharedContext.makeGalleryCaptionPanelView(context: self.context, chatLocation: self.presentationInterfaceState.chatLocation, isScheduledMessages: isScheduledMessages, customEmojiAvailable: self.presentationInterfaceState.customEmojiAvailable, present: { [weak self] c in
|
||||
self?.present(c, in: .window(.root))
|
||||
}, presentInGlobalOverlay: { [weak self] c in
|
||||
guard let self else {
|
||||
@ -13443,7 +13447,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
strongSelf.canReadHistory.set(false)
|
||||
|
||||
let attachmentController = AttachmentController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, chatLocation: strongSelf.chatLocation, buttons: buttons, initialButton: initialButton, makeEntityInputView: { [weak self] in
|
||||
let attachmentController = AttachmentController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, chatLocation: strongSelf.chatLocation, isScheduledMessages: isScheduledMessages, buttons: buttons, initialButton: initialButton, makeEntityInputView: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return nil
|
||||
}
|
||||
@ -14230,7 +14234,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let peer = self.presentationInterfaceState.renderedPeer?.peer else {
|
||||
return
|
||||
}
|
||||
let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), threadTitle: self.threadInfo?.title, chatLocation: self.chatLocation, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, subject: subject, saveEditedPhotos: saveEditedPhotos)
|
||||
var isScheduledMessages = false
|
||||
if case .scheduledMessages = self.presentationInterfaceState.subject {
|
||||
isScheduledMessages = true
|
||||
}
|
||||
let controller = MediaPickerScreen(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: EnginePeer(peer), threadTitle: self.threadInfo?.title, chatLocation: self.chatLocation, isScheduledMessages: isScheduledMessages, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, subject: subject, saveEditedPhotos: saveEditedPhotos)
|
||||
let mediaPickerContext = controller.mediaPickerContext
|
||||
controller.openCamera = { [weak self] cameraView in
|
||||
self?.openCamera(cameraView: cameraView)
|
||||
|
@ -489,6 +489,25 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
|
||||
let botsKey = ValueBoxKey(length: 8)
|
||||
botsKey.setInt64(0, value: 0)
|
||||
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|
||||
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
|
||||
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
|
||||
return context.engine.data.subscribe(
|
||||
EngineDataMap(bots.map(\.peerId).map(TelegramEngine.EngineData.Item.Peer.Peer.init))
|
||||
)
|
||||
|> map { peersMap -> [AttachMenuBot] in
|
||||
var result: [AttachMenuBot] = []
|
||||
for bot in bots {
|
||||
if let maybePeer = peersMap[bot.peerId], let peer = maybePeer {
|
||||
result.append(AttachMenuBot(peer: peer, shortName: bot.name, icons: bot.icons, peerTypes: bot.peerTypes, flags: bot.flags))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(
|
||||
context.account.viewTracker.peerView(peerId, updateData: true),
|
||||
accountsAndPeers,
|
||||
@ -512,7 +531,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
|
||||
}
|
||||
|> distinctUntilChanged,
|
||||
hasStories,
|
||||
context.engine.messages.attachMenuBots()
|
||||
bots
|
||||
)
|
||||
|> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, hasWatchApp, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots -> PeerInfoScreenData in
|
||||
let (notificationExceptions, notificationsAuthorizationStatus, notificationsWarningSuppressed) = notifications
|
||||
|
@ -4640,10 +4640,29 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.openBotAppDisposable.set(((self.context.engine.messages.requestSimpleWebView(botId: bot.peer.id, url: nil, source: .settings, themeParams: generateWebAppThemeParams(self.presentationData.theme))
|
||||
|
||||
let presentationData = self.presentationData
|
||||
let progressSignal = Signal<Never, NoError> { [weak self] subscriber in
|
||||
let controller = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil))
|
||||
self?.controller?.present(controller, in: .window(.root))
|
||||
return ActionDisposable { [weak controller] in
|
||||
Queue.mainQueue().async() {
|
||||
controller?.dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|> runOn(Queue.mainQueue())
|
||||
|> delay(0.35, queue: Queue.mainQueue())
|
||||
let progressDisposable = progressSignal.start()
|
||||
|
||||
let signal: Signal<String, RequestSimpleWebViewError> = self.context.engine.messages.requestSimpleWebView(botId: bot.peer.id, url: nil, source: .settings, themeParams: generateWebAppThemeParams(self.presentationData.theme))
|
||||
|> afterDisposed {
|
||||
// updateProgress()
|
||||
})
|
||||
Queue.mainQueue().async {
|
||||
progressDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
self.openBotAppDisposable.set((signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self] url in
|
||||
guard let self else {
|
||||
return
|
||||
@ -4670,6 +4689,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if bot.flags.contains(.showInSettingsDisclaimer) {
|
||||
let _ = self.context.engine.messages.acceptAttachMenuBotDisclaimer(botId: bot.peer.id).start()
|
||||
}
|
||||
if bot.flags.contains(.notActivated) {
|
||||
let _ = (self.context.engine.messages.addBotToAttachMenu(botId: bot.peer.id, allowWrite: allowWrite)
|
||||
|> deliverOnMainQueue).start(error: { _ in
|
||||
|
@ -1627,109 +1627,14 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
return makeAttachmentFileControllerImpl(context: context, updatedPresentationData: updatedPresentationData, bannedSendMedia: bannedSendMedia, presentGallery: presentGallery, presentFiles: presentFiles, send: send)
|
||||
}
|
||||
|
||||
public func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject? {
|
||||
// var presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
// presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
//
|
||||
// var presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: .builtin(WallpaperSettings()), theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: presentationData.chatFontSize, bubbleCorners: presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: .standard(previewing: false), chatLocation: chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
|
||||
//
|
||||
// var updateChatPresentationInterfaceStateImpl: (((ChatPresentationInterfaceState) -> ChatPresentationInterfaceState) -> Void)?
|
||||
// var ensureFocusedImpl: (() -> Void)?
|
||||
//
|
||||
// let interfaceInteraction = ChatPanelInterfaceInteraction(updateTextInputStateAndMode: { f in
|
||||
// updateChatPresentationInterfaceStateImpl?({
|
||||
// let (updatedState, updatedMode) = f($0.interfaceState.effectiveInputState, $0.inputMode)
|
||||
// return $0.updatedInterfaceState { interfaceState in
|
||||
// return interfaceState.withUpdatedEffectiveInputState(updatedState)
|
||||
// }.updatedInputMode({ _ in updatedMode })
|
||||
// })
|
||||
// }, updateInputModeAndDismissedButtonKeyboardMessageId: { f in
|
||||
// updateChatPresentationInterfaceStateImpl?({
|
||||
// let (updatedInputMode, updatedClosedButtonKeyboardMessageId) = f($0)
|
||||
// return $0.updatedInputMode({ _ in return updatedInputMode }).updatedInterfaceState({
|
||||
// $0.withUpdatedMessageActionsState({ value in
|
||||
// var value = value
|
||||
// value.closedButtonKeyboardMessageId = updatedClosedButtonKeyboardMessageId
|
||||
// return value
|
||||
// })
|
||||
// })
|
||||
// })
|
||||
// }, openLinkEditing: {
|
||||
// var selectionRange: Range<Int>?
|
||||
// var text: NSAttributedString?
|
||||
// var inputMode: ChatInputMode?
|
||||
// updateChatPresentationInterfaceStateImpl?({ state in
|
||||
// selectionRange = state.interfaceState.effectiveInputState.selectionRange
|
||||
// if let selectionRange = selectionRange {
|
||||
// text = state.interfaceState.effectiveInputState.inputText.attributedSubstring(from: NSRange(location: selectionRange.startIndex, length: selectionRange.count))
|
||||
// }
|
||||
// inputMode = state.inputMode
|
||||
// return state
|
||||
// })
|
||||
//
|
||||
// var link: String?
|
||||
// if let text {
|
||||
// text.enumerateAttributes(in: NSMakeRange(0, text.length)) { attributes, _, _ in
|
||||
// if let linkAttribute = attributes[ChatTextInputAttributes.textUrl] as? ChatTextInputTextUrlAttribute {
|
||||
// link = linkAttribute.url
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// let controller = chatTextLinkEditController(sharedContext: context.sharedContext, updatedPresentationData: (presentationData, .never()), account: context.account, text: text?.string ?? "", link: link, apply: { link in
|
||||
// if let inputMode = inputMode, let selectionRange = selectionRange {
|
||||
// if let link = link {
|
||||
// updateChatPresentationInterfaceStateImpl?({
|
||||
// return $0.updatedInterfaceState({
|
||||
// $0.withUpdatedEffectiveInputState(chatTextInputAddLinkAttribute($0.effectiveInputState, selectionRange: selectionRange, url: link))
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// ensureFocusedImpl?()
|
||||
// updateChatPresentationInterfaceStateImpl?({
|
||||
// return $0.updatedInputMode({ _ in return inputMode }).updatedInterfaceState({
|
||||
// $0.withUpdatedEffectiveInputState(ChatTextInputState(inputText: $0.effectiveInputState.inputText, selectionRange: selectionRange.endIndex ..< selectionRange.endIndex))
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
// present(controller)
|
||||
// })
|
||||
//
|
||||
// let inputPanelNode = AttachmentTextInputPanelNode(context: context, presentationInterfaceState: presentationInterfaceState, isCaption: true, presentController: { c in
|
||||
// presentInGlobalOverlay(c)
|
||||
// }, makeEntityInputView: {
|
||||
// return EntityInputView(context: context, isDark: true, areCustomEmojiEnabled: customEmojiAvailable)
|
||||
// })
|
||||
// inputPanelNode.interfaceInteraction = interfaceInteraction
|
||||
// inputPanelNode.effectivePresentationInterfaceState = {
|
||||
// return presentationInterfaceState
|
||||
// }
|
||||
//
|
||||
// updateChatPresentationInterfaceStateImpl = { [weak inputPanelNode] f in
|
||||
// let updatedPresentationInterfaceState = f(presentationInterfaceState)
|
||||
// let updateInputTextState = presentationInterfaceState.interfaceState.effectiveInputState != updatedPresentationInterfaceState.interfaceState.effectiveInputState
|
||||
//
|
||||
// presentationInterfaceState = updatedPresentationInterfaceState
|
||||
//
|
||||
// if let inputPanelNode = inputPanelNode, updateInputTextState {
|
||||
// inputPanelNode.updateInputTextState(updatedPresentationInterfaceState.interfaceState.effectiveInputState, animated: true)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ensureFocusedImpl = { [weak inputPanelNode] in
|
||||
// inputPanelNode?.ensureFocused()
|
||||
// }
|
||||
//
|
||||
// return inputPanelNode
|
||||
|
||||
public func makeGalleryCaptionPanelView(context: AccountContext, chatLocation: ChatLocation, isScheduledMessages: Bool, customEmojiAvailable: Bool, present: @escaping (ViewController) -> Void, presentInGlobalOverlay: @escaping (ViewController) -> Void) -> NSObject? {
|
||||
let inputPanelNode = LegacyMessageInputPanelNode(
|
||||
context: context,
|
||||
chatLocation: chatLocation,
|
||||
isScheduledMessages: isScheduledMessages,
|
||||
present: present,
|
||||
presentInGlobalOverlay: presentInGlobalOverlay
|
||||
)
|
||||
|
||||
return inputPanelNode
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,11 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
private let strings: PresentationStrings
|
||||
private let title: String
|
||||
private let text: String
|
||||
private let additionalText: String?
|
||||
|
||||
private let titleNode: ImmediateTextNode
|
||||
private let textNode: ImmediateTextNode
|
||||
private let additionalTextNode: ImmediateTextNode
|
||||
|
||||
private let acceptTermsCheckNode: InteractiveCheckNode
|
||||
private let acceptTermsLabelNode: ImmediateTextNode
|
||||
@ -53,10 +55,11 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
|
||||
var openTerms: () -> Void = {}
|
||||
|
||||
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, title: String, text: String, actions: [TextAlertAction]) {
|
||||
init(context: AccountContext, theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, title: String, text: String, additionalText: String?, actions: [TextAlertAction]) {
|
||||
self.strings = strings
|
||||
self.title = title
|
||||
self.text = text
|
||||
self.additionalText = additionalText
|
||||
|
||||
self.titleNode = ImmediateTextNode()
|
||||
self.titleNode.displaysAsynchronously = false
|
||||
@ -69,6 +72,12 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
self.textNode.lineSpacing = 0.1
|
||||
self.textNode.textAlignment = .center
|
||||
|
||||
self.additionalTextNode = ImmediateTextNode()
|
||||
self.additionalTextNode.maximumNumberOfLines = 0
|
||||
self.additionalTextNode.displaysAsynchronously = false
|
||||
self.additionalTextNode.lineSpacing = 0.1
|
||||
self.additionalTextNode.textAlignment = .center
|
||||
|
||||
self.acceptTermsCheckNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: theme.accentColor, strokeColor: theme.contrastColor, borderColor: theme.controlBorderColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
||||
self.acceptTermsLabelNode = ImmediateTextNode()
|
||||
self.acceptTermsLabelNode.maximumNumberOfLines = 4
|
||||
@ -94,6 +103,7 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
|
||||
self.addSubnode(self.titleNode)
|
||||
self.addSubnode(self.textNode)
|
||||
self.addSubnode(self.additionalTextNode)
|
||||
|
||||
self.addSubnode(self.acceptTermsCheckNode)
|
||||
self.addSubnode(self.acceptTermsLabelNode)
|
||||
@ -179,6 +189,11 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
override func updateTheme(_ theme: AlertControllerTheme) {
|
||||
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.semibold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
|
||||
self.textNode.attributedText = formattedText(self.text, fontSize: 13.0, color: theme.primaryColor, linkColor: theme.accentColor, textAlignment: .center)
|
||||
if let additionalText = self.additionalText {
|
||||
self.additionalTextNode.attributedText = formattedText(additionalText, fontSize: 13.0, color: theme.primaryColor, linkColor: theme.accentColor, textAlignment: .center)
|
||||
} else {
|
||||
self.additionalTextNode.attributedText = nil
|
||||
}
|
||||
|
||||
let attributedAgreeText = parseMarkdownIntoAttributedString(
|
||||
self.strings.WebApp_DisclaimerAgree,
|
||||
@ -242,6 +257,14 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
transition.updateFrame(node: self.acceptTermsLabelNode, frame: CGRect(origin: CGPoint(x: acceptTermsOriginX + checkSize.width + spacing, y: origin.y), size: acceptTermsSize))
|
||||
origin.y += acceptTermsSize.height
|
||||
entriesHeight += acceptTermsSize.height
|
||||
origin.y += 21.0
|
||||
}
|
||||
|
||||
let additionalTextSize = self.additionalTextNode.updateLayout(CGSize(width: size.width - 48.0, height: size.height))
|
||||
transition.updateFrame(node: self.additionalTextNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - additionalTextSize.width) / 2.0), y: origin.y), size: additionalTextSize))
|
||||
origin.y += additionalTextSize.height
|
||||
if additionalTextSize.height > 0.0 {
|
||||
entriesHeight += 20.0
|
||||
}
|
||||
|
||||
let actionButtonHeight: CGFloat = 44.0
|
||||
@ -275,7 +298,7 @@ private final class WebAppTermsAlertContentNode: AlertContentNode, UIGestureReco
|
||||
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
|
||||
}
|
||||
|
||||
let resultSize = CGSize(width: contentWidth, height: titleSize.height + textSize.height + entriesHeight + actionsHeight + 3.0 + insets.top + insets.bottom)
|
||||
let resultSize = CGSize(width: contentWidth, height: titleSize.height + textSize.height + additionalTextSize.height + entriesHeight + actionsHeight + 3.0 + insets.top + insets.bottom)
|
||||
|
||||
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
|
||||
|
||||
@ -350,9 +373,17 @@ public func webAppTermsAlertController(
|
||||
})]
|
||||
|
||||
let title = presentationData.strings.WebApp_DisclaimerTitle
|
||||
let text = presentationData.strings.WebApp_DisclaimerText(bot.peer.compactDisplayTitle).string
|
||||
let text = presentationData.strings.WebApp_DisclaimerText
|
||||
let additionalText: String?
|
||||
if bot.flags.contains(.showInSettings) {
|
||||
additionalText = presentationData.strings.WebApp_DisclaimerShortcutsSettingsText(bot.peer.compactDisplayTitle).string
|
||||
} else if bot.flags.contains(.showInAttachMenu) {
|
||||
additionalText = presentationData.strings.WebApp_DisclaimerShortcutsText(bot.peer.compactDisplayTitle).string
|
||||
} else {
|
||||
additionalText = nil
|
||||
}
|
||||
|
||||
let contentNode = WebAppTermsAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, actions: actions)
|
||||
let contentNode = WebAppTermsAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), ptheme: theme, strings: strings, title: title, text: text, additionalText: additionalText, actions: actions)
|
||||
contentNode.openTerms = {
|
||||
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.WebApp_Disclaimer_URL, forceExternal: true, presentationData: context.sharedContext.currentPresentationData.with { $0 }, navigationController: nil, dismissInput: {
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user