mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-10-09 03:20:48 +00:00
Stories
This commit is contained in:
parent
75c01b0897
commit
53aa40353a
@ -939,6 +939,7 @@ public enum PremiumIntroSource {
|
|||||||
case voiceToText
|
case voiceToText
|
||||||
case fasterDownload
|
case fasterDownload
|
||||||
case translation
|
case translation
|
||||||
|
case stories
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PremiumDemoSubject {
|
public enum PremiumDemoSubject {
|
||||||
@ -956,6 +957,7 @@ public enum PremiumDemoSubject {
|
|||||||
case animatedEmoji
|
case animatedEmoji
|
||||||
case emojiStatus
|
case emojiStatus
|
||||||
case translation
|
case translation
|
||||||
|
case stories
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PremiumLimitSubject {
|
public enum PremiumLimitSubject {
|
||||||
|
@ -158,7 +158,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
private var activeDownloadsDisposable: Disposable?
|
private var activeDownloadsDisposable: Disposable?
|
||||||
private var clearUnseenDownloadsTimer: SwiftSignalKit.Timer?
|
private var clearUnseenDownloadsTimer: SwiftSignalKit.Timer?
|
||||||
|
|
||||||
private var isPremium: Bool = false
|
private(set) var isPremium: Bool = false
|
||||||
|
|
||||||
private var didSetupTabs = false
|
private var didSetupTabs = false
|
||||||
|
|
||||||
@ -2341,6 +2341,19 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func openStoryCamera() {
|
fileprivate func openStoryCamera() {
|
||||||
|
guard self.isPremium else {
|
||||||
|
let context = self.context
|
||||||
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
|
let controller = context.sharedContext.makePremiumDemoController(context: self.context, subject: .stories, action: {
|
||||||
|
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .stories)
|
||||||
|
replaceImpl?(controller)
|
||||||
|
})
|
||||||
|
replaceImpl = { [weak controller] c in
|
||||||
|
controller?.replace(with: c)
|
||||||
|
}
|
||||||
|
self.push(controller)
|
||||||
|
return
|
||||||
|
}
|
||||||
var cameraTransitionIn: StoryCameraTransitionIn?
|
var cameraTransitionIn: StoryCameraTransitionIn?
|
||||||
if let componentView = self.chatListHeaderView() {
|
if let componentView = self.chatListHeaderView() {
|
||||||
if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
if let (transitionView, _) = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
@ -2501,7 +2514,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
})))
|
})))
|
||||||
|
|
||||||
let isMuted = notificationSettings.storiesMuted == true
|
let isMuted = notificationSettings.storiesMuted == true
|
||||||
items.append(.action(ContextMenuActionItem(text: isMuted ? "Unmute" : "Mute", icon: { theme in
|
items.append(.action(ContextMenuActionItem(text: isMuted ? "Notify" : "Not Notify", icon: { theme in
|
||||||
return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Muted": "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor)
|
return generateTintedImage(image: UIImage(bundleImageName: isMuted ? "Chat/Context Menu/Muted": "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor)
|
||||||
}, action: { [weak self] _, f in
|
}, action: { [weak self] _, f in
|
||||||
f(.default)
|
f(.default)
|
||||||
|
@ -1191,7 +1191,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
return bandingStart + (1.0 - (1.0 / ((bandedOffset * coefficient / range) + 1.0))) * range
|
return bandingStart + (1.0 - (1.0 / ((bandedOffset * coefficient / range) + 1.0))) * range
|
||||||
}
|
}
|
||||||
|
|
||||||
if case .compact = layout.metrics.widthClass {
|
if case .compact = layout.metrics.widthClass, self.controller?.isPremium == true {
|
||||||
let cameraIsAlreadyOpened = self.controller?.hasStoryCameraTransition ?? false
|
let cameraIsAlreadyOpened = self.controller?.hasStoryCameraTransition ?? false
|
||||||
if selectedIndex <= 0 && translation.x > 0.0 {
|
if selectedIndex <= 0 && translation.x > 0.0 {
|
||||||
transitionFraction = 0.0
|
transitionFraction = 0.0
|
||||||
@ -1204,6 +1204,11 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
transitionFraction = 0.0
|
transitionFraction = 0.0
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if selectedIndex <= 0 && translation.x > 0.0 {
|
||||||
|
let overscroll = translation.x
|
||||||
|
transitionFraction = rubberBandingOffset(offset: overscroll, bandingStart: 0.0) / layout.size.width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if selectedIndex >= maxFilterIndex && translation.x < 0.0 {
|
if selectedIndex >= maxFilterIndex && translation.x < 0.0 {
|
||||||
|
@ -68,6 +68,9 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
private var presentationDataDisposable: Disposable?
|
private var presentationDataDisposable: Disposable?
|
||||||
private let stringsPromise = Promise<PresentationStrings>()
|
private let stringsPromise = Promise<PresentationStrings>()
|
||||||
|
|
||||||
|
private var isPremium = false
|
||||||
|
private var isPremiumDisposable: Disposable?
|
||||||
|
|
||||||
weak var controller: ContactsController?
|
weak var controller: ContactsController?
|
||||||
|
|
||||||
private var initialScrollingOffset: CGFloat?
|
private var initialScrollingOffset: CGFloat?
|
||||||
@ -258,11 +261,22 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
self.storiesReady.set(.single(true))
|
self.storiesReady.set(.single(true))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
self.isPremiumDisposable = (self.context.engine.data.subscribe(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||||
|
|> map {
|
||||||
|
return $0?.isPremium ?? false
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] isPremium in
|
||||||
|
if let self {
|
||||||
|
self.isPremium = isPremium
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
deinit {
|
deinit {
|
||||||
self.presentationDataDisposable?.dispose()
|
self.presentationDataDisposable?.dispose()
|
||||||
self.storySubscriptionsDisposable?.dispose()
|
self.storySubscriptionsDisposable?.dispose()
|
||||||
|
self.isPremiumDisposable?.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
@ -293,6 +307,10 @@ final class ContactsControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||||
|
return self.isPremium
|
||||||
|
}
|
||||||
|
|
||||||
private func updateThemeAndStrings() {
|
private func updateThemeAndStrings() {
|
||||||
self.backgroundColor = self.presentationData.theme.chatList.backgroundColor
|
self.backgroundColor = self.presentationData.theme.chatList.backgroundColor
|
||||||
self.searchDisplayController?.updatePresentationData(self.presentationData)
|
self.searchDisplayController?.updatePresentationData(self.presentationData)
|
||||||
|
@ -471,7 +471,7 @@ private final class DemoSheetContent: CombinedComponent {
|
|||||||
self.context = context
|
self.context = context
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.source = source
|
self.source = source
|
||||||
self.order = order ?? [.moreUpload, .fasterDownload, .voiceToText, .noAds, .uniqueReactions, .premiumStickers, .animatedEmoji, .advancedChatManagement, .profileBadge, .animatedUserpics, .appIcons, .translation]
|
self.order = order ?? [.moreUpload, .fasterDownload, .voiceToText, .noAds, .uniqueReactions, .premiumStickers, .animatedEmoji, .advancedChatManagement, .profileBadge, .animatedUserpics, .appIcons, .translation, .stories]
|
||||||
self.action = action
|
self.action = action
|
||||||
self.dismiss = dismiss
|
self.dismiss = dismiss
|
||||||
}
|
}
|
||||||
@ -939,6 +939,25 @@ private final class DemoSheetContent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
//TODO:localize
|
||||||
|
availableItems[.stories] = DemoPagerComponent.Item(
|
||||||
|
AnyComponentWithIdentity(
|
||||||
|
id: PremiumDemoScreen.Subject.stories,
|
||||||
|
component: AnyComponent(
|
||||||
|
PageComponent(
|
||||||
|
content: AnyComponent(PhoneDemoComponent(
|
||||||
|
context: component.context,
|
||||||
|
position: .top,
|
||||||
|
videoFile: configuration.videos["voice_to_text"],
|
||||||
|
decoration: .badgeStars
|
||||||
|
)),
|
||||||
|
title: "Story Posting",
|
||||||
|
text: "Be one of the first to share your stories with your contacts or an unlimited audience.",
|
||||||
|
textColor: textColor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
var items: [DemoPagerComponent.Item] = component.order.compactMap { availableItems[$0] }
|
var items: [DemoPagerComponent.Item] = component.order.compactMap { availableItems[$0] }
|
||||||
let index: Int
|
let index: Int
|
||||||
@ -1029,6 +1048,10 @@ private final class DemoSheetContent: CombinedComponent {
|
|||||||
buttonAnimationName = "premium_unlock"
|
buttonAnimationName = "premium_unlock"
|
||||||
case .translation:
|
case .translation:
|
||||||
buttonText = strings.Premium_Translation_Proceed
|
buttonText = strings.Premium_Translation_Proceed
|
||||||
|
case .stories:
|
||||||
|
//TODO:localize
|
||||||
|
buttonText = "Unlock Story Posting"
|
||||||
|
buttonAnimationName = "premium_unlock"
|
||||||
default:
|
default:
|
||||||
buttonText = strings.Common_OK
|
buttonText = strings.Common_OK
|
||||||
}
|
}
|
||||||
@ -1210,6 +1233,7 @@ public class PremiumDemoScreen: ViewControllerComponentContainer {
|
|||||||
case animatedEmoji
|
case animatedEmoji
|
||||||
case emojiStatus
|
case emojiStatus
|
||||||
case translation
|
case translation
|
||||||
|
case stories
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Source: Equatable {
|
public enum Source: Equatable {
|
||||||
|
@ -397,6 +397,8 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent {
|
|||||||
demoSubject = .emojiStatus
|
demoSubject = .emojiStatus
|
||||||
case .translation:
|
case .translation:
|
||||||
demoSubject = .translation
|
demoSubject = .translation
|
||||||
|
case .stories:
|
||||||
|
demoSubject = .stories
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttonText: String
|
let buttonText: String
|
||||||
|
@ -184,6 +184,12 @@ public enum PremiumSource: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case .stories:
|
||||||
|
if case .stories = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,63 +219,66 @@ public enum PremiumSource: Equatable {
|
|||||||
case translation
|
case translation
|
||||||
case linksPerSharedFolder
|
case linksPerSharedFolder
|
||||||
case membershipInSharedFolders
|
case membershipInSharedFolders
|
||||||
|
case stories
|
||||||
|
|
||||||
var identifier: String? {
|
var identifier: String? {
|
||||||
switch self {
|
switch self {
|
||||||
case .settings:
|
case .settings:
|
||||||
return "settings"
|
return "settings"
|
||||||
case .stickers:
|
case .stickers:
|
||||||
return "premium_stickers"
|
return "premium_stickers"
|
||||||
case .reactions:
|
case .reactions:
|
||||||
return "infinite_reactions"
|
return "infinite_reactions"
|
||||||
case .ads:
|
case .ads:
|
||||||
return "no_ads"
|
return "no_ads"
|
||||||
case .upload:
|
case .upload:
|
||||||
return "more_upload"
|
return "more_upload"
|
||||||
case .appIcons:
|
case .appIcons:
|
||||||
return "app_icons"
|
return "app_icons"
|
||||||
case .groupsAndChannels:
|
case .groupsAndChannels:
|
||||||
return "double_limits__channels"
|
return "double_limits__channels"
|
||||||
case .pinnedChats:
|
case .pinnedChats:
|
||||||
return "double_limits__dialog_pinned"
|
return "double_limits__dialog_pinned"
|
||||||
case .publicLinks:
|
case .publicLinks:
|
||||||
return "double_limits__channels_public"
|
return "double_limits__channels_public"
|
||||||
case .savedGifs:
|
case .savedGifs:
|
||||||
return "double_limits__saved_gifs"
|
return "double_limits__saved_gifs"
|
||||||
case .savedStickers:
|
case .savedStickers:
|
||||||
return "double_limits__stickers_faved"
|
return "double_limits__stickers_faved"
|
||||||
case .folders:
|
case .folders:
|
||||||
return "double_limits__dialog_filters"
|
return "double_limits__dialog_filters"
|
||||||
case .chatsPerFolder:
|
case .chatsPerFolder:
|
||||||
return "double_limits__dialog_filters_chats"
|
return "double_limits__dialog_filters_chats"
|
||||||
case .accounts:
|
case .accounts:
|
||||||
return "double_limits__accounts"
|
return "double_limits__accounts"
|
||||||
case .about:
|
case .about:
|
||||||
return "double_limits__about"
|
return "double_limits__about"
|
||||||
case .animatedEmoji:
|
case .animatedEmoji:
|
||||||
return "animated_emoji"
|
return "animated_emoji"
|
||||||
case let .profile(id):
|
case let .profile(id):
|
||||||
return "profile__\(id.id._internalGetInt64Value())"
|
return "profile__\(id.id._internalGetInt64Value())"
|
||||||
case .emojiStatus:
|
case .emojiStatus:
|
||||||
return "emoji_status"
|
return "emoji_status"
|
||||||
case .voiceToText:
|
case .voiceToText:
|
||||||
return "voice_to_text"
|
return "voice_to_text"
|
||||||
case .fasterDownload:
|
case .fasterDownload:
|
||||||
return "faster_download"
|
return "faster_download"
|
||||||
case .gift, .giftTerms:
|
case .gift, .giftTerms:
|
||||||
return nil
|
return nil
|
||||||
case let .deeplink(reference):
|
case let .deeplink(reference):
|
||||||
if let reference = reference {
|
if let reference = reference {
|
||||||
return "deeplink_\(reference)"
|
return "deeplink_\(reference)"
|
||||||
} else {
|
} else {
|
||||||
return "deeplink"
|
return "deeplink"
|
||||||
}
|
}
|
||||||
case .translation:
|
case .translation:
|
||||||
return "translations"
|
return "translations"
|
||||||
case .linksPerSharedFolder:
|
case .linksPerSharedFolder:
|
||||||
return "double_limits__community_invites"
|
return "double_limits__community_invites"
|
||||||
case .membershipInSharedFolders:
|
case .membershipInSharedFolders:
|
||||||
return "double_limits__communities_joined"
|
return "double_limits__communities_joined"
|
||||||
|
case .stories:
|
||||||
|
return "stories"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -289,6 +298,7 @@ enum PremiumPerk: CaseIterable {
|
|||||||
case animatedEmoji
|
case animatedEmoji
|
||||||
case emojiStatus
|
case emojiStatus
|
||||||
case translation
|
case translation
|
||||||
|
case stories
|
||||||
|
|
||||||
static var allCases: [PremiumPerk] {
|
static var allCases: [PremiumPerk] {
|
||||||
return [
|
return [
|
||||||
@ -321,133 +331,142 @@ enum PremiumPerk: CaseIterable {
|
|||||||
|
|
||||||
var identifier: String {
|
var identifier: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .doubleLimits:
|
case .doubleLimits:
|
||||||
return "double_limits"
|
return "double_limits"
|
||||||
case .moreUpload:
|
case .moreUpload:
|
||||||
return "more_upload"
|
return "more_upload"
|
||||||
case .fasterDownload:
|
case .fasterDownload:
|
||||||
return "faster_download"
|
return "faster_download"
|
||||||
case .voiceToText:
|
case .voiceToText:
|
||||||
return "voice_to_text"
|
return "voice_to_text"
|
||||||
case .noAds:
|
case .noAds:
|
||||||
return "no_ads"
|
return "no_ads"
|
||||||
case .uniqueReactions:
|
case .uniqueReactions:
|
||||||
return "infinite_reactions"
|
return "infinite_reactions"
|
||||||
case .premiumStickers:
|
case .premiumStickers:
|
||||||
return "premium_stickers"
|
return "premium_stickers"
|
||||||
case .advancedChatManagement:
|
case .advancedChatManagement:
|
||||||
return "advanced_chat_management"
|
return "advanced_chat_management"
|
||||||
case .profileBadge:
|
case .profileBadge:
|
||||||
return "profile_badge"
|
return "profile_badge"
|
||||||
case .animatedUserpics:
|
case .animatedUserpics:
|
||||||
return "animated_userpics"
|
return "animated_userpics"
|
||||||
case .appIcons:
|
case .appIcons:
|
||||||
return "app_icons"
|
return "app_icons"
|
||||||
case .animatedEmoji:
|
case .animatedEmoji:
|
||||||
return "animated_emoji"
|
return "animated_emoji"
|
||||||
case .emojiStatus:
|
case .emojiStatus:
|
||||||
return "emoji_status"
|
return "emoji_status"
|
||||||
case .translation:
|
case .translation:
|
||||||
return "translations"
|
return "translations"
|
||||||
|
case .stories:
|
||||||
|
return "stories"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func title(strings: PresentationStrings) -> String {
|
func title(strings: PresentationStrings) -> String {
|
||||||
switch self {
|
switch self {
|
||||||
case .doubleLimits:
|
case .doubleLimits:
|
||||||
return strings.Premium_DoubledLimits
|
return strings.Premium_DoubledLimits
|
||||||
case .moreUpload:
|
case .moreUpload:
|
||||||
return strings.Premium_UploadSize
|
return strings.Premium_UploadSize
|
||||||
case .fasterDownload:
|
case .fasterDownload:
|
||||||
return strings.Premium_FasterSpeed
|
return strings.Premium_FasterSpeed
|
||||||
case .voiceToText:
|
case .voiceToText:
|
||||||
return strings.Premium_VoiceToText
|
return strings.Premium_VoiceToText
|
||||||
case .noAds:
|
case .noAds:
|
||||||
return strings.Premium_NoAds
|
return strings.Premium_NoAds
|
||||||
case .uniqueReactions:
|
case .uniqueReactions:
|
||||||
return strings.Premium_InfiniteReactions
|
return strings.Premium_InfiniteReactions
|
||||||
case .premiumStickers:
|
case .premiumStickers:
|
||||||
return strings.Premium_Stickers
|
return strings.Premium_Stickers
|
||||||
case .advancedChatManagement:
|
case .advancedChatManagement:
|
||||||
return strings.Premium_ChatManagement
|
return strings.Premium_ChatManagement
|
||||||
case .profileBadge:
|
case .profileBadge:
|
||||||
return strings.Premium_Badge
|
return strings.Premium_Badge
|
||||||
case .animatedUserpics:
|
case .animatedUserpics:
|
||||||
return strings.Premium_Avatar
|
return strings.Premium_Avatar
|
||||||
case .appIcons:
|
case .appIcons:
|
||||||
return strings.Premium_AppIcon
|
return strings.Premium_AppIcon
|
||||||
case .animatedEmoji:
|
case .animatedEmoji:
|
||||||
return strings.Premium_AnimatedEmoji
|
return strings.Premium_AnimatedEmoji
|
||||||
case .emojiStatus:
|
case .emojiStatus:
|
||||||
return strings.Premium_EmojiStatus
|
return strings.Premium_EmojiStatus
|
||||||
case .translation:
|
case .translation:
|
||||||
return strings.Premium_Translation
|
return strings.Premium_Translation
|
||||||
|
case .stories:
|
||||||
|
//TODO:localize
|
||||||
|
return "Story Posting"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func subtitle(strings: PresentationStrings) -> String {
|
func subtitle(strings: PresentationStrings) -> String {
|
||||||
switch self {
|
switch self {
|
||||||
case .doubleLimits:
|
case .doubleLimits:
|
||||||
return strings.Premium_DoubledLimitsInfo
|
return strings.Premium_DoubledLimitsInfo
|
||||||
case .moreUpload:
|
case .moreUpload:
|
||||||
return strings.Premium_UploadSizeInfo
|
return strings.Premium_UploadSizeInfo
|
||||||
case .fasterDownload:
|
case .fasterDownload:
|
||||||
return strings.Premium_FasterSpeedInfo
|
return strings.Premium_FasterSpeedInfo
|
||||||
case .voiceToText:
|
case .voiceToText:
|
||||||
return strings.Premium_VoiceToTextInfo
|
return strings.Premium_VoiceToTextInfo
|
||||||
case .noAds:
|
case .noAds:
|
||||||
return strings.Premium_NoAdsInfo
|
return strings.Premium_NoAdsInfo
|
||||||
case .uniqueReactions:
|
case .uniqueReactions:
|
||||||
return strings.Premium_InfiniteReactionsInfo
|
return strings.Premium_InfiniteReactionsInfo
|
||||||
case .premiumStickers:
|
case .premiumStickers:
|
||||||
return strings.Premium_StickersInfo
|
return strings.Premium_StickersInfo
|
||||||
case .advancedChatManagement:
|
case .advancedChatManagement:
|
||||||
return strings.Premium_ChatManagementInfo
|
return strings.Premium_ChatManagementInfo
|
||||||
case .profileBadge:
|
case .profileBadge:
|
||||||
return strings.Premium_BadgeInfo
|
return strings.Premium_BadgeInfo
|
||||||
case .animatedUserpics:
|
case .animatedUserpics:
|
||||||
return strings.Premium_AvatarInfo
|
return strings.Premium_AvatarInfo
|
||||||
case .appIcons:
|
case .appIcons:
|
||||||
return strings.Premium_AppIconInfo
|
return strings.Premium_AppIconInfo
|
||||||
case .animatedEmoji:
|
case .animatedEmoji:
|
||||||
return strings.Premium_AnimatedEmojiInfo
|
return strings.Premium_AnimatedEmojiInfo
|
||||||
case .emojiStatus:
|
case .emojiStatus:
|
||||||
return strings.Premium_EmojiStatusInfo
|
return strings.Premium_EmojiStatusInfo
|
||||||
case .translation:
|
case .translation:
|
||||||
return strings.Premium_TranslationInfo
|
return strings.Premium_TranslationInfo
|
||||||
|
case .stories:
|
||||||
|
return "Be one of the first to share your stories with your contacts or an unlimited audience."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var iconName: String {
|
var iconName: String {
|
||||||
switch self {
|
switch self {
|
||||||
case .doubleLimits:
|
case .doubleLimits:
|
||||||
return "Premium/Perk/Limits"
|
return "Premium/Perk/Limits"
|
||||||
case .moreUpload:
|
case .moreUpload:
|
||||||
return "Premium/Perk/Upload"
|
return "Premium/Perk/Upload"
|
||||||
case .fasterDownload:
|
case .fasterDownload:
|
||||||
return "Premium/Perk/Speed"
|
return "Premium/Perk/Speed"
|
||||||
case .voiceToText:
|
case .voiceToText:
|
||||||
return "Premium/Perk/Voice"
|
return "Premium/Perk/Voice"
|
||||||
case .noAds:
|
case .noAds:
|
||||||
return "Premium/Perk/NoAds"
|
return "Premium/Perk/NoAds"
|
||||||
case .uniqueReactions:
|
case .uniqueReactions:
|
||||||
return "Premium/Perk/Reactions"
|
return "Premium/Perk/Reactions"
|
||||||
case .premiumStickers:
|
case .premiumStickers:
|
||||||
return "Premium/Perk/Stickers"
|
return "Premium/Perk/Stickers"
|
||||||
case .advancedChatManagement:
|
case .advancedChatManagement:
|
||||||
return "Premium/Perk/Chat"
|
return "Premium/Perk/Chat"
|
||||||
case .profileBadge:
|
case .profileBadge:
|
||||||
return "Premium/Perk/Badge"
|
return "Premium/Perk/Badge"
|
||||||
case .animatedUserpics:
|
case .animatedUserpics:
|
||||||
return "Premium/Perk/Avatar"
|
return "Premium/Perk/Avatar"
|
||||||
case .appIcons:
|
case .appIcons:
|
||||||
return "Premium/Perk/AppIcon"
|
return "Premium/Perk/AppIcon"
|
||||||
case .animatedEmoji:
|
case .animatedEmoji:
|
||||||
return "Premium/Perk/Emoji"
|
return "Premium/Perk/Emoji"
|
||||||
case .emojiStatus:
|
case .emojiStatus:
|
||||||
return "Premium/Perk/Status"
|
return "Premium/Perk/Status"
|
||||||
case .translation:
|
case .translation:
|
||||||
return "Premium/Perk/Translation"
|
return "Premium/Perk/Translation"
|
||||||
|
case .stories:
|
||||||
|
return "Premium/Perk/Translation"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1714,6 +1733,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
|
|||||||
demoSubject = .emojiStatus
|
demoSubject = .emojiStatus
|
||||||
case .translation:
|
case .translation:
|
||||||
demoSubject = .translation
|
demoSubject = .translation
|
||||||
|
case .stories:
|
||||||
|
demoSubject = .stories
|
||||||
}
|
}
|
||||||
|
|
||||||
let isPremium = state?.isPremium == true
|
let isPremium = state?.isPremium == true
|
||||||
|
@ -888,7 +888,7 @@ final class MediaEditorScreenComponent: Component {
|
|||||||
timeoutSelected = false
|
timeoutSelected = false
|
||||||
|
|
||||||
var inputPanelAvailableWidth = previewSize.width
|
var inputPanelAvailableWidth = previewSize.width
|
||||||
var inputPanelAvailableHeight = 115.0
|
var inputPanelAvailableHeight = 103.0
|
||||||
if case .regular = environment.metrics.widthClass {
|
if case .regular = environment.metrics.widthClass {
|
||||||
if (self.inputPanelExternalState.isEditing || self.inputPanelExternalState.hasText) {
|
if (self.inputPanelExternalState.isEditing || self.inputPanelExternalState.hasText) {
|
||||||
inputPanelAvailableWidth += 200.0
|
inputPanelAvailableWidth += 200.0
|
||||||
@ -1547,6 +1547,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
private var isDismissing = false
|
private var isDismissing = false
|
||||||
private var dismissOffset: CGFloat = 0.0
|
private var dismissOffset: CGFloat = 0.0
|
||||||
private var isDismissed = false
|
private var isDismissed = false
|
||||||
|
private var isDismissBySwipeSuppressed = false
|
||||||
|
|
||||||
private var presentationData: PresentationData
|
private var presentationData: PresentationData
|
||||||
private var validLayout: ContainerViewLayout?
|
private var validLayout: ContainerViewLayout?
|
||||||
@ -1955,6 +1956,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
if abs(translation.y) > 10.0 && !self.isEnhancing && hasSwipeToDismiss {
|
if abs(translation.y) > 10.0 && !self.isEnhancing && hasSwipeToDismiss {
|
||||||
if !self.isDismissing {
|
if !self.isDismissing {
|
||||||
self.isDismissing = true
|
self.isDismissing = true
|
||||||
|
self.isDismissBySwipeSuppressed = controller.isEligibleForDraft()
|
||||||
controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut))
|
controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut))
|
||||||
}
|
}
|
||||||
} else if abs(translation.x) > 10.0 && !self.isDismissing {
|
} else if abs(translation.x) > 10.0 && !self.isDismissing {
|
||||||
@ -1965,6 +1967,12 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
if self.isDismissing {
|
if self.isDismissing {
|
||||||
self.dismissOffset = translation.y
|
self.dismissOffset = translation.y
|
||||||
controller.requestLayout(transition: .immediate)
|
controller.requestLayout(transition: .immediate)
|
||||||
|
|
||||||
|
if abs(self.dismissOffset) > 20.0, controller.isEligibleForDraft() {
|
||||||
|
gestureRecognizer.isEnabled = false
|
||||||
|
gestureRecognizer.isEnabled = true
|
||||||
|
controller.maybePresentDiscardAlert()
|
||||||
|
}
|
||||||
} else if self.isEnhancing {
|
} else if self.isEnhancing {
|
||||||
if let mediaEditor = self.mediaEditor {
|
if let mediaEditor = self.mediaEditor {
|
||||||
let value = mediaEditor.getToolValue(.enhance) as? Float ?? 0.0
|
let value = mediaEditor.getToolValue(.enhance) as? Float ?? 0.0
|
||||||
@ -1977,7 +1985,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
case .ended, .cancelled:
|
case .ended, .cancelled:
|
||||||
if self.isDismissing {
|
if self.isDismissing {
|
||||||
if abs(translation.y) > self.view.frame.height * 0.33 || abs(velocity.y) > 1000.0 {
|
if abs(translation.y) > self.view.frame.height * 0.33 || abs(velocity.y) > 1000.0, !controller.isEligibleForDraft() {
|
||||||
controller.requestDismiss(saveDraft: false, animated: true)
|
controller.requestDismiss(saveDraft: false, animated: true)
|
||||||
} else {
|
} else {
|
||||||
self.dismissOffset = 0.0
|
self.dismissOffset = 0.0
|
||||||
@ -2532,7 +2540,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
isInteractingWithEntities: self.isInteractingWithEntities,
|
isInteractingWithEntities: self.isInteractingWithEntities,
|
||||||
isSavingAvailable: controller.isSavingAvailable,
|
isSavingAvailable: controller.isSavingAvailable,
|
||||||
hasAppeared: self.hasAppeared,
|
hasAppeared: self.hasAppeared,
|
||||||
isDismissing: self.isDismissing,
|
isDismissing: self.isDismissing && !self.isDismissBySwipeSuppressed,
|
||||||
bottomSafeInset: layout.intrinsicInsets.bottom,
|
bottomSafeInset: layout.intrinsicInsets.bottom,
|
||||||
mediaEditor: self.mediaEditor,
|
mediaEditor: self.mediaEditor,
|
||||||
privacy: controller.state.privacy,
|
privacy: controller.state.privacy,
|
||||||
@ -2697,7 +2705,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
}
|
}
|
||||||
|
|
||||||
transition.setFrame(view: self.backgroundDimView, frame: CGRect(origin: .zero, size: layout.size))
|
transition.setFrame(view: self.backgroundDimView, frame: CGRect(origin: .zero, size: layout.size))
|
||||||
transition.setAlpha(view: self.backgroundDimView, alpha: self.isDismissing ? 0.0 : 1.0)
|
transition.setAlpha(view: self.backgroundDimView, alpha: self.isDismissing && !self.isDismissBySwipeSuppressed ? 0.0 : 1.0)
|
||||||
|
|
||||||
var bottomInputOffset: CGFloat = 0.0
|
var bottomInputOffset: CGFloat = 0.0
|
||||||
if inputHeight > 0.0 {
|
if inputHeight > 0.0 {
|
||||||
@ -3042,19 +3050,27 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
|
|||||||
self.present(controller, in: .current)
|
self.present(controller, in: .current)
|
||||||
}
|
}
|
||||||
|
|
||||||
func maybePresentDiscardAlert() {
|
func isEligibleForDraft() -> Bool {
|
||||||
guard let mediaEditor = self.node.mediaEditor else {
|
guard let mediaEditor = self.node.mediaEditor else {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
let entities = self.node.entitiesView.entities.filter { !($0 is DrawingMediaEntity) }
|
let entities = self.node.entitiesView.entities.filter { !($0 is DrawingMediaEntity) }
|
||||||
let codableEntities = DrawingEntitiesView.encodeEntities(entities, entitiesView: self.node.entitiesView)
|
let codableEntities = DrawingEntitiesView.encodeEntities(entities, entitiesView: self.node.entitiesView)
|
||||||
mediaEditor.setDrawingAndEntities(data: nil, image: mediaEditor.values.drawing, entities: codableEntities)
|
mediaEditor.setDrawingAndEntities(data: nil, image: mediaEditor.values.drawing, entities: codableEntities)
|
||||||
|
|
||||||
self.hapticFeedback.impact(.light)
|
|
||||||
if let subject = self.node.subject, case .asset = subject, self.node.mediaEditor?.values.hasChanges == false {
|
if let subject = self.node.subject, case .asset = subject, self.node.mediaEditor?.values.hasChanges == false {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func maybePresentDiscardAlert() {
|
||||||
|
self.hapticFeedback.impact(.light)
|
||||||
|
if !self.isEligibleForDraft() {
|
||||||
self.requestDismiss(saveDraft: false, animated: true)
|
self.requestDismiss(saveDraft: false, animated: true)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: String
|
let title: String
|
||||||
let save: String
|
let save: String
|
||||||
if case .draft = self.node.subject {
|
if case .draft = self.node.subject {
|
||||||
|
@ -1768,6 +1768,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mappedSource = .fasterDownload
|
mappedSource = .fasterDownload
|
||||||
case .translation:
|
case .translation:
|
||||||
mappedSource = .translation
|
mappedSource = .translation
|
||||||
|
case .stories:
|
||||||
|
mappedSource = .stories
|
||||||
}
|
}
|
||||||
return PremiumIntroScreen(context: context, source: mappedSource)
|
return PremiumIntroScreen(context: context, source: mappedSource)
|
||||||
}
|
}
|
||||||
@ -1803,6 +1805,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||||||
mappedSubject = .emojiStatus
|
mappedSubject = .emojiStatus
|
||||||
case .translation:
|
case .translation:
|
||||||
mappedSubject = .translation
|
mappedSubject = .translation
|
||||||
|
case .stories:
|
||||||
|
mappedSubject = .stories
|
||||||
}
|
}
|
||||||
return PremiumDemoScreen(context: context, subject: mappedSubject, action: action)
|
return PremiumDemoScreen(context: context, subject: mappedSubject, action: action)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user