mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 21:45:19 +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 let selectionToolbarNode = self.selectionToolbarNode {
|
||||
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)
|
||||
}), in: .current)
|
||||
}
|
||||
|
@ -165,11 +165,13 @@ private final class VideoRecorderImpl {
|
||||
if !self.savedTransitionImage, let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
|
||||
self.savedTransitionImage = true
|
||||
|
||||
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
|
||||
if let cgImage = self.imageContext.createCGImage(ciImage, from: ciImage.extent) {
|
||||
self.transitionImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
|
||||
} else {
|
||||
self.savedTransitionImage = false
|
||||
Queue.concurrentDefaultQueue().async {
|
||||
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
|
||||
if let cgImage = self.imageContext.createCGImage(ciImage, from: ciImage.extent) {
|
||||
self.transitionImage = UIImage(cgImage: cgImage, scale: 1.0, orientation: .right)
|
||||
} else {
|
||||
self.savedTransitionImage = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2356,7 +2356,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
|
||||
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 {
|
||||
return .dismiss(consume: false)
|
||||
}
|
||||
@ -2697,11 +2697,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
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(
|
||||
context: self.context,
|
||||
account: self.context.account,
|
||||
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),
|
||||
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
||||
)
|
||||
|
@ -96,15 +96,25 @@ func contactContextMenuItems(context: AccountContext, peerId: EnginePeer.Id, con
|
||||
return
|
||||
}
|
||||
|
||||
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY - 8.0), size: CGSize())
|
||||
let tooltipController = TooltipScreen(
|
||||
account: context.account,
|
||||
sharedContext: context.sharedContext,
|
||||
text: "Stories from \(peer?.compactDisplayTitle ?? "") will now be shown in Chats, not Contacts.",
|
||||
location: .point(location, .bottom),
|
||||
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
||||
)
|
||||
contactsController?.present(tooltipController, in: .window(.root))
|
||||
if let peer {
|
||||
let location = CGRect(origin: CGPoint(x: sourceFrame.midX, y: sourceFrame.minY + 1.0), size: CGSize())
|
||||
let tooltipController = TooltipScreen(
|
||||
context: context,
|
||||
account: context.account,
|
||||
sharedContext: context.sharedContext,
|
||||
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),
|
||||
shouldDismissOnTouch: { _ in return .dismiss(consume: false) }
|
||||
)
|
||||
contactsController?.present(tooltipController, in: .window(.root))
|
||||
}
|
||||
})))
|
||||
|
||||
return items
|
||||
|
@ -828,7 +828,7 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
|
||||
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)
|
||||
}))
|
||||
})
|
||||
|
@ -179,7 +179,7 @@ public final class QrCodeScanScreen: ViewController {
|
||||
return
|
||||
}
|
||||
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 {
|
||||
let _ = activeSessionsContext.remove(hash: session.hash).start()
|
||||
return true
|
||||
|
@ -456,7 +456,7 @@ public final class ThemePreviewController: ViewController {
|
||||
guard let strongSelf = self, !displayed else {
|
||||
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 {
|
||||
Queue.mainQueue().after(0.2) {
|
||||
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) {
|
||||
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)
|
||||
})
|
||||
strongSelf.galleryController()?.present(controller, in: .current)
|
||||
|
@ -529,7 +529,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
|
||||
let _ = (ApplicationSpecificNotice.incrementAudioRateOptionsTip(accountManager: self.context.sharedContext.accountManager)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] value in
|
||||
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)
|
||||
})
|
||||
controller.present(tooltipController, in: .window(.root))
|
||||
|
@ -761,7 +761,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
||||
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)
|
||||
}))
|
||||
}
|
||||
|
@ -2308,7 +2308,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
} else {
|
||||
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)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
@ -3505,7 +3505,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
if !callState.subscribedToScheduled {
|
||||
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))
|
||||
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)
|
||||
}), in: .window(.root))
|
||||
}
|
||||
@ -6409,7 +6409,7 @@ public final class VoiceChatControllerImpl: ViewController, VoiceChatController
|
||||
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)
|
||||
}), 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 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
|
||||
})
|
||||
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 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
|
||||
})
|
||||
self.controller?.present(tooltipController, in: .current)
|
||||
@ -1617,9 +1617,9 @@ public class CameraScreen: ViewController {
|
||||
|
||||
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 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
|
||||
})
|
||||
self.controller?.present(tooltipController, in: .current)
|
||||
@ -2106,6 +2106,11 @@ public class CameraScreen: ViewController {
|
||||
if let layout = self.validLayout, case .regular = layout.metrics.widthClass {
|
||||
return
|
||||
}
|
||||
|
||||
if self.node.hasAppeared {
|
||||
self.dismissAllTooltips()
|
||||
}
|
||||
|
||||
let transitionFraction = max(0.0, min(1.0, transitionFraction))
|
||||
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))
|
||||
|
@ -265,6 +265,7 @@ public final class MediaEditor {
|
||||
videoTrimRange: nil,
|
||||
videoIsMuted: false,
|
||||
videoIsFullHd: false,
|
||||
videoIsMirrored: false,
|
||||
additionalVideoPath: nil,
|
||||
additionalVideoPosition: 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) {
|
||||
self.updateValues(mode: .skipRendering) { values in
|
||||
return values.withUpdatedVideoIsFullHd(videoIsFullHd)
|
||||
|
@ -84,6 +84,9 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
if lhs.videoIsFullHd != rhs.videoIsFullHd {
|
||||
return false
|
||||
}
|
||||
if lhs.videoIsMirrored != rhs.videoIsMirrored {
|
||||
return false
|
||||
}
|
||||
if lhs.additionalVideoPath != rhs.additionalVideoPath {
|
||||
return false
|
||||
}
|
||||
@ -143,6 +146,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
case videoTrimRange
|
||||
case videoIsMuted
|
||||
case videoIsFullHd
|
||||
case videoIsMirrored
|
||||
|
||||
case additionalVideoPath
|
||||
case additionalVideoPosition
|
||||
@ -167,6 +171,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
public let videoTrimRange: Range<Double>?
|
||||
public let videoIsMuted: Bool
|
||||
public let videoIsFullHd: Bool
|
||||
public let videoIsMirrored: Bool
|
||||
|
||||
public let additionalVideoPath: String?
|
||||
public let additionalVideoPosition: CGPoint?
|
||||
@ -189,6 +194,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
videoTrimRange: Range<Double>?,
|
||||
videoIsMuted: Bool,
|
||||
videoIsFullHd: Bool,
|
||||
videoIsMirrored: Bool,
|
||||
additionalVideoPath: String?,
|
||||
additionalVideoPosition: CGPoint?,
|
||||
additionalVideoScale: CGFloat?,
|
||||
@ -208,6 +214,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
self.videoTrimRange = videoTrimRange
|
||||
self.videoIsMuted = videoIsMuted
|
||||
self.videoIsFullHd = videoIsFullHd
|
||||
self.videoIsMirrored = videoIsMirrored
|
||||
self.additionalVideoPath = additionalVideoPath
|
||||
self.additionalVideoPosition = additionalVideoPosition
|
||||
self.additionalVideoScale = additionalVideoScale
|
||||
@ -240,6 +247,7 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
self.videoTrimRange = try container.decodeIfPresent(Range<Double>.self, forKey: .videoTrimRange)
|
||||
self.videoIsMuted = try container.decode(Bool.self, forKey: .videoIsMuted)
|
||||
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.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.encode(self.videoIsMuted, forKey: .videoIsMuted)
|
||||
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.additionalVideoPosition, forKey: .additionalVideoPosition)
|
||||
@ -306,43 +315,48 @@ public final class MediaEditorValues: Codable, Equatable {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
|
@ -345,11 +345,17 @@ public final class MediaEditorVideoExport {
|
||||
|
||||
private func setupWithAsset(_ asset: AVAsset, additionalAsset: AVAsset?) {
|
||||
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 {
|
||||
self.additionalReader = try? AVAssetReader(asset: additionalAsset)
|
||||
self.additionalTextureRotation = textureRotatonForAVAsset(additionalAsset)
|
||||
self.additionalTextureRotation = textureRotatonForAVAsset(additionalAsset, mirror: true)
|
||||
}
|
||||
guard let reader = self.reader else {
|
||||
return
|
||||
|
@ -696,7 +696,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
guard let controller = environment.controller() as? MediaEditorScreen else {
|
||||
return
|
||||
}
|
||||
controller.requestCompletion(animated: true)
|
||||
controller.openPrivacySettings(completion: { [weak controller] in
|
||||
controller?.requestCompletion(animated: true)
|
||||
})
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
@ -1142,7 +1144,7 @@ final class MediaEditorScreenComponent: Component {
|
||||
}
|
||||
if let privacyButtonView = self.privacyButton.view {
|
||||
if privacyButtonView.superview == nil {
|
||||
self.addSubview(privacyButtonView)
|
||||
//self.addSubview(privacyButtonView)
|
||||
}
|
||||
transition.setPosition(view: privacyButtonView, position: privacyButtonFrame.center)
|
||||
transition.setBounds(view: privacyButtonView, bounds: CGRect(origin: .zero, size: privacyButtonFrame.size))
|
||||
@ -1841,19 +1843,22 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
imageEntity.scale = 1.49
|
||||
imageEntity.position = position.getPosition(storyDimensions)
|
||||
self.entitiesView.add(imageEntity, announce: false)
|
||||
} else if case let .video(_, _, _, additionalVideoPath, _, _, _, changes, position) = subject, let additionalVideoPath {
|
||||
let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
||||
videoEntity.referenceDrawingSize = storyDimensions
|
||||
videoEntity.scale = 1.49
|
||||
videoEntity.position = position.getPosition(storyDimensions)
|
||||
self.entitiesView.add(videoEntity, announce: false)
|
||||
|
||||
mediaEditor.setAdditionalVideo(additionalVideoPath, positionChanges: changes.map { VideoPositionChange(additional: $0.0, timestamp: $0.1) })
|
||||
mediaEditor.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation)
|
||||
if let entityView = self.entitiesView.getView(for: videoEntity.uuid) as? DrawingStickerEntityView {
|
||||
entityView.updated = { [weak videoEntity, weak self] in
|
||||
if let self, let videoEntity {
|
||||
self.mediaEditor?.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation)
|
||||
} else if case let .video(_, _, mirror, additionalVideoPath, _, _, _, changes, position) = subject {
|
||||
mediaEditor.setVideoIsMirrored(mirror)
|
||||
if let additionalVideoPath {
|
||||
let videoEntity = DrawingStickerEntity(content: .dualVideoReference)
|
||||
videoEntity.referenceDrawingSize = storyDimensions
|
||||
videoEntity.scale = 1.49
|
||||
videoEntity.position = position.getPosition(storyDimensions)
|
||||
self.entitiesView.add(videoEntity, announce: false)
|
||||
|
||||
mediaEditor.setAdditionalVideo(additionalVideoPath, positionChanges: changes.map { VideoPositionChange(additional: $0.0, timestamp: $0.1) })
|
||||
mediaEditor.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation)
|
||||
if let entityView = self.entitiesView.getView(for: videoEntity.uuid) as? DrawingStickerEntityView {
|
||||
entityView.updated = { [weak videoEntity, weak self] in
|
||||
if let self, let videoEntity {
|
||||
self.mediaEditor?.setAdditionalVideoPosition(videoEntity.position, scale: videoEntity.scale, rotation: videoEntity.rotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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 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
|
||||
})
|
||||
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 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
|
||||
})
|
||||
self.muteTooltip = tooltipController
|
||||
@ -2642,7 +2647,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
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
|
||||
})
|
||||
self.storyArchiveTooltip = tooltipController
|
||||
@ -3133,7 +3138,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
self.displayNode.view.addInteraction(dropInteraction)
|
||||
}
|
||||
|
||||
func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil) {
|
||||
func openPrivacySettings(_ privacy: MediaEditorResultPrivacy? = nil, completion: @escaping () -> Void = {}) {
|
||||
self.hapticFeedback.impact(.light)
|
||||
|
||||
let privacy = privacy ?? self.state.privacy
|
||||
@ -3157,6 +3162,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
return
|
||||
}
|
||||
self.state.privacy = MediaEditorResultPrivacy(privacy: privacy, timeout: timeout, archive: archive)
|
||||
completion()
|
||||
},
|
||||
editCategory: { [weak self] privacy in
|
||||
guard let self else {
|
||||
@ -3166,7 +3172,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
||||
guard let self else {
|
||||
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
|
||||
if section.id == 0 {
|
||||
let hours = component.timeout / 3600
|
||||
sectionTitle = "WHO CAN VIEW FOR \(hours) HOURS"
|
||||
sectionTitle = "WHO CAN VIEW"
|
||||
} else {
|
||||
if case .chats = component.stateContext.subject {
|
||||
sectionTitle = "CHATS"
|
||||
@ -1063,10 +1062,12 @@ final class ShareWithPeersScreenComponent: Component {
|
||||
}
|
||||
navigationButtonsWidth += navigationLeftButtonSize.width + navigationSideInset
|
||||
|
||||
var actionButtonTitle = "Save Settings"
|
||||
let title: String
|
||||
switch component.stateContext.subject {
|
||||
case .stories:
|
||||
title = "Share Story"
|
||||
actionButtonTitle = "Post Story"
|
||||
case .chats:
|
||||
title = "Send as a Message"
|
||||
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)))
|
||||
|
||||
let actionButtonTitle: String = "Save Settings"
|
||||
let actionButtonSize = self.actionButton.update(
|
||||
transition: transition,
|
||||
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 {
|
||||
return true
|
||||
}
|
||||
if let reactionContextNode = self.reactionContextNode, reactionContextNode.isReactionSearchActive {
|
||||
return true
|
||||
}
|
||||
if self.privacyController != nil {
|
||||
return true
|
||||
}
|
||||
@ -2235,7 +2238,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
let tooltipScreen = TooltipScreen(
|
||||
account: component.context.account,
|
||||
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)
|
||||
}
|
||||
)
|
||||
|
@ -338,7 +338,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
Queue.mainQueue().after(0.3) {
|
||||
controller.present(UndoOverlayController(
|
||||
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,
|
||||
animateInAsReplacement: false,
|
||||
action: { [weak view] action in
|
||||
@ -380,7 +380,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
Queue.mainQueue().after(0.3) {
|
||||
controller.present(UndoOverlayController(
|
||||
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,
|
||||
animateInAsReplacement: false,
|
||||
action: { [weak view] action in
|
||||
@ -442,7 +442,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
Queue.mainQueue().after(0.3) {
|
||||
controller.present(UndoOverlayController(
|
||||
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,
|
||||
animateInAsReplacement: false,
|
||||
action: { [weak view] action in
|
||||
@ -491,7 +491,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
if isVideo {
|
||||
if self.videoRecorderValue == nil {
|
||||
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 {
|
||||
return
|
||||
}
|
||||
@ -2057,28 +2057,36 @@ final class StoryItemSetContainerSendMessage {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
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))
|
||||
|> 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])
|
||||
|
||||
if let attachmentController = self.attachmentController {
|
||||
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 = {}) {
|
||||
@ -2139,9 +2147,7 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
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)
|
||||
}
|
||||
} 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
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
|
@ -14490,7 +14490,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var found = false
|
||||
self.forEachController({ controller in
|
||||
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
|
||||
controller.dismiss()
|
||||
return false
|
||||
@ -14502,7 +14502,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
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
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
@ -14583,7 +14583,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var found = false
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
if controller.text == psaText {
|
||||
if controller.text == .plain(text: psaText) {
|
||||
found = true
|
||||
controller.dismiss()
|
||||
return false
|
||||
@ -14595,7 +14595,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
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
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
@ -14683,7 +14683,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
var found = false
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
if controller.text == psaText {
|
||||
if controller.text == .plain(text: psaText) {
|
||||
found = true
|
||||
controller.resetDismissTimeout()
|
||||
|
||||
@ -14709,7 +14709,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
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
|
||||
}, openActiveTextItem: { [weak self] item, action in
|
||||
guard let strongSelf = self else {
|
||||
|
@ -1484,7 +1484,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
tooltipController.location = .point(location, .bottom)
|
||||
}
|
||||
} 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
|
||||
})
|
||||
controller.alwaysVisible = true
|
||||
|
@ -1262,7 +1262,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
|
||||
if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
|
||||
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)
|
||||
}))
|
||||
|
||||
|
@ -8691,7 +8691,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||
return
|
||||
}
|
||||
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)
|
||||
}), in: .current)
|
||||
}
|
||||
|
@ -20,6 +20,10 @@ swift_library(
|
||||
"//submodules/TextFormat:TextFormat",
|
||||
"//submodules/UrlEscaping:UrlEscaping",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/Markdown",
|
||||
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -11,11 +11,11 @@ import TelegramCore
|
||||
import TextFormat
|
||||
import UrlEscaping
|
||||
import AccountContext
|
||||
|
||||
public protocol TooltipCustomContentNode: ASDisplayNode {
|
||||
func animateIn()
|
||||
func updateLayout(size: CGSize) -> CGSize
|
||||
}
|
||||
import AvatarNode
|
||||
import ComponentFlow
|
||||
import AvatarStoryIndicatorComponent
|
||||
import AccountContext
|
||||
import Markdown
|
||||
|
||||
public enum TooltipActiveTextItem {
|
||||
case url(String, Bool)
|
||||
@ -109,7 +109,7 @@ private class DownArrowsIconNode: ASDisplayNode {
|
||||
private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
private let tooltipStyle: TooltipScreen.Style
|
||||
private let icon: TooltipScreen.Icon?
|
||||
private let customContentNode: TooltipCustomContentNode?
|
||||
private let action: TooltipScreen.Action?
|
||||
var location: TooltipScreen.Location {
|
||||
didSet {
|
||||
if let layout = self.validLayout {
|
||||
@ -134,8 +134,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
private let arrowContainer: ASDisplayNode
|
||||
private let animatedStickerNode: AnimatedStickerNode
|
||||
private var downArrowsNode: DownArrowsIconNode?
|
||||
private var avatarNode: AvatarNode?
|
||||
private var avatarStoryIndicator: ComponentView<Empty>?
|
||||
private let textNode: ImmediateTextNode
|
||||
private let closeButtonNode: HighlightableButtonNode
|
||||
private var closeButtonNode: HighlightableButtonNode?
|
||||
private var actionButtonNode: HighlightableButtonNode?
|
||||
|
||||
private var isArrowInverted: Bool = false
|
||||
|
||||
@ -143,10 +146,24 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
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.icon = icon
|
||||
self.customContentNode = customContentNode
|
||||
self.action = action
|
||||
self.location = location
|
||||
self.displayDuration = displayDuration
|
||||
self.inset = inset
|
||||
@ -164,6 +181,8 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
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 {
|
||||
var index: UnsafePointer<UInt8> = path.utf8Start
|
||||
let end = path.utf8Start.advanced(by: path.utf8CodeUnitCount)
|
||||
@ -210,7 +229,6 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
self.arrowContainer = ASDisplayNode()
|
||||
|
||||
let theme = sharedContext.currentPresentationData.with { $0 }.theme
|
||||
let fontSize: CGFloat
|
||||
if case .top = location {
|
||||
let backgroundColor: UIColor
|
||||
@ -310,25 +328,56 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.textNode = ImmediateTextNode()
|
||||
self.textNode.displaysAsynchronously = false
|
||||
self.textNode.maximumNumberOfLines = 0
|
||||
|
||||
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)
|
||||
|
||||
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 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()
|
||||
switch icon {
|
||||
case .none:
|
||||
break
|
||||
case .chatListPress:
|
||||
self.animatedStickerNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "ChatListFoldersTooltip"), 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))
|
||||
case let .animation(animationName, _):
|
||||
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 .downArrows:
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
self.closeButtonNode = HighlightableButtonNode()
|
||||
self.closeButtonNode.setImage(UIImage(bundleImageName: "Components/Close"), for: .normal)
|
||||
if case .manual = displayDuration {
|
||||
self.closeButtonNode = HighlightableButtonNode()
|
||||
self.closeButtonNode?.setImage(UIImage(bundleImageName: "Components/Close"), for: .normal)
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
@ -343,16 +392,28 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.containerNode.addSubnode(self.textNode)
|
||||
self.containerNode.addSubnode(self.animatedStickerNode)
|
||||
|
||||
if case .manual = displayDuration {
|
||||
self.containerNode.addSubnode(self.closeButtonNode)
|
||||
if let closeButtonNode = self.closeButtonNode {
|
||||
self.containerNode.addSubnode(closeButtonNode)
|
||||
}
|
||||
|
||||
if let downArrowsNode = self.downArrowsNode {
|
||||
self.containerNode.addSubnode(downArrowsNode)
|
||||
}
|
||||
if let avatarNode = self.avatarNode {
|
||||
self.containerNode.addSubnode(avatarNode)
|
||||
}
|
||||
self.scrollingContainer.addSubnode(self.containerNode)
|
||||
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.highlightAttributeAction = { attributes in
|
||||
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() {
|
||||
@ -441,11 +510,15 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
animationSize = CGSize(width: 24.0, height: 32.0)
|
||||
animationInset = (40.0 - animationSize.width) / 2.0
|
||||
animationSpacing = 8.0
|
||||
case .chatListPress:
|
||||
case let .animation(animationName, _):
|
||||
animationSize = CGSize(width: 32.0, height: 32.0)
|
||||
animationInset = (70.0 - animationSize.width) / 2.0
|
||||
if animationName == "ChatListFoldersTooltip" {
|
||||
animationInset = (70.0 - animationSize.width) / 2.0
|
||||
} else {
|
||||
animationInset = 0.0
|
||||
}
|
||||
animationSpacing = 8.0
|
||||
case .info:
|
||||
case .peer:
|
||||
animationSize = CGSize(width: 32.0, height: 32.0)
|
||||
animationInset = 0.0
|
||||
animationSpacing = 8.0
|
||||
@ -453,24 +526,41 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
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
|
||||
|
||||
let backgroundHeight: CGFloat
|
||||
var backgroundHeight: CGFloat
|
||||
switch self.tooltipStyle {
|
||||
case .default, .gradient, .customBlur:
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||
case .light:
|
||||
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
||||
backgroundHeight = max(animationSize.height, textSize.height) + contentVerticalInset * 2.0
|
||||
if self.actionButtonNode != nil {
|
||||
backgroundHeight += 2.0
|
||||
}
|
||||
case .light:
|
||||
backgroundHeight = max(28.0, max(animationSize.height, textSize.height) + 4.0 * 2.0)
|
||||
}
|
||||
|
||||
var invertArrow = false
|
||||
switch self.location {
|
||||
case let .point(rect, arrowPosition):
|
||||
var backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
||||
if self.closeButtonNode.supernode != nil {
|
||||
backgroundWidth += 24.0
|
||||
if self.closeButtonNode != nil || self.actionButtonNode != nil {
|
||||
backgroundWidth += buttonInset
|
||||
}
|
||||
if self.actionButtonNode != nil, case .compact = layout.metrics.widthClass {
|
||||
backgroundWidth = containerWidth
|
||||
}
|
||||
switch arrowPosition {
|
||||
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)
|
||||
transition.updateFrame(node: self.textNode, frame: textFrame)
|
||||
|
||||
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))
|
||||
if let closeButtonNode = self.closeButtonNode {
|
||||
let closeSize = CGSize(width: 44.0, height: 44.0)
|
||||
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))
|
||||
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))
|
||||
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? {
|
||||
@ -587,6 +736,9 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if let actionButtonNode = self.actionButtonNode, let result = actionButtonNode.hitTest(self.convert(point, to: actionButtonNode), with: event) {
|
||||
return result
|
||||
}
|
||||
switch self.shouldDismissOnTouch(point) {
|
||||
case .ignore:
|
||||
break
|
||||
@ -628,12 +780,12 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
let animationDelay: Double
|
||||
switch self.icon {
|
||||
case .chatListPress:
|
||||
animationDelay = 0.6
|
||||
case .info:
|
||||
animationDelay = 0.2
|
||||
case let .animation(_, delay):
|
||||
animationDelay = delay
|
||||
case .none, .downArrows:
|
||||
animationDelay = 0.0
|
||||
case .peer:
|
||||
animationDelay = 0.0
|
||||
}
|
||||
|
||||
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 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 {
|
||||
case info
|
||||
case chatListPress
|
||||
case animation(name: String, delay: Double)
|
||||
case peer(peer: EnginePeer, isStory: Bool)
|
||||
case downArrows
|
||||
}
|
||||
|
||||
@ -720,13 +891,19 @@ public final class TooltipScreen: ViewController {
|
||||
case gradient(UIColor, UIColor)
|
||||
}
|
||||
|
||||
public enum Alignment {
|
||||
case natural
|
||||
case center
|
||||
}
|
||||
|
||||
private let context: AccountContext?
|
||||
private let account: Account
|
||||
private let sharedContext: SharedAccountContext
|
||||
public let text: String
|
||||
public let textEntities: [MessageTextEntity]
|
||||
public let text: TooltipScreen.Text
|
||||
public let textAlignment: TooltipScreen.Alignment
|
||||
private let style: TooltipScreen.Style
|
||||
private let icon: TooltipScreen.Icon?
|
||||
private let customContentNode: TooltipCustomContentNode?
|
||||
private let action: TooltipScreen.Action?
|
||||
public var location: TooltipScreen.Location {
|
||||
didSet {
|
||||
if self.isNodeLoaded {
|
||||
@ -755,13 +932,14 @@ public final class TooltipScreen: ViewController {
|
||||
public var alwaysVisible = false
|
||||
|
||||
public init(
|
||||
context: AccountContext? = nil,
|
||||
account: Account,
|
||||
sharedContext: SharedAccountContext,
|
||||
text: String,
|
||||
textEntities: [MessageTextEntity] = [],
|
||||
text: TooltipScreen.Text,
|
||||
textAlignment: TooltipScreen.Alignment = .natural,
|
||||
style: TooltipScreen.Style = .default,
|
||||
icon: TooltipScreen.Icon? = nil,
|
||||
customContentNode: TooltipCustomContentNode? = nil,
|
||||
action: TooltipScreen.Action? = nil,
|
||||
location: TooltipScreen.Location,
|
||||
displayDuration: DisplayDuration = .default,
|
||||
inset: CGFloat = 13.0,
|
||||
@ -769,13 +947,14 @@ public final class TooltipScreen: ViewController {
|
||||
shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch,
|
||||
openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil
|
||||
) {
|
||||
self.context = context
|
||||
self.account = account
|
||||
self.sharedContext = sharedContext
|
||||
self.text = text
|
||||
self.textEntities = textEntities
|
||||
self.textAlignment = textAlignment
|
||||
self.style = style
|
||||
self.icon = icon
|
||||
self.customContentNode = customContentNode
|
||||
self.action = action
|
||||
self.location = location
|
||||
self.displayDuration = displayDuration
|
||||
self.inset = inset
|
||||
@ -839,7 +1018,7 @@ public final class TooltipScreen: ViewController {
|
||||
}
|
||||
|
||||
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 {
|
||||
return
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public enum UndoOverlayContent {
|
||||
case info(title: String?, text: String, timeout: Double?)
|
||||
case emoji(name: 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 dice(dice: TelegramMediaDice, context: AccountContext, text: String, action: String?)
|
||||
case chatAddedToFolder(chatTitle: String, folderTitle: String)
|
||||
|
@ -221,14 +221,16 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
|
||||
isUserInteractionEnabled = true
|
||||
}
|
||||
|
||||
case let .actionSucceeded(title, text, cancel):
|
||||
case let .actionSucceeded(title, text, cancel, destructive):
|
||||
self.avatarNode = nil
|
||||
self.iconNode = 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.animatedStickerNode = nil
|
||||
|
||||
undoTextColor = UIColor(rgb: 0xff7b74)
|
||||
if destructive {
|
||||
undoTextColor = UIColor(rgb: 0xff7b74)
|
||||
}
|
||||
|
||||
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
|
||||
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
|
||||
|
Loading…
x
Reference in New Issue
Block a user