mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
29707a7264
commit
d6923ba451
@ -9414,6 +9414,7 @@ Sorry for the inconvenience.";
|
|||||||
"ChatList.ContextSelectChats" = "Select Chats";
|
"ChatList.ContextSelectChats" = "Select Chats";
|
||||||
|
|
||||||
"StoryFeed.TooltipPremiumPosting" = "Posting stories is currently available only\nto subscribers of [Telegram Premium]().";
|
"StoryFeed.TooltipPremiumPosting" = "Posting stories is currently available only\nto subscribers of [Telegram Premium]().";
|
||||||
|
"StoryFeed.TooltipPremiumPostingLimited" = "This month, posting stories is only available to subscribers of [Telegram Premium]().";
|
||||||
"StoryFeed.TooltipStoryLimitValue_1" = "1 story";
|
"StoryFeed.TooltipStoryLimitValue_1" = "1 story";
|
||||||
"StoryFeed.TooltipStoryLimitValue_any" = "%d stories";
|
"StoryFeed.TooltipStoryLimitValue_any" = "%d stories";
|
||||||
"StoryFeed.TooltipStoryLimit" = "You can't post more than **%@** stories in **24 hours**.";
|
"StoryFeed.TooltipStoryLimit" = "You can't post more than **%@** stories in **24 hours**.";
|
||||||
@ -9623,7 +9624,7 @@ Sorry for the inconvenience.";
|
|||||||
"Story.Editor.ExpirationValue_1" = "1 Hour";
|
"Story.Editor.ExpirationValue_1" = "1 Hour";
|
||||||
"Story.Editor.ExpirationValue_any" = "%d Hours";
|
"Story.Editor.ExpirationValue_any" = "%d Hours";
|
||||||
|
|
||||||
"Story.Editor.TooltipPremiumExpiration" = "Subscribe to **Telegram Premium** to make your stories disappear after 6, 12 or 48 hours.";
|
"Story.Editor.TooltipPremiumExpiration" = "Subscribe to [Telegram Premium]() to make your stories disappear after 6, 12 or 48 hours.";
|
||||||
|
|
||||||
"Story.Editor.InputPlaceholderAddCaption" = "Add a caption...";
|
"Story.Editor.InputPlaceholderAddCaption" = "Add a caption...";
|
||||||
|
|
||||||
|
@ -894,7 +894,7 @@ public protocol SharedAccountContext: AnyObject {
|
|||||||
|
|
||||||
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController
|
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController
|
||||||
|
|
||||||
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool) -> ViewController
|
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
|
||||||
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, action: @escaping () -> Void) -> ViewController
|
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, action: @escaping () -> Void) -> ViewController
|
||||||
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, action: @escaping () -> Void) -> ViewController
|
func makePremiumLimitController(context: AccountContext, subject: PremiumLimitSubject, count: Int32, action: @escaping () -> Void) -> ViewController
|
||||||
|
|
||||||
|
@ -2612,7 +2612,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
let text: String
|
let text: String
|
||||||
if premiumNeeded {
|
if premiumNeeded {
|
||||||
text = self.presentationData.strings.StoryFeed_TooltipPremiumPosting
|
text = self.presentationData.strings.StoryFeed_TooltipPremiumPostingLimited
|
||||||
} else if reachedCountLimit {
|
} else if reachedCountLimit {
|
||||||
let valueText = self.presentationData.strings.StoryFeed_TooltipStoryLimitValue(Int32(storiesCountLimit))
|
let valueText = self.presentationData.strings.StoryFeed_TooltipStoryLimitValue(Int32(storiesCountLimit))
|
||||||
text = self.presentationData.strings.StoryFeed_TooltipStoryLimit(valueText).string
|
text = self.presentationData.strings.StoryFeed_TooltipStoryLimit(valueText).string
|
||||||
@ -2634,7 +2634,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
location: .point(location, .top),
|
location: .point(location, .top),
|
||||||
shouldDismissOnTouch: { [weak self] point, containerFrame in
|
shouldDismissOnTouch: { [weak self] point, containerFrame in
|
||||||
if containerFrame.contains(point), premiumNeeded {
|
if containerFrame.contains(point), premiumNeeded {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: false, dismissed: nil)
|
||||||
self?.push(controller)
|
self?.push(controller)
|
||||||
return .dismiss(consume: true)
|
return .dismiss(consume: true)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1562,7 +1562,7 @@ public final class ChatListNode: ListView {
|
|||||||
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .restorePremium).start()
|
let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .restorePremium).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false)
|
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads, forceDark: false, dismissed: nil)
|
||||||
self.push?(controller)
|
self.push?(controller)
|
||||||
}, openChatFolderUpdates: { [weak self] in
|
}, openChatFolderUpdates: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
@ -291,8 +291,8 @@ private final class StickerSelectionComponent: Component {
|
|||||||
topPanelScrollingOffset: { [weak self] offset, transition in
|
topPanelScrollingOffset: { [weak self] offset, transition in
|
||||||
if let self {
|
if let self {
|
||||||
if self.ignoreNextZeroScrollingOffset && offset == 0.0 {
|
if self.ignoreNextZeroScrollingOffset && offset == 0.0 {
|
||||||
self.ignoreNextZeroScrollingOffset = false
|
|
||||||
} else {
|
} else {
|
||||||
|
self.ignoreNextZeroScrollingOffset = false
|
||||||
self.topPanelScrollingOffset = offset
|
self.topPanelScrollingOffset = offset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -337,6 +337,12 @@ private final class StickerSelectionComponent: Component {
|
|||||||
},
|
},
|
||||||
peekBehavior: stickerPeekBehavior
|
peekBehavior: stickerPeekBehavior
|
||||||
)
|
)
|
||||||
|
searchContainerNode.openGifContextMenu = { [weak self] item, sourceNode, sourceRect, gesture, isSaved in
|
||||||
|
guard let self, let node = self.component?.getController()?.node else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
node.openGifContextMenu(file: item.file, contextResult: item.contextResult, sourceView: sourceNode.view, sourceRect: sourceRect, gesture: gesture, isSaved: isSaved)
|
||||||
|
}
|
||||||
return searchContainerNode
|
return searchContainerNode
|
||||||
},
|
},
|
||||||
contentIdUpdated: { [weak self] id in
|
contentIdUpdated: { [weak self] id in
|
||||||
@ -522,10 +528,105 @@ public class StickerPickerScreen: ViewController {
|
|||||||
self?.controller?.presentLocationPicker()
|
self?.controller?.presentLocationPicker()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let gifItems: Signal<EntityKeyboardGifContent?, NoError>
|
||||||
|
if controller.hasGifs {
|
||||||
|
let hasRecentGifs = context.engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs))
|
||||||
|
|> map { savedGifs -> Bool in
|
||||||
|
return !savedGifs.isEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
self.hasRecentGifsDisposable = (hasRecentGifs
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] hasRecentGifs in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let gifMode = strongSelf.gifMode {
|
||||||
|
if !hasRecentGifs, case .recent = gifMode {
|
||||||
|
strongSelf.gifMode = .trending
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strongSelf.gifMode = hasRecentGifs ? .recent : .trending
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
self.trendingGifsPromise.set(.single(nil))
|
||||||
|
self.trendingGifsPromise.set(paneGifSearchForQuery(context: context, query: "", offset: nil, incompleteResults: true, delayRequest: false, updateActivity: nil)
|
||||||
|
|> map { items -> ChatMediaInputGifPaneTrendingState? in
|
||||||
|
if let items = items {
|
||||||
|
return ChatMediaInputGifPaneTrendingState(files: items.files, nextOffset: items.nextOffset)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let gifInputInteraction = GifPagerContentComponent.InputInteraction(
|
||||||
|
performItemAction: { [weak self] item, view, rect in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.controller?.completion(.video(item.file.media))
|
||||||
|
self.controller?.dismiss(animated: true)
|
||||||
|
},
|
||||||
|
openGifContextMenu: { [weak self] item, sourceView, sourceRect, gesture, isSaved in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.openGifContextMenu(file: item.file, contextResult: item.contextResult, sourceView: sourceView, sourceRect: sourceRect, gesture: gesture, isSaved: isSaved)
|
||||||
|
},
|
||||||
|
loadMore: { [weak self] token in
|
||||||
|
guard let strongSelf = self, let gifContext = strongSelf.gifContext else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gifContext.loadMore(token: token)
|
||||||
|
},
|
||||||
|
openSearch: { [weak self] in
|
||||||
|
if let self, let componentView = self.hostView.componentView as? StickerSelectionComponent.View {
|
||||||
|
if let pagerView = componentView.keyboardView.view as? EntityKeyboardComponent.View {
|
||||||
|
pagerView.openSearch()
|
||||||
|
}
|
||||||
|
self.update(isExpanded: true, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateSearchQuery: { [weak self] query in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let query {
|
||||||
|
self.gifMode = .emojiSearch(query)
|
||||||
|
} else {
|
||||||
|
self.gifMode = .recent
|
||||||
|
}
|
||||||
|
},
|
||||||
|
hideBackground: true,
|
||||||
|
hasSearch: true
|
||||||
|
)
|
||||||
|
self.gifInputInteraction = gifInputInteraction
|
||||||
|
|
||||||
|
gifItems = .single(EntityKeyboardGifContent(
|
||||||
|
hasRecentGifs: true,
|
||||||
|
component: GifPagerContentComponent(
|
||||||
|
context: context,
|
||||||
|
inputInteraction: gifInputInteraction,
|
||||||
|
subject: .recent,
|
||||||
|
items: [],
|
||||||
|
isLoading: false,
|
||||||
|
loadMoreToken: nil,
|
||||||
|
displaySearchWithPlaceholder: nil,
|
||||||
|
searchCategories: nil,
|
||||||
|
searchInitiallyHidden: true,
|
||||||
|
searchState: .empty(hasResults: false),
|
||||||
|
hideBackground: true
|
||||||
|
)
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
gifItems = .single(nil)
|
||||||
|
}
|
||||||
|
|
||||||
let data = combineLatest(
|
let data = combineLatest(
|
||||||
queue: Queue.mainQueue(),
|
queue: Queue.mainQueue(),
|
||||||
controller.inputData,
|
controller.inputData,
|
||||||
.single(nil) |> then(self.gifComponent.get() |> map(Optional.init)),
|
gifItems |> then(self.gifComponent.get() |> map(Optional.init)),
|
||||||
self.stickerSearchState.get(),
|
self.stickerSearchState.get(),
|
||||||
self.emojiSearchState.get()
|
self.emojiSearchState.get()
|
||||||
)
|
)
|
||||||
@ -573,80 +674,6 @@ public class StickerPickerScreen: ViewController {
|
|||||||
strongSelf.updateContent(inputData)
|
strongSelf.updateContent(inputData)
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if controller.hasGifs {
|
|
||||||
let hasRecentGifs = context.engine.data.subscribe(TelegramEngine.EngineData.Item.OrderedLists.ListItems(collectionId: Namespaces.OrderedItemList.CloudRecentGifs))
|
|
||||||
|> map { savedGifs -> Bool in
|
|
||||||
return !savedGifs.isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
self.hasRecentGifsDisposable = (hasRecentGifs
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] hasRecentGifs in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let gifMode = strongSelf.gifMode {
|
|
||||||
if !hasRecentGifs, case .recent = gifMode {
|
|
||||||
strongSelf.gifMode = .trending
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
strongSelf.gifMode = hasRecentGifs ? .recent : .trending
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
self.trendingGifsPromise.set(.single(nil))
|
|
||||||
self.trendingGifsPromise.set(paneGifSearchForQuery(context: context, query: "", offset: nil, incompleteResults: true, delayRequest: false, updateActivity: nil)
|
|
||||||
|> map { items -> ChatMediaInputGifPaneTrendingState? in
|
|
||||||
if let items = items {
|
|
||||||
return ChatMediaInputGifPaneTrendingState(files: items.files, nextOffset: items.nextOffset)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.gifInputInteraction = GifPagerContentComponent.InputInteraction(
|
|
||||||
performItemAction: { [weak self] item, view, rect in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.controller?.completion(.video(item.file.media))
|
|
||||||
self.controller?.dismiss(animated: true)
|
|
||||||
},
|
|
||||||
openGifContextMenu: { [weak self] item, sourceView, sourceRect, gesture, isSaved in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
self.openGifContextMenu(file: item.file, contextResult: item.contextResult, sourceView: sourceView, sourceRect: sourceRect, gesture: gesture, isSaved: isSaved)
|
|
||||||
},
|
|
||||||
loadMore: { [weak self] token in
|
|
||||||
guard let strongSelf = self, let gifContext = strongSelf.gifContext else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gifContext.loadMore(token: token)
|
|
||||||
},
|
|
||||||
openSearch: { [weak self] in
|
|
||||||
if let self, let componentView = self.hostView.componentView as? StickerSelectionComponent.View {
|
|
||||||
if let pagerView = componentView.keyboardView.view as? EntityKeyboardComponent.View {
|
|
||||||
pagerView.openSearch()
|
|
||||||
}
|
|
||||||
self.update(isExpanded: true, transition: .animated(duration: 0.4, curve: .spring))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
updateSearchQuery: { [weak self] query in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let query {
|
|
||||||
self.gifMode = .emojiSearch(query)
|
|
||||||
} else {
|
|
||||||
self.gifMode = .recent
|
|
||||||
}
|
|
||||||
},
|
|
||||||
hideBackground: true,
|
|
||||||
hasSearch: true
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
@ -662,7 +689,7 @@ public class StickerPickerScreen: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openGifContextMenu(file: FileMediaReference, contextResult: (ChatContextResultCollection, ChatContextResult)?, sourceView: UIView, sourceRect: CGRect, gesture: ContextGesture, isSaved: Bool) {
|
fileprivate func openGifContextMenu(file: FileMediaReference, contextResult: (ChatContextResultCollection, ChatContextResult)?, sourceView: UIView, sourceRect: CGRect, gesture: ContextGesture, isSaved: Bool) {
|
||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -698,14 +725,14 @@ public class StickerPickerScreen: ViewController {
|
|||||||
if isSaved {
|
if isSaved {
|
||||||
self.controller?.completion(.video(file.media))
|
self.controller?.completion(.video(file.media))
|
||||||
self.controller?.dismiss(animated: true)
|
self.controller?.dismiss(animated: true)
|
||||||
} else {
|
} else if let (_, result) = contextResult {
|
||||||
|
if case let .internalReference(reference) = result {
|
||||||
|
if let file = reference.file {
|
||||||
|
self.controller?.completion(.video(file))
|
||||||
|
self.controller?.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if isSaved {
|
|
||||||
// let _ = self.interaction?.sendGif(file, sourceView, sourceRect, false, false)
|
|
||||||
// } else if let (collection, result) = contextResult {
|
|
||||||
// let _ = self.interaction?.sendBotContextResultAsGif(collection, result, sourceView, sourceRect, false, false)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
|
|
||||||
@ -746,7 +773,7 @@ public class StickerPickerScreen: ViewController {
|
|||||||
}
|
}
|
||||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { [weak controller] action in
|
controller.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: false, action: { [weak controller] action in
|
||||||
if case .info = action {
|
if case .info = action {
|
||||||
let premiumController = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: true)
|
let premiumController = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: true, dismissed: nil)
|
||||||
controller?.push(premiumController)
|
controller?.push(premiumController)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -1353,7 +1353,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
}
|
}
|
||||||
controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
||||||
if case .info = action {
|
if case .info = action {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: false, dismissed: nil)
|
||||||
controllerInteraction?.pushController(controller)
|
controllerInteraction?.pushController(controller)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -1566,7 +1566,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
|||||||
}
|
}
|
||||||
controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
controllerInteraction?.presentController(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_gif", scale: 0.075, colors: [:], title: presentationData.strings.Premium_MaxSavedGifsTitle("\(limit)").string, text: text, customUndoText: nil, timeout: nil), elevatedLayout: true, animateInAsReplacement: false, action: { action in
|
||||||
if case .info = action {
|
if case .info = action {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .savedGifs, forceDark: false, dismissed: nil)
|
||||||
controllerInteraction?.pushController(controller)
|
controllerInteraction?.pushController(controller)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -208,7 +208,7 @@ public func archiveSettingsController(context: AccountContext) -> ViewController
|
|||||||
guard let controller else {
|
guard let controller else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let premiumController = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false)
|
let premiumController = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false, dismissed: nil)
|
||||||
controller.push(premiumController)
|
controller.push(premiumController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,26 +404,29 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
|
|
||||||
private var nextTransitionUserData: Any?
|
private var nextTransitionUserData: Any?
|
||||||
@objc private func deactivateInput() {
|
@objc private func deactivateInput() {
|
||||||
guard let view = self.inputPanel.view as? MessageInputPanelComponent.View else {
|
guard let _ = self.inputPanel.view as? MessageInputPanelComponent.View else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if view.canDeactivateInput() {
|
// if view.canDeactivateInput() {
|
||||||
self.currentInputMode = .text
|
self.currentInputMode = .text
|
||||||
if hasFirstResponder(self) {
|
if hasFirstResponder(self) {
|
||||||
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
if let view = self.inputPanel.view as? MessageInputPanelComponent.View {
|
||||||
self.nextTransitionUserData = TextFieldComponent.AnimationHint(kind: .textFocusChanged)
|
self.nextTransitionUserData = TextFieldComponent.AnimationHint(kind: .textFocusChanged)
|
||||||
if view.isActive {
|
if view.isActive {
|
||||||
view.deactivateInput()
|
view.deactivateInput()
|
||||||
} else {
|
} else {
|
||||||
self.endEditing(true)
|
self.endEditing(true)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
self.state?.updated(transition: .spring(duration: 0.4).withUserData(TextFieldComponent.AnimationHint(kind: .textFocusChanged)))
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
view.animateError()
|
self.state?.updated(transition: .spring(duration: 0.4).withUserData(TextFieldComponent.AnimationHint(kind: .textFocusChanged)))
|
||||||
}
|
}
|
||||||
|
// } else {
|
||||||
|
// if let controller = self.environment?.controller() as? MediaEditorScreen {
|
||||||
|
// controller.presentCaptionLimitPremiumSuggestion(isPremium: self.sta)
|
||||||
|
// }
|
||||||
|
// view.animateError()
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private var animatingButtons = false
|
private var animatingButtons = false
|
||||||
@ -1168,7 +1171,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else {
|
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
controller.presentCaptionLimitPremiumSuggestion()
|
controller.presentCaptionLimitPremiumSuggestion(isPremium: self.state?.isPremium ?? false)
|
||||||
},
|
},
|
||||||
presentTextFormattingTooltip: { [weak self] in
|
presentTextFormattingTooltip: { [weak self] in
|
||||||
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else {
|
guard let self, let controller = self.environment?.controller() as? MediaEditorScreen else {
|
||||||
@ -1193,6 +1196,11 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
controller.node.interaction?.insertEntity(entity, scale: 2.5)
|
controller.node.interaction?.insertEntity(entity, scale: 2.5)
|
||||||
self.deactivateInput()
|
self.deactivateInput()
|
||||||
}
|
}
|
||||||
|
case .text:
|
||||||
|
let text = self.getInputText()
|
||||||
|
if text.length > component.context.userLimits.maxStoryCaptionLength {
|
||||||
|
controller.presentCaptionLimitPremiumSuggestion(isPremium: self.state?.isPremium ?? false)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -2977,7 +2985,15 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
if let self {
|
if let self {
|
||||||
if let content {
|
if let content {
|
||||||
let stickerEntity = DrawingStickerEntity(content: content)
|
let stickerEntity = DrawingStickerEntity(content: content)
|
||||||
self.interaction?.insertEntity(stickerEntity, scale: 1.33)
|
let scale: CGFloat
|
||||||
|
if case .image = content {
|
||||||
|
scale = 2.5
|
||||||
|
} else if case .video = content {
|
||||||
|
scale = 2.5
|
||||||
|
} else {
|
||||||
|
scale = 1.33
|
||||||
|
}
|
||||||
|
self.interaction?.insertEntity(stickerEntity, scale: scale)
|
||||||
|
|
||||||
self.hasAnyChanges = true
|
self.hasAnyChanges = true
|
||||||
self.controller?.isSavingAvailable = true
|
self.controller?.isSavingAvailable = true
|
||||||
@ -3641,7 +3657,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
|
|
||||||
let controller = UndoOverlayController(presentationData: presentationData, content: .autoDelete(isOn: true, title: nil, text: text, customUndoText: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
let controller = UndoOverlayController(presentationData: presentationData, content: .autoDelete(isOn: true, title: nil, text: text, customUndoText: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
||||||
if case .info = action, let self {
|
if case .info = action, let self {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true, dismissed: nil)
|
||||||
self.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
return false }
|
return false }
|
||||||
@ -3649,7 +3665,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
self.present(controller, in: .current)
|
self.present(controller, in: .current)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func presentCaptionLimitPremiumSuggestion() {
|
fileprivate func presentCaptionLimitPremiumSuggestion(isPremium: Bool) {
|
||||||
self.dismissAllTooltips()
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
let context = self.context
|
let context = self.context
|
||||||
@ -3660,7 +3676,9 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
|
|
||||||
let controller = UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_read", scale: 0.25, colors: [:], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
let controller = UndoOverlayController(presentationData: presentationData, content: .universal(animation: "anim_read", scale: 0.25, colors: [:], title: title, text: text, customUndoText: nil, timeout: nil), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
||||||
if case .info = action, let self {
|
if case .info = action, let self {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true, dismissed: {
|
||||||
|
|
||||||
|
})
|
||||||
self.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
return false }
|
return false }
|
||||||
@ -3678,7 +3696,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
|
|
||||||
let controller = UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: text), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
let controller = UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: text), elevatedLayout: false, position: .top, animateInAsReplacement: false, action: { [weak self] action in
|
||||||
if case .info = action, let self {
|
if case .info = action, let self {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories, forceDark: true, dismissed: nil)
|
||||||
self.push(controller)
|
self.push(controller)
|
||||||
}
|
}
|
||||||
return false }
|
return false }
|
||||||
@ -3960,6 +3978,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
if mediaEditor.resultIsVideo {
|
if mediaEditor.resultIsVideo {
|
||||||
|
self.saveDraft(id: randomId)
|
||||||
|
|
||||||
var firstFrame: Signal<(UIImage?, UIImage?), NoError>
|
var firstFrame: Signal<(UIImage?, UIImage?), NoError>
|
||||||
let firstFrameTime = CMTime(seconds: mediaEditor.values.videoTrimRange?.lowerBound ?? 0.0, preferredTimescale: CMTimeScale(60))
|
let firstFrameTime = CMTime(seconds: mediaEditor.values.videoTrimRange?.lowerBound ?? 0.0, preferredTimescale: CMTimeScale(60))
|
||||||
|
|
||||||
|
@ -765,7 +765,7 @@ public final class MessageInputPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let maxLength = component.maxLength, maxLength - self.textFieldExternalState.textLength < 5 {
|
if let maxLength = component.maxLength, maxLength - self.textFieldExternalState.textLength < 5 && isEditing {
|
||||||
let remainingLength = max(-999, maxLength - self.textFieldExternalState.textLength)
|
let remainingLength = max(-999, maxLength - self.textFieldExternalState.textLength)
|
||||||
let counterSize = self.counter.update(
|
let counterSize = self.counter.update(
|
||||||
transition: .immediate,
|
transition: .immediate,
|
||||||
|
@ -277,7 +277,7 @@ final class StickersResultPanelComponent: Component {
|
|||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let controller = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .stickers, forceDark: false)
|
let controller = component.context.sharedContext.makePremiumIntroController(context: component.context, source: .stickers, forceDark: false, dismissed: nil)
|
||||||
component.present(controller)
|
component.present(controller)
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
|
@ -2226,6 +2226,8 @@ public final class StoryItemSetContainerComponent: Component {
|
|||||||
self.sendMessageContext.enqueueGifData(view: self, data: data)
|
self.sendMessageContext.enqueueGifData(view: self, data: data)
|
||||||
case let .sticker(image, isMemoji):
|
case let .sticker(image, isMemoji):
|
||||||
self.sendMessageContext.enqueueStickerImage(view: self, image: image, isMemoji: isMemoji)
|
self.sendMessageContext.enqueueStickerImage(view: self, image: image, isMemoji: isMemoji)
|
||||||
|
case .text:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
audioRecorder: self.sendMessageContext.audioRecorderValue,
|
audioRecorder: self.sendMessageContext.audioRecorderValue,
|
||||||
|
@ -60,6 +60,7 @@ public final class TextFieldComponent: Component {
|
|||||||
case images([UIImage])
|
case images([UIImage])
|
||||||
case video(Data)
|
case video(Data)
|
||||||
case gif(Data)
|
case gif(Data)
|
||||||
|
case text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -348,6 +349,7 @@ public final class TextFieldComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component.paste(.text)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
|
|||||||
if case .undo = action {
|
if case .undo = action {
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .voiceToText, action: {
|
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .voiceToText, action: {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false, dismissed: nil)
|
||||||
replaceImpl?(controller)
|
replaceImpl?(controller)
|
||||||
})
|
})
|
||||||
replaceImpl = { [weak controller] c in
|
replaceImpl = { [weak controller] c in
|
||||||
|
@ -1548,7 +1548,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
|
|||||||
let context = item.context
|
let context = item.context
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .voiceToText, action: {
|
let controller = context.sharedContext.makePremiumDemoController(context: context, subject: .voiceToText, action: {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .settings, forceDark: false, dismissed: nil)
|
||||||
replaceImpl?(controller)
|
replaceImpl?(controller)
|
||||||
})
|
})
|
||||||
replaceImpl = { [weak controller] c in
|
replaceImpl = { [weak controller] c in
|
||||||
|
@ -201,7 +201,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||||||
let context = strongSelf.context
|
let context = strongSelf.context
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
let controller = context.sharedContext.makePremiumLimitController(context: context, subject: .folders, count: strongSelf.tabContainerNode?.filtersCount ?? 0, action: {
|
let controller = context.sharedContext.makePremiumLimitController(context: context, subject: .folders, count: strongSelf.tabContainerNode?.filtersCount ?? 0, action: {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .folders, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .folders, forceDark: false, dismissed: nil)
|
||||||
replaceImpl?(controller)
|
replaceImpl?(controller)
|
||||||
})
|
})
|
||||||
replaceImpl = { [weak controller] c in
|
replaceImpl = { [weak controller] c in
|
||||||
|
@ -293,7 +293,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
let controller = context.sharedContext.makePremiumLimitController(context: context, subject: .folders, count: strongSelf.controller?.tabContainerNode?.filtersCount ?? 0, action: {
|
let controller = context.sharedContext.makePremiumLimitController(context: context, subject: .folders, count: strongSelf.controller?.tabContainerNode?.filtersCount ?? 0, action: {
|
||||||
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .folders, forceDark: false)
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .folders, forceDark: false, dismissed: nil)
|
||||||
replaceImpl?(controller)
|
replaceImpl?(controller)
|
||||||
})
|
})
|
||||||
replaceImpl = { [weak controller] c in
|
replaceImpl = { [weak controller] c in
|
||||||
|
@ -1732,7 +1732,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
return archiveSettingsController(context: context)
|
return archiveSettingsController(context: context)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool) -> ViewController {
|
public func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController {
|
||||||
let mappedSource: PremiumSource
|
let mappedSource: PremiumSource
|
||||||
switch source {
|
switch source {
|
||||||
case .settings:
|
case .settings:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user