diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index e7ebc8905b..184bacf28b 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -899,7 +899,7 @@ public protocol SharedAccountContext: AnyObject { func makeProxySettingsController(sharedContext: SharedAccountContext, account: UnauthorizedAccount) -> ViewController - func makeInstalledStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode) -> ViewController + func makeInstalledStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, forceTheme: PresentationTheme?) -> ViewController func makeDebugSettingsController(context: AccountContext?) -> ViewController? diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 6df8f407db..9fab152207 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2566,10 +2566,42 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return } let _ = self.context.engine.peers.togglePeerStoriesMuted(peerId: peer.id).start() + + let iconColor = UIColor.white + let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } + if isMuted { + self.present(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will now get a notification whenever **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + } else { + self.present(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will no longer receive a notification when **\(peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), in: .current) + } }))) - items.append(.action(ContextMenuActionItem(text: "Archive", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) + items.append(.action(ContextMenuActionItem(text: "Hide", icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/MoveToContacts"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) @@ -2577,6 +2609,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController return } self.context.engine.peers.updatePeerStoriesHidden(id: peer.id, isHidden: true) + + }))) } diff --git a/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift b/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift index ddd732d64b..58194b2174 100644 --- a/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift +++ b/submodules/FeaturedStickersScreen/Sources/FeaturedStickersScreen.swift @@ -370,6 +370,7 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { let highlightedPackId = controller.highlightedPackId + let forceTheme = controller.forceTheme self.disposable = (combineLatest(queue: .mainQueue(), mappedFeatured, self.additionalPacks.get(), @@ -377,6 +378,11 @@ private final class FeaturedStickersScreenNode: ViewControllerTracingNode { context.sharedContext.presentationData ) |> map { featuredEntries, additionalPacks, view, presentationData -> FeaturedTransition in + var presentationData = presentationData + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + var installedPacks = Set() if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView { if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] { @@ -801,6 +807,7 @@ public final class FeaturedStickersScreen: ViewController { private var presentationData: PresentationData private var presentationDataDisposable: Disposable? + fileprivate let forceTheme: PresentationTheme? private let _ready = Promise() override public var ready: Promise { @@ -809,12 +816,18 @@ public final class FeaturedStickersScreen: ViewController { fileprivate var searchNavigationNode: SearchNavigationContentNode? - public init(context: AccountContext, highlightedPackId: ItemCollectionId?, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil) { + public init(context: AccountContext, highlightedPackId: ItemCollectionId?, forceTheme: PresentationTheme? = nil, sendSticker: ((FileMediaReference, UIView, CGRect) -> Bool)? = nil) { self.context = context self.highlightedPackId = highlightedPackId self.sendSticker = sendSticker - self.presentationData = context.sharedContext.currentPresentationData.with { $0 } + var presentationData = context.sharedContext.currentPresentationData.with { $0 } + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + + self.presentationData = presentationData + self.forceTheme = forceTheme super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData)) @@ -833,6 +846,11 @@ public final class FeaturedStickersScreen: ViewController { |> deliverOnMainQueue).start(next: { [weak self] presentationData in if let strongSelf = self { let previous = strongSelf.presentationData + + var presentationData = presentationData + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } strongSelf.presentationData = presentationData if previous.theme !== presentationData.theme || previous.strings !== presentationData.strings { diff --git a/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift b/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift index c72c87f6c8..7cb21fde38 100644 --- a/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift +++ b/submodules/SettingsUI/Sources/Stickers/ArchivedStickerPacksController.swift @@ -242,7 +242,7 @@ private func archivedStickerPacksControllerEntries(context: AccountContext, pres return entries } -public func archivedStickerPacksController(context: AccountContext, mode: ArchivedStickerPacksControllerMode, archived: [ArchivedStickerPackItem]?, updatedPacks: @escaping ([ArchivedStickerPackItem]?) -> Void) -> ViewController { +public func archivedStickerPacksController(context: AccountContext, mode: ArchivedStickerPacksControllerMode, archived: [ArchivedStickerPackItem]?, forceTheme: PresentationTheme? = nil, updatedPacks: @escaping ([ArchivedStickerPackItem]?) -> Void) -> ViewController { let statePromise = ValuePromise(ArchivedStickerPacksControllerState(), ignoreRepeated: true) let stateValue = Atomic(value: ArchivedStickerPacksControllerState()) let updateState: ((ArchivedStickerPacksControllerState) -> ArchivedStickerPacksControllerState) -> Void = { f in @@ -279,6 +279,11 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv let installedStickerPacks = Promise() installedStickerPacks.set(context.account.postbox.combinedView(keys: [.itemCollectionIds(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])])) + var presentationData = context.sharedContext.currentPresentationData.with { $0 } + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + var presentStickerPackController: ((StickerPackCollectionInfo) -> Void)? let arguments = ArchivedStickerPacksControllerArguments(context: context, openStickerPack: { info in @@ -325,8 +330,6 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv return .complete() } |> deliverOnMainQueue).start(next: { info, items in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - var animateInAsReplacement = false if let navigationController = navigationControllerImpl?() { for controller in navigationController.overlayControllers { @@ -419,6 +422,11 @@ public func archivedStickerPacksController(context: AccountContext, mode: Archiv let signal = combineLatest(context.sharedContext.presentationData, statePromise.get() |> deliverOnMainQueue, stickerPacks.get() |> deliverOnMainQueue, installedStickerPacks.get() |> deliverOnMainQueue, context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings]) |> deliverOnMainQueue) |> deliverOnMainQueue |> map { presentationData, state, packs, installedView, sharedData -> (ItemListControllerState, (ItemListNodeState, Any)) in + var presentationData = presentationData + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + var stickerSettings = StickerSettings.defaultSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value diff --git a/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift b/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift index 3df985500b..fa6bbb2bdd 100644 --- a/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift +++ b/submodules/SettingsUI/Sources/Stickers/InstalledStickerPacksController.swift @@ -616,7 +616,7 @@ private func installedStickerPacksControllerEntries(context: AccountContext, pre return entries } -public func installedStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, archivedPacks: [ArchivedStickerPackItem]? = nil, updatedPacks: @escaping ([ArchivedStickerPackItem]?) -> Void = { _ in }, focusOnItemTag: InstalledStickerPacksEntryTag? = nil) -> ViewController { +public func installedStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, archivedPacks: [ArchivedStickerPackItem]? = nil, updatedPacks: @escaping ([ArchivedStickerPackItem]?) -> Void = { _ in }, focusOnItemTag: InstalledStickerPacksEntryTag? = nil, forceTheme: PresentationTheme? = nil) -> ViewController { let initialState = InstalledStickerPacksControllerState().withUpdatedEditing(mode == .modal).withUpdatedSelectedPackIds(mode == .modal ? Set() : nil) let statePromise = ValuePromise(initialState, ignoreRepeated: true) let stateValue = Atomic(value: initialState) @@ -624,6 +624,11 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta statePromise.set(stateValue.modify { f($0) }) } + var presentationData = context.sharedContext.currentPresentationData.with { $0 } + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? var pushControllerImpl: ((ViewController) -> Void)? var navigateToChatControllerImpl: ((PeerId) -> Void)? @@ -650,7 +655,6 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta } } }, removePack: { archivedItem in - let presentationData = context.sharedContext.currentPresentationData.with { $0 } let controller = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak controller] in controller?.dismissAnimated() @@ -734,15 +738,15 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta } })) }, openMasks: { - pushControllerImpl?(installedStickerPacksController(context: context, mode: .masks, archivedPacks: archivedPacks, updatedPacks: { _ in})) + pushControllerImpl?(installedStickerPacksController(context: context, mode: .masks, archivedPacks: archivedPacks, updatedPacks: { _ in }, forceTheme: forceTheme)) }, openEmoji: { - pushControllerImpl?(installedStickerPacksController(context: context, mode: .emoji, archivedPacks: archivedPacks, updatedPacks: { _ in})) + pushControllerImpl?(installedStickerPacksController(context: context, mode: .emoji, archivedPacks: archivedPacks, updatedPacks: { _ in }, forceTheme: forceTheme)) }, openQuickReaction: { pushControllerImpl?(quickReactionSetupController( context: context )) }, openFeatured: { - pushControllerImpl?(FeaturedStickersScreen(context: context, highlightedPackId: nil)) + pushControllerImpl?(FeaturedStickersScreen(context: context, highlightedPackId: nil, forceTheme: forceTheme)) }, openArchived: { archived in let archivedMode: ArchivedStickerPacksControllerMode switch mode { @@ -753,12 +757,11 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta default: archivedMode = .stickers } - pushControllerImpl?(archivedStickerPacksController(context: context, mode: archivedMode, archived: archived, updatedPacks: { packs in + pushControllerImpl?(archivedStickerPacksController(context: context, mode: archivedMode, archived: archived, forceTheme: forceTheme, updatedPacks: { packs in archivedPromise.set(.single(packs)) updatedPacks(packs) })) }, openSuggestOptions: { - let presentationData = context.sharedContext.currentPresentationData.with { $0 } let controller = ActionSheetController(presentationData: presentationData) let dismissAction: () -> Void = { [weak controller] in controller?.dismissAnimated() @@ -889,6 +892,11 @@ public func installedStickerPacksController(context: AccountContext, mode: Insta ) |> deliverOnMainQueue |> map { presentationData, state, view, temporaryPackOrder, featuredAndArchived, sharedData, quickReaction, availableReactions, emojiCount -> (ItemListControllerState, (ItemListNodeState, Any)) in + var presentationData = presentationData + if let forceTheme { + presentationData = presentationData.withUpdated(theme: forceTheme) + } + var stickerSettings = StickerSettings.defaultSettings if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) { stickerSettings = value diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift index 155aa5352f..f8519c044b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift @@ -609,7 +609,11 @@ private func apiInputPrivacyRules(privacy: EngineStoryPrivacy, transaction: Tran case .closeFriends: privacyRules = [.inputPrivacyValueAllowCloseFriends] case .nobody: - privacyRules = [.inputPrivacyValueDisallowAll] + if privacy.additionallyIncludePeers.isEmpty { + privacyRules = [.inputPrivacyValueDisallowAll] + } else { + privacyRules = [] + } } var privacyUsers: [Api.InputUser] = [] var privacyChats: [Int64] = [] @@ -833,7 +837,7 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId } } -func _internal_editStory(account: Account, media: EngineStoryInputMedia?, id: Int32, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy?) -> Signal { +func _internal_editStory(account: Account, media: EngineStoryInputMedia?, id: Int32, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy?) -> Signal { let contentSignal: Signal let originalMedia: Media? if let media = media { @@ -865,13 +869,11 @@ func _internal_editStory(account: Account, media: EngineStoryInputMedia?, id: In if let _ = inputMedia { flags |= 1 << 0 } - if !text.isEmpty { + if let text = text { flags |= 1 << 1 apiCaption = text - if !entities.isEmpty { - flags |= 1 << 1 - + if let entities = entities { var associatedPeers: [PeerId: Peer] = [:] for entity in entities { for entityPeerId in entity.associatedPeerIds { @@ -1184,6 +1186,10 @@ extension Stories.StoredItem { for id in users { additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) } + case let .privacyValueDisallowUsers(users): + for id in users { + additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) + } case let .privacyValueAllowChatParticipants(chats): for id in chats { if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 4638c3eb67..58a44b0d09 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -939,7 +939,7 @@ public extension TelegramEngine { _internal_cancelStoryUpload(account: self.account, stableId: stableId) } - public func editStory(media: EngineStoryInputMedia?, id: Int32, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy?) -> Signal { + public func editStory(media: EngineStoryInputMedia?, id: Int32, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy?) -> Signal { return _internal_editStory(account: self.account, media: media, id: id, text: text, entities: entities, privacy: privacy) } diff --git a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift index 12a164e5c0..9f605e94c4 100644 --- a/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/ChatEntityKeyboardInputNode/Sources/ChatEntityKeyboardInputNode.swift @@ -88,6 +88,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { let presentGlobalOverlayController: (ViewController, Any?) -> Void let getNavigationController: () -> NavigationController? let requestLayout: (ContainedViewLayoutTransition) -> Void + public var forceTheme: PresentationTheme? public init( sendSticker: @escaping (FileMediaReference, Bool, Bool, String?, Bool, UIView, CGRect, CALayer?, [ItemCollectionId]) -> Bool, @@ -1333,6 +1334,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { interaction.getNavigationController()?.pushViewController(FeaturedStickersScreen( context: context, highlightedPackId: featuredStickerPack.info.id, + forceTheme: interaction.forceTheme, sendSticker: { [weak interaction] fileReference, sourceNode, sourceRect in guard let interaction else { return false @@ -1369,7 +1371,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { guard let interaction else { return } - let controller = context.sharedContext.makeInstalledStickerPacksController(context: context, mode: .modal) + let controller = context.sharedContext.makeInstalledStickerPacksController(context: context, mode: .modal, forceTheme: interaction.forceTheme) controller.navigationPresentation = .modal interaction.getNavigationController()?.pushViewController(controller) }, @@ -1381,6 +1383,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode { interaction.getNavigationController()?.pushViewController(FeaturedStickersScreen( context: context, highlightedPackId: nil, + forceTheme: interaction.forceTheme, sendSticker: { [weak interaction] fileReference, sourceNode, sourceRect in guard let interaction else { return false diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index 638ea6f41d..5ea0fe1d83 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -417,22 +417,22 @@ final class MediaEditorScreenComponent: Component { } if let view = self.saveButton.view { - view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + view.layer.animateAlpha(from: 0.0, to: view.alpha, duration: 0.2) view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2) } if let view = self.muteButton.view { - view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + view.layer.animateAlpha(from: 0.0, to: view.alpha, duration: 0.2) view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2) } if let view = self.settingsButton.view { - view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + view.layer.animateAlpha(from: 0.0, to: view.alpha, 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.animateAlpha(from: 0.0, to: view.alpha, duration: 0.2) view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2) } @@ -603,6 +603,12 @@ final class MediaEditorScreenComponent: Component { let environment = environment[ViewControllerComponentContainer.Environment.self].value self.environment = environment + if self.component == nil { + if let controller = environment.controller() as? MediaEditorScreen { + self.inputPanelExternalState.initialText = controller.initialCaption + } + } + self.component = component self.state = state @@ -1051,7 +1057,8 @@ final class MediaEditorScreenComponent: Component { transition.setAlpha(view: inputPanelView, alpha: isEditingTextEntity || component.isDisplayingTool || component.isDismissing || component.isInteractingWithEntities ? 0.0 : 1.0) } - let privacyText: String + let additionalPeersCount = component.privacy.privacy.additionallyIncludePeers.count + var privacyText: String switch component.privacy.privacy.base { case .everyone: privacyText = "Everyone" @@ -1059,8 +1066,16 @@ final class MediaEditorScreenComponent: Component { privacyText = "Close Friends" case .contacts: privacyText = "Contacts" + if additionalPeersCount > 0 { + privacyText += " (-\(additionalPeersCount))" + } case .nobody: privacyText = "Selected Contacts" + if additionalPeersCount > 0 { + privacyText += " (\(additionalPeersCount))" + } else { + privacyText = "Only You" + } } let displayTopButtons = !(self.inputPanelExternalState.isEditing || isEditingTextEntity || component.isDisplayingTool) @@ -1549,6 +1564,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate private var isDismissed = false private var isDismissBySwipeSuppressed = false + fileprivate var hasAnyChanges = false + private var presentationData: PresentationData private var validLayout: ContainerViewLayout? @@ -1698,7 +1715,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let isSavingAvailable: Bool switch subject { case .image, .video: - isSavingAvailable = true + isSavingAvailable = !controller.isEditingStory default: isSavingAvailable = false } @@ -1776,6 +1793,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate if !isSavingAvailable && controller.previousSavedValues == nil { controller.previousSavedValues = values } else { + self.hasAnyChanges = true + controller.isSavingAvailable = true controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut)) } @@ -2258,11 +2277,17 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate completion() }) } else { - self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.4, removeOnCompletion: false) - self.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - self.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: self.bounds.height), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { _ in - completion() - }) + if controller.isEditingStory { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.4, removeOnCompletion: false, completion: { _ in + completion() + }) + } else { + self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.4, removeOnCompletion: false) + self.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) + self.layer.animatePosition(from: .zero, to: CGPoint(x: 0.0, y: self.bounds.height), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true, completion: { _ in + completion() + }) + } } } @@ -2566,6 +2591,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let stickerEntity = DrawingStickerEntity(content: .file(file)) self.interaction?.insertEntity(stickerEntity) + self.hasAnyChanges = true self.controller?.isSavingAvailable = true self.controller?.requestLayout(transition: .immediate) } @@ -2585,6 +2611,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let textEntity = DrawingTextEntity(text: NSAttributedString(), style: .regular, animation: .none, font: .sanFrancisco, alignment: .center, fontSize: 1.0, color: DrawingColor(color: .white)) self.interaction?.insertEntity(textEntity) + self.hasAnyChanges = true self.controller?.isSavingAvailable = true self.controller?.requestLayout(transition: .immediate) return @@ -2817,17 +2844,22 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate case videoFile(path: String) case asset(localIdentifier: String) } - case image(image: UIImage, dimensions: PixelDimensions, caption: NSAttributedString?) - case video(video: VideoResult, coverImage: UIImage?, values: MediaEditorValues, duration: Double, dimensions: PixelDimensions, caption: NSAttributedString?) + case image(image: UIImage, dimensions: PixelDimensions) + case video(video: VideoResult, coverImage: UIImage?, values: MediaEditorValues, duration: Double, dimensions: PixelDimensions) } fileprivate let context: AccountContext fileprivate let subject: Signal + fileprivate let isEditingStory: Bool + + fileprivate let initialCaption: NSAttributedString? + fileprivate let initialPrivacy: EngineStoryPrivacy? + fileprivate let transitionIn: TransitionIn? fileprivate let transitionOut: (Bool, Bool?) -> TransitionOut? public var cancelled: (Bool) -> Void = { _ in } - public var completion: (Int64, MediaEditorScreen.Result, MediaEditorResultPrivacy, @escaping (@escaping () -> Void) -> Void) -> Void = { _, _, _, _ in } + public var completion: (Int64, MediaEditorScreen.Result?, NSAttributedString, MediaEditorResultPrivacy , @escaping (@escaping () -> Void) -> Void) -> Void = { _, _, _, _, _ in } public var dismissed: () -> Void = { } private let hapticFeedback = HapticFeedback() @@ -2835,12 +2867,18 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate public init( context: AccountContext, subject: Signal, + isEditing: Bool, + initialCaption: NSAttributedString? = nil, + initialPrivacy: EngineStoryPrivacy? = nil, transitionIn: TransitionIn?, transitionOut: @escaping (Bool, Bool?) -> TransitionOut?, - completion: @escaping (Int64, MediaEditorScreen.Result, MediaEditorResultPrivacy, @escaping (@escaping () -> Void) -> Void) -> Void + completion: @escaping (Int64, MediaEditorScreen.Result?, NSAttributedString, MediaEditorResultPrivacy, @escaping (@escaping () -> Void) -> Void) -> Void ) { self.context = context self.subject = subject + self.isEditingStory = isEditing + self.initialCaption = initialCaption + self.initialPrivacy = initialPrivacy self.transitionIn = transitionIn self.transitionOut = transitionOut self.completion = completion @@ -2851,6 +2889,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate super.init(navigationBarPresentationData: nil) + if let initialPrivacy { + self.state.privacy = MediaEditorResultPrivacy(privacy: initialPrivacy, timeout: 86400, archive: false) + } + self.automaticallyControlPresentationContextLayout = false self.navigationPresentation = .flatModal @@ -2894,6 +2936,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate ShareWithPeersScreen( context: self.context, initialPrivacy: initialPrivacy, + timeout: timeout, stateContext: stateContext, completion: { [weak self] privacy in guard let self else { @@ -2928,6 +2971,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate ShareWithPeersScreen( context: self.context, initialPrivacy: privacy, + timeout: 0, stateContext: stateContext, completion: { [weak self] result in guard let self else { @@ -2935,8 +2979,10 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } if case .closeFriends = privacy.base { let _ = self.context.engine.privacy.updateCloseFriends(peerIds: result.additionallyIncludePeers).start() + completion(EngineStoryPrivacy(base: .closeFriends, additionallyIncludePeers: [])) + } else { + completion(result) } - completion(result) }, editCategory: { _ in } ) @@ -3051,6 +3097,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } func isEligibleForDraft() -> Bool { + if self.isEditingStory { + return false + } guard let mediaEditor = self.node.mediaEditor else { return false } @@ -3235,13 +3284,26 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate mediaEditor.setDrawingAndEntities(data: nil, image: mediaEditor.values.drawing, entities: codableEntities) let caption = self.getCaption() - let randomId: Int64 if case let .draft(_, id) = subject, let id { randomId = id } else { randomId = Int64.random(in: .min ... .max) } + + if self.isEditingStory && !self.node.hasAnyChanges { + self.completion(randomId, nil, caption, self.state.privacy, { [weak self] finished in + self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in + self?.dismiss() + Queue.mainQueue().justDispatch { + finished() + } + }) + }) + + return + } + if mediaEditor.resultIsVideo { var firstFrame: Signal let firstFrameTime = CMTime(seconds: mediaEditor.values.videoTrimRange?.lowerBound ?? 0.0, preferredTimescale: CMTimeScale(60)) @@ -3357,7 +3419,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate if let self { makeEditorImageComposition(account: self.context.account, inputImage: image ?? UIImage(), dimensions: storyDimensions, values: mediaEditor.values, time: .zero, completion: { [weak self] coverImage in if let self { - self.completion(randomId, .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions, caption: caption), self.state.privacy, { [weak self] finished in + self.completion(randomId, .video(video: videoResult, coverImage: coverImage, values: mediaEditor.values, duration: duration, dimensions: mediaEditor.values.resultDimensions), caption, self.state.privacy, { [weak self] finished in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.dismiss() Queue.mainQueue().justDispatch { @@ -3379,7 +3441,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate makeEditorImageComposition(account: self.context.account, inputImage: image, dimensions: storyDimensions, values: mediaEditor.values, time: .zero, completion: { [weak self] resultImage in if let self, let resultImage { - self.completion(randomId, .image(image: resultImage, dimensions: PixelDimensions(resultImage.size), caption: caption), self.state.privacy, { [weak self] finished in + self.completion(randomId, .image(image: resultImage, dimensions: PixelDimensions(resultImage.size)), caption, self.state.privacy, { [weak self] finished in self?.node.animateOut(finished: true, saveDraft: false, completion: { [weak self] in self?.dismiss() Queue.mainQueue().justDispatch { diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaToolsScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaToolsScreen.swift index ae5a6d0f1b..087f543e9f 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaToolsScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaToolsScreen.swift @@ -268,7 +268,7 @@ private final class MediaToolsScreenComponent: Component { view.layer.animatePosition(from: CGPoint(x: 0.0, y: 64.0), to: .zero, duration: 0.3, delay: delay, timingFunction: kCAMediaTimingFunctionSpring, additive: true) view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, delay: delay) view.layer.animateScale(from: 0.1, to: 1.0, duration: 0.2, delay: delay) - delay += 0.05 + delay += 0.03 } } diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/VideoScrubberComponent.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/VideoScrubberComponent.swift index 5852caa200..ce70885505 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/VideoScrubberComponent.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/VideoScrubberComponent.swift @@ -116,6 +116,7 @@ final class VideoScrubberComponent: Component { private let leftHandleView = HandleView() private let rightHandleView = HandleView() private let borderView = UIImageView() + private let zoneView = HandleView() private let cursorView = HandleView() private let transparentFramesContainer = UIView() @@ -202,11 +203,13 @@ final class VideoScrubberComponent: Component { self.addSubview(self.transparentFramesContainer) self.addSubview(self.opaqueFramesContainer) + self.addSubview(self.zoneView) self.addSubview(self.leftHandleView) self.addSubview(self.rightHandleView) self.addSubview(self.borderView) self.addSubview(self.cursorView) + self.zoneView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handleZoneHandlePan(_:)))) self.leftHandleView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handleLeftHandlePan(_:)))) self.rightHandleView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handleRightHandlePan(_:)))) self.cursorView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.handlePositionHandlePan(_:)))) @@ -225,6 +228,42 @@ final class VideoScrubberComponent: Component { self.displayLink?.invalidate() } + @objc private func handleZoneHandlePan(_ gestureRecognizer: UIPanGestureRecognizer) { + guard let component = self.component else { + return + } + let translation = gestureRecognizer.translation(in: self) + + let start = handleWidth / 2.0 + let end = self.frame.width - handleWidth / 2.0 + let length = end - start + + let delta = translation.x / length + + let duration = component.endPosition - component.startPosition + let startValue = max(0.0, min(component.duration - duration, component.startPosition + delta)) + let endValue = startValue + duration + + var transition: Transition = .immediate + switch gestureRecognizer.state { + case .began, .changed: + self.isPanningTrimHandle = true + component.trimUpdated(startValue, endValue, false, false) + if case .began = gestureRecognizer.state { + transition = .easeInOut(duration: 0.25) + } + case .ended, .cancelled: + self.isPanningTrimHandle = false + component.trimUpdated(startValue, endValue, false, true) + transition = .easeInOut(duration: 0.25) + default: + break + } + + gestureRecognizer.setTranslation(.zero, in: self) + self.state?.updated(transition: transition) + } + @objc private func handleLeftHandlePan(_ gestureRecognizer: UIPanGestureRecognizer) { guard let component = self.component else { return @@ -413,6 +452,9 @@ final class VideoScrubberComponent: Component { let rightHandleFrame = CGRect(origin: CGPoint(x: max(leftHandleFrame.maxX, rightHandlePosition - handleWidth / 2.0), y: 0.0), size: CGSize(width: handleWidth, height: scrubberSize.height)) transition.setFrame(view: self.rightHandleView, frame: rightHandleFrame) + + let zoneFrame = CGRect(x: leftHandleFrame.maxX, y: 0.0, width: rightHandleFrame.minX - leftHandleFrame.maxX, height: scrubberSize.height) + transition.setFrame(view: self.zoneView, frame: zoneFrame) if self.isPanningPositionHandle || !component.isPlaying { self.positionAnimation = nil diff --git a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/InputContextQueries.swift b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/InputContextQueries.swift index bfc41b5b60..4a36e6044c 100644 --- a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/InputContextQueries.swift +++ b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/InputContextQueries.swift @@ -118,7 +118,7 @@ private func updatedContextQueryResultStateForQuery(context: AccountContext, inp let peers: Signal<(ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult?, ChatContextQueryError> = context.engine.contacts.searchLocalPeers(query: normalizedQuery) |> map { peersAndPresences -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in let peers = peersAndPresences.filter { peer in - if let peer = peer.peer, case .user = peer { + if let peer = peer.peer, case .user = peer, peer.addressName != nil { return true } else { return false diff --git a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift index d84aadf523..37270d3685 100644 --- a/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift +++ b/submodules/TelegramUI/Components/MessageInputPanelComponent/Sources/MessageInputPanelComponent.swift @@ -30,6 +30,8 @@ public final class MessageInputPanelComponent: Component { public fileprivate(set) var hasText: Bool = false public fileprivate(set) var isKeyboardHidden: Bool = false + public var initialText: NSAttributedString? + public fileprivate(set) var insertText: (NSAttributedString) -> Void = { _ in } public fileprivate(set) var deleteBackward: () -> Void = { } @@ -366,6 +368,11 @@ public final class MessageInputPanelComponent: Component { self.component = component self.state = state + + if let initialText = component.externalState.initialText { + component.externalState.initialText = nil + self.textFieldExternalState.initialText = initialText + } let hasMediaRecording = component.audioRecorder != nil || component.videoRecordingStatus != nil let hasMediaEditing = component.recordedAudioPreview != nil diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index 59e5ad059b..160441f87e 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -25,6 +25,7 @@ final class ShareWithPeersScreenComponent: Component { let context: AccountContext let stateContext: ShareWithPeersScreen.StateContext let initialPrivacy: EngineStoryPrivacy + let timeout: Int let categoryItems: [CategoryItem] let completion: (EngineStoryPrivacy) -> Void let editCategory: (EngineStoryPrivacy) -> Void @@ -34,6 +35,7 @@ final class ShareWithPeersScreenComponent: Component { context: AccountContext, stateContext: ShareWithPeersScreen.StateContext, initialPrivacy: EngineStoryPrivacy, + timeout: Int, categoryItems: [CategoryItem], completion: @escaping (EngineStoryPrivacy) -> Void, editCategory: @escaping (EngineStoryPrivacy) -> Void, @@ -42,6 +44,7 @@ final class ShareWithPeersScreenComponent: Component { self.context = context self.stateContext = stateContext self.initialPrivacy = initialPrivacy + self.timeout = timeout self.categoryItems = categoryItems self.completion = completion self.editCategory = editCategory @@ -58,6 +61,9 @@ final class ShareWithPeersScreenComponent: Component { if lhs.initialPrivacy != rhs.initialPrivacy { return false } + if lhs.timeout != rhs.timeout { + return false + } if lhs.categoryItems != rhs.categoryItems { return false } @@ -237,6 +243,7 @@ final class ShareWithPeersScreenComponent: Component { private var selectedPeers: [EnginePeer.Id] = [] private var selectedCategories = Set() + private var selectedPeersByCategory: [CategoryId: [EnginePeer.Id]] = [:] private var component: ShareWithPeersScreenComponent? private weak var state: EmptyComponentState? @@ -447,7 +454,8 @@ final class ShareWithPeersScreenComponent: Component { let sectionTitle: String if section.id == 0 { - sectionTitle = "WHO CAN VIEW FOR 24 HOURS" + let hours = component.timeout / 3600 + sectionTitle = "WHO CAN VIEW FOR \(hours) HOURS" } else { if case .chats = component.stateContext.subject { sectionTitle = "CHATS" @@ -522,8 +530,14 @@ final class ShareWithPeersScreenComponent: Component { if self.selectedCategories.contains(categoryId) { } else { self.selectedPeers = [] + self.selectedCategories.removeAll() self.selectedCategories.insert(categoryId) + + if self.selectedPeers.isEmpty && categoryId == .selectedContacts { + component.editCategory(EngineStoryPrivacy(base: .nobody, additionallyIncludePeers: [])) + controller.dismiss() + } } self.state?.updated(transition: Transition(animation: .curve(duration: 0.35, curve: .spring))) }, @@ -1233,7 +1247,7 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer { self.initialPeerIds = Set(selectedPeers.map { $0.id }) } else { for peer in contactList.peers { - if case let .user(user) = peer, initialPeerIds.contains(user.id) { + if case let .user(user) = peer, initialPeerIds.contains(user.id), !user.isDeleted { selectedPeers.append(peer) } } @@ -1249,7 +1263,7 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer { }) var peers: [EnginePeer] = [] - peers = contactList.peers.filter { !self.initialPeerIds.contains($0.id) && $0.id != context.account.peerId }.sorted(by: { lhs, rhs in + peers = contactList.peers.filter { !self.initialPeerIds.contains($0.id) && $0.id != context.account.peerId && !$0.isDeleted }.sorted(by: { lhs, rhs in let result = lhs.indexName.isLessThan(other: rhs.indexName, ordering: .firstLast) if result == .orderedSame { return lhs.id < rhs.id @@ -1297,7 +1311,7 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer { private var isDismissed: Bool = false - public init(context: AccountContext, initialPrivacy: EngineStoryPrivacy, stateContext: StateContext, completion: @escaping (EngineStoryPrivacy) -> Void, editCategory: @escaping (EngineStoryPrivacy) -> Void, secondaryAction: @escaping () -> Void = {}) { + public init(context: AccountContext, initialPrivacy: EngineStoryPrivacy, timeout: Int, stateContext: StateContext, completion: @escaping (EngineStoryPrivacy) -> Void, editCategory: @escaping (EngineStoryPrivacy) -> Void, secondaryAction: @escaping () -> Void = {}) { self.context = context var categoryItems: [ShareWithPeersScreenComponent.CategoryItem] = [] @@ -1328,7 +1342,7 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer { title: "Selected Contacts", icon: "Chat List/Filters/Group", iconColor: .violet, - actionTitle: "edit list" + actionTitle: "choose" )) } @@ -1336,6 +1350,7 @@ public class ShareWithPeersScreen: ViewControllerComponentContainer { context: context, stateContext: stateContext, initialPrivacy: initialPrivacy, + timeout: timeout, categoryItems: categoryItems, completion: completion, editCategory: editCategory, diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/BUILD b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/BUILD index e3cc085688..7a06ea4503 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/BUILD +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/BUILD @@ -65,6 +65,8 @@ swift_library( "//submodules/OverlayStatusController", "//submodules/Utils/VolumeButtons", "//submodules/TelegramUI/Components/PeerReportScreen", + "//submodules/LocalMediaResources", + "//submodules/SaveToCameraRoll", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift index 301f6ff08d..551b34ae58 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerComponent.swift @@ -25,6 +25,9 @@ import PresentationDataUtils import PeerReportScreen import ChatEntityKeyboardInputNode import TextFieldComponent +import TextFormat +import LocalMediaResources +import SaveToCameraRoll public final class StoryItemSetContainerComponent: Component { public final class ExternalState { @@ -578,7 +581,8 @@ public final class StoryItemSetContainerComponent: Component { return true } if let navigationController = component.controller()?.navigationController as? NavigationController { - if !(navigationController.topViewController is StoryContainerScreen) { + let topViewController = navigationController.topViewController + if !(topViewController is StoryContainerScreen) && !(topViewController is MediaEditorScreen) { return true } } @@ -1222,7 +1226,9 @@ public final class StoryItemSetContainerComponent: Component { let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) var items: [ContextMenuItem] = [] - items.append(.action(ContextMenuActionItem(text: component.slice.additionalPeerData.isMuted ? "Notify" : "Not Notify", icon: { theme in + + let isMuted = component.slice.additionalPeerData.isMuted + items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Not Notify", icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: component.slice.additionalPeerData.isMuted ? "Chat/Context Menu/Unmute" : "Chat/Context Menu/Muted"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, a in a(.default) @@ -1232,6 +1238,38 @@ public final class StoryItemSetContainerComponent: Component { } let _ = component.context.engine.peers.togglePeerStoriesMuted(peerId: component.slice.peer.id).start() + + let iconColor = UIColor.white + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) + if isMuted { + self.component?.presentController(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will now get a notification whenever **\(component.slice.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), nil) + } else { + self.component?.presentController(UndoOverlayController( + presentationData: presentationData, + content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: "You will no longer receive a notification when **\(component.slice.peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder))** posts a story.", customUndoText: nil, timeout: nil), + elevatedLayout: false, + animateInAsReplacement: false, + action: { _ in return false } + ), nil) + } }))) var isHidden = false @@ -1240,7 +1278,7 @@ public final class StoryItemSetContainerComponent: Component { } items.append(.action(ContextMenuActionItem(text: isHidden ? "Unhide \(component.slice.peer.compactDisplayTitle)" : "Hide \(component.slice.peer.compactDisplayTitle)", icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: component.slice.item.storyItem.isPinned ? "Chat/Context Menu/Archive" : "Chat/Context Menu/Archive"), color: theme.contextMenu.primaryColor) + return generateTintedImage(image: UIImage(bundleImageName: isHidden ? "Chat/Context Menu/MoveToChats" : "Chat/Context Menu/MoveToContacts"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, a in a(.default) @@ -1359,7 +1397,7 @@ public final class StoryItemSetContainerComponent: Component { self.sendMessageContext.updateInputMediaNode(inputPanel: self.inputPanel, availableSize: availableSize, bottomInset: component.safeInsets.bottom, inputHeight: component.inputHeight, effectiveInputHeight: inputHeight, metrics: component.metrics, deviceMetrics: component.deviceMetrics, transition: transition) - let bottomContentInsetWithoutInput = bottomContentInset + //let bottomContentInsetWithoutInput = bottomContentInset var viewListInset: CGFloat = 0.0 var inputPanelBottomInset: CGFloat @@ -1505,14 +1543,10 @@ public final class StoryItemSetContainerComponent: Component { let privacyText: String switch component.slice.item.storyItem.privacy?.base { case .closeFriends: - if additionalCount != 0 { - privacyText = "Close Friends (+\(additionalCount)" - } else { - privacyText = "Close Friends" - } + privacyText = "Close Friends" case .contacts: if additionalCount != 0 { - privacyText = "Contacts (+\(additionalCount)" + privacyText = "Contacts (-\(additionalCount))" } else { privacyText = "Contacts" } @@ -1565,8 +1599,8 @@ public final class StoryItemSetContainerComponent: Component { let _ = component.context.engine.messages.updateStoriesArePinned(ids: [component.slice.item.storyItem.id: component.slice.item.storyItem], isPinned: !component.slice.item.storyItem.isPinned).start() + let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) if component.slice.item.storyItem.isPinned { - let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) self.component?.presentController(UndoOverlayController( presentationData: presentationData, content: .info(title: nil, text: "Story removed from your profile", timeout: nil), @@ -1575,7 +1609,6 @@ public final class StoryItemSetContainerComponent: Component { action: { _ in return false } ), nil) } else { - let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: component.theme) self.component?.presentController(UndoOverlayController( presentationData: presentationData, content: .info(title: "Story saved to your profile", text: "Saved stories can be viewed by others on your profile until you remove them.", timeout: nil), @@ -1833,7 +1866,8 @@ public final class StoryItemSetContainerComponent: Component { transition.setFrame(layer: self.topContentGradientLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: contentFrame.width, height: gradientHeight))) transition.setAlpha(layer: self.topContentGradientLayer, alpha: (component.hideUI || self.displayViewList) ? 0.0 : 1.0) - let itemLayout = ItemLayout(size: CGSize(width: contentFrame.width, height: availableSize.height - component.containerInsets.top - 44.0 - bottomContentInsetWithoutInput)) + let itemSize = CGSize(width: contentFrame.width, height: floorToScreenPixels(contentFrame.width * 1.77778)) + let itemLayout = ItemLayout(size: itemSize) //ItemLayout(size: CGSize(width: contentFrame.width, height: availableSize.height - component.containerInsets.top - 44.0 - bottomContentInsetWithoutInput)) self.itemLayout = itemLayout let inputPanelFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - inputPanelSize.width) / 2.0), y: availableSize.height - inputPanelBottomInset - inputPanelSize.height), size: inputPanelSize) @@ -2236,12 +2270,17 @@ public final class StoryItemSetContainerComponent: Component { return contentSize } - private func openItemPrivacySettings() { - guard let context = self.component?.context, let privacy = self.component?.slice.item.storyItem.privacy else { + private func openItemPrivacySettings(initialPrivacy: EngineStoryPrivacy? = nil) { + guard let context = self.component?.context else { return } - let stateContext = ShareWithPeersScreen.StateContext(context: context, subject: .stories) + let privacy = initialPrivacy ?? self.component?.slice.item.storyItem.privacy + guard let privacy else { + return + } + + let stateContext = ShareWithPeersScreen.StateContext(context: context, subject: .stories, initialPeerIds: Set(privacy.additionallyIncludePeers)) let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in guard let self else { return @@ -2249,6 +2288,7 @@ public final class StoryItemSetContainerComponent: Component { let controller = ShareWithPeersScreen( context: context, initialPrivacy: privacy, + timeout: 86400, stateContext: stateContext, completion: { [weak self] privacy in guard let self, let component = self.component else { @@ -2259,10 +2299,15 @@ public final class StoryItemSetContainerComponent: Component { self.updateIsProgressPaused() }, editCategory: { [weak self] privacy in - guard let self, let component = self.component else { + guard let self else { return } - let _ = component.context.engine.messages.editStoryPrivacy(id: component.slice.item.storyItem.id, privacy: privacy).start() + self.openItemPrivacyCategory(privacy: privacy, completion: { [weak self] privacy in + guard let self else { + return + } + self.openItemPrivacySettings(initialPrivacy: privacy) + }) } ) self.component?.controller()?.push(controller) @@ -2272,6 +2317,38 @@ public final class StoryItemSetContainerComponent: Component { }) } + private func openItemPrivacyCategory(privacy: EngineStoryPrivacy, completion: @escaping (EngineStoryPrivacy) -> Void) { + guard let context = self.component?.context else { + return + } + + let stateContext = ShareWithPeersScreen.StateContext(context: context, subject: .contacts(privacy.base), initialPeerIds: Set(privacy.additionallyIncludePeers)) + let _ = (stateContext.ready |> filter { $0 } |> take(1) |> deliverOnMainQueue).start(next: { [weak self] _ in + guard let self else { + return + } + let controller = ShareWithPeersScreen( + context: context, + initialPrivacy: privacy, + timeout: 86400, + stateContext: stateContext, + completion: { result in + if case .closeFriends = privacy.base { + let _ = context.engine.privacy.updateCloseFriends(peerIds: result.additionallyIncludePeers).start() + completion(EngineStoryPrivacy(base: .closeFriends, additionallyIncludePeers: [])) + } else { + completion(result) + } + }, + editCategory: { _ in } + ) + self.component?.controller()?.push(controller) + + self.privacyController = controller + self.updateIsProgressPaused() + }) + } + private func navigateToPeer(peer: EnginePeer, messageId: EngineMessage.Id? = nil) { guard let component = self.component else { return @@ -2300,48 +2377,227 @@ public final class StoryItemSetContainerComponent: Component { } private func openStoryEditing() { - guard let context = self.component?.context, let id = self.component?.slice.item.storyItem.id else { + guard let context = self.component?.context, let item = self.component?.slice.item.storyItem else { return } - let _ = (getStorySource(engine: context.engine, id: Int64(id)) - |> deliverOnMainQueue).start(next: { [weak self] source in - guard let self else { - return + let id = item.id + + self.isEditingStory = true + self.updateIsProgressPaused() + + let subject: Signal +// if let source { +// subject = .single(.draft(source, Int64(id))) +// } else { + let media = item.media._asMedia() + subject = fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: .standalone(media: media)) + |> mapToSignal { (value, isImage) -> Signal in + guard case let .data(data) = value, data.complete else { + return .complete() } - self.isEditingStory = true - self.updateIsProgressPaused() - - if let source { - var updateProgressImpl: ((Float) -> Void)? - let controller = MediaEditorScreen( - context: context, - subject: .single(.draft(source, Int64(id))), - transitionIn: nil, - transitionOut: { _, _ in return nil }, - completion: { [weak self] _, mediaResult, privacy, commit in - switch mediaResult { - case let .image(image, dimensions, caption): - if let imageData = compressImageToJPEG(image, quality: 0.6) { - let _ = (context.engine.messages.editStory(media: .image(dimensions: dimensions, data: imageData), id: id, text: caption?.string ?? "", entities: [], privacy: privacy.privacy) - |> deliverOnMainQueue).start(next: { [weak self] result in - switch result { - case let .progress(progress): - updateProgressImpl?(progress) - case .completed: - Queue.mainQueue().after(0.1) { - if let self { - self.isEditingStory = false - self.rewindCurrentItem() - self.updateIsProgressPaused() - } - commit({}) - } - } - }) + if let image = UIImage(contentsOfFile: data.path) { + return .single(nil) + |> then( + .single(.image(image, PixelDimensions(image.size), nil, .bottomRight)) + |> delay(0.2, queue: Queue.mainQueue()) + ) + } else { + return .single(.video(data.path, nil, nil, nil, PixelDimensions(width: 720, height: 1280), .bottomRight)) + } + } + + var updateProgressImpl: ((Float) -> Void)? + let controller = MediaEditorScreen( + context: context, + subject: subject, + isEditing: true, + initialCaption: chatInputStateStringWithAppliedEntities(item.text, entities: item.entities), + initialPrivacy: item.privacy, + transitionIn: nil, + transitionOut: { _, _ in return nil }, + completion: { [weak self] _, mediaResult, caption, privacy, commit in + guard let self else { + return + } + let entities = generateChatInputTextEntities(caption) + var updatedText: String? + var updatedEntities: [MessageTextEntity]? + var updatedPrivacy: EngineStoryPrivacy? + if caption.string != item.text || entities != item.entities { + updatedText = caption.string + updatedEntities = entities + } + if privacy.privacy != item.privacy { + updatedPrivacy = privacy.privacy + } + + if let mediaResult { + switch mediaResult { + case let .image(image, dimensions): + if let imageData = compressImageToJPEG(image, quality: 0.7) { + let _ = (context.engine.messages.editStory(media: .image(dimensions: dimensions, data: imageData), id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let self else { + return + } + switch result { + case let .progress(progress): + updateProgressImpl?(progress) + case .completed: + Queue.mainQueue().after(0.1) { + self.isEditingStory = false + self.rewindCurrentItem() + self.updateIsProgressPaused() + + commit({}) + } + } + }) + } + case let .video(content, firstFrameImage, values, duration, dimensions): + if let valuesData = try? JSONEncoder().encode(values) { + let data = MemoryBuffer(data: valuesData) + let digest = MemoryBuffer(data: data.md5Digest()) + let adjustments = VideoMediaResourceAdjustments(data: data, digest: digest, isStory: true) + + let resource: TelegramMediaResource + switch content { + case let .imageFile(path): + resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments) + case let .videoFile(path): + resource = LocalFileVideoMediaResource(randomId: Int64.random(in: .min ... .max), path: path, adjustments: adjustments) + case let .asset(localIdentifier): + resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments)) + } + + let firstFrameImageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6) } + let _ = (context.engine.messages.editStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameImageData: firstFrameImageData), id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) + |> deliverOnMainQueue).start(next: { [weak self] result in + guard let self else { + return + } + switch result { + case let .progress(progress): + updateProgressImpl?(progress) + case .completed: + Queue.mainQueue().after(0.1) { + self.isEditingStory = false + self.rewindCurrentItem() + self.updateIsProgressPaused() + + commit({}) + } + } + }) + } + } + } else if updatedText != nil || updatedPrivacy != nil { + let _ = (context.engine.messages.editStory(media: nil, id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) + |> deliverOnMainQueue).start(next: { [weak self] result in + switch result { + case .completed: + Queue.mainQueue().after(0.1) { + if let self { + self.isEditingStory = false + self.rewindCurrentItem() + self.updateIsProgressPaused() + } + commit({}) } default: break -// case let .video(content, _, values, duration, dimensions, caption): + } + }) + } else { + self.isEditingStory = false + self.rewindCurrentItem() + self.updateIsProgressPaused() + + commit({}) + } + + } + ) + controller.dismissed = { [weak self] in + self?.isEditingStory = false + self?.updateIsProgressPaused() + } + self.component?.controller()?.push(controller) + updateProgressImpl = { [weak controller] progress in + controller?.updateEditProgress(progress) + } + +// } + +// let _ = (getStorySource(engine: context.engine, id: Int64(id)) +// |> deliverOnMainQueue).start(next: { [weak self] source in +// guard let self else { +// return +// } +// +// self.isEditingStory = true +// self.updateIsProgressPaused() +// +// let subject: Signal +// if let source { +// subject = .single(.draft(source, Int64(id))) +// } else { +// let media = item.media._asMedia() +// subject = fetchMediaData(context: context, postbox: context.account.postbox, userLocation: .other, mediaReference: .standalone(media: media)) +// |> mapToSignal { (value, isImage) -> Signal in +// guard case let .data(data) = value, data.complete else { +// return .complete() +// } +// if let image = UIImage(contentsOfFile: data.path) { +// return .single(.image(image, PixelDimensions(image.size), nil, .bottomRight)) +// } else { +// return .single(.video(data.path, nil, nil, nil, PixelDimensions(width: 720, height: 1280), .bottomRight)) +// } +// } +// } +// +// var updateProgressImpl: ((Float) -> Void)? +// let controller = MediaEditorScreen( +// context: context, +// subject: subject, +// isEditing: true, +// transitionIn: nil, +// transitionOut: { _, _ in return nil }, +// completion: { [weak self] randomId, mediaResult, caption, privacy, commit in +// let entities = generateChatInputTextEntities(caption) +// var updatedText: String? +// var updatedEntities: [MessageTextEntity]? +// var updatedPrivacy: EngineStoryPrivacy? +// if caption.string != item.text || entities != item.entities { +// updatedText = caption.string +// updatedEntities = entities +// } +// if privacy.privacy != item.privacy { +// updatedPrivacy = privacy.privacy +// } +// +// if let mediaResult { +// switch mediaResult { +// case let .image(image, dimensions, caption): +// if let imageData = compressImageToJPEG(image, quality: 0.7) { +// let _ = (context.engine.messages.editStory(media: .image(dimensions: dimensions, data: imageData), id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) +// |> deliverOnMainQueue).start(next: { [weak self] result in +// switch result { +// case let .progress(progress): +// updateProgressImpl?(progress) +// case .completed: +// Queue.mainQueue().after(0.1) { +// if let self { +// self.isEditingStory = false +// self.rewindCurrentItem() +// self.updateIsProgressPaused() +// } +// commit({}) +// } +// } +// }) +// } +// case let .video(content, firstFrameImage, values, duration, dimensions, caption): // let adjustments: VideoMediaResourceAdjustments // if let valuesData = try? JSONEncoder().encode(values) { // let data = MemoryBuffer(data: valuesData) @@ -2357,41 +2613,62 @@ public final class StoryItemSetContainerComponent: Component { // case let .asset(localIdentifier): // resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments)) // } -// if case let .story(storyPrivacy, period, pin) = privacy { -// let _ = (context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource), text: caption?.string ?? "", entities: [], pin: pin, privacy: storyPrivacy, period: period, randomId: randomId) -// |> deliverOnMainQueue).start(next: { [weak chatListController] result in -// if let chatListController { -// switch result { -// case let .progress(progress): -// let _ = progress -// break -// case .completed: -// Queue.mainQueue().after(0.1) { -// commit() -// } +// let imageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6) } +// +// let _ = (context.engine.messages.editStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameImageData: imageData), id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) +// |> deliverOnMainQueue).start(next: { [weak self] result in +// switch result { +// case let .progress(progress): +// updateProgressImpl?(progress) +// case .completed: +// Queue.mainQueue().after(0.1) { +// if let self { +// self.isEditingStory = false +// self.rewindCurrentItem() +// self.updateIsProgressPaused() // } +// commit({}) // } -// }) -// Queue.mainQueue().justDispatch { -// commit({ [weak chatListController] in -// chatListController?.animateStoryUploadRipple() -// }) // } -// } +// }) // } - } - } - ) - controller.dismissed = { [weak self] in - self?.isEditingStory = false - self?.updateIsProgressPaused() - } - self.component?.controller()?.push(controller) - updateProgressImpl = { [weak controller] progress in - controller?.updateEditProgress(progress) - } - } - }) +// } +// } else if updatedText != nil || updatedPrivacy != nil { +// let _ = (context.engine.messages.editStory(media: nil, id: id, text: updatedText, entities: updatedEntities, privacy: updatedPrivacy) +// |> deliverOnMainQueue).start(next: { [weak self] result in +// switch result { +// case .completed: +// Queue.mainQueue().after(0.1) { +// if let self { +// self.isEditingStory = false +// self.rewindCurrentItem() +// self.updateIsProgressPaused() +// } +// commit({}) +// } +// default: +// break +// } +// }) +// } else { +// if let self { +// self.isEditingStory = false +// self.rewindCurrentItem() +// self.updateIsProgressPaused() +// } +// commit({}) +// } +// } +// ) +// controller.dismissed = { [weak self] in +// self?.isEditingStory = false +// self?.updateIsProgressPaused() +// } +// self.component?.controller()?.push(controller) +// updateProgressImpl = { [weak controller] progress in +// controller?.updateEditProgress(progress) +// } +// }) } } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index 06d3c7afcc..74cb004f93 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -169,6 +169,7 @@ final class StoryItemSetContainerSendMessage { } } ) + self.inputMediaInteraction?.forceTheme = defaultDarkColorPresentationTheme } func toggleInputMode() { diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift index 1d9ce0595b..3207764c66 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetViewListComponent.swift @@ -603,8 +603,7 @@ final class StoryItemSetViewListComponent: Component { moreAction: { [weak self] sourceView, gesture in guard let self, let component = self.component else { return - } - + } component.moreAction(sourceView, gesture) } )), diff --git a/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift b/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift index e2797b9590..8e81aee6c0 100644 --- a/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift +++ b/submodules/TelegramUI/Components/TextFieldComponent/Sources/TextFieldComponent.swift @@ -20,6 +20,7 @@ public final class TextFieldComponent: Component { public final class ExternalState { public fileprivate(set) var isEditing: Bool = false public fileprivate(set) var hasText: Bool = false + public var initialText: NSAttributedString? public init() { } @@ -92,6 +93,17 @@ public final class TextFieldComponent: Component { public struct InputState { public var inputText: NSAttributedString public var selectionRange: Range + + public init(inputText: NSAttributedString, selectionRange: Range) { + self.inputText = inputText + self.selectionRange = selectionRange + } + + public init(inputText: NSAttributedString) { + self.inputText = inputText + let length = inputText.length + self.selectionRange = length ..< length + } } public final class View: UIView, UITextViewDelegate, UIScrollViewDelegate { @@ -104,8 +116,6 @@ public final class TextFieldComponent: Component { private var customEmojiContainerView: CustomEmojiContainerView? private var emojiViewProvider: ((ChatTextInputTextCustomEmojiAttribute) -> UIView)? - //private var inputState = InputState(inputText: NSAttributedString(), selectionRange: 0 ..< 0) - private var inputState: InputState { let selectionRange: Range = self.textView.selectedRange.location ..< (self.textView.selectedRange.location + self.textView.selectedRange.length) return InputState(inputText: stateAttributedStringForText(self.textView.attributedText ?? NSAttributedString()), selectionRange: selectionRange) @@ -445,6 +455,13 @@ public final class TextFieldComponent: Component { self.component = component self.state = state + if let initialText = component.externalState.initialText { + component.externalState.initialText = nil + self.updateInputState { _ in + return TextFieldComponent.InputState(inputText: initialText) + } + } + if self.emojiViewProvider == nil { self.emojiViewProvider = { [weak self] emoji in guard let component = self?.component else { diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/Contents.json new file mode 100644 index 0000000000..ba24ab79ca --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "movetochats_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/movetochats_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/movetochats_24.pdf new file mode 100644 index 0000000000..fc03db3b6f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToChats.imageset/movetochats_24.pdf @@ -0,0 +1,191 @@ +%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 0.335022 2.295349 cm +1.000000 1.000000 1.000000 scn +6.142120 15.779264 m +7.480694 17.157986 9.452373 18.039629 11.664999 18.039629 c +15.777071 18.039629 19.000000 15.023025 19.000000 11.431902 c +19.000000 7.840779 15.777071 4.824175 11.664999 4.824175 c +11.037781 4.824175 10.429922 4.895034 9.850378 5.027961 c +9.469110 5.115411 9.178260 4.904372 9.078142 4.829156 c +8.976803 4.753022 8.861000 4.645836 8.759948 4.552301 c +8.759891 4.552247 l +8.759882 4.552238 l +8.699350 4.496364 l +8.446663 4.264504 8.099366 3.961192 7.552770 3.654654 c +7.352402 3.542285 7.115053 3.463325 6.872348 3.411900 c +6.929290 3.488448 6.986062 3.569141 7.041155 3.653596 c +7.389184 4.187105 7.489088 4.765461 7.466393 5.236623 c +7.448723 5.603467 7.137013 5.886529 6.770169 5.868859 c +6.403325 5.851189 6.120263 5.539478 6.137933 5.172635 c +6.149623 4.929938 6.096569 4.639868 5.927217 4.380261 c +5.748320 4.106021 5.559394 3.900901 5.381646 3.707916 c +5.381536 3.707796 l +5.337605 3.660100 5.294358 3.613144 5.252113 3.566068 c +5.201833 3.510037 5.145585 3.445241 5.095825 3.378344 c +5.050557 3.317486 4.981599 3.217117 4.936990 3.090534 c +4.889143 2.954765 4.849132 2.725258 4.970338 2.484573 c +5.083405 2.260048 5.273345 2.155308 5.385351 2.108326 c +5.486843 2.065754 5.591929 2.046288 5.659274 2.035854 c +5.739243 2.023464 5.827882 2.014999 5.920462 2.010006 c +6.106138 1.999989 6.331503 2.002670 6.575747 2.024937 c +7.054850 2.068615 7.665498 2.193001 8.203329 2.494621 c +8.876777 2.872299 9.310046 3.251671 9.598545 3.516390 c +9.688824 3.599475 l +9.724767 3.632614 9.754330 3.659869 9.779459 3.682659 c +10.387117 3.559157 11.018166 3.494175 11.664999 3.494175 c +16.389484 3.494175 20.329998 6.989792 20.329998 11.431902 c +20.329998 15.874012 16.389484 19.369629 11.664999 19.369629 c +9.098855 19.369629 6.781081 18.346710 5.187877 16.705719 c +4.932044 16.442213 4.938264 16.021204 5.201771 15.765370 c +5.465278 15.509537 5.886287 15.515757 6.142120 15.779264 c +h +5.843703 3.353676 m +5.847516 3.352829 l +5.844881 3.353352 5.843657 3.353655 5.843703 3.353676 c +h +6.159736 2.580116 m +6.157165 2.576271 l +6.157100 2.576252 6.157888 2.577515 6.159736 2.580116 c +h +9.892341 3.775630 m +9.895166 3.777505 9.896662 3.778707 9.896752 3.778999 c +9.896927 3.779562 9.891918 3.776763 9.881212 3.768926 c +9.886010 3.771608 9.889739 3.773905 9.892341 3.775630 c +h +20.929787 12.381819 m +20.751503 12.702913 20.867275 13.107740 21.188370 13.286022 c +21.509464 13.464306 21.914291 13.348534 22.092573 13.027439 c +22.691111 11.949450 23.030014 10.727039 23.030014 9.431902 c +23.030014 6.938105 21.869383 4.889858 19.940552 3.448150 c +19.940319 3.447509 l +19.919962 3.390541 19.898252 3.296368 19.892189 3.174892 c +19.880058 2.931812 19.932896 2.640709 20.102795 2.380260 c +20.281693 2.106022 20.470617 1.900900 20.648365 1.707916 c +20.692333 1.660179 20.735619 1.613182 20.777899 1.566067 c +20.828178 1.510036 20.884426 1.445240 20.934187 1.378344 c +20.979456 1.317486 21.048412 1.217117 21.093021 1.090534 c +21.140869 0.954765 21.180880 0.725258 21.059673 0.484573 c +20.946608 0.260048 20.756666 0.155308 20.644661 0.108326 c +20.543169 0.065756 20.438084 0.046288 20.370739 0.035854 c +20.290770 0.023464 20.202129 0.014999 20.109550 0.010004 c +19.923874 -0.000013 19.698509 0.002670 19.454264 0.024937 c +18.975163 0.068615 18.364513 0.193001 17.826683 0.494623 c +17.153234 0.872299 16.719965 1.251671 16.431467 1.516390 c +16.341227 1.599442 l +16.340408 1.600197 l +16.339453 1.601078 l +16.304291 1.633493 16.275278 1.660238 16.250553 1.682659 c +15.642897 1.559156 15.011847 1.494175 14.365013 1.494175 c +13.738460 1.494175 13.126695 1.555145 12.536637 1.671227 c +12.176275 1.742119 11.941614 2.091721 12.012507 2.452084 c +12.083401 2.812447 12.433002 3.047108 12.793365 2.976213 c +13.299057 2.876730 13.824845 2.824175 14.365013 2.824175 c +14.992231 2.824175 15.600090 2.895035 16.179634 3.027962 c +16.560902 3.115410 16.851753 2.904373 16.951870 2.829155 c +17.053213 2.753019 17.169022 2.645828 17.270073 2.552288 c +17.270130 2.552237 l +17.330662 2.496365 l +17.583349 2.264503 17.930645 1.961193 18.477242 1.654654 c +18.677610 1.542286 18.914959 1.463326 19.157663 1.411900 c +19.100721 1.488449 19.043949 1.569141 18.988857 1.653595 c +18.639727 2.188793 18.540283 2.769123 18.563843 3.241184 c +18.575624 3.477282 18.618753 3.701606 18.687880 3.895054 c +18.746796 4.059927 18.860445 4.305161 19.081284 4.466843 c +20.750088 5.688613 21.700012 7.375656 21.700012 9.431902 c +21.700012 10.491108 21.423624 11.492397 20.929787 12.381819 c +h +19.953547 3.480234 m +19.956055 3.485239 l +19.957342 3.487652 19.958071 3.488707 19.958145 3.488573 c +19.958214 3.488447 19.957697 3.487259 19.956514 3.485152 c +19.953547 3.480234 l +h +16.133259 1.778999 m +16.133430 1.778439 16.138786 1.774525 16.148804 1.768925 c +16.138100 1.776760 16.133089 1.779560 16.133259 1.778999 c +h +20.186310 1.353676 m +20.182497 1.352829 l +20.185133 1.353352 20.186356 1.353657 20.186310 1.353676 c +h +19.870279 0.580111 m +19.872847 0.576271 l +19.872919 0.576242 19.872131 0.577499 19.870279 0.580111 c +h +5.559548 10.869629 m +3.694774 12.734404 l +3.435075 12.994102 3.435075 13.415156 3.694774 13.674854 c +3.954473 13.934553 4.375527 13.934553 4.635226 13.674854 c +7.635226 10.674855 l +7.894925 10.415156 7.894925 9.994102 7.635226 9.734403 c +4.635226 6.734404 l +4.375527 6.474705 3.954473 6.474705 3.694774 6.734404 c +3.435075 6.994102 3.435075 7.415156 3.694774 7.674854 c +5.559548 9.539629 l +0.665000 9.539629 l +0.297730 9.539629 0.000000 9.837359 0.000000 10.204629 c +0.000000 10.571898 0.297730 10.869629 0.665000 10.869629 c +5.559548 10.869629 l +h +f* +n +Q + +endstream +endobj + +3 0 obj + 5655 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.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 +0000000034 00000 n +0000005745 00000 n +0000005768 00000 n +0000005941 00000 n +0000006015 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +6074 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/Contents.json new file mode 100644 index 0000000000..e06b24e282 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "movetocontacts_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/movetocontacts_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/movetocontacts_24.pdf new file mode 100644 index 0000000000..84fd0dccf4 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/MoveToContacts.imageset/movetocontacts_24.pdf @@ -0,0 +1,115 @@ +%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 0.335022 3.335083 cm +1.000000 1.000000 1.000000 scn +11.664982 15.999956 m +9.732011 15.999956 7.974946 15.253136 6.664206 14.031046 c +6.395582 13.780590 5.974784 13.795319 5.724329 14.063942 c +5.473873 14.332565 5.488601 14.753363 5.757225 15.003819 c +7.304427 16.446377 9.382257 17.329956 11.664982 17.329956 c +16.450529 17.329956 20.329983 13.450504 20.329983 8.664956 c +20.329983 3.879409 16.450529 -0.000046 11.664982 -0.000046 c +9.467892 -0.000046 7.460371 0.818539 5.933279 2.166380 c +5.881387 2.212180 5.830048 2.258594 5.779273 2.305608 c +5.521967 2.543855 5.495585 2.938190 5.710920 3.207923 c +6.184868 3.968952 7.955641 6.329956 11.664997 6.329956 c +13.847623 6.329956 15.371711 5.506486 16.347773 4.669862 c +16.690248 4.376310 16.964067 4.082387 17.175648 3.823866 c +18.311298 5.115568 18.999981 6.809836 18.999981 8.664956 c +18.999981 12.715965 15.715990 15.999956 11.664982 15.999956 c +h +16.207489 2.905417 m +16.032719 3.127470 15.793164 3.393527 15.482220 3.660050 c +14.708282 4.323426 13.482370 4.999956 11.664997 4.999956 c +9.138727 4.999956 7.731341 3.681140 7.121977 2.905769 c +8.371500 1.918601 9.948810 1.329956 11.664982 1.329956 c +13.380391 1.329956 14.958264 1.918815 16.207489 2.905417 c +h +11.665061 12.499956 m +10.651619 12.499956 9.830061 11.678398 9.830061 10.664956 c +9.830061 9.651514 10.651619 8.829956 11.665061 8.829956 c +12.678503 8.829956 13.500061 9.651514 13.500061 10.664956 c +13.500061 11.678398 12.678503 12.499956 11.665061 12.499956 c +h +8.500061 10.664956 m +8.500061 12.412937 9.917080 13.829956 11.665061 13.829956 c +13.413042 13.829956 14.830061 12.412937 14.830061 10.664956 c +14.830061 8.916975 13.413042 7.499956 11.665061 7.499956 c +9.917080 7.499956 8.500061 8.916975 8.500061 10.664956 c +h +5.559548 7.999956 m +3.694774 6.135181 l +3.435075 5.875484 3.435075 5.454429 3.694774 5.194731 c +3.954473 4.935032 4.375527 4.935032 4.635226 5.194731 c +7.635226 8.194730 l +7.894925 8.454429 7.894925 8.875484 7.635226 9.135182 c +4.635226 12.135181 l +4.375527 12.394880 3.954473 12.394880 3.694774 12.135181 c +3.435075 11.875484 3.435075 11.454429 3.694774 11.194731 c +5.559548 9.329956 l +0.665000 9.329956 l +0.297730 9.329956 0.000000 9.032226 0.000000 8.664956 c +0.000000 8.297687 0.297730 7.999956 0.665000 7.999956 c +5.559548 7.999956 l +h +f* +n +Q + +endstream +endobj + +3 0 obj + 2353 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 24.000000 24.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 +0000000034 00000 n +0000002443 00000 n +0000002466 00000 n +0000002639 00000 n +0000002713 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +2772 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Contents.json index 23704b4f64..ac64efccdb 100644 --- a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Contents.json +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "Stories.svg", + "filename" : "stories_30.pdf", "idiom" : "universal" } ], diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Stories.svg b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Stories.svg deleted file mode 100644 index 2d84bcf928..0000000000 --- a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/Stories.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/stories_30.pdf b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/stories_30.pdf new file mode 100644 index 0000000000..e6ca6eae1b --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Settings/Menu/Stories.imageset/stories_30.pdf @@ -0,0 +1,221 @@ +%PDF-1.7 + +1 0 obj + << /Type /XObject + /Length 2 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 30.000000 30.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.996078 0.172549 0.333333 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q +q +1.000000 0.000000 -0.000000 1.000000 6.000000 6.000000 cm +1.000000 1.000000 1.000000 scn +8.819326 15.997714 m +8.879366 15.999235 8.939594 16.000000 9.000000 16.000000 c +9.217377 16.000000 9.432181 15.990122 9.644025 15.970834 c +10.194035 15.920755 10.680502 16.326031 10.730579 16.876040 c +10.780658 17.426048 10.375383 17.912516 9.825374 17.962595 c +9.553321 17.987366 9.278004 18.000000 9.000000 18.000000 c +4.029437 18.000000 0.000000 13.970563 0.000000 9.000000 c +0.000000 6.631216 0.915133 4.476173 2.411141 2.869128 c +2.583210 2.684289 2.762962 2.506699 2.949891 2.336866 c +4.481421 0.945414 6.494651 0.074747 8.709856 0.004589 c +8.806196 0.001537 8.902919 0.000000 9.000000 0.000000 c +9.278004 0.000000 9.553321 0.012634 9.825375 0.037405 c +10.375384 0.087484 10.780659 0.573952 10.730580 1.123960 c +10.680502 1.673969 10.194035 2.079245 9.644025 2.029166 c +9.432181 2.009878 9.217377 2.000000 9.000000 2.000000 c +8.935744 2.000000 8.871692 2.000866 8.807852 2.002586 c +7.071224 2.049389 5.492391 2.728685 4.293358 3.818473 c +4.126952 3.969717 3.967862 4.128867 3.816680 4.295331 c +2.725542 5.496764 2.046374 7.079132 2.002286 8.819326 c +2.000765 8.879366 2.000000 8.939594 2.000000 9.000000 c +2.000000 9.065163 2.000890 9.130116 2.002660 9.194851 c +2.051733 10.990423 2.776973 12.617154 3.932920 13.829583 c +4.027086 13.928350 4.124111 14.024369 4.223862 14.117506 c +5.433672 15.247099 7.044405 15.952745 8.819326 15.997714 c +h +14.753499 15.921051 m +14.328968 16.274309 13.698444 16.216534 13.345185 15.792002 c +12.991926 15.367472 13.049703 14.736948 13.474234 14.383689 c +13.804405 14.108947 14.108946 13.804406 14.383688 13.474234 c +14.736948 13.049704 15.367471 12.991926 15.792002 13.345186 c +16.216534 13.698445 16.274309 14.328969 15.921049 14.753500 c +15.568322 15.177391 15.177390 15.568323 14.753499 15.921051 c +h +17.962595 9.825375 m +17.912516 10.375383 17.426048 10.780659 16.876040 10.730579 c +16.326031 10.680502 15.920755 10.194035 15.970834 9.644025 c +15.990122 9.432182 16.000000 9.217377 16.000000 9.000000 c +16.000000 8.782623 15.990122 8.567819 15.970834 8.355975 c +15.920755 7.805965 16.326031 7.319498 16.876040 7.269421 c +17.426048 7.219342 17.912516 7.624617 17.962595 8.174626 c +17.987366 8.446679 18.000000 8.721996 18.000000 9.000000 c +18.000000 9.278004 17.987366 9.553321 17.962595 9.825375 c +h +15.921050 3.246501 m +16.274311 3.671032 16.216534 4.301556 15.792003 4.654815 c +15.367472 5.008074 14.736948 4.950297 14.383689 4.525766 c +14.108947 4.195595 13.804406 3.891054 13.474235 3.616312 c +13.049704 3.263052 12.991927 2.632529 13.345186 2.207998 c +13.698445 1.783466 14.328969 1.725691 14.753500 2.078951 c +15.177391 2.431678 15.568323 2.822610 15.921050 3.246501 c +h +f* +n +Q + +endstream +endobj + +2 0 obj + 3662 +endobj + +3 0 obj + << /Type /XObject + /Length 4 0 R + /Group << /Type /Group + /S /Transparency + >> + /Subtype /Form + /Resources << >> + /BBox [ 0.000000 0.000000 30.000000 30.000000 ] + >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm +0.000000 0.000000 0.000000 scn +0.000000 18.799999 m +0.000000 22.720367 0.000000 24.680552 0.762954 26.177933 c +1.434068 27.495068 2.504932 28.565931 3.822066 29.237045 c +5.319448 30.000000 7.279633 30.000000 11.200000 30.000000 c +18.799999 30.000000 l +22.720367 30.000000 24.680552 30.000000 26.177933 29.237045 c +27.495068 28.565931 28.565931 27.495068 29.237045 26.177933 c +30.000000 24.680552 30.000000 22.720367 30.000000 18.799999 c +30.000000 11.200001 l +30.000000 7.279633 30.000000 5.319448 29.237045 3.822067 c +28.565931 2.504932 27.495068 1.434069 26.177933 0.762955 c +24.680552 0.000000 22.720367 0.000000 18.799999 0.000000 c +11.200000 0.000000 l +7.279633 0.000000 5.319448 0.000000 3.822066 0.762955 c +2.504932 1.434069 1.434068 2.504932 0.762954 3.822067 c +0.000000 5.319448 0.000000 7.279633 0.000000 11.200001 c +0.000000 18.799999 l +h +f +n +Q + +endstream +endobj + +4 0 obj + 944 +endobj + +5 0 obj + << /XObject << /X1 1 0 R >> + /ExtGState << /E1 << /SMask << /Type /Mask + /G 3 0 R + /S /Alpha + >> + /Type /ExtGState + >> >> + >> +endobj + +6 0 obj + << /Length 7 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +/E1 gs +/X1 Do +Q + +endstream +endobj + +7 0 obj + 46 +endobj + +8 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 30.000000 30.000000 ] + /Resources 5 0 R + /Contents 6 0 R + /Parent 9 0 R + >> +endobj + +9 0 obj + << /Kids [ 8 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +10 0 obj + << /Pages 9 0 R + /Type /Catalog + >> +endobj + +xref +0 11 +0000000000 65535 f +0000000010 00000 n +0000003920 00000 n +0000003943 00000 n +0000005135 00000 n +0000005157 00000 n +0000005455 00000 n +0000005557 00000 n +0000005578 00000 n +0000005751 00000 n +0000005825 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 10 0 R + /Size 11 +>> +startxref +5885 +%%EOF \ No newline at end of file diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 481470f812..c6932c415e 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1846,8 +1846,8 @@ public final class SharedAccountContextImpl: SharedAccountContext { return proxySettingsController(accountManager: sharedContext.accountManager, postbox: account.postbox, network: account.network, mode: .modal, presentationData: sharedContext.currentPresentationData.with { $0 }, updatedPresentationData: sharedContext.presentationData) } - public func makeInstalledStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode) -> ViewController { - return installedStickerPacksController(context: context, mode: mode) + public func makeInstalledStickerPacksController(context: AccountContext, mode: InstalledStickerPacksControllerMode, forceTheme: PresentationTheme?) -> ViewController { + return installedStickerPacksController(context: context, mode: mode, forceTheme: forceTheme) } } diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index c6f8e03e0e..260109549c 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -330,6 +330,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon let controller = MediaEditorScreen( context: context, subject: subject, + isEditing: false, transitionIn: transitionIn, transitionOut: { finished, isNew in if finished, let transitionOut = transitionOut(finished), let destinationView = transitionOut.destinationView { @@ -347,8 +348,8 @@ public final class TelegramRootController: NavigationController, TelegramRootCon } else { return nil } - }, completion: { [weak self] randomId, mediaResult, privacy, commit in - guard let self else { + }, completion: { [weak self] randomId, mediaResult, caption, privacy, commit in + guard let self, let mediaResult else { dismissCameraImpl?() commit({}) return @@ -357,16 +358,15 @@ public final class TelegramRootController: NavigationController, TelegramRootCon if let chatListController = self.chatListController as? ChatListControllerImpl { chatListController.scrollToStories() switch mediaResult { - case let .image(image, dimensions, caption): + case let .image(image, dimensions): if let imageData = compressImageToJPEG(image, quality: 0.7) { - let text = caption ?? NSAttributedString() - let entities = generateChatInputTextEntities(text) - self.context.engine.messages.uploadStory(media: .image(dimensions: dimensions, data: imageData), text: text.string, entities: entities, pin: privacy.archive, privacy: privacy.privacy, period: privacy.timeout, randomId: randomId) + let entities = generateChatInputTextEntities(caption) + self.context.engine.messages.uploadStory(media: .image(dimensions: dimensions, data: imageData), text: caption.string, entities: entities, pin: privacy.archive, privacy: privacy.privacy, period: privacy.timeout, randomId: randomId) Queue.mainQueue().justDispatch { commit({}) } } - case let .video(content, firstFrameImage, values, duration, dimensions, caption): + case let .video(content, firstFrameImage, values, duration, dimensions): let adjustments: VideoMediaResourceAdjustments if let valuesData = try? JSONEncoder().encode(values) { let data = MemoryBuffer(data: valuesData) @@ -383,9 +383,8 @@ public final class TelegramRootController: NavigationController, TelegramRootCon resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments)) } let imageData = firstFrameImage.flatMap { compressImageToJPEG($0, quality: 0.6) } - let text = caption ?? NSAttributedString() - let entities = generateChatInputTextEntities(text) - self.context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameImageData: imageData), text: text.string, entities: entities, pin: privacy.archive, privacy: privacy.privacy, period: privacy.timeout, randomId: randomId) + let entities = generateChatInputTextEntities(caption) + self.context.engine.messages.uploadStory(media: .video(dimensions: dimensions, duration: duration, resource: resource, firstFrameImageData: imageData), text: caption.string, entities: entities, pin: privacy.archive, privacy: privacy.privacy, period: privacy.timeout, randomId: randomId) Queue.mainQueue().justDispatch { commit({}) }