mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Stories improvements
This commit is contained in:
parent
b10ae1b12a
commit
8ac9121c5e
@ -1369,7 +1369,7 @@ public final class CalendarMessageScreen: ViewController {
|
|||||||
if self.selectionState?.dayRange == nil {
|
if self.selectionState?.dayRange == nil {
|
||||||
if let selectionToolbarNode = self.selectionToolbarNode {
|
if let selectionToolbarNode = self.selectionToolbarNode {
|
||||||
let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view)
|
let toolbarFrame = selectionToolbarNode.view.convert(selectionToolbarNode.bounds, to: self.view)
|
||||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip, style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in
|
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.MessageCalendar_EmptySelectionTooltip), style: .default, icon: .none, location: .point(toolbarFrame.insetBy(dx: 0.0, dy: 10.0), .bottom), shouldDismissOnTouch: { point in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}), in: .current)
|
}), in: .current)
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,7 @@ private final class VideoRecorderImpl {
|
|||||||
if !self.savedTransitionImage, let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
|
if !self.savedTransitionImage, let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
|
||||||
self.savedTransitionImage = true
|
self.savedTransitionImage = true
|
||||||
|
|
||||||
|
Queue.concurrentDefaultQueue().async {
|
||||||
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
|
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
|
||||||
if let cgImage = self.imageContext.createCGImage(ciImage, from: ciImage.extent) {
|
if let cgImage = self.imageContext.createCGImage(ciImage, from: ciImage.extent) {
|
||||||
self.transitionImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
|
self.transitionImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
|
||||||
@ -172,6 +173,7 @@ private final class VideoRecorderImpl {
|
|||||||
self.savedTransitionImage = false
|
self.savedTransitionImage = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if videoInput.append(sampleBuffer) {
|
if videoInput.append(sampleBuffer) {
|
||||||
self.lastVideoSampleTime = presentationTime
|
self.lastVideoSampleTime = presentationTime
|
||||||
|
@ -2356,7 +2356,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 8.0), size: CGSize())
|
||||||
|
|
||||||
parentController.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: .chatListPress, location: .point(location, .bottom), shouldDismissOnTouch: { point in
|
parentController.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: text), icon: .animation(name: "ChatListFoldersTooltip", delay: 0.6), location: .point(location, .bottom), shouldDismissOnTouch: { point in
|
||||||
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
guard let strongSelf = self, let parentController = strongSelf.parent as? TabBarController else {
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}
|
}
|
||||||
@ -2697,11 +2697,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY - 8.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY + 1.0), size: CGSize())
|
||||||
let tooltipController = TooltipScreen(
|
let tooltipController = TooltipScreen(
|
||||||
|
context: self.context,
|
||||||
account: self.context.account,
|
account: self.context.account,
|
||||||
sharedContext: self.context.sharedContext,
|
sharedContext: self.context.sharedContext,
|
||||||
text: "Stories from \(peer.compactDisplayTitle) will now be shown in Contacts, not Chats.",
|
text: .markdown(text: "Stories from **\(peer.compactDisplayTitle)** will now be shown in Contacts, not Chats."),
|
||||||
|
icon: .peer(peer: peer, isStory: true),
|
||||||
|
action: TooltipScreen.Action(
|
||||||
|
title: "Undo",
|
||||||
|
action: { [weak self] in
|
||||||
|
if let self {
|
||||||
|
self.context.engine.peers.updatePeerStoriesHidden(id: peer.id, isHidden: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
location: .point(location, .bottom),
|
location: .point(location, .bottom),
|
||||||
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
||||||
)
|
)
|
||||||
|
@ -96,15 +96,25 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY - 8.0), size: CGSize())
|
if let peer {
|
||||||
|
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY + 1.0), size: CGSize())
|
||||||
let tooltipController = TooltipScreen(
|
let tooltipController = TooltipScreen(
|
||||||
|
context: context,
|
||||||
account: context.account,
|
account: context.account,
|
||||||
sharedContext: context.sharedContext,
|
sharedContext: context.sharedContext,
|
||||||
text: "Stories from \(peer?.compactDisplayTitle ?? "") will now be shown in Chats, not Contacts.",
|
text: .markdown(text: "Stories from \(peer.compactDisplayTitle) will now be shown in Chats, not Contacts."),
|
||||||
|
icon: .peer(peer: peer, isStory: true),
|
||||||
|
action: TooltipScreen.Action(
|
||||||
|
title: "Undo",
|
||||||
|
action: {
|
||||||
|
context.engine.peers.updatePeerStoriesHidden(id: peer.id, isHidden: true)
|
||||||
|
}
|
||||||
|
),
|
||||||
location: .point(location, .bottom),
|
location: .point(location, .bottom),
|
||||||
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
||||||
)
|
)
|
||||||
contactsController?.present(tooltipController, in: .window(.root))
|
contactsController?.present(tooltipController, in: .window(.root))
|
||||||
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
@ -828,7 +828,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
|||||||
text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string
|
text = strongSelf.presentationData.strings.Location_ProximityTip(EnginePeer(peer).compactDisplayTitle).string
|
||||||
}
|
}
|
||||||
|
|
||||||
strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
strongSelf.interaction.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: text), icon: nil, location: .point(location.offsetBy(dx: -9.0, dy: 0.0), .right), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
@ -179,7 +179,7 @@ public final class QrCodeScanScreen: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let navigationController = navigationController as? NavigationController {
|
if let navigationController = navigationController as? NavigationController {
|
||||||
self.present(UndoOverlayController(presentationData: self.presentationData, content: .actionSucceeded(title: self.presentationData.strings.AuthSessions_AddedDeviceTitle, text: session?.appName ?? "Telegram for macOS", cancel: self.presentationData.strings.AuthSessions_AddedDeviceTerminate), elevatedLayout: false, animateInAsReplacement: false, action: { value in
|
self.present(UndoOverlayController(presentationData: self.presentationData, content: .actionSucceeded(title: self.presentationData.strings.AuthSessions_AddedDeviceTitle, text: session?.appName ?? "Telegram for macOS", cancel: self.presentationData.strings.AuthSessions_AddedDeviceTerminate, destructive: true), elevatedLayout: false, animateInAsReplacement: false, action: { value in
|
||||||
if value == .undo, let session = session {
|
if value == .undo, let session = session {
|
||||||
let _ = activeSessionsContext.remove(hash: session.hash).start()
|
let _ = activeSessionsContext.remove(hash: session.hash).start()
|
||||||
return true
|
return true
|
||||||
|
@ -456,7 +456,7 @@ public final class ThemePreviewController: ViewController {
|
|||||||
guard let strongSelf = self, !displayed else {
|
guard let strongSelf = self, !displayed else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .actionSucceeded(title: strongSelf.presentationData.strings.Theme_ThemeChanged, text: strongSelf.presentationData.strings.Theme_ThemeChangedText, cancel: strongSelf.presentationData.strings.Undo_Undo), elevatedLayout: true, animateInAsReplacement: false, action: { value in
|
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .actionSucceeded(title: strongSelf.presentationData.strings.Theme_ThemeChanged, text: strongSelf.presentationData.strings.Theme_ThemeChangedText, cancel: strongSelf.presentationData.strings.Undo_Undo, destructive: false), elevatedLayout: true, animateInAsReplacement: false, action: { value in
|
||||||
if value == .undo {
|
if value == .undo {
|
||||||
Queue.mainQueue().after(0.2) {
|
Queue.mainQueue().after(0.2) {
|
||||||
let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current -> PresentationThemeSettings in
|
let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current -> PresentationThemeSettings in
|
||||||
|
@ -1729,7 +1729,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
|
|||||||
if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) {
|
if let strongSelf = self, (count < 2 && currentTimestamp > timestamp + 24 * 60 * 60) {
|
||||||
strongSelf.displayedPreviewTooltip = true
|
strongSelf.displayedPreviewTooltip = true
|
||||||
|
|
||||||
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode, style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.35)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
let controller = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: isDark ? strongSelf.presentationData.strings.WallpaperPreview_PreviewInDayMode : strongSelf.presentationData.strings.WallpaperPreview_PreviewInNightMode), style: .customBlur(UIColor(rgb: 0x333333, alpha: 0.35)), icon: nil, location: .point(frame.offsetBy(dx: 1.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
})
|
})
|
||||||
strongSelf.galleryController()?.present(controller, in: .current)
|
strongSelf.galleryController()?.present(controller, in: .current)
|
||||||
|
@ -529,7 +529,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
|||||||
let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager)
|
let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager)
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||||
if let strongSelf = self, let controller = strongSelf.getController?(), value == 2 {
|
if let strongSelf = self, let controller = strongSelf.getController?(), value == 2 {
|
||||||
let tooltipController = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: strongSelf.strings.Conversation_AudioRateOptionsTooltip, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: strongSelf.strings.Conversation_AudioRateOptionsTooltip), style: .default, icon: nil, location: .point(frame.offsetBy(dx: 0.0, dy: 4.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
})
|
})
|
||||||
controller.present(tooltipController, in: .window(.root))
|
controller.present(tooltipController, in: .window(.root))
|
||||||
|
@ -761,7 +761,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
self.present?(TooltipScreen(account: self.account, sharedContext: self.sharedContext, text: self.presentationData.strings.Call_CameraOrScreenTooltip, style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in
|
self.present?(TooltipScreen(account: self.account, sharedContext: self.sharedContext, text: .plain(text: self.presentationData.strings.Call_CameraOrScreenTooltip), style: .light, icon: nil, location: .point(location.offsetBy(dx: 0.0, dy: -14.0), .bottom), displayDuration: .custom(5.0), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -2308,7 +2308,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
|||||||
} else {
|
} else {
|
||||||
text = presentationData.strings.VoiceChat_RecordingInProgress
|
text = presentationData.strings.VoiceChat_RecordingInProgress
|
||||||
}
|
}
|
||||||
strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: text, icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
strongSelf.controller?.present(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: text), icon: nil, location: .point(location.offsetBy(dx: 1.0, dy: 0.0), .top), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: true)
|
return .dismiss(consume: true)
|
||||||
}), in: .window(.root))
|
}), in: .window(.root))
|
||||||
}
|
}
|
||||||
@ -3505,7 +3505,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
|||||||
if !callState.subscribedToScheduled {
|
if !callState.subscribedToScheduled {
|
||||||
let location = self.actionButton.view.convert(self.actionButton.bounds, to: self.view).center
|
let location = self.actionButton.view.convert(self.actionButton.bounds, to: self.view).center
|
||||||
let point = CGRect(origin: CGPoint(x: location.x - 5.0, y: location.y - 5.0 - 68.0), size: CGSize(width: 10.0, height: 10.0))
|
let point = CGRect(origin: CGPoint(x: location.x - 5.0, y: location.y - 5.0 - 68.0), size: CGSize(width: 10.0, height: 10.0))
|
||||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_ReminderNotify, style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.VoiceChat_ReminderNotify), style: .gradient(UIColor(rgb: 0x262c5a), UIColor(rgb: 0x5d2835)), icon: nil, location: .point(point, .bottom), displayDuration: .custom(3.0), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}), in: .window(.root))
|
}), in: .window(.root))
|
||||||
}
|
}
|
||||||
@ -6409,7 +6409,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
|||||||
point.origin.y += 32.0
|
point.origin.y += 32.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.VoiceChat_UnmuteSuggestion, style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in
|
self.controller?.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.VoiceChat_UnmuteSuggestion), style: .gradient(UIColor(rgb: 0x1d446c), UIColor(rgb: 0x193e63)), icon: nil, location: .point(point, position), displayDuration: .custom(8.0), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}), in: .window(.root))
|
}), in: .window(.root))
|
||||||
}
|
}
|
||||||
|
@ -1589,7 +1589,7 @@ public class CameraScreen: ViewController {
|
|||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 4.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 4.0), size: CGSize())
|
||||||
|
|
||||||
let controller = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "Draft Saved", location: .point(location, .bottom), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _ in
|
let controller = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Draft Saved"), location: .point(location, .bottom), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.controller?.present(controller, in: .current)
|
self.controller?.present(controller, in: .current)
|
||||||
@ -1604,7 +1604,7 @@ public class CameraScreen: ViewController {
|
|||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
||||||
|
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "Enable Dual Camera Mode", location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Enable Dual Camera Mode"), location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.controller?.present(tooltipController, in: .current)
|
self.controller?.present(tooltipController, in: .current)
|
||||||
@ -1617,9 +1617,9 @@ public class CameraScreen: ViewController {
|
|||||||
|
|
||||||
let parentFrame = self.view.convert(self.bounds, to: nil)
|
let parentFrame = self.view.convert(self.bounds, to: nil)
|
||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 3.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
|
||||||
|
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "Take photos or videos to share with all your contacts or close friends at once.", location: .point(location, .bottom), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "Take photos or videos to share with all\nyour contacts or close friends at once."), textAlignment: .center, location: .point(location, .bottom), displayDuration: .custom(3.0), inset: 16.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.controller?.present(tooltipController, in: .current)
|
self.controller?.present(tooltipController, in: .current)
|
||||||
@ -2106,6 +2106,11 @@ public class CameraScreen: ViewController {
|
|||||||
if let layout = self.validLayout, case .regular = layout.metrics.widthClass {
|
if let layout = self.validLayout, case .regular = layout.metrics.widthClass {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.node.hasAppeared {
|
||||||
|
self.dismissAllTooltips()
|
||||||
|
}
|
||||||
|
|
||||||
let transitionFraction = max(0.0, min(1.0, transitionFraction))
|
let transitionFraction = max(0.0, min(1.0, transitionFraction))
|
||||||
let offsetX = floorToScreenPixels((1.0 - transitionFraction) * self.node.frame.width * -1.0)
|
let offsetX = floorToScreenPixels((1.0 - transitionFraction) * self.node.frame.width * -1.0)
|
||||||
transition.updateTransform(layer: self.node.backgroundView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
transition.updateTransform(layer: self.node.backgroundView.layer, transform: CGAffineTransform(translationX: offsetX, y: 0.0))
|
||||||
|
@ -265,6 +265,7 @@ public final class MediaEditor {
|
|||||||
videoTrimRange: nil,
|
videoTrimRange: nil,
|
||||||
videoIsMuted: false,
|
videoIsMuted: false,
|
||||||
videoIsFullHd: false,
|
videoIsFullHd: false,
|
||||||
|
videoIsMirrored: false,
|
||||||
additionalVideoPath: nil,
|
additionalVideoPath: nil,
|
||||||
additionalVideoPosition: nil,
|
additionalVideoPosition: nil,
|
||||||
additionalVideoScale: nil,
|
additionalVideoScale: nil,
|
||||||
@ -582,6 +583,12 @@ public final class MediaEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func setVideoIsMirrored(_ videoIsMirrored: Bool) {
|
||||||
|
self.updateValues(mode: .skipRendering) { values in
|
||||||
|
return values.withUpdatedVideoIsMirrored(videoIsMirrored)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public func setVideoIsFullHd(_ videoIsFullHd: Bool) {
|
public func setVideoIsFullHd(_ videoIsFullHd: Bool) {
|
||||||
self.updateValues(mode: .skipRendering) { values in
|
self.updateValues(mode: .skipRendering) { values in
|
||||||
return values.withUpdatedVideoIsFullHd(videoIsFullHd)
|
return values.withUpdatedVideoIsFullHd(videoIsFullHd)
|
||||||
|
@ -84,6 +84,9 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
if lhs.videoIsFullHd != rhs.videoIsFullHd {
|
if lhs.videoIsFullHd != rhs.videoIsFullHd {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.videoIsMirrored != rhs.videoIsMirrored {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if lhs.additionalVideoPath != rhs.additionalVideoPath {
|
if lhs.additionalVideoPath != rhs.additionalVideoPath {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -143,6 +146,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
case videoTrimRange
|
case videoTrimRange
|
||||||
case videoIsMuted
|
case videoIsMuted
|
||||||
case videoIsFullHd
|
case videoIsFullHd
|
||||||
|
case videoIsMirrored
|
||||||
|
|
||||||
case additionalVideoPath
|
case additionalVideoPath
|
||||||
case additionalVideoPosition
|
case additionalVideoPosition
|
||||||
@ -167,6 +171,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
public let videoTrimRange: Range<Double>?
|
public let videoTrimRange: Range<Double>?
|
||||||
public let videoIsMuted: Bool
|
public let videoIsMuted: Bool
|
||||||
public let videoIsFullHd: Bool
|
public let videoIsFullHd: Bool
|
||||||
|
public let videoIsMirrored: Bool
|
||||||
|
|
||||||
public let additionalVideoPath: String?
|
public let additionalVideoPath: String?
|
||||||
public let additionalVideoPosition: CGPoint?
|
public let additionalVideoPosition: CGPoint?
|
||||||
@ -189,6 +194,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
videoTrimRange: Range<Double>?,
|
videoTrimRange: Range<Double>?,
|
||||||
videoIsMuted: Bool,
|
videoIsMuted: Bool,
|
||||||
videoIsFullHd: Bool,
|
videoIsFullHd: Bool,
|
||||||
|
videoIsMirrored: Bool,
|
||||||
additionalVideoPath: String?,
|
additionalVideoPath: String?,
|
||||||
additionalVideoPosition: CGPoint?,
|
additionalVideoPosition: CGPoint?,
|
||||||
additionalVideoScale: CGFloat?,
|
additionalVideoScale: CGFloat?,
|
||||||
@ -208,6 +214,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
self.videoTrimRange = videoTrimRange
|
self.videoTrimRange = videoTrimRange
|
||||||
self.videoIsMuted = videoIsMuted
|
self.videoIsMuted = videoIsMuted
|
||||||
self.videoIsFullHd = videoIsFullHd
|
self.videoIsFullHd = videoIsFullHd
|
||||||
|
self.videoIsMirrored = videoIsMirrored
|
||||||
self.additionalVideoPath = additionalVideoPath
|
self.additionalVideoPath = additionalVideoPath
|
||||||
self.additionalVideoPosition = additionalVideoPosition
|
self.additionalVideoPosition = additionalVideoPosition
|
||||||
self.additionalVideoScale = additionalVideoScale
|
self.additionalVideoScale = additionalVideoScale
|
||||||
@ -240,6 +247,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
self.videoTrimRange = try container.decodeIfPresent(Range<Double>.self, forKey: .videoTrimRange)
|
self.videoTrimRange = try container.decodeIfPresent(Range<Double>.self, forKey: .videoTrimRange)
|
||||||
self.videoIsMuted = try container.decode(Bool.self, forKey: .videoIsMuted)
|
self.videoIsMuted = try container.decode(Bool.self, forKey: .videoIsMuted)
|
||||||
self.videoIsFullHd = try container.decodeIfPresent(Bool.self, forKey: .videoIsFullHd) ?? false
|
self.videoIsFullHd = try container.decodeIfPresent(Bool.self, forKey: .videoIsFullHd) ?? false
|
||||||
|
self.videoIsMirrored = try container.decodeIfPresent(Bool.self, forKey: .videoIsMirrored) ?? false
|
||||||
|
|
||||||
self.additionalVideoPath = try container.decodeIfPresent(String.self, forKey: .additionalVideoPath)
|
self.additionalVideoPath = try container.decodeIfPresent(String.self, forKey: .additionalVideoPath)
|
||||||
self.additionalVideoPosition = try container.decodeIfPresent(CGPoint.self, forKey: .additionalVideoPosition)
|
self.additionalVideoPosition = try container.decodeIfPresent(CGPoint.self, forKey: .additionalVideoPosition)
|
||||||
@ -283,6 +291,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
try container.encodeIfPresent(self.videoTrimRange, forKey: .videoTrimRange)
|
try container.encodeIfPresent(self.videoTrimRange, forKey: .videoTrimRange)
|
||||||
try container.encode(self.videoIsMuted, forKey: .videoIsMuted)
|
try container.encode(self.videoIsMuted, forKey: .videoIsMuted)
|
||||||
try container.encode(self.videoIsFullHd, forKey: .videoIsFullHd)
|
try container.encode(self.videoIsFullHd, forKey: .videoIsFullHd)
|
||||||
|
try container.encode(self.videoIsMirrored, forKey: .videoIsMirrored)
|
||||||
|
|
||||||
try container.encodeIfPresent(self.additionalVideoPath, forKey: .additionalVideoPath)
|
try container.encodeIfPresent(self.additionalVideoPath, forKey: .additionalVideoPath)
|
||||||
try container.encodeIfPresent(self.additionalVideoPosition, forKey: .additionalVideoPosition)
|
try container.encodeIfPresent(self.additionalVideoPosition, forKey: .additionalVideoPosition)
|
||||||
@ -306,43 +315,48 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func makeCopy() -> MediaEditorValues {
|
public func makeCopy() -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedCrop(offset: CGPoint, scale: CGFloat, rotation: CGFloat, mirroring: Bool) -> MediaEditorValues {
|
func withUpdatedCrop(offset: CGPoint, scale: CGFloat, rotation: CGFloat, mirroring: Bool) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: offset, cropSize: self.cropSize, cropScale: scale, cropRotation: rotation, cropMirroring: mirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: offset, cropSize: self.cropSize, cropScale: scale, cropRotation: rotation, cropMirroring: mirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedGradientColors(gradientColors: [UIColor]) -> MediaEditorValues {
|
func withUpdatedGradientColors(gradientColors: [UIColor]) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedVideoIsMuted(_ videoIsMuted: Bool) -> MediaEditorValues {
|
func withUpdatedVideoIsMuted(_ videoIsMuted: Bool) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedVideoIsFullHd(_ videoIsFullHd: Bool) -> MediaEditorValues {
|
func withUpdatedVideoIsFullHd(_ videoIsFullHd: Bool) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func withUpdatedVideoIsMirrored(_ videoIsMirrored: Bool) -> MediaEditorValues {
|
||||||
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedAdditionalVideo(path: String, positionChanges: [VideoPositionChange]) -> MediaEditorValues {
|
func withUpdatedAdditionalVideo(path: String, positionChanges: [VideoPositionChange]) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: path, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: positionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: path, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: positionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedAdditionalVideo(position: CGPoint, scale: CGFloat, rotation: CGFloat) -> MediaEditorValues {
|
func withUpdatedAdditionalVideo(position: CGPoint, scale: CGFloat, rotation: CGFloat) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: position, additionalVideoScale: scale, additionalVideoRotation: rotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: position, additionalVideoScale: scale, additionalVideoRotation: rotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedVideoTrimRange(_ videoTrimRange: Range<Double>) -> MediaEditorValues {
|
func withUpdatedVideoTrimRange(_ videoTrimRange: Range<Double>) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedDrawingAndEntities(drawing: UIImage?, entities: [CodableDrawingEntity]) -> MediaEditorValues {
|
func withUpdatedDrawingAndEntities(drawing: UIImage?, entities: [CodableDrawingEntity]) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: drawing, entities: entities, toolValues: self.toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: drawing, entities: entities, toolValues: self.toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func withUpdatedToolValues(_ toolValues: [EditorToolKey: Any]) -> MediaEditorValues {
|
func withUpdatedToolValues(_ toolValues: [EditorToolKey: Any]) -> MediaEditorValues {
|
||||||
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: toolValues)
|
return MediaEditorValues(originalDimensions: self.originalDimensions, cropOffset: self.cropOffset, cropSize: self.cropSize, cropScale: self.cropScale, cropRotation: self.cropRotation, cropMirroring: self.cropMirroring, gradientColors: self.gradientColors, videoTrimRange: self.videoTrimRange, videoIsMuted: self.videoIsMuted, videoIsFullHd: self.videoIsFullHd, videoIsMirrored: self.videoIsMirrored, additionalVideoPath: self.additionalVideoPath, additionalVideoPosition: self.additionalVideoPosition, additionalVideoScale: self.additionalVideoScale, additionalVideoRotation: self.additionalVideoRotation, additionalVideoPositionChanges: self.additionalVideoPositionChanges, drawing: self.drawing, entities: self.entities, toolValues: toolValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var resultDimensions: PixelDimensions {
|
public var resultDimensions: PixelDimensions {
|
||||||
|
@ -345,11 +345,17 @@ public final class MediaEditorVideoExport {
|
|||||||
|
|
||||||
private func setupWithAsset(_ asset: AVAsset, additionalAsset: AVAsset?) {
|
private func setupWithAsset(_ asset: AVAsset, additionalAsset: AVAsset?) {
|
||||||
self.reader = try? AVAssetReader(asset: asset)
|
self.reader = try? AVAssetReader(asset: asset)
|
||||||
self.textureRotation = textureRotatonForAVAsset(asset)
|
|
||||||
|
var mirror = false
|
||||||
|
if additionalAsset == nil, self.configuration.values.videoIsMirrored {
|
||||||
|
mirror = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textureRotation = textureRotatonForAVAsset(asset, mirror: mirror)
|
||||||
|
|
||||||
if let additionalAsset {
|
if let additionalAsset {
|
||||||
self.additionalReader = try? AVAssetReader(asset: additionalAsset)
|
self.additionalReader = try? AVAssetReader(asset: additionalAsset)
|
||||||
self.additionalTextureRotation = textureRotatonForAVAsset(additionalAsset)
|
self.additionalTextureRotation = textureRotatonForAVAsset(additionalAsset, mirror: true)
|
||||||
}
|
}
|
||||||
guard let reader = self.reader else {
|
guard let reader = self.reader else {
|
||||||
return
|
return
|
||||||
|
@ -696,7 +696,9 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
guard let controller = environment.controller() as? MediaEditorScreen else {
|
guard let controller = environment.controller() as? MediaEditorScreen else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
controller.requestCompletion(animated: true)
|
controller.openPrivacySettings(completion: { [weak controller] in
|
||||||
|
controller?.requestCompletion(animated: true)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -1142,7 +1144,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
if let privacyButtonView = self.privacyButton.view {
|
if let privacyButtonView = self.privacyButton.view {
|
||||||
if privacyButtonView.superview == nil {
|
if privacyButtonView.superview == nil {
|
||||||
self.addSubview(privacyButtonView)
|
//self.addSubview(privacyButtonView)
|
||||||
}
|
}
|
||||||
transition.setPosition(view: privacyButtonView, position: privacyButtonFrame.center)
|
transition.setPosition(view: privacyButtonView, position: privacyButtonFrame.center)
|
||||||
transition.setBounds(view: privacyButtonView, bounds: CGRect(origin: .zero, size: privacyButtonFrame.size))
|
transition.setBounds(view: privacyButtonView, bounds: CGRect(origin: .zero, size: privacyButtonFrame.size))
|
||||||
@ -1841,7 +1843,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
imageEntity.scale = 1.49
|
imageEntity.scale = 1.49
|
||||||
imageEntity.position = position.getPosition(storyDimensions)
|
imageEntity.position = position.getPosition(storyDimensions)
|
||||||
self.entitiesView.add(imageEntity, announce: false)
|
self.entitiesView.add(imageEntity, announce: false)
|
||||||
} else if case let .video(_, _, _, additionalVideoPath, _, _, _, changes, position) = subject, let additionalVideoPath {
|
} else if case let .video(_, _, mirror, additionalVideoPath, _, _, _, changes, position) = subject {
|
||||||
|
mediaEditor.setVideoIsMirrored(mirror)
|
||||||
|
if let additionalVideoPath {
|
||||||
let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
||||||
videoEntity.referenceDrawingSize = storyDimensions
|
videoEntity.referenceDrawingSize = storyDimensions
|
||||||
videoEntity.scale = 1.49
|
videoEntity.scale = 1.49
|
||||||
@ -1857,6 +1861,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if case let .asset(asset) = subject, asset.mediaType == .video {
|
} else if case let .asset(asset) = subject, asset.mediaType == .video {
|
||||||
//#if DEBUG
|
//#if DEBUG
|
||||||
// let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
// let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
||||||
@ -2504,7 +2509,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
||||||
|
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "You can set who can view this story.", location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: "You can set who can view this story."), location: .point(location, .top), displayDuration: .manual(false), inset: 16.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.controller?.present(tooltipController, in: .current)
|
self.controller?.present(tooltipController, in: .current)
|
||||||
@ -2527,7 +2532,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
let absoluteFrame = sourceView.convert(sourceView.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
|
||||||
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.maxY + 3.0), size: CGSize())
|
||||||
|
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: isMuted ? "The story will have no sound." : "The story will have sound." , location: .point(location, .top), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: isMuted ? "The story will have no sound." : "The story will have sound."), location: .point(location, .top), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.muteTooltip = tooltipController
|
self.muteTooltip = tooltipController
|
||||||
@ -2642,7 +2647,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
text = "Story will disappear in 24 hours."
|
text = "Story will disappear in 24 hours."
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: text, location: .point(location, .bottom), displayDuration: .default, inset: 7.0, cornerRadius: 9.0, shouldDismissOnTouch: { _ in
|
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: text), location: .point(location, .bottom), displayDuration: .default, inset: 7.0, cornerRadius: 9.0, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
self.storyArchiveTooltip = tooltipController
|
self.storyArchiveTooltip = tooltipController
|
||||||
@ -3133,7 +3138,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
self.displayNode.view.addInteraction(dropInteraction)
|
self.displayNode.view.addInteraction(dropInteraction)
|
||||||
}
|
}
|
||||||
|
|
||||||
func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil) {
|
func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil, completion: @escaping () -> Void = {}) {
|
||||||
self.hapticFeedback.impact(.light)
|
self.hapticFeedback.impact(.light)
|
||||||
|
|
||||||
let privacy = privacy ?? self.state.privacy
|
let privacy = privacy ?? self.state.privacy
|
||||||
@ -3157,6 +3162,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.state.privacy = MediaEditorResultPrivacy(privacy: privacy, timeout: timeout, archive: archive)
|
self.state.privacy = MediaEditorResultPrivacy(privacy: privacy, timeout: timeout, archive: archive)
|
||||||
|
completion()
|
||||||
},
|
},
|
||||||
editCategory: { [weak self] privacy in
|
editCategory: { [weak self] privacy in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -3166,7 +3172,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
self.openPrivacySettings(MediaEditorResultPrivacy(privacy: privacy, timeout: timeout, archive: archive))
|
self.openPrivacySettings(MediaEditorResultPrivacy(privacy: privacy, timeout: timeout, archive: archive), completion: completion)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -458,8 +458,7 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
|
|
||||||
let sectionTitle: String
|
let sectionTitle: String
|
||||||
if section.id == 0 {
|
if section.id == 0 {
|
||||||
let hours = component.timeout / 3600
|
sectionTitle = "WHO CAN VIEW"
|
||||||
sectionTitle = "WHO CAN VIEW FOR \(hours) HOURS"
|
|
||||||
} else {
|
} else {
|
||||||
if case .chats = component.stateContext.subject {
|
if case .chats = component.stateContext.subject {
|
||||||
sectionTitle = "CHATS"
|
sectionTitle = "CHATS"
|
||||||
@ -1063,10 +1062,12 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
navigationButtonsWidth += navigationLeftButtonSize.width + navigationSideInset
|
navigationButtonsWidth += navigationLeftButtonSize.width + navigationSideInset
|
||||||
|
|
||||||
|
var actionButtonTitle = "Save Settings"
|
||||||
let title: String
|
let title: String
|
||||||
switch component.stateContext.subject {
|
switch component.stateContext.subject {
|
||||||
case .stories:
|
case .stories:
|
||||||
title = "Share Story"
|
title = "Share Story"
|
||||||
|
actionButtonTitle = "Post Story"
|
||||||
case .chats:
|
case .chats:
|
||||||
title = "Send as a Message"
|
title = "Send as a Message"
|
||||||
case let .contacts(category):
|
case let .contacts(category):
|
||||||
@ -1125,7 +1126,6 @@ final class ShareWithPeersScreenComponent: Component {
|
|||||||
|
|
||||||
transition.setFrame(layer: self.navigationSeparatorLayer, frame: CGRect(origin: CGPoint(x: containerSideInset, y: navigationHeight), size: CGSize(width: containerWidth, height: UIScreenPixel)))
|
transition.setFrame(layer: self.navigationSeparatorLayer, frame: CGRect(origin: CGPoint(x: containerSideInset, y: navigationHeight), size: CGSize(width: containerWidth, height: UIScreenPixel)))
|
||||||
|
|
||||||
let actionButtonTitle: String = "Save Settings"
|
|
||||||
let actionButtonSize = self.actionButton.update(
|
let actionButtonSize = self.actionButton.update(
|
||||||
transition: transition,
|
transition: transition,
|
||||||
component: AnyComponent(ButtonComponent(
|
component: AnyComponent(ButtonComponent(
|
||||||
|
@ -712,6 +712,9 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
if self.inputPanelExternalState.isEditing || component.isProgressPaused || self.actionSheet != nil || self.contextController != nil || self.sendMessageContext.audioRecorderValue != nil || self.sendMessageContext.videoRecorderValue != nil || self.displayViewList {
|
if self.inputPanelExternalState.isEditing || component.isProgressPaused || self.actionSheet != nil || self.contextController != nil || self.sendMessageContext.audioRecorderValue != nil || self.sendMessageContext.videoRecorderValue != nil || self.displayViewList {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if let reactionContextNode = self.reactionContextNode, reactionContextNode.isReactionSearchActive {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if self.privacyController != nil {
|
if self.privacyController != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -2235,7 +2238,7 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
let tooltipScreen = TooltipScreen(
|
let tooltipScreen = TooltipScreen(
|
||||||
account: component.context.account,
|
account: component.context.account,
|
||||||
sharedContext: component.context.sharedContext,
|
sharedContext: component.context.sharedContext,
|
||||||
text: "You are seeing this story because you have\nbeen added to \(component.slice.peer.compactDisplayTitle)'s list of close friends.", style: .default, location: TooltipScreen.Location.point(closeFriendIconView.convert(closeFriendIconView.bounds, to: self).offsetBy(dx: 1.0, dy: 6.0), .top), displayDuration: .manual(true), shouldDismissOnTouch: { _ in
|
text: .markdown(text: "You are seeing this story because you have\nbeen added to **\(component.slice.peer.compactDisplayTitle)'s** list of close friends."), style: .default, location: TooltipScreen.Location.point(closeFriendIconView.convert(closeFriendIconView.bounds, to: self).offsetBy(dx: 1.0, dy: 6.0), .top), displayDuration: .manual(true), shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -338,7 +338,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
Queue.mainQueue().after(0.3) {
|
Queue.mainQueue().after(0.3) {
|
||||||
controller.present(UndoOverlayController(
|
controller.present(UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat"),
|
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
animateInAsReplacement: false,
|
animateInAsReplacement: false,
|
||||||
action: { [weak view] action in
|
action: { [weak view] action in
|
||||||
@ -380,7 +380,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
Queue.mainQueue().after(0.3) {
|
Queue.mainQueue().after(0.3) {
|
||||||
controller.present(UndoOverlayController(
|
controller.present(UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat"),
|
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
animateInAsReplacement: false,
|
animateInAsReplacement: false,
|
||||||
action: { [weak view] action in
|
action: { [weak view] action in
|
||||||
@ -442,7 +442,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
Queue.mainQueue().after(0.3) {
|
Queue.mainQueue().after(0.3) {
|
||||||
controller.present(UndoOverlayController(
|
controller.present(UndoOverlayController(
|
||||||
presentationData: presentationData,
|
presentationData: presentationData,
|
||||||
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat"),
|
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
|
||||||
elevatedLayout: false,
|
elevatedLayout: false,
|
||||||
animateInAsReplacement: false,
|
animateInAsReplacement: false,
|
||||||
action: { [weak view] action in
|
action: { [weak view] action in
|
||||||
@ -491,7 +491,7 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
if isVideo {
|
if isVideo {
|
||||||
if self.videoRecorderValue == nil {
|
if self.videoRecorderValue == nil {
|
||||||
if let currentInputPanelFrame = view.inputPanel.view?.frame {
|
if let currentInputPanelFrame = view.inputPanel.view?.frame {
|
||||||
self.videoRecorder.set(.single(legacyInstantVideoController(theme: component.theme, panelFrame: view.convert(currentInputPanelFrame, to: nil), context: component.context, peerId: peer.id, slowmodeState: nil, hasSchedule: peer.id.namespace != Namespaces.Peer.SecretChat, send: { [weak self, weak view] videoController, message in
|
self.videoRecorder.set(.single(legacyInstantVideoController(theme: component.theme, panelFrame: view.convert(currentInputPanelFrame, to: nil), context: component.context, peerId: peer.id, slowmodeState: nil, hasSchedule: true, send: { [weak self, weak view] videoController, message in
|
||||||
guard let self, let view, let component = view.component else {
|
guard let self, let view, let component = view.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -2057,28 +2057,36 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func sendMessages(view: StoryItemSetContainerComponent.View, peer: EnginePeer, messages: [EnqueueMessage], media: Bool = false, commit: Bool = false) {
|
private func sendMessages(view: StoryItemSetContainerComponent.View, peer: EnginePeer, messages: [EnqueueMessage], media: Bool = false, commit: Bool = false) {
|
||||||
guard let component = view.component else {
|
guard let component = view.component, let controller = component.controller() else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
|
|
||||||
let _ = (enqueueMessages(account: component.context.account, peerId: peer.id, messages: self.transformEnqueueMessages(view: view, messages: messages, silentPosting: false))
|
let _ = (enqueueMessages(account: component.context.account, peerId: peer.id, messages: self.transformEnqueueMessages(view: view, messages: messages, silentPosting: false))
|
||||||
|> deliverOnMainQueue).start()
|
|> deliverOnMainQueue).start(next: { [weak controller] messageIds in
|
||||||
|
if let controller {
|
||||||
|
Queue.mainQueue().after(0.3) {
|
||||||
|
controller.present(UndoOverlayController(
|
||||||
|
presentationData: presentationData,
|
||||||
|
content: .actionSucceeded(title: "", text: "Message Sent", cancel: "View in Chat", destructive: false),
|
||||||
|
elevatedLayout: false,
|
||||||
|
animateInAsReplacement: false,
|
||||||
|
action: { [weak view] action in
|
||||||
|
if case .undo = action, let messageId = messageIds.first {
|
||||||
|
view?.navigateToPeer(peer: peer, messageId: messageId)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
), in: .current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
donateSendMessageIntent(account: component.context.account, sharedContext: component.context.sharedContext, intentContext: .chat, peerIds: [peer.id])
|
donateSendMessageIntent(account: component.context.account, sharedContext: component.context.sharedContext, intentContext: .chat, peerIds: [peer.id])
|
||||||
|
|
||||||
if let attachmentController = self.attachmentController {
|
if let attachmentController = self.attachmentController {
|
||||||
attachmentController.dismiss(animated: true)
|
attachmentController.dismiss(animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let controller = component.controller() {
|
|
||||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
controller.present(UndoOverlayController(
|
|
||||||
presentationData: presentationData,
|
|
||||||
content: .succeed(text: "Message Sent"),
|
|
||||||
elevatedLayout: false,
|
|
||||||
animateInAsReplacement: false,
|
|
||||||
action: { _ in return false }
|
|
||||||
), in: .current)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func enqueueMediaMessages(view: StoryItemSetContainerComponent.View, peer: EnginePeer, replyToMessageId: EngineMessage.Id?, replyToStoryId: StoryId?, signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
|
private func enqueueMediaMessages(view: StoryItemSetContainerComponent.View, peer: EnginePeer, replyToMessageId: EngineMessage.Id?, replyToStoryId: StoryId?, signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
|
||||||
@ -2139,10 +2147,8 @@ final class StoryItemSetContainerSendMessage {
|
|||||||
|
|
||||||
strongSelf.sendMessages(view: view, peer: peer, messages: messages.map { $0.withUpdatedReplyToMessageId(replyToMessageId).withUpdatedReplyToStoryId(replyToStoryId) }, media: true)
|
strongSelf.sendMessages(view: view, peer: peer, messages: messages.map { $0.withUpdatedReplyToMessageId(replyToMessageId).withUpdatedReplyToStoryId(replyToStoryId) }, media: true)
|
||||||
|
|
||||||
if let _ = scheduleTime {
|
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ final class ChatBotStartInputPanelNode: ChatInputPanelNode {
|
|||||||
tooltipController.location = .point(location, .bottom)
|
tooltipController.location = .point(location, .bottom)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: self.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: .plain(text: self.strings.Bot_TapToUse), icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
controller.alwaysVisible = true
|
controller.alwaysVisible = true
|
||||||
|
@ -14490,7 +14490,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
var found = false
|
var found = false
|
||||||
self.forEachController({ controller in
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? TooltipScreen {
|
if let controller = controller as? TooltipScreen {
|
||||||
if controller.text == solution.text && controller.textEntities == solution.entities {
|
if controller.text == .entities(text: solution.text, entities: solution.entities) {
|
||||||
found = true
|
found = true
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
return false
|
return false
|
||||||
@ -14502,7 +14502,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: solution.text, textEntities: solution.entities, icon: .info, location: .top, shouldDismissOnTouch: { point in
|
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .entities(text: solution.text, entities: solution.entities), icon: .animation(name: "anim_infotip", delay: 0.2), location: .top, shouldDismissOnTouch: { point in
|
||||||
return .ignore
|
return .ignore
|
||||||
}, openActiveTextItem: { [weak self] item, action in
|
}, openActiveTextItem: { [weak self] item, action in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -14583,7 +14583,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
var found = false
|
var found = false
|
||||||
self.forEachController({ controller in
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? TooltipScreen {
|
if let controller = controller as? TooltipScreen {
|
||||||
if controller.text == psaText {
|
if controller.text == .plain(text: psaText) {
|
||||||
found = true
|
found = true
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
return false
|
return false
|
||||||
@ -14595,7 +14595,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .entities(text: psaText, entities: psaEntities), icon: .animation(name: "anim_infotip", delay: 0.2), location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||||
return .ignore
|
return .ignore
|
||||||
}, openActiveTextItem: { [weak self] item, action in
|
}, openActiveTextItem: { [weak self] item, action in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -14683,7 +14683,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
var found = false
|
var found = false
|
||||||
self.forEachController({ controller in
|
self.forEachController({ controller in
|
||||||
if let controller = controller as? TooltipScreen {
|
if let controller = controller as? TooltipScreen {
|
||||||
if controller.text == psaText {
|
if controller.text == .plain(text: psaText) {
|
||||||
found = true
|
found = true
|
||||||
controller.resetDismissTimeout()
|
controller.resetDismissTimeout()
|
||||||
|
|
||||||
@ -14709,7 +14709,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: psaText, textEntities: psaEntities, icon: .info, location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
let tooltipScreen = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .entities(text: psaText, entities: psaEntities), icon: .animation(name: "anim_infotip", delay: 0.2), location: .top, displayDuration: .custom(10.0), shouldDismissOnTouch: { point in
|
||||||
return .ignore
|
return .ignore
|
||||||
}, openActiveTextItem: { [weak self] item, action in
|
}, openActiveTextItem: { [weak self] item, action in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
@ -1484,7 +1484,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
|||||||
tooltipController.location = .point(location, .bottom)
|
tooltipController.location = .point(location, .bottom)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: interfaceState.strings.Bot_TapToUse, icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
let controller = TooltipScreen(account: context.account, sharedContext: context.sharedContext, text: .plain(text: interfaceState.strings.Bot_TapToUse), icon: .downArrows, location: .point(location, .bottom), displayDuration: .infinite, shouldDismissOnTouch: { _ in
|
||||||
return .ignore
|
return .ignore
|
||||||
})
|
})
|
||||||
controller.alwaysVisible = true
|
controller.alwaysVisible = true
|
||||||
|
@ -1262,7 +1262,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
|||||||
if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
|
if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
|
||||||
strongSelf.displayedPreviewTooltip = true
|
strongSelf.displayedPreviewTooltip = true
|
||||||
|
|
||||||
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLightShort : strongSelf.presentationData.strings.Conversation_Theme_PreviewDarkShort, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, sharedContext: strongSelf.context.sharedContext, text: .plain(text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLightShort : strongSelf.presentationData.strings.Conversation_Theme_PreviewDarkShort), style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
@ -8691,7 +8691,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view)
|
let buttonFrame = buttonNode.view.convert(buttonNode.bounds, to: self.view)
|
||||||
controller.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: self.presentationData.strings.SharedMedia_CalendarTooltip, style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
|
controller.present(TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .plain(text: self.presentationData.strings.SharedMedia_CalendarTooltip), style: .default, icon: .none, location: .point(buttonFrame.insetBy(dx: 0.0, dy: 5.0), .top), shouldDismissOnTouch: { point in
|
||||||
return .dismiss(consume: false)
|
return .dismiss(consume: false)
|
||||||
}), in: .current)
|
}), in: .current)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,10 @@ swift_library(
|
|||||||
"//submodules/TextFormat:TextFormat",
|
"//submodules/TextFormat:TextFormat",
|
||||||
"//submodules/UrlEscaping:UrlEscaping",
|
"//submodules/UrlEscaping:UrlEscaping",
|
||||||
"//submodules/AccountContext:AccountContext",
|
"//submodules/AccountContext:AccountContext",
|
||||||
|
"//submodules/AvatarNode:AvatarNode",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/Markdown",
|
||||||
|
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -11,11 +11,11 @@ import TelegramCore
|
|||||||
import TextFormat
|
import TextFormat
|
||||||
import UrlEscaping
|
import UrlEscaping
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
import AvatarNode
|
||||||
public protocol TooltipCustomContentNode: ASDisplayNode {
|
import ComponentFlow
|
||||||
func animateIn()
|
import AvatarStoryIndicatorComponent
|
||||||
func updateLayout(size: CGSize) -> CGSize
|
import AccountContext
|
||||||
}
|
import Markdown
|
||||||
|
|
||||||
public enum TooltipActiveTextItem {
|
public enum TooltipActiveTextItem {
|
||||||
case url(String, Bool)
|
case url(String, Bool)
|
||||||
@ -109,7 +109,7 @@ private class DownArrowsIconNode: ASDisplayNode {
|
|||||||
private final class TooltipScreenNode: ViewControllerTracingNode {
|
private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||||
private let tooltipStyle: TooltipScreen.Style
|
private let tooltipStyle: TooltipScreen.Style
|
||||||
private let icon: TooltipScreen.Icon?
|
private let icon: TooltipScreen.Icon?
|
||||||
private let customContentNode: TooltipCustomContentNode?
|
private let action: TooltipScreen.Action?
|
||||||
var location: TooltipScreen.Location {
|
var location: TooltipScreen.Location {
|
||||||
didSet {
|
didSet {
|
||||||
if let layout = self.validLayout {
|
if let layout = self.validLayout {
|
||||||
@ -134,8 +134,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
private let arrowContainer: ASDisplayNode
|
private let arrowContainer: ASDisplayNode
|
||||||
private let animatedStickerNode: AnimatedStickerNode
|
private let animatedStickerNode: AnimatedStickerNode
|
||||||
private var downArrowsNode: DownArrowsIconNode?
|
private var downArrowsNode: DownArrowsIconNode?
|
||||||
|
private var avatarNode: AvatarNode?
|
||||||
|
private var avatarStoryIndicator: ComponentView<Empty>?
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
private let closeButtonNode: HighlightableButtonNode
|
private var closeButtonNode: HighlightableButtonNode?
|
||||||
|
private var actionButtonNode: HighlightableButtonNode?
|
||||||
|
|
||||||
private var isArrowInverted: Bool = false
|
private var isArrowInverted: Bool = false
|
||||||
|
|
||||||
@ -143,10 +146,24 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
|
|
||||||
init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon? = nil, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, cornerRadius: CGFloat? = nil, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) {
|
init(
|
||||||
|
context: AccountContext?,
|
||||||
|
account: Account,
|
||||||
|
sharedContext: SharedAccountContext,
|
||||||
|
text: TooltipScreen.Text,
|
||||||
|
textAlignment: TooltipScreen.Alignment,
|
||||||
|
style: TooltipScreen.Style,
|
||||||
|
icon: TooltipScreen.Icon? = nil,
|
||||||
|
action: TooltipScreen.Action? = nil,
|
||||||
|
location: TooltipScreen.Location,
|
||||||
|
displayDuration: TooltipScreen.DisplayDuration,
|
||||||
|
inset: CGFloat = 13.0,
|
||||||
|
cornerRadius: CGFloat? = nil,
|
||||||
|
shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?)
|
||||||
|
{
|
||||||
self.tooltipStyle = style
|
self.tooltipStyle = style
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.customContentNode = customContentNode
|
self.action = action
|
||||||
self.location = location
|
self.location = location
|
||||||
self.displayDuration = displayDuration
|
self.displayDuration = displayDuration
|
||||||
self.inset = inset
|
self.inset = inset
|
||||||
@ -164,6 +181,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
self.scrollingContainer = ASDisplayNode()
|
self.scrollingContainer = ASDisplayNode()
|
||||||
|
|
||||||
|
let theme = sharedContext.currentPresentationData.with { $0 }.theme
|
||||||
|
|
||||||
func svgPath(_ path: StaticString, scale: CGPoint = CGPoint(x: 1.0, y: 1.0), offset: CGPoint = CGPoint()) throws -> UIBezierPath {
|
func svgPath(_ path: StaticString, scale: CGPoint = CGPoint(x: 1.0, y: 1.0), offset: CGPoint = CGPoint()) throws -> UIBezierPath {
|
||||||
var index: UnsafePointer<UInt8> = path.utf8Start
|
var index: UnsafePointer<UInt8> = path.utf8Start
|
||||||
let end = path.utf8Start.advanced(by: path.utf8CodeUnitCount)
|
let end = path.utf8Start.advanced(by: path.utf8CodeUnitCount)
|
||||||
@ -210,7 +229,6 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
self.arrowContainer = ASDisplayNode()
|
self.arrowContainer = ASDisplayNode()
|
||||||
|
|
||||||
let theme = sharedContext.currentPresentationData.with { $0 }.theme
|
|
||||||
let fontSize: CGFloat
|
let fontSize: CGFloat
|
||||||
if case .top = location {
|
if case .top = location {
|
||||||
let backgroundColor: UIColor
|
let backgroundColor: UIColor
|
||||||
@ -311,24 +329,55 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
self.textNode.displaysAsynchronously = false
|
self.textNode.displaysAsynchronously = false
|
||||||
self.textNode.maximumNumberOfLines = 0
|
self.textNode.maximumNumberOfLines = 0
|
||||||
|
|
||||||
self.textNode.attributedText = stringWithAppliedEntities(text, entities: textEntities, baseColor: .white, linkColor: .white, baseFont: Font.regular(fontSize), linkFont: Font.regular(fontSize), boldFont: Font.semibold(14.0), italicFont: Font.italic(fontSize), boldItalicFont: Font.semiboldItalic(fontSize), fixedFont: Font.monospace(fontSize), blockQuoteFont: Font.regular(fontSize), underlineLinks: true, external: false, message: nil)
|
let baseFont = Font.regular(fontSize)
|
||||||
|
let boldFont = Font.semibold(14.0)
|
||||||
|
let italicFont = Font.italic(fontSize)
|
||||||
|
let boldItalicFont = Font.semiboldItalic(fontSize)
|
||||||
|
let fixedFont = Font.monospace(fontSize)
|
||||||
|
|
||||||
|
let textColor: UIColor = .white
|
||||||
|
|
||||||
|
let attributedText: NSAttributedString
|
||||||
|
switch text {
|
||||||
|
case let .plain(text):
|
||||||
|
attributedText = NSAttributedString(string: text, font: baseFont, textColor: textColor)
|
||||||
|
case let .entities(text, entities):
|
||||||
|
attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: textColor, linkColor: textColor, baseFont: baseFont, linkFont: baseFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: fixedFont, blockQuoteFont: baseFont, underlineLinks: true, external: false, message: nil)
|
||||||
|
case let .markdown(text):
|
||||||
|
let markdownAttributes = MarkdownAttributes(
|
||||||
|
body: MarkdownAttributeSet(font: baseFont, textColor: textColor),
|
||||||
|
bold: MarkdownAttributeSet(font: boldFont, textColor: textColor),
|
||||||
|
link: MarkdownAttributeSet(font: baseFont, textColor: textColor),
|
||||||
|
linkAttribute: { _ in
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
)
|
||||||
|
attributedText = parseMarkdownIntoAttributedString(text, attributes: markdownAttributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.textNode.attributedText = attributedText
|
||||||
|
self.textNode.textAlignment = textAlignment == .center ? .center : .natural
|
||||||
|
|
||||||
self.animatedStickerNode = DefaultAnimatedStickerNodeImpl()
|
self.animatedStickerNode = DefaultAnimatedStickerNodeImpl()
|
||||||
switch icon {
|
switch icon {
|
||||||
case .none:
|
case .none:
|
||||||
break
|
break
|
||||||
case .chatListPress:
|
case let .animation(animationName, _):
|
||||||
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ChatListFoldersTooltip"), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(name: animationName), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
||||||
self.animatedStickerNode.automaticallyLoadFirstFrame = true
|
|
||||||
case .info:
|
|
||||||
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "anim_infotip"), width: Int(70 * UIScreenScale), height: Int(70 * UIScreenScale), playbackMode: .once, mode: .direct(cachePathPrefix: nil))
|
|
||||||
self.animatedStickerNode.automaticallyLoadFirstFrame = true
|
self.animatedStickerNode.automaticallyLoadFirstFrame = true
|
||||||
case .downArrows:
|
case .downArrows:
|
||||||
self.downArrowsNode = DownArrowsIconNode()
|
self.downArrowsNode = DownArrowsIconNode()
|
||||||
|
case let .peer(peer, _):
|
||||||
|
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 15.0))
|
||||||
|
if let context {
|
||||||
|
self.avatarNode?.setPeer(context: context, theme: defaultDarkPresentationTheme, peer: peer)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .manual = displayDuration {
|
||||||
self.closeButtonNode = HighlightableButtonNode()
|
self.closeButtonNode = HighlightableButtonNode()
|
||||||
self.closeButtonNode.setImage(UIImage(bundleImageName: "Components/Close"), for: .normal)
|
self.closeButtonNode?.setImage(UIImage(bundleImageName: "Components/Close"), for: .normal)
|
||||||
|
}
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
@ -343,16 +392,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
self.containerNode.addSubnode(self.textNode)
|
self.containerNode.addSubnode(self.textNode)
|
||||||
self.containerNode.addSubnode(self.animatedStickerNode)
|
self.containerNode.addSubnode(self.animatedStickerNode)
|
||||||
|
|
||||||
if case .manual = displayDuration {
|
if let closeButtonNode = self.closeButtonNode {
|
||||||
self.containerNode.addSubnode(self.closeButtonNode)
|
self.containerNode.addSubnode(closeButtonNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let downArrowsNode = self.downArrowsNode {
|
if let downArrowsNode = self.downArrowsNode {
|
||||||
self.containerNode.addSubnode(downArrowsNode)
|
self.containerNode.addSubnode(downArrowsNode)
|
||||||
}
|
}
|
||||||
|
if let avatarNode = self.avatarNode {
|
||||||
|
self.containerNode.addSubnode(avatarNode)
|
||||||
|
}
|
||||||
self.scrollingContainer.addSubnode(self.containerNode)
|
self.scrollingContainer.addSubnode(self.containerNode)
|
||||||
self.addSubnode(self.scrollingContainer)
|
self.addSubnode(self.scrollingContainer)
|
||||||
|
|
||||||
|
if let action {
|
||||||
|
let actionColor = theme.list.itemAccentColor.withMultiplied(hue: 1.0, saturation: 0.64, brightness: 1.08)
|
||||||
|
let actionButtonNode = HighlightableButtonNode()
|
||||||
|
actionButtonNode.hitTestSlop = UIEdgeInsets(top: -16.0, left: -16.0, bottom: -16.0, right: -16.0)
|
||||||
|
actionButtonNode.setAttributedTitle(NSAttributedString(string: action.title, font: Font.regular(17.0), textColor: actionColor), for: .normal)
|
||||||
|
self.containerNode.addSubnode(actionButtonNode)
|
||||||
|
self.actionButtonNode = actionButtonNode
|
||||||
|
}
|
||||||
|
|
||||||
self.textNode.linkHighlightColor = UIColor.white.withAlphaComponent(0.5)
|
self.textNode.linkHighlightColor = UIColor.white.withAlphaComponent(0.5)
|
||||||
self.textNode.highlightAttributeAction = { attributes in
|
self.textNode.highlightAttributeAction = { attributes in
|
||||||
let highlightedAttributes = [
|
let highlightedAttributes = [
|
||||||
@ -412,7 +473,15 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.closeButtonNode.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside)
|
self.actionButtonNode?.addTarget(self, action: #selector(self.actionPressed), forControlEvents: .touchUpInside)
|
||||||
|
self.closeButtonNode?.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc private func actionPressed() {
|
||||||
|
if let action = self.action {
|
||||||
|
action.action()
|
||||||
|
self.requestDismiss()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func closePressed() {
|
@objc private func closePressed() {
|
||||||
@ -441,11 +510,15 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
animationSize = CGSize(width: 24.0, height: 32.0)
|
animationSize = CGSize(width: 24.0, height: 32.0)
|
||||||
animationInset = (40.0 - animationSize.width) / 2.0
|
animationInset = (40.0 - animationSize.width) / 2.0
|
||||||
animationSpacing = 8.0
|
animationSpacing = 8.0
|
||||||
case .chatListPress:
|
case let .animation(animationName, _):
|
||||||
animationSize = CGSize(width: 32.0, height: 32.0)
|
animationSize = CGSize(width: 32.0, height: 32.0)
|
||||||
|
if animationName == "ChatListFoldersTooltip" {
|
||||||
animationInset = (70.0 - animationSize.width) / 2.0
|
animationInset = (70.0 - animationSize.width) / 2.0
|
||||||
|
} else {
|
||||||
|
animationInset = 0.0
|
||||||
|
}
|
||||||
animationSpacing = 8.0
|
animationSpacing = 8.0
|
||||||
case .info:
|
case .peer:
|
||||||
animationSize = CGSize(width: 32.0, height: 32.0)
|
animationSize = CGSize(width: 32.0, height: 32.0)
|
||||||
animationInset = 0.0
|
animationInset = 0.0
|
||||||
animationSpacing = 8.0
|
animationSpacing = 8.0
|
||||||
@ -453,14 +526,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
let containerWidth = max(100.0, min(layout.size.width, 614.0) - (sideInset + layout.safeInsets.left) * 2.0)
|
let containerWidth = max(100.0, min(layout.size.width, 614.0) - (sideInset + layout.safeInsets.left) * 2.0)
|
||||||
|
|
||||||
let textSize = self.textNode.updateLayout(CGSize(width: containerWidth - contentInset * 2.0 - animationSize.width - animationSpacing, height: .greatestFiniteMagnitude))
|
var actionSize: CGSize = .zero
|
||||||
|
|
||||||
|
var buttonInset: CGFloat = 0.0
|
||||||
|
if let actionButtonNode = self.actionButtonNode {
|
||||||
|
actionSize = actionButtonNode.measure(CGSize(width: containerWidth, height: .greatestFiniteMagnitude))
|
||||||
|
buttonInset += actionSize.width + 32.0
|
||||||
|
}
|
||||||
|
if self.closeButtonNode != nil {
|
||||||
|
buttonInset += 24.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: containerWidth - contentInset * 2.0 - animationSize.width - animationSpacing - buttonInset, height: .greatestFiniteMagnitude))
|
||||||
|
|
||||||
var backgroundFrame: CGRect
|
var backgroundFrame: CGRect
|
||||||
|
|
||||||
let backgroundHeight: CGFloat
|
var backgroundHeight: CGFloat
|
||||||
switch self.tooltipStyle {
|
switch self.tooltipStyle {
|
||||||
case .default, .gradient, .customBlur:
|
case .default, .gradient, .customBlur:
|
||||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||||
|
if self.actionButtonNode != nil {
|
||||||
|
backgroundHeight += 2.0
|
||||||
|
}
|
||||||
case .light:
|
case .light:
|
||||||
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
||||||
}
|
}
|
||||||
@ -469,8 +556,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
switch self.location {
|
switch self.location {
|
||||||
case let .point(rect, arrowPosition):
|
case let .point(rect, arrowPosition):
|
||||||
var backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
var backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
||||||
if self.closeButtonNode.supernode != nil {
|
if self.closeButtonNode != nil || self.actionButtonNode != nil {
|
||||||
backgroundWidth += 24.0
|
backgroundWidth += buttonInset
|
||||||
|
}
|
||||||
|
if self.actionButtonNode != nil, case .compact = layout.metrics.widthClass {
|
||||||
|
backgroundWidth = containerWidth
|
||||||
}
|
}
|
||||||
switch arrowPosition {
|
switch arrowPosition {
|
||||||
case .bottom, .top:
|
case .bottom, .top:
|
||||||
@ -554,8 +644,14 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
let textFrame = CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize)
|
let textFrame = CGRect(origin: CGPoint(x: contentInset + animationSize.width + animationSpacing, y: floor((backgroundHeight - textSize.height) / 2.0)), size: textSize)
|
||||||
transition.updateFrame(node: self.textNode, frame: textFrame)
|
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||||
|
|
||||||
|
if let closeButtonNode = self.closeButtonNode {
|
||||||
let closeSize = CGSize(width: 44.0, height: 44.0)
|
let closeSize = CGSize(width: 44.0, height: 44.0)
|
||||||
transition.updateFrame(node: self.closeButtonNode, frame: CGRect(origin: CGPoint(x: textFrame.maxX - 6.0, y: floor((backgroundHeight - closeSize.height) / 2.0)), size: closeSize))
|
transition.updateFrame(node: closeButtonNode, frame: CGRect(origin: CGPoint(x: textFrame.maxX - 6.0, y: floor((backgroundHeight - closeSize.height) / 2.0)), size: closeSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let actionButtonNode = self.actionButtonNode {
|
||||||
|
transition.updateFrame(node: actionButtonNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.width - actionSize.width - 16.0, y: floor((backgroundHeight - actionSize.height) / 2.0)), size: actionSize))
|
||||||
|
}
|
||||||
|
|
||||||
let animationFrame = CGRect(origin: CGPoint(x: contentInset - animationInset, y: contentVerticalInset - animationInset), size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0))
|
let animationFrame = CGRect(origin: CGPoint(x: contentInset - animationInset, y: contentVerticalInset - animationInset), size: CGSize(width: animationSize.width + animationInset * 2.0, height: animationSize.height + animationInset * 2.0))
|
||||||
transition.updateFrame(node: self.animatedStickerNode, frame: animationFrame)
|
transition.updateFrame(node: self.animatedStickerNode, frame: animationFrame)
|
||||||
@ -566,6 +662,59 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
transition.updateFrame(node: downArrowsNode, frame: CGRect(origin: CGPoint(x: animationFrame.midX - arrowsSize.width / 2.0, y: animationFrame.midY - arrowsSize.height / 2.0), size: arrowsSize))
|
transition.updateFrame(node: downArrowsNode, frame: CGRect(origin: CGPoint(x: animationFrame.midX - arrowsSize.width / 2.0, y: animationFrame.midY - arrowsSize.height / 2.0), size: arrowsSize))
|
||||||
downArrowsNode.setupAnimations()
|
downArrowsNode.setupAnimations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let avatarNode = self.avatarNode {
|
||||||
|
var avatarFrame = animationFrame
|
||||||
|
|
||||||
|
if let icon, case let .peer(_, isStory) = icon, isStory {
|
||||||
|
let indicatorTransition: Transition = .immediate
|
||||||
|
let avatarStoryIndicator: ComponentView<Empty>
|
||||||
|
if let current = self.avatarStoryIndicator {
|
||||||
|
avatarStoryIndicator = current
|
||||||
|
} else {
|
||||||
|
avatarStoryIndicator = ComponentView()
|
||||||
|
self.avatarStoryIndicator = avatarStoryIndicator
|
||||||
|
}
|
||||||
|
|
||||||
|
let storyIndicatorScale: CGFloat = 1.0
|
||||||
|
var indicatorFrame = CGRect(origin: CGPoint(x: avatarFrame.minX + 4.0, y: avatarFrame.minY + 4.0), size: CGSize(width: avatarFrame.width - 4.0 - 4.0, height: avatarFrame.height - 4.0 - 4.0))
|
||||||
|
indicatorFrame.origin.x -= (avatarFrame.width - avatarFrame.width * storyIndicatorScale) * 0.5
|
||||||
|
|
||||||
|
let _ = avatarStoryIndicator.update(
|
||||||
|
transition: indicatorTransition,
|
||||||
|
component: AnyComponent(AvatarStoryIndicatorComponent(
|
||||||
|
hasUnseen: true,
|
||||||
|
hasUnseenCloseFriendsItems: false,
|
||||||
|
theme: defaultDarkPresentationTheme,
|
||||||
|
activeLineWidth: 1.0 + UIScreenPixel,
|
||||||
|
inactiveLineWidth: 1.0 + UIScreenPixel,
|
||||||
|
counters: nil
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: indicatorFrame.size
|
||||||
|
)
|
||||||
|
if let avatarStoryIndicatorView = avatarStoryIndicator.view {
|
||||||
|
if avatarStoryIndicatorView.superview == nil {
|
||||||
|
avatarStoryIndicatorView.isUserInteractionEnabled = false
|
||||||
|
self.containerNode.view.addSubview(avatarStoryIndicatorView)
|
||||||
|
}
|
||||||
|
|
||||||
|
indicatorTransition.setPosition(view: avatarStoryIndicatorView, position: indicatorFrame.center)
|
||||||
|
indicatorTransition.setBounds(view: avatarStoryIndicatorView, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size))
|
||||||
|
indicatorTransition.setScale(view: avatarStoryIndicatorView, scale: storyIndicatorScale)
|
||||||
|
}
|
||||||
|
|
||||||
|
avatarFrame = avatarFrame.insetBy(dx: 4.0, dy: 4.0)
|
||||||
|
} else {
|
||||||
|
if let avatarStoryIndicator = self.avatarStoryIndicator {
|
||||||
|
self.avatarStoryIndicator = nil
|
||||||
|
avatarStoryIndicator.view?.removeFromSuperview()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateFrame(node: avatarNode, frame: avatarFrame)
|
||||||
|
avatarNode.updateSize(size: avatarFrame.size)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
@ -587,6 +736,9 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let actionButtonNode = self.actionButtonNode, let result = actionButtonNode.hitTest(self.convert(point, to: actionButtonNode), with: event) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
switch self.shouldDismissOnTouch(point) {
|
switch self.shouldDismissOnTouch(point) {
|
||||||
case .ignore:
|
case .ignore:
|
||||||
break
|
break
|
||||||
@ -628,12 +780,12 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
|
|
||||||
let animationDelay: Double
|
let animationDelay: Double
|
||||||
switch self.icon {
|
switch self.icon {
|
||||||
case .chatListPress:
|
case let .animation(_, delay):
|
||||||
animationDelay = 0.6
|
animationDelay = delay
|
||||||
case .info:
|
|
||||||
animationDelay = 0.2
|
|
||||||
case .none, .downArrows:
|
case .none, .downArrows:
|
||||||
animationDelay = 0.0
|
animationDelay = 0.0
|
||||||
|
case .peer:
|
||||||
|
animationDelay = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + animationDelay, execute: { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + animationDelay, execute: { [weak self] in
|
||||||
@ -684,9 +836,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class TooltipScreen: ViewController {
|
public final class TooltipScreen: ViewController {
|
||||||
|
public enum Text: Equatable {
|
||||||
|
case plain(text: String)
|
||||||
|
case entities(text: String, entities: [MessageTextEntity])
|
||||||
|
case markdown(text: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Action {
|
||||||
|
public let title: String
|
||||||
|
public let action: () -> Void
|
||||||
|
|
||||||
|
public init(
|
||||||
|
title: String,
|
||||||
|
action: @escaping () -> Void
|
||||||
|
) {
|
||||||
|
self.title = title
|
||||||
|
self.action = action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public enum Icon {
|
public enum Icon {
|
||||||
case info
|
case animation(name: String, delay: Double)
|
||||||
case chatListPress
|
case peer(peer: EnginePeer, isStory: Bool)
|
||||||
case downArrows
|
case downArrows
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -720,13 +891,19 @@ public final class TooltipScreen: ViewController {
|
|||||||
case gradient(UIColor, UIColor)
|
case gradient(UIColor, UIColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Alignment {
|
||||||
|
case natural
|
||||||
|
case center
|
||||||
|
}
|
||||||
|
|
||||||
|
private let context: AccountContext?
|
||||||
private let account: Account
|
private let account: Account
|
||||||
private let sharedContext: SharedAccountContext
|
private let sharedContext: SharedAccountContext
|
||||||
public let text: String
|
public let text: TooltipScreen.Text
|
||||||
public let textEntities: [MessageTextEntity]
|
public let textAlignment: TooltipScreen.Alignment
|
||||||
private let style: TooltipScreen.Style
|
private let style: TooltipScreen.Style
|
||||||
private let icon: TooltipScreen.Icon?
|
private let icon: TooltipScreen.Icon?
|
||||||
private let customContentNode: TooltipCustomContentNode?
|
private let action: TooltipScreen.Action?
|
||||||
public var location: TooltipScreen.Location {
|
public var location: TooltipScreen.Location {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isNodeLoaded {
|
if self.isNodeLoaded {
|
||||||
@ -755,13 +932,14 @@ public final class TooltipScreen: ViewController {
|
|||||||
public var alwaysVisible = false
|
public var alwaysVisible = false
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
|
context: AccountContext? = nil,
|
||||||
account: Account,
|
account: Account,
|
||||||
sharedContext: SharedAccountContext,
|
sharedContext: SharedAccountContext,
|
||||||
text: String,
|
text: TooltipScreen.Text,
|
||||||
textEntities: [MessageTextEntity] = [],
|
textAlignment: TooltipScreen.Alignment = .natural,
|
||||||
style: TooltipScreen.Style = .default,
|
style: TooltipScreen.Style = .default,
|
||||||
icon: TooltipScreen.Icon? = nil,
|
icon: TooltipScreen.Icon? = nil,
|
||||||
customContentNode: TooltipCustomContentNode? = nil,
|
action: TooltipScreen.Action? = nil,
|
||||||
location: TooltipScreen.Location,
|
location: TooltipScreen.Location,
|
||||||
displayDuration: DisplayDuration = .default,
|
displayDuration: DisplayDuration = .default,
|
||||||
inset: CGFloat = 13.0,
|
inset: CGFloat = 13.0,
|
||||||
@ -769,13 +947,14 @@ public final class TooltipScreen: ViewController {
|
|||||||
shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch,
|
shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch,
|
||||||
openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil
|
openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
|
self.context = context
|
||||||
self.account = account
|
self.account = account
|
||||||
self.sharedContext = sharedContext
|
self.sharedContext = sharedContext
|
||||||
self.text = text
|
self.text = text
|
||||||
self.textEntities = textEntities
|
self.textAlignment = textAlignment
|
||||||
self.style = style
|
self.style = style
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
self.customContentNode = customContentNode
|
self.action = action
|
||||||
self.location = location
|
self.location = location
|
||||||
self.displayDuration = displayDuration
|
self.displayDuration = displayDuration
|
||||||
self.inset = inset
|
self.inset = inset
|
||||||
@ -839,7 +1018,7 @@ public final class TooltipScreen: ViewController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
self.displayNode = TooltipScreenNode(account: self.account, sharedContext: self.sharedContext, text: self.text, textEntities: self.textEntities, style: self.style, icon: self.icon, customContentNode: self.customContentNode, location: self.location, displayDuration: self.displayDuration, inset: self.inset, cornerRadius: self.cornerRadius, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
|
self.displayNode = TooltipScreenNode(context: self.context, account: self.account, sharedContext: self.sharedContext, text: self.text, textAlignment: self.textAlignment, style: self.style, icon: self.icon, action: self.action, location: self.location, displayDuration: self.displayDuration, inset: self.inset, cornerRadius: self.cornerRadius, shouldDismissOnTouch: self.shouldDismissOnTouch, requestDismiss: { [weak self] in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ public enum UndoOverlayContent {
|
|||||||
case info(title: String?, text: String, timeout: Double?)
|
case info(title: String?, text: String, timeout: Double?)
|
||||||
case emoji(name: String, text: String)
|
case emoji(name: String, text: String)
|
||||||
case swipeToReply(title: String, text: String)
|
case swipeToReply(title: String, text: String)
|
||||||
case actionSucceeded(title: String, text: String, cancel: String)
|
case actionSucceeded(title: String, text: String, cancel: String, destructive: Bool)
|
||||||
case stickersModified(title: String, text: String, undo: Bool, info: StickerPackCollectionInfo, topItem: StickerPackItem?, context: AccountContext)
|
case stickersModified(title: String, text: String, undo: Bool, info: StickerPackCollectionInfo, topItem: StickerPackItem?, context: AccountContext)
|
||||||
case dice(dice: TelegramMediaDice, context: AccountContext, text: String, action: String?)
|
case dice(dice: TelegramMediaDice, context: AccountContext, text: String, action: String?)
|
||||||
case chatAddedToFolder(chatTitle: String, folderTitle: String)
|
case chatAddedToFolder(chatTitle: String, folderTitle: String)
|
||||||
|
@ -221,14 +221,16 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
|||||||
isUserInteractionEnabled = true
|
isUserInteractionEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
case let .actionSucceeded(title, text, cancel):
|
case let .actionSucceeded(title, text, cancel, destructive):
|
||||||
self.avatarNode = nil
|
self.avatarNode = nil
|
||||||
self.iconNode = nil
|
self.iconNode = nil
|
||||||
self.iconCheckNode = nil
|
self.iconCheckNode = nil
|
||||||
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
self.animationNode = AnimationNode(animation: "anim_success", colors: ["info1.info1.stroke": self.animationBackgroundColor, "info2.info2.Fill": self.animationBackgroundColor], scale: 1.0)
|
||||||
self.animatedStickerNode = nil
|
self.animatedStickerNode = nil
|
||||||
|
|
||||||
|
if destructive {
|
||||||
undoTextColor = UIColor(rgb: 0xff7b74)
|
undoTextColor = UIColor(rgb: 0xff7b74)
|
||||||
|
}
|
||||||
|
|
||||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user