mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit 'd6207366d2af2164344e1bbe61fd5526e9f58c50'
This commit is contained in:
commit
2e0efe4e31
@ -2454,9 +2454,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
||||
initialFocusedId = AnyHashable(peer.id)
|
||||
}
|
||||
|
||||
if !initialContent.contains(where: { slice in
|
||||
return !slice.items.isEmpty
|
||||
}) {
|
||||
if initialFocusedId == AnyHashable(self.context.account.peerId), let firstItem = initialContent.first, firstItem.id == initialFocusedId && firstItem.items.isEmpty {
|
||||
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||
rootController.openStoryCamera(transitionIn: cameraTransitionIn, transitionOut: { [weak self] _ in
|
||||
guard let self else {
|
||||
|
@ -69,6 +69,7 @@ swift_library(
|
||||
"//submodules/Camera",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/BlurredBackgroundComponent",
|
||||
"//submodules/Components/LottieAnimationComponent:LottieAnimationComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -14,6 +14,7 @@ import Camera
|
||||
import MultilineTextComponent
|
||||
import BlurredBackgroundComponent
|
||||
import Photos
|
||||
import LottieAnimationComponent
|
||||
|
||||
let videoRedColor = UIColor(rgb: 0xff3b30)
|
||||
|
||||
@ -284,17 +285,39 @@ private final class CameraScreenComponent: CombinedComponent {
|
||||
.cornerRadius(20.0)
|
||||
)
|
||||
|
||||
let flashIconName: String
|
||||
switch state.cameraState.flashMode {
|
||||
case .off:
|
||||
flashIconName = "flash_off"
|
||||
case .on:
|
||||
flashIconName = "flash_on"
|
||||
case .auto:
|
||||
flashIconName = "flash_auto"
|
||||
@unknown default:
|
||||
flashIconName = "flash_off"
|
||||
}
|
||||
|
||||
let flashButton = flashButton.update(
|
||||
component: CameraButton(
|
||||
content: AnyComponent(Image(
|
||||
image: state.image(.flash)
|
||||
)),
|
||||
content: AnyComponent(
|
||||
LottieAnimationComponent(
|
||||
animation: LottieAnimationComponent.AnimationItem(
|
||||
name: flashIconName,
|
||||
mode: .animating(loop: false),
|
||||
range: nil
|
||||
),
|
||||
colors: [:],
|
||||
size: CGSize(width: 40.0, height: 40.0)
|
||||
)
|
||||
),
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
if state.cameraState.flashMode == .off {
|
||||
state.camera.setFlashMode(.on)
|
||||
} else if state.cameraState.flashMode == .on {
|
||||
state.camera.setFlashMode(.auto)
|
||||
} else {
|
||||
state.camera.setFlashMode(.off)
|
||||
}
|
||||
@ -885,6 +908,13 @@ public class CameraScreen: ViewController {
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
}
|
||||
|
||||
if let view = self.componentHost.findTaggedView(tag: flashButtonTag) {
|
||||
view.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
|
||||
view.layer.shadowRadius = 4.0
|
||||
view.layer.shadowColor = UIColor.black.cgColor
|
||||
view.layer.shadowOpacity = 0.2
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(completion: @escaping () -> Void) {
|
||||
@ -928,11 +958,11 @@ public class CameraScreen: ViewController {
|
||||
func animateOutToEditor() {
|
||||
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
||||
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: flashButtonTag) {
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
view.layer.animateScale(from: 1.0, to: 0.1, duration: 0.2)
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: zoomControlTag) {
|
||||
@ -973,15 +1003,15 @@ public class CameraScreen: ViewController {
|
||||
|
||||
let transition = Transition(animation: .curve(duration: 0.2, curve: .easeInOut))
|
||||
if let view = self.componentHost.findTaggedView(tag: cancelButtonTag) {
|
||||
transition.setScale(view: view, scale: 1.0)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
transition.setAlpha(view: view, alpha: 1.0)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: flashButtonTag) {
|
||||
transition.setScale(view: view, scale: 1.0)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
transition.setAlpha(view: view, alpha: 1.0)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: zoomControlTag) {
|
||||
transition.setScale(view: view, scale: 1.0)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
transition.setAlpha(view: view, alpha: 1.0)
|
||||
}
|
||||
if let view = self.componentHost.findTaggedView(tag: captureControlsTag) as? CaptureControlsComponent.View {
|
||||
@ -1143,6 +1173,7 @@ public class CameraScreen: ViewController {
|
||||
let controller = self.context.sharedContext.makeMediaPickerScreen(context: self.context, completion: { [weak self] asset in
|
||||
dismissGalleryControllerImpl?()
|
||||
if let self {
|
||||
self.node.animateOutToEditor()
|
||||
self.completion(.single(.asset(asset)))
|
||||
}
|
||||
})
|
||||
|
@ -16,7 +16,7 @@ final class ImageTextureSource: TextureSource {
|
||||
let textureLoader = MTKTextureLoader(device: device)
|
||||
self.textureLoader = textureLoader
|
||||
|
||||
self.texture = try? textureLoader.newTexture(cgImage: cgImage, options: nil)
|
||||
self.texture = try? textureLoader.newTexture(cgImage: cgImage, options: [.SRGB : false])
|
||||
}
|
||||
|
||||
func start() {
|
||||
|
@ -113,7 +113,7 @@ final class MediaEditorComposer {
|
||||
}
|
||||
if self.filteredImage == nil, let device = self.device, let cgImage = inputImage.cgImage {
|
||||
let textureLoader = MTKTextureLoader(device: device)
|
||||
if let texture = try? textureLoader.newTexture(cgImage: cgImage) {
|
||||
if let texture = try? textureLoader.newTexture(cgImage: cgImage, options: [.SRGB : false]) {
|
||||
self.renderer.consumeTexture(texture, rotation: .rotate0Degrees)
|
||||
self.renderer.renderFrame()
|
||||
|
||||
|
@ -44,7 +44,6 @@ public final class MediaEditorVideoAVAssetWriter: MediaEditorVideoExportWriter {
|
||||
private var writer: AVAssetWriter?
|
||||
private var videoInput: AVAssetWriterInput?
|
||||
private var audioInput: AVAssetWriterInput?
|
||||
|
||||
private var adaptor: AVAssetWriterInputPixelBufferAdaptor!
|
||||
|
||||
func setup(configuration: MediaEditorVideoExport.Configuration, outputPath: String) {
|
||||
@ -83,8 +82,6 @@ public final class MediaEditorVideoAVAssetWriter: MediaEditorVideoExportWriter {
|
||||
|
||||
if writer.canAdd(videoInput) {
|
||||
writer.add(videoInput)
|
||||
} else {
|
||||
//throw Error.cannotAddVideoInput
|
||||
}
|
||||
self.videoInput = videoInput
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ swift_library(
|
||||
"//submodules/Components/LottieAnimationComponent:LottieAnimationComponent",
|
||||
"//submodules/TelegramUI/Components/MessageInputPanelComponent",
|
||||
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
||||
"//submodules/TooltipUI",
|
||||
"//submodules/Components/BlurredBackgroundComponent",
|
||||
"//submodules/AvatarNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -16,6 +16,9 @@ import Photos
|
||||
import LottieAnimationComponent
|
||||
import MessageInputPanelComponent
|
||||
import EntityKeyboard
|
||||
import TooltipUI
|
||||
import BlurredBackgroundComponent
|
||||
import AvatarNode
|
||||
|
||||
enum DrawingScreenType {
|
||||
case drawing
|
||||
@ -23,6 +26,7 @@ enum DrawingScreenType {
|
||||
case sticker
|
||||
}
|
||||
|
||||
private let privacyButtonTag = GenericComponentViewTag()
|
||||
private let muteButtonTag = GenericComponentViewTag()
|
||||
private let saveButtonTag = GenericComponentViewTag()
|
||||
|
||||
@ -31,17 +35,20 @@ final class MediaEditorScreenComponent: Component {
|
||||
|
||||
let context: AccountContext
|
||||
let mediaEditor: MediaEditor?
|
||||
let privacy: EngineStoryPrivacy
|
||||
let openDrawing: (DrawingScreenType) -> Void
|
||||
let openTools: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
mediaEditor: MediaEditor?,
|
||||
privacy: EngineStoryPrivacy,
|
||||
openDrawing: @escaping (DrawingScreenType) -> Void,
|
||||
openTools: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.mediaEditor = mediaEditor
|
||||
self.privacy = privacy
|
||||
self.openDrawing = openDrawing
|
||||
self.openTools = openTools
|
||||
}
|
||||
@ -50,6 +57,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
if lhs.privacy != rhs.privacy {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -139,8 +149,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
|
||||
private let scrubber = ComponentView<Empty>()
|
||||
|
||||
private let saveButton = ComponentView<Empty>()
|
||||
private let privacyButton = ComponentView<Empty>()
|
||||
private let muteButton = ComponentView<Empty>()
|
||||
private let saveButton = ComponentView<Empty>()
|
||||
|
||||
private var component: MediaEditorScreenComponent?
|
||||
private weak var state: State?
|
||||
@ -199,6 +210,11 @@ final class MediaEditorScreenComponent: Component {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
if let view = self.privacyButton.view {
|
||||
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOutToCamera() {
|
||||
@ -243,6 +259,11 @@ final class MediaEditorScreenComponent: Component {
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
}
|
||||
|
||||
if let view = self.privacyButton.view {
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
func animateOutToTool() {
|
||||
@ -285,6 +306,11 @@ final class MediaEditorScreenComponent: Component {
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
}
|
||||
|
||||
if let view = self.privacyButton.view {
|
||||
transition.setAlpha(view: view, alpha: 0.0)
|
||||
transition.setScale(view: view, scale: 0.1)
|
||||
}
|
||||
}
|
||||
|
||||
func animateInFromTool() {
|
||||
@ -327,6 +353,11 @@ final class MediaEditorScreenComponent: Component {
|
||||
transition.setAlpha(view: view, alpha: 1.0)
|
||||
transition.setScale(view: view, scale: 1.0)
|
||||
}
|
||||
|
||||
if let view = self.privacyButton.view {
|
||||
transition.setAlpha(view: view, alpha: 1.0)
|
||||
transition.setScale(view: view, scale: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: MediaEditorScreenComponent, availableSize: CGSize, state: State, environment: Environment<ViewControllerComponentContainer.Environment>, transition: Transition) -> CGSize {
|
||||
@ -592,6 +623,49 @@ final class MediaEditorScreenComponent: Component {
|
||||
transition.setFrame(view: inputPanelView, frame: inputPanelFrame)
|
||||
}
|
||||
|
||||
let privacyText: String
|
||||
switch component.privacy.base {
|
||||
case .everyone:
|
||||
privacyText = "Everyone"
|
||||
case .closeFriends:
|
||||
privacyText = "Close Friends"
|
||||
case .contacts:
|
||||
privacyText = "Contacts"
|
||||
}
|
||||
|
||||
|
||||
let privacyButtonSize = self.privacyButton.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Button(
|
||||
content: AnyComponent(
|
||||
PrivacyButtonComponent(
|
||||
icon: UIImage(bundleImageName: "Media Editor/Recipient")!,
|
||||
text: privacyText
|
||||
)
|
||||
),
|
||||
action: {
|
||||
if let controller = environment.controller() as? MediaEditorScreen {
|
||||
controller.presentPrivacySettings()
|
||||
}
|
||||
}
|
||||
).tagged(privacyButtonTag)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: 44.0, height: 44.0)
|
||||
)
|
||||
let privacyButtonFrame = CGRect(
|
||||
origin: CGPoint(x: 16.0, y: environment.safeInsets.top + 20.0 - inputPanelOffset),
|
||||
size: privacyButtonSize
|
||||
)
|
||||
if let privacyButtonView = self.privacyButton.view {
|
||||
if privacyButtonView.superview == nil {
|
||||
self.addSubview(privacyButtonView)
|
||||
}
|
||||
transition.setPosition(view: privacyButtonView, position: privacyButtonFrame.center)
|
||||
transition.setBounds(view: privacyButtonView, bounds: CGRect(origin: .zero, size: privacyButtonFrame.size))
|
||||
transition.setScale(view: privacyButtonView, scale: self.inputPanelExternalState.isEditing ? 0.01 : 1.0)
|
||||
transition.setAlpha(view: privacyButtonView, alpha: self.inputPanelExternalState.isEditing ? 0.0 : 1.0)
|
||||
}
|
||||
|
||||
let saveButtonSize = self.saveButton.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(Button(
|
||||
@ -625,9 +699,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
if let saveButtonView = self.saveButton.view {
|
||||
if saveButtonView.superview == nil {
|
||||
saveButtonView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
|
||||
saveButtonView.layer.shadowRadius = 2.0
|
||||
saveButtonView.layer.shadowRadius = 4.0
|
||||
saveButtonView.layer.shadowColor = UIColor.black.cgColor
|
||||
saveButtonView.layer.shadowOpacity = 0.25
|
||||
saveButtonView.layer.shadowOpacity = 0.2
|
||||
self.addSubview(saveButtonView)
|
||||
}
|
||||
transition.setPosition(view: saveButtonView, position: saveButtonFrame.center)
|
||||
@ -669,9 +743,9 @@ final class MediaEditorScreenComponent: Component {
|
||||
if let muteButtonView = self.muteButton.view {
|
||||
if muteButtonView.superview == nil {
|
||||
muteButtonView.layer.shadowOffset = CGSize(width: 0.0, height: 0.0)
|
||||
muteButtonView.layer.shadowRadius = 2.0
|
||||
muteButtonView.layer.shadowRadius = 4.0
|
||||
muteButtonView.layer.shadowColor = UIColor.black.cgColor
|
||||
muteButtonView.layer.shadowOpacity = 0.25
|
||||
muteButtonView.layer.shadowOpacity = 0.2
|
||||
//self.addSubview(muteButtonView)
|
||||
}
|
||||
transition.setPosition(view: muteButtonView, position: muteButtonFrame.center)
|
||||
@ -735,6 +809,7 @@ public final class MediaEditorScreen: ViewController {
|
||||
|
||||
fileprivate var subject: MediaEditorScreen.Subject?
|
||||
private var subjectDisposable: Disposable?
|
||||
fileprivate var storyPrivacy: EngineStoryPrivacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
|
||||
|
||||
private let backgroundDimView: UIView
|
||||
fileprivate let componentHost: ComponentView<ViewControllerComponentContainer.Environment>
|
||||
@ -974,6 +1049,10 @@ public final class MediaEditorScreen: ViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.5) {
|
||||
self.presentPrivacyTooltip()
|
||||
}
|
||||
}
|
||||
|
||||
func animateOut(finished: Bool, completion: @escaping () -> Void) {
|
||||
@ -1041,6 +1120,21 @@ public final class MediaEditorScreen: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
func presentPrivacyTooltip() {
|
||||
guard let sourceView = self.componentHost.findTaggedView(tag: privacyButtonTag) else {
|
||||
return
|
||||
}
|
||||
|
||||
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.maxY + 3.0), size: CGSize())
|
||||
|
||||
let controller = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: "You can set who can view this story", location: .point(location, .top), displayDuration: .manual, inset: 16.0, shouldDismissOnTouch: { _ in
|
||||
return .ignore
|
||||
})
|
||||
self.controller?.present(controller, in: .current)
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result == self.componentHost.view {
|
||||
@ -1051,6 +1145,12 @@ public final class MediaEditorScreen: ViewController {
|
||||
return result
|
||||
}
|
||||
|
||||
func requestUpdate() {
|
||||
if let layout = self.validLayout {
|
||||
self.containerLayoutUpdated(layout: layout, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
private var drawingScreen: DrawingScreen?
|
||||
func containerLayoutUpdated(layout: ContainerViewLayout, forceUpdate: Bool = false, animateOut: Bool = false, transition: Transition) {
|
||||
guard let _ = self.controller else {
|
||||
@ -1090,6 +1190,7 @@ public final class MediaEditorScreen: ViewController {
|
||||
MediaEditorScreenComponent(
|
||||
context: self.context,
|
||||
mediaEditor: self.mediaEditor,
|
||||
privacy: self.storyPrivacy,
|
||||
openDrawing: { [weak self] mode in
|
||||
if let self {
|
||||
let controller = DrawingScreen(context: self.context, sourceHint: .storyEditor, size: self.previewContainerView.frame.size, originalSize: storyDimensions, isVideo: false, isAvatar: false, drawingView: self.drawingView, entitiesView: self.entitiesView, existingStickerPickerInputData: self.stickerPickerInputData)
|
||||
@ -1291,6 +1392,81 @@ public final class MediaEditorScreen: ViewController {
|
||||
super.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
func presentPrivacySettings() {
|
||||
enum AdditionalCategoryId: Int {
|
||||
case everyone
|
||||
case contacts
|
||||
case closeFriends
|
||||
}
|
||||
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
|
||||
|
||||
let additionalCategories: [ChatListNodeAdditionalCategory] = [
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.everyone.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white), cornerRadius: nil, color: .blue),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Filters/Channel"), color: .white), iconScale: 0.6, cornerRadius: 6.0, circleCorners: true, color: .blue),
|
||||
title: "Everyone",
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.contacts.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Tabs/IconContacts"), color: .white), iconScale: 1.0 * 0.8, cornerRadius: nil, color: .yellow),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Chat List/Tabs/IconContacts"), color: .white), iconScale: 0.6 * 0.8, cornerRadius: 6.0, circleCorners: true, color: .yellow),
|
||||
title: presentationData.strings.ChatListFolder_CategoryContacts,
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
),
|
||||
ChatListNodeAdditionalCategory(
|
||||
id: AdditionalCategoryId.closeFriends.rawValue,
|
||||
icon: generateAvatarImage(size: CGSize(width: 40.0, height: 40.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Call/StarHighlighted"), color: .white), iconScale: 1.0 * 0.6, cornerRadius: nil, color: .green),
|
||||
smallIcon: generateAvatarImage(size: CGSize(width: 22.0, height: 22.0), icon: generateTintedImage(image: UIImage(bundleImageName: "Call/StarHighlighted"), color: .white), iconScale: 0.6 * 0.6, cornerRadius: 6.0, circleCorners: true, color: .green),
|
||||
title: "Close Friends",
|
||||
appearance: .option(sectionTitle: "WHO CAN VIEW FOR 24 HOURS")
|
||||
)
|
||||
]
|
||||
|
||||
let updatedPresentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
|
||||
let selectionController = self.context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: self.context, updatedPresentationData: (initial: updatedPresentationData, signal: .single(updatedPresentationData)), mode: .chatSelection(ContactMultiselectionControllerMode.ChatSelection(
|
||||
title: "Share Story",
|
||||
searchPlaceholder: "Search contacts",
|
||||
selectedChats: Set(),
|
||||
additionalCategories: ContactMultiselectionControllerAdditionalCategories(categories: additionalCategories, selectedCategories: Set([AdditionalCategoryId.everyone.rawValue])),
|
||||
chatListFilters: nil,
|
||||
displayPresence: true
|
||||
)), options: [], filters: [.excludeSelf], alwaysEnabled: true, limit: 1000, reachedLimit: { _ in
|
||||
}))
|
||||
selectionController.navigationPresentation = .modal
|
||||
self.push(selectionController)
|
||||
|
||||
let _ = (selectionController.result
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak selectionController, weak self] result in
|
||||
selectionController?.dismiss()
|
||||
guard case let .result(peerIds, additionalCategoryIds) = result else {
|
||||
return
|
||||
}
|
||||
var privacy = EngineStoryPrivacy(base: .everyone, additionallyIncludePeers: [])
|
||||
if additionalCategoryIds.contains(AdditionalCategoryId.everyone.rawValue) {
|
||||
privacy.base = .everyone
|
||||
} else if additionalCategoryIds.contains(AdditionalCategoryId.contacts.rawValue) {
|
||||
privacy.base = .contacts
|
||||
} else if additionalCategoryIds.contains(AdditionalCategoryId.closeFriends.rawValue) {
|
||||
privacy.base = .closeFriends
|
||||
}
|
||||
privacy.additionallyIncludePeers = peerIds.compactMap { id -> EnginePeer.Id? in
|
||||
switch id {
|
||||
case let .peer(peerId):
|
||||
return peerId
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
self?.node.storyPrivacy = privacy
|
||||
self?.node.requestUpdate()
|
||||
})
|
||||
}
|
||||
|
||||
func requestDismiss(animated: Bool) {
|
||||
self.cancelled()
|
||||
|
||||
@ -1298,7 +1474,7 @@ public final class MediaEditorScreen: ViewController {
|
||||
self?.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
func requestCompletion(caption: NSAttributedString, animated: Bool) {
|
||||
guard let mediaEditor = self.node.mediaEditor, let subject = self.node.subject else {
|
||||
return
|
||||
@ -1383,32 +1559,56 @@ public final class MediaEditorScreen: ViewController {
|
||||
}
|
||||
|
||||
if mediaEditor.resultIsVideo {
|
||||
let exportSubject: MediaEditorVideoExport.Subject
|
||||
let exportSubject: Signal<MediaEditorVideoExport.Subject, NoError>
|
||||
switch subject {
|
||||
case let .video(path, _):
|
||||
let asset = AVURLAsset(url: NSURL(fileURLWithPath: path) as URL)
|
||||
exportSubject = .video(asset)
|
||||
exportSubject = .single(.video(asset))
|
||||
case let .image(image, _):
|
||||
exportSubject = .image(image)
|
||||
default:
|
||||
fatalError()
|
||||
exportSubject = .single(.image(image))
|
||||
case let .asset(asset):
|
||||
exportSubject = Signal { subscriber in
|
||||
if asset.mediaType == .video {
|
||||
PHImageManager.default().requestAVAsset(forVideo: asset, options: nil) { avAsset, _, _ in
|
||||
if let avAsset {
|
||||
subscriber.putNext(.video(avAsset))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let options = PHImageRequestOptions()
|
||||
options.deliveryMode = .highQualityFormat
|
||||
PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .default, options: options) { image, _ in
|
||||
if let image {
|
||||
subscriber.putNext(.image(image))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
}
|
||||
return EmptyDisposable
|
||||
}
|
||||
}
|
||||
|
||||
let configuration = recommendedVideoExportConfiguration(values: mediaEditor.values)
|
||||
let outputPath = NSTemporaryDirectory() + "\(Int64.random(in: 0 ..< .max)).mp4"
|
||||
let videoExport = MediaEditorVideoExport(account: self.context.account, subject: exportSubject, configuration: configuration, outputPath: outputPath)
|
||||
self.videoExport = videoExport
|
||||
|
||||
videoExport.startExport()
|
||||
|
||||
self.exportDisposable = (videoExport.status
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let self {
|
||||
if case .completed = status {
|
||||
self.videoExport = nil
|
||||
saveToPhotos(outputPath, true)
|
||||
}
|
||||
let _ = exportSubject.start(next: { [weak self] exportSubject in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let configuration = recommendedVideoExportConfiguration(values: mediaEditor.values)
|
||||
let outputPath = NSTemporaryDirectory() + "\(Int64.random(in: 0 ..< .max)).mp4"
|
||||
let videoExport = MediaEditorVideoExport(account: self.context.account, subject: exportSubject, configuration: configuration, outputPath: outputPath)
|
||||
self.videoExport = videoExport
|
||||
|
||||
videoExport.startExport()
|
||||
|
||||
self.exportDisposable = (videoExport.status
|
||||
|> deliverOnMainQueue).start(next: { [weak self] status in
|
||||
if let self {
|
||||
if case .completed = status {
|
||||
self.videoExport = nil
|
||||
saveToPhotos(outputPath, true)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
if let image = mediaEditor.resultImage {
|
||||
@ -1429,3 +1629,70 @@ public final class MediaEditorScreen: ViewController {
|
||||
(self.displayNode as! Node).containerLayoutUpdated(layout: layout, transition: Transition(transition))
|
||||
}
|
||||
}
|
||||
|
||||
final class PrivacyButtonComponent: CombinedComponent {
|
||||
let icon: UIImage
|
||||
let text: String
|
||||
|
||||
init(
|
||||
icon: UIImage,
|
||||
text: String
|
||||
) {
|
||||
self.icon = icon
|
||||
self.text = text
|
||||
}
|
||||
|
||||
static func ==(lhs: PrivacyButtonComponent, rhs: PrivacyButtonComponent) -> Bool {
|
||||
if lhs.text != rhs.text {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let background = Child(BlurredBackgroundComponent.self)
|
||||
let icon = Child(Image.self)
|
||||
let text = Child(Text.self)
|
||||
|
||||
return { context in
|
||||
let icon = icon.update(
|
||||
component: Image(image: context.component.icon, size: CGSize(width: 9.0, height: 11.0)),
|
||||
availableSize: CGSize(width: 180.0, height: 100.0),
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
let text = text.update(
|
||||
component: Text(
|
||||
text: "\(context.component.text)",
|
||||
font: Font.medium(14.0),
|
||||
color: .white
|
||||
),
|
||||
availableSize: CGSize(width: 180.0, height: 100.0),
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
let backgroundSize = CGSize(width: text.size.width + 38.0, height: 30.0)
|
||||
let background = background.update(
|
||||
component: BlurredBackgroundComponent(color: UIColor(white: 0.0, alpha: 0.5)),
|
||||
availableSize: backgroundSize,
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
context.add(background
|
||||
.position(CGPoint(x: backgroundSize.width / 2.0, y: backgroundSize.height / 2.0))
|
||||
.cornerRadius(min(backgroundSize.width, backgroundSize.height) / 2.0)
|
||||
.clipsToBounds(true)
|
||||
)
|
||||
|
||||
context.add(icon
|
||||
.position(CGPoint(x: 16.0, y: backgroundSize.height / 2.0))
|
||||
)
|
||||
|
||||
context.add(text
|
||||
.position(CGPoint(x: backgroundSize.width / 2.0 + 7.0, y: backgroundSize.height / 2.0))
|
||||
)
|
||||
|
||||
return backgroundSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Components/Close.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Components/Close.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "close.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
90
submodules/TelegramUI/Images.xcassets/Components/Close.imageset/close.pdf
vendored
Normal file
90
submodules/TelegramUI/Images.xcassets/Components/Close.imageset/close.pdf
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< /ExtGState << /E1 << /ca 0.500000 >> >> >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
/E1 gs
|
||||
1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
8.000000 0.000000 m
|
||||
12.418278 0.000000 16.000000 3.581722 16.000000 8.000000 c
|
||||
16.000000 12.418278 12.418278 16.000000 8.000000 16.000000 c
|
||||
3.581722 16.000000 0.000000 12.418278 0.000000 8.000000 c
|
||||
0.000000 3.581722 3.581722 0.000000 8.000000 0.000000 c
|
||||
h
|
||||
4.469631 11.530369 m
|
||||
4.762524 11.823262 5.237398 11.823262 5.530291 11.530369 c
|
||||
7.999961 9.060699 l
|
||||
10.469630 11.530369 l
|
||||
10.762524 11.823262 11.237397 11.823262 11.530291 11.530369 c
|
||||
11.823184 11.237476 11.823184 10.762602 11.530291 10.469709 c
|
||||
9.060621 8.000039 l
|
||||
11.530291 5.530370 l
|
||||
11.823184 5.237476 11.823184 4.762603 11.530291 4.469709 c
|
||||
11.237397 4.176816 10.762524 4.176816 10.469630 4.469709 c
|
||||
7.999961 6.939379 l
|
||||
5.530291 4.469709 l
|
||||
5.237398 4.176816 4.762524 4.176816 4.469631 4.469709 c
|
||||
4.176738 4.762603 4.176738 5.237476 4.469631 5.530370 c
|
||||
6.939301 8.000039 l
|
||||
4.469631 10.469709 l
|
||||
4.176738 10.762602 4.176738 11.237476 4.469631 11.530369 c
|
||||
h
|
||||
f*
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1048
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 16.000000 16.000000 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000074 00000 n
|
||||
0000001178 00000 n
|
||||
0000001201 00000 n
|
||||
0000001374 00000 n
|
||||
0000001448 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1507
|
||||
%%EOF
|
12
submodules/TelegramUI/Images.xcassets/Media Editor/Recipient.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Media Editor/Recipient.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Recipient.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
114
submodules/TelegramUI/Images.xcassets/Media Editor/Recipient.imageset/Recipient.pdf
vendored
Normal file
114
submodules/TelegramUI/Images.xcassets/Media Editor/Recipient.imageset/Recipient.pdf
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
%PDF-1.7
|
||||
|
||||
1 0 obj
|
||||
<< >>
|
||||
endobj
|
||||
|
||||
2 0 obj
|
||||
<< /Length 3 0 R >>
|
||||
stream
|
||||
/DeviceRGB CS
|
||||
/DeviceRGB cs
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 4.330078 -0.830017 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
-0.830000 1.660004 m
|
||||
-0.830000 1.201607 -0.458396 0.830004 0.000000 0.830004 c
|
||||
0.458396 0.830004 0.830000 1.201607 0.830000 1.660004 c
|
||||
-0.830000 1.660004 l
|
||||
h
|
||||
0.830000 9.160004 m
|
||||
0.830000 9.618400 0.458396 9.990004 0.000000 9.990004 c
|
||||
-0.458396 9.990004 -0.830000 9.618400 -0.830000 9.160004 c
|
||||
0.830000 9.160004 l
|
||||
h
|
||||
0.830000 1.660004 m
|
||||
0.830000 9.160004 l
|
||||
-0.830000 9.160004 l
|
||||
-0.830000 1.660004 l
|
||||
0.830000 1.660004 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
q
|
||||
1.000000 0.000000 -0.000000 1.000000 0.830078 4.507935 cm
|
||||
1.000000 1.000000 1.000000 scn
|
||||
-0.586899 2.408951 m
|
||||
-0.911034 2.084816 -0.911034 1.559289 -0.586899 1.235153 c
|
||||
-0.262763 0.911018 0.262763 0.911018 0.586899 1.235153 c
|
||||
-0.586899 2.408951 l
|
||||
h
|
||||
3.500000 5.322052 m
|
||||
4.086899 5.908951 l
|
||||
3.762764 6.233086 3.237236 6.233086 2.913101 5.908951 c
|
||||
3.500000 5.322052 l
|
||||
h
|
||||
6.413101 1.235153 m
|
||||
6.737236 0.911018 7.262764 0.911018 7.586899 1.235153 c
|
||||
7.911034 1.559289 7.911034 2.084816 7.586899 2.408951 c
|
||||
6.413101 1.235153 l
|
||||
h
|
||||
0.586899 1.235153 m
|
||||
4.086899 4.735153 l
|
||||
2.913101 5.908951 l
|
||||
-0.586899 2.408951 l
|
||||
0.586899 1.235153 l
|
||||
h
|
||||
2.913101 4.735153 m
|
||||
6.413101 1.235153 l
|
||||
7.586899 2.408951 l
|
||||
4.086899 5.908951 l
|
||||
2.913101 4.735153 l
|
||||
h
|
||||
f
|
||||
n
|
||||
Q
|
||||
|
||||
endstream
|
||||
endobj
|
||||
|
||||
3 0 obj
|
||||
1279
|
||||
endobj
|
||||
|
||||
4 0 obj
|
||||
<< /Annots []
|
||||
/Type /Page
|
||||
/MediaBox [ 0.000000 0.000000 8.660156 10.660004 ]
|
||||
/Resources 1 0 R
|
||||
/Contents 2 0 R
|
||||
/Parent 5 0 R
|
||||
>>
|
||||
endobj
|
||||
|
||||
5 0 obj
|
||||
<< /Kids [ 4 0 R ]
|
||||
/Count 1
|
||||
/Type /Pages
|
||||
>>
|
||||
endobj
|
||||
|
||||
6 0 obj
|
||||
<< /Pages 5 0 R
|
||||
/Type /Catalog
|
||||
>>
|
||||
endobj
|
||||
|
||||
xref
|
||||
0 7
|
||||
0000000000 65535 f
|
||||
0000000010 00000 n
|
||||
0000000034 00000 n
|
||||
0000001369 00000 n
|
||||
0000001392 00000 n
|
||||
0000001564 00000 n
|
||||
0000001638 00000 n
|
||||
trailer
|
||||
<< /ID [ (some) (id) ]
|
||||
/Root 6 0 R
|
||||
/Size 7
|
||||
>>
|
||||
startxref
|
||||
1697
|
||||
%%EOF
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
submodules/TelegramUI/Resources/Animations/flash_on.json
Normal file
1
submodules/TelegramUI/Resources/Animations/flash_on.json
Normal file
File diff suppressed because one or more lines are too long
@ -135,6 +135,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
private let animatedStickerNode: AnimatedStickerNode
|
||||
private var downArrowsNode: DownArrowsIconNode?
|
||||
private let textNode: ImmediateTextNode
|
||||
private let closeButtonNode: HighlightableButtonNode
|
||||
|
||||
private var isArrowInverted: Bool = false
|
||||
|
||||
@ -142,7 +143,7 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity], style: TooltipScreen.Style, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: TooltipScreen.DisplayDuration, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) {
|
||||
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, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, requestDismiss: @escaping () -> Void, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)?) {
|
||||
self.tooltipStyle = style
|
||||
self.icon = icon
|
||||
self.customContentNode = customContentNode
|
||||
@ -326,6 +327,9 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.downArrowsNode = DownArrowsIconNode()
|
||||
}
|
||||
|
||||
self.closeButtonNode = HighlightableButtonNode()
|
||||
self.closeButtonNode.setImage(UIImage(bundleImageName: "Components/Close"), for: .normal)
|
||||
|
||||
super.init()
|
||||
|
||||
self.containerNode.addSubnode(self.backgroundContainerNode)
|
||||
@ -338,6 +342,11 @@ 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 downArrowsNode = self.downArrowsNode {
|
||||
self.containerNode.addSubnode(downArrowsNode)
|
||||
}
|
||||
@ -402,6 +411,12 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
openActiveTextItem?(.hashtag(hashtag.hashtag), .longTap)
|
||||
}
|
||||
}
|
||||
|
||||
self.closeButtonNode.addTarget(self, action: #selector(self.closePressed), forControlEvents: .touchUpInside)
|
||||
}
|
||||
|
||||
@objc private func closePressed() {
|
||||
self.requestDismiss()
|
||||
}
|
||||
|
||||
func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
@ -453,7 +468,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
var invertArrow = false
|
||||
switch self.location {
|
||||
case let .point(rect, arrowPosition):
|
||||
let backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
||||
var backgroundWidth = textSize.width + contentInset * 2.0 + animationSize.width + animationSpacing
|
||||
if self.closeButtonNode.supernode != nil {
|
||||
backgroundWidth += 24.0
|
||||
}
|
||||
switch arrowPosition {
|
||||
case .bottom, .top:
|
||||
backgroundFrame = CGRect(origin: CGPoint(x: rect.midX - backgroundWidth / 2.0, y: rect.minY - bottomInset - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight))
|
||||
@ -533,7 +551,11 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
self.arrowNode.isHidden = true
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.textNode, frame: 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)
|
||||
|
||||
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))
|
||||
|
||||
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)
|
||||
@ -557,6 +579,10 @@ private final class TooltipScreenNode: ViewControllerTracingNode {
|
||||
eventIsPresses = event.type == .presses
|
||||
}
|
||||
if event.type == .touches || eventIsPresses {
|
||||
if case .manual = self.displayDuration {
|
||||
self.requestDismiss()
|
||||
return self.view
|
||||
}
|
||||
switch self.shouldDismissOnTouch(point) {
|
||||
case .ignore:
|
||||
break
|
||||
@ -680,6 +706,7 @@ public final class TooltipScreen: ViewController {
|
||||
case `default`
|
||||
case custom(Double)
|
||||
case infinite
|
||||
case manual
|
||||
}
|
||||
|
||||
public enum Style {
|
||||
@ -722,7 +749,20 @@ public final class TooltipScreen: ViewController {
|
||||
|
||||
public var alwaysVisible = false
|
||||
|
||||
public init(account: Account, sharedContext: SharedAccountContext, text: String, textEntities: [MessageTextEntity] = [], style: TooltipScreen.Style = .default, icon: TooltipScreen.Icon?, customContentNode: TooltipCustomContentNode? = nil, location: TooltipScreen.Location, displayDuration: DisplayDuration = .default, inset: CGFloat = 13.0, shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch, openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil) {
|
||||
public init(
|
||||
account: Account,
|
||||
sharedContext: SharedAccountContext,
|
||||
text: String,
|
||||
textEntities: [MessageTextEntity] = [],
|
||||
style: TooltipScreen.Style = .default,
|
||||
icon: TooltipScreen.Icon? = nil,
|
||||
customContentNode: TooltipCustomContentNode? = nil,
|
||||
location: TooltipScreen.Location,
|
||||
displayDuration: DisplayDuration = .default,
|
||||
inset: CGFloat = 13.0,
|
||||
shouldDismissOnTouch: @escaping (CGPoint) -> TooltipScreen.DismissOnTouch,
|
||||
openActiveTextItem: ((TooltipActiveTextItem, TooltipActiveTextAction) -> Void)? = nil
|
||||
) {
|
||||
self.account = account
|
||||
self.sharedContext = sharedContext
|
||||
self.text = text
|
||||
@ -766,7 +806,7 @@ public final class TooltipScreen: ViewController {
|
||||
timeout = 5.0
|
||||
case let .custom(value):
|
||||
timeout = value
|
||||
case .infinite:
|
||||
case .infinite, .manual:
|
||||
return
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user