Various improvements

This commit is contained in:
Ilya Laktyushin 2025-01-21 03:41:22 +04:00
parent d6964efa67
commit 24533df255
10 changed files with 105 additions and 48 deletions

View File

@ -1103,6 +1103,7 @@ public protocol SharedAccountContext: AnyObject {
func makeStarsIntroScreen(context: AccountContext) -> ViewController func makeStarsIntroScreen(context: AccountContext) -> ViewController
func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: (() -> Void)?) -> ViewController func makeGiftViewScreen(context: AccountContext, message: EngineMessage, shareStory: (() -> Void)?) -> ViewController
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController
func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController

View File

@ -880,6 +880,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return sourceView return sourceView
} }
) )
controller.pushController = { [weak self] c in
self?.push(c)
}
self.emojiStatusSelectionController = controller self.emojiStatusSelectionController = controller
self.present(controller, in: .window(.root)) self.present(controller, in: .window(.root))
} }

View File

@ -304,6 +304,7 @@ public enum PresentationResourceKey: Int32 {
case storyViewListLikeIcon case storyViewListLikeIcon
case navigationPostStoryIcon case navigationPostStoryIcon
case navigationSortIcon
case chatReplyBackgroundTemplateIncomingImage case chatReplyBackgroundTemplateIncomingImage
case chatReplyBackgroundTemplateOutgoingDashedImage case chatReplyBackgroundTemplateOutgoingDashedImage

View File

@ -195,7 +195,7 @@ public struct PresentationResourcesRootController {
} }
public static func navigationSortIcon(_ theme: PresentationTheme) -> UIImage? { public static func navigationSortIcon(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.navigationPostStoryIcon.rawValue, { theme in return theme.image(PresentationResourceKey.navigationSortIcon.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white) return generateTintedImage(image: UIImage(bundleImageName: "Peer Info/SortIcon"), color: .white)
}) })
} }

View File

@ -16,6 +16,7 @@ swift_library(
"//submodules/TelegramCore:TelegramCore", "//submodules/TelegramCore:TelegramCore",
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit", "//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/ComponentFlow:ComponentFlow", "//submodules/ComponentFlow:ComponentFlow",
"//submodules/TelegramNotices",
"//submodules/TelegramUI/Components/AnimationCache:AnimationCache", "//submodules/TelegramUI/Components/AnimationCache:AnimationCache",
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer", "//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
"//submodules/TelegramUI/Components/EntityKeyboard:EntityKeyboard", "//submodules/TelegramUI/Components/EntityKeyboard:EntityKeyboard",

View File

@ -19,6 +19,7 @@ import AppBundle
import GZip import GZip
import EmojiStatusComponent import EmojiStatusComponent
import Postbox import Postbox
import TelegramNotices
private func randomGenericReactionEffect(context: AccountContext) -> Signal<String?, NoError> { private func randomGenericReactionEffect(context: AccountContext) -> Signal<String?, NoError> {
return context.engine.stickers.loadedStickerPack(reference: .emojiGenericAnimations, forceActualized: false) return context.engine.stickers.loadedStickerPack(reference: .emojiGenericAnimations, forceActualized: false)
@ -1323,22 +1324,24 @@ public final class EmojiStatusSelectionController: ViewController {
animateOutToView = true animateOutToView = true
} }
if animateOutToView, item != nil, let destinationView = controller.destinationItemView() {
if let snapshotView = destinationView.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = destinationView.frame
destinationView.superview?.insertSubview(snapshotView, belowSubview: destinationView)
snapshotView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.15, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
destinationView.isHidden = true
}
switch controller.mode { switch controller.mode {
case .statusSelection: case .statusSelection:
if let gift = item?.itemGift { if let gift = item?.itemGift {
let _ = (self.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: nil) animateOutToView = false
|> deliverOnMainQueue).start()
let _ = (ApplicationSpecificNotice.getStarGiftWearTips(accountManager: self.context.sharedContext.accountManager)
|> deliverOnMainQueue).start(next: { [weak self] count in
guard let self else {
return
}
if !self.context.isPremium || count < 3, let pushController = controller.pushController {
let controller = self.context.sharedContext.makeGiftWearPreviewScreen(context: self.context, gift: gift)
pushController(controller)
} else {
let _ = (self.context.engine.accountData.setStarGiftStatus(starGift: gift, expirationDate: nil)
|> deliverOnMainQueue).start()
}
})
} else { } else {
let _ = (self.context.engine.accountData.setEmojiStatus(file: item?.itemFile, expirationDate: nil) let _ = (self.context.engine.accountData.setEmojiStatus(file: item?.itemFile, expirationDate: nil)
|> deliverOnMainQueue).start() |> deliverOnMainQueue).start()
@ -1372,6 +1375,17 @@ public final class EmojiStatusSelectionController: ViewController {
completion() completion()
} }
if animateOutToView, item != nil, let destinationView = controller.destinationItemView() {
if let snapshotView = destinationView.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = destinationView.frame
destinationView.superview?.insertSubview(snapshotView, belowSubview: destinationView)
snapshotView.layer.animateScale(from: 1.0, to: 0.001, duration: 0.15, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
destinationView.isHidden = true
}
if animateOutToView, let item = item, let destinationView = controller.destinationItemView() { if animateOutToView, let item = item, let destinationView = controller.destinationItemView() {
var emojiString: String? var emojiString: String?
if let itemFile = item.itemFile { if let itemFile = item.itemFile {
@ -1454,6 +1468,8 @@ public final class EmojiStatusSelectionController: ViewController {
return true return true
} }
public var pushController: ((ViewController) -> Void)?
public init(context: AccountContext, mode: Mode, sourceView: UIView, emojiContent: Signal<EmojiPagerContentComponent, NoError>, currentSelection: Int64?, color: UIColor? = nil, destinationItemView: @escaping () -> UIView?) { public init(context: AccountContext, mode: Mode, sourceView: UIView, emojiContent: Signal<EmojiPagerContentComponent, NoError>, currentSelection: Int64?, color: UIColor? = nil, destinationItemView: @escaping () -> UIView?) {
self.context = context self.context = context
self.mode = mode self.mode = mode

View File

@ -498,12 +498,19 @@ private final class GiftViewSheetContent: CombinedComponent {
showUpgradePreview = true showUpgradePreview = true
} }
var showWearPreview = false
if state.inWearPreview {
showWearPreview = true
} else if case .wearPreview = component.subject {
showWearPreview = true
}
let cancel = component.cancel let cancel = component.cancel
let buttons = buttons.update( let buttons = buttons.update(
component: ButtonsComponent( component: ButtonsComponent(
theme: theme, theme: theme,
isOverlay: showUpgradePreview || uniqueGift != nil, isOverlay: showUpgradePreview || uniqueGift != nil,
showMoreButton: uniqueGift != nil && !state.inWearPreview, showMoreButton: uniqueGift != nil && !showWearPreview,
closePressed: { [weak state] in closePressed: { [weak state] in
guard let state else { guard let state else {
return return
@ -534,7 +541,7 @@ private final class GiftViewSheetContent: CombinedComponent {
let headerHeight: CGFloat let headerHeight: CGFloat
let headerSubject: GiftCompositionComponent.Subject? let headerSubject: GiftCompositionComponent.Subject?
if let uniqueGift { if let uniqueGift {
if state.inWearPreview { if showWearPreview {
headerHeight = 200.0 headerHeight = 200.0
} else if case let .peerId(peerId) = uniqueGift.owner, peerId == component.context.account.peerId { } else if case let .peerId(peerId) = uniqueGift.owner, peerId == component.context.account.peerId {
headerHeight = 314.0 headerHeight = 314.0
@ -557,7 +564,7 @@ private final class GiftViewSheetContent: CombinedComponent {
} }
var wearPeerNameChild: _UpdatedChildComponent? var wearPeerNameChild: _UpdatedChildComponent?
if state.inWearPreview, let uniqueGift { if showWearPreview, let uniqueGift {
var peerName = "" var peerName = ""
if let accountPeer = state.peerMap[component.context.account.peerId] { if let accountPeer = state.peerMap[component.context.account.peerId] {
peerName = accountPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder) peerName = accountPeer.displayTitle(strings: strings, displayOrder: nameDisplayOrder)
@ -577,10 +584,17 @@ private final class GiftViewSheetContent: CombinedComponent {
transition: .immediate transition: .immediate
) )
let giftTitle: String
if case .wearPreview = component.subject {
giftTitle = uniqueGift.title
} else {
giftTitle = "\(uniqueGift.title) #\(uniqueGift.number)"
}
let wearTitle = wearTitle.update( let wearTitle = wearTitle.update(
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain(NSAttributedString( text: .plain(NSAttributedString(
string: strings.Gift_Wear_Wear("\(uniqueGift.title) #\(uniqueGift.number)").string, string: strings.Gift_Wear_Wear(giftTitle).string,
font: Font.bold(24.0), font: Font.bold(24.0),
textColor: theme.actionSheet.primaryTextColor, textColor: theme.actionSheet.primaryTextColor,
paragraphAlignment: .center paragraphAlignment: .center
@ -638,7 +652,7 @@ private final class GiftViewSheetContent: CombinedComponent {
subject: headerSubject, subject: headerSubject,
animationOffset: animationOffset, animationOffset: animationOffset,
animationScale: animationScale, animationScale: animationScale,
displayAnimationStars: state.inWearPreview, displayAnimationStars: showWearPreview,
externalState: giftCompositionExternalState, externalState: giftCompositionExternalState,
requestUpdate: { [weak state] in requestUpdate: { [weak state] in
state?.updated() state?.updated()
@ -660,22 +674,24 @@ private final class GiftViewSheetContent: CombinedComponent {
vibrantColor = UIColor.white.withAlphaComponent(0.6) vibrantColor = UIColor.white.withAlphaComponent(0.6)
} }
if let wearPeerNameChild, let accountPeer = state.peerMap[component.context.account.peerId] { if let wearPeerNameChild {
let wearAvatar = wearAvatar.update( if let accountPeer = state.peerMap[component.context.account.peerId] {
component: AvatarComponent( let wearAvatar = wearAvatar.update(
context: component.context, component: AvatarComponent(
theme: theme, context: component.context,
peer: accountPeer theme: theme,
), peer: accountPeer
environment: {}, ),
availableSize: CGSize(width: 100.0, height: 100.0), environment: {},
transition: context.transition availableSize: CGSize(width: 100.0, height: 100.0),
) transition: context.transition
context.add(wearAvatar )
.position(CGPoint(x: context.availableSize.width / 2.0, y: 67.0)) context.add(wearAvatar
.appear(.default(scale: true, alpha: true)) .position(CGPoint(x: context.availableSize.width / 2.0, y: 67.0))
.disappear(.default(scale: true, alpha: true)) .appear(.default(scale: true, alpha: true))
) .disappear(.default(scale: true, alpha: true))
)
}
let wearPeerStatus = wearPeerStatus.update( let wearPeerStatus = wearPeerStatus.update(
component: MultilineTextComponent( component: MultilineTextComponent(
@ -1772,7 +1788,7 @@ private final class GiftViewSheetContent: CombinedComponent {
originY += table.size.height + 23.0 originY += table.size.height + 23.0
} }
if incoming && !converted && !upgraded && !showUpgradePreview && !state.inWearPreview { if incoming && !converted && !upgraded && !showUpgradePreview && !showWearPreview {
let linkColor = theme.actionSheet.controlAccentColor let linkColor = theme.actionSheet.controlAccentColor
if state.cachedSmallChevronImage == nil || state.cachedSmallChevronImage?.1 !== environment.theme { if state.cachedSmallChevronImage == nil || state.cachedSmallChevronImage?.1 !== environment.theme {
state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: linkColor)!, theme) state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: linkColor)!, theme)
@ -1838,7 +1854,7 @@ private final class GiftViewSheetContent: CombinedComponent {
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9) pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9)
) )
let buttonChild: _UpdatedChildComponent let buttonChild: _UpdatedChildComponent
if state.inWearPreview, let uniqueGift { if showWearPreview, let uniqueGift {
let buttonContent: AnyComponentWithIdentity<Empty> let buttonContent: AnyComponentWithIdentity<Empty>
if !component.context.isPremium { if !component.context.isPremium {
buttonContent = AnyComponentWithIdentity( buttonContent = AnyComponentWithIdentity(
@ -1898,8 +1914,12 @@ private final class GiftViewSheetContent: CombinedComponent {
controller.present(tooltipController, in: .window(.root)) controller.present(tooltipController, in: .window(.root))
} else { } else {
state.commitWear(uniqueGift) state.commitWear(uniqueGift)
Queue.mainQueue().after(0.2) { if case .wearPreview = component.subject {
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string) component.cancel(true)
} else {
Queue.mainQueue().after(0.2) {
component.showAttributeInfo(statusTag, strings.Gift_View_PutOn("\(uniqueGift.title) #\(uniqueGift.number)").string)
}
} }
} }
} }
@ -2212,6 +2232,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift) case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift)
case soldOutGift(StarGift.Gift) case soldOutGift(StarGift.Gift)
case upgradePreview([StarGift.UniqueGift.Attribute], String) case upgradePreview([StarGift.UniqueGift.Attribute], String)
case wearPreview(StarGift.UniqueGift)
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? { var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?, upgradeMessageId: Int32?)? {
switch self { switch self {
@ -2250,7 +2271,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
return nil return nil
} }
} }
case let .uniqueGift(gift): case let .uniqueGift(gift), let .wearPreview(gift):
return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, false, false, false, nil, nil, nil, nil) return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, false, false, false, nil, nil, nil, nil)
case let .profileGift(peerId, gift): case let .profileGift(peerId, gift):
var messageId: EngineMessage.Id? var messageId: EngineMessage.Id?

View File

@ -168,7 +168,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
var displayPremiumIntro: ((UIView, PeerEmojiStatus?, Signal<(TelegramMediaFile, LoadedStickerPack)?, NoError>, Bool) -> Void)? var displayPremiumIntro: ((UIView, PeerEmojiStatus?, Signal<(TelegramMediaFile, LoadedStickerPack)?, NoError>, Bool) -> Void)?
var displayStatusPremiumIntro: (() -> Void)? var displayStatusPremiumIntro: (() -> Void)?
var displayUniqueGiftInfo: ((UIView, String) -> Void)? var displayUniqueGiftInfo: ((UIView, String) -> Void)?
var openUniqueGift: ((String) -> Void)? var openUniqueGift: ((UIView, String) -> Void)?
var navigateToForum: (() -> Void)? var navigateToForum: (() -> Void)?
@ -918,7 +918,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
return return
} }
if let uniqueGiftSlug { if let uniqueGiftSlug {
strongSelf.openUniqueGift?(uniqueGiftSlug) strongSelf.openUniqueGift?(strongSelf.titleStatusIconView, uniqueGiftSlug)
} else { } else {
strongSelf.displayPremiumIntro?(strongSelf.titleStatusIconView, currentEmojiStatus, strongSelf.emojiStatusFileAndPackTitle.get(), false) strongSelf.displayPremiumIntro?(strongSelf.titleStatusIconView, currentEmojiStatus, strongSelf.emojiStatusFileAndPackTitle.get(), false)
} }
@ -979,7 +979,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
return return
} }
if let uniqueGiftSlug { if let uniqueGiftSlug {
strongSelf.openUniqueGift?(uniqueGiftSlug) strongSelf.openUniqueGift?(strongSelf.titleExpandedStatusIconView, uniqueGiftSlug)
} else { } else {
strongSelf.displayPremiumIntro?(strongSelf.titleExpandedStatusIconView, currentEmojiStatus, strongSelf.emojiStatusFileAndPackTitle.get(), true) strongSelf.displayPremiumIntro?(strongSelf.titleExpandedStatusIconView, currentEmojiStatus, strongSelf.emojiStatusFileAndPackTitle.get(), true)
} }
@ -2266,7 +2266,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
if let status = peer?.emojiStatus, case .starGift = status.content { if let status = peer?.emojiStatus, case .starGift = status.content {
backgroundCoverSubject = .status(status) backgroundCoverSubject = .status(status)
if !self.didSetupBackgroundCover { if !self.didSetupBackgroundCover {
backgroundCoverAnimateIn = true if !self.isSettings {
backgroundCoverAnimateIn = true
}
self.didSetupBackgroundCover = true self.didSetupBackgroundCover = true
} }
} else if let peer { } else if let peer {

View File

@ -4587,9 +4587,16 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
return sourceView return sourceView
} }
) )
emojiStatusSelectionController.pushController = { [weak self] c in
self?.controller?.push(c)
}
strongSelf.emojiStatusSelectionController = emojiStatusSelectionController strongSelf.emojiStatusSelectionController = emojiStatusSelectionController
strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root)) strongSelf.controller?.present(emojiStatusSelectionController, in: .window(.root))
} }
self.headerNode.openUniqueGift = { [weak self] sourceView, _ in
self?.headerNode.displayPremiumIntro?(sourceView, nil, .single(nil), false)
}
} else { } else {
if peerId == context.account.peerId { if peerId == context.account.peerId {
self.privacySettings.set(.single(nil) |> then(context.engine.privacy.requestAccountPrivacySettings() |> map(Optional.init))) self.privacySettings.set(.single(nil) |> then(context.engine.privacy.requestAccountPrivacySettings() |> map(Optional.init)))
@ -4673,7 +4680,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
controller.present(tooltipController, in: .current) controller.present(tooltipController, in: .current)
} }
self.headerNode.openUniqueGift = { [weak self] slug in self.headerNode.openUniqueGift = { [weak self] _, slug in
guard let self else { guard let self else {
return return
} }

View File

@ -2956,6 +2956,11 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return controller return controller
} }
public func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController {
let controller = GiftViewScreen(context: context, subject: .wearPreview(gift))
return controller
}
public func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController { public func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController {
let editorSubject: Signal<MediaEditorScreenImpl.Subject?, NoError> let editorSubject: Signal<MediaEditorScreenImpl.Subject?, NoError>
switch subject { switch subject {