Various improvements

This commit is contained in:
Ilya Laktyushin 2025-01-22 20:33:42 +04:00
parent c178c19f88
commit 103b244216
10 changed files with 107 additions and 73 deletions

View File

@ -50,7 +50,7 @@ public enum PremiumGiftSource: Equatable {
case settings([EnginePeer.Id: TelegramBirthday]?)
case chatList([EnginePeer.Id: TelegramBirthday]?)
case stars([EnginePeer.Id: TelegramBirthday]?)
case starGiftTransfer([EnginePeer.Id: TelegramBirthday]?, StarGiftReference, StarGift.UniqueGift, Int64, Int32?)
case starGiftTransfer([EnginePeer.Id: TelegramBirthday]?, StarGiftReference, StarGift.UniqueGift, Int64, Int32?, Bool)
case channelBoost
case deeplink(String?)
}

View File

@ -626,7 +626,7 @@ private final class GiftViewSheetContent: CombinedComponent {
horizontalAlignment: .center,
maximumNumberOfLines: 1
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: CGFloat.greatestFiniteMagnitude),
transition: .immediate
)
let wearDescription = wearDescription.update(
@ -1284,7 +1284,7 @@ private final class GiftViewSheetContent: CombinedComponent {
id: "address_owner",
title: strings.Gift_Unique_Owner,
component: AnyComponent(
MultilineTextComponent(text: .plain(NSAttributedString(string: address, font: tableMonospaceFont, textColor: tableTextColor)))
MultilineTextComponent(text: .plain(NSAttributedString(string: address, font: tableMonospaceFont, textColor: tableLinkColor)))
)
))
}
@ -1379,36 +1379,47 @@ private final class GiftViewSheetContent: CombinedComponent {
if let uniqueGift {
if case let .peerId(peerId) = uniqueGift.owner, peerId == component.context.account.peerId || isChannelGift {
var canTransfer = true
if let peer = state.peerMap[peerId], case let .channel(channel) = peer, !channel.flags.contains(.isCreator) {
canTransfer = false
}
let buttonsCount = canTransfer ? 3 : 2
let buttonSpacing: CGFloat = 10.0
let buttonWidth = floor(context.availableSize.width - sideInset * 2.0 - buttonSpacing * 2.0) / 3.0
let buttonWidth = floor(context.availableSize.width - sideInset * 2.0 - buttonSpacing * CGFloat(buttonsCount - 1)) / CGFloat(buttonsCount)
let buttonHeight: CGFloat = 58.0
let transferButton = transferButton.update(
component: PlainButtonComponent(
content: AnyComponent(
HeaderButtonComponent(
title: strings.Gift_View_Header_Transfer,
iconName: "Premium/Collectible/Transfer"
)
var buttonOriginX = sideInset
if canTransfer {
let transferButton = transferButton.update(
component: PlainButtonComponent(
content: AnyComponent(
HeaderButtonComponent(
title: strings.Gift_View_Header_Transfer,
iconName: "Premium/Collectible/Transfer"
)
),
effectAlignment: .center,
action: {
component.transferGift()
Queue.mainQueue().after(0.6, {
component.cancel(false)
})
}
),
effectAlignment: .center,
action: {
component.transferGift()
Queue.mainQueue().after(0.6, {
component.cancel(false)
})
}
),
environment: {},
availableSize: CGSize(width: buttonWidth, height: buttonHeight),
transition: context.transition
)
context.add(transferButton
.position(CGPoint(x: sideInset + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
environment: {},
availableSize: CGSize(width: buttonWidth, height: buttonHeight),
transition: context.transition
)
context.add(transferButton
.position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
buttonOriginX += buttonWidth + buttonSpacing
}
let wearButton = wearButton.update(
component: PlainButtonComponent(
content: AnyComponent(
@ -1462,10 +1473,11 @@ private final class GiftViewSheetContent: CombinedComponent {
transition: context.transition
)
context.add(wearButton
.position(CGPoint(x: context.availableSize.width / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
buttonOriginX += buttonWidth + buttonSpacing
let shareButton = shareButton.update(
component: PlainButtonComponent(
@ -1485,7 +1497,7 @@ private final class GiftViewSheetContent: CombinedComponent {
transition: context.transition
)
context.add(shareButton
.position(CGPoint(x: context.availableSize.width - sideInset - buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.position(CGPoint(x: buttonOriginX + buttonWidth / 2.0, y: headerHeight - buttonHeight / 2.0 - 16.0))
.appear(.default(scale: true, alpha: true))
.disappear(.default(scale: true, alpha: true))
)
@ -2676,7 +2688,11 @@ public class GiftViewScreen: ViewControllerComponentContainer {
let _ = (context.account.stateManager.contactBirthdays
|> take(1)
|> deliverOnMainQueue).start(next: { birthdays in
let controller = context.sharedContext.makePremiumGiftController(context: context, source: .starGiftTransfer(birthdays, reference, gift, transferStars, arguments.canExportDate), completion: { peerIds in
var showSelf = false
if arguments.peerId?.namespace == Namespaces.Peer.CloudChannel {
showSelf = true
}
let controller = context.sharedContext.makePremiumGiftController(context: context, source: .starGiftTransfer(birthdays, reference, gift, transferStars, arguments.canExportDate, showSelf), completion: { peerIds in
guard let peerId = peerIds.first else {
return
}
@ -2820,41 +2836,53 @@ public class GiftViewScreen: ViewControllerComponentContainer {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let link = "https://t.me/nft/\(gift.slug)"
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in
c?.dismiss(completion: nil)
let _ = (context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: arguments.peerId ?? context.account.peerId)
)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let self else {
return
}
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_CopyLink, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Link"), color: theme.contextMenu.primaryColor)
}, action: { [weak self] c, _ in
c?.dismiss(completion: nil)
guard let self else {
return
}
UIPasteboard.general.string = link
self.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})))
UIPasteboard.general.string = link
self.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: nil, text: presentationData.strings.Conversation_LinkCopied), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
})))
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Share, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c?.dismiss(completion: nil)
shareGiftImpl?()
})))
if let _ = arguments.transferStars {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Transfer, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replace"), color: theme.contextMenu.primaryColor)
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Share, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c?.dismiss(completion: nil)
transferGiftImpl?()
shareGiftImpl?()
})))
}
let contextController = ContextController(presentationData: presentationData, source: .reference(GiftViewContextReferenceContentSource(controller: self, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.presentInGlobalOverlay(contextController)
if let _ = arguments.transferStars {
if case let .channel(channel) = peer, !channel.flags.contains(.isCreator) {
} else {
items.append(.action(ContextMenuActionItem(text: presentationData.strings.Gift_View_Context_Transfer, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Replace"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c?.dismiss(completion: nil)
transferGiftImpl?()
})))
}
}
let contextController = ContextController(presentationData: presentationData, source: .reference(GiftViewContextReferenceContentSource(controller: self, sourceNode: node)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
self.presentInGlobalOverlay(contextController)
})
}
}

View File

@ -367,7 +367,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let title = self.currentIsCaptionAbove ? presentationData.strings.MediaPicker_InvertCaption_Updated_Up_Title : presentationData.strings.MediaPicker_InvertCaption_Updated_Down_Title
let text = self.currentIsCaptionAbove ? presentationData.strings.MediaPicker_InvertCaption_Updated_Up_Text : presentationData.strings.MediaPicker_InvertCaption_Updated_Down_Title
let text = self.currentIsCaptionAbove ? presentationData.strings.MediaPicker_InvertCaption_Updated_Up_Text : presentationData.strings.MediaPicker_InvertCaption_Updated_Down_Text
let animationName = self.currentIsCaptionAbove ? "message_preview_sort_above" : "message_preview_sort_below"
let controller = UndoOverlayController(

View File

@ -126,6 +126,8 @@ final class MediaEditorComposer {
if values.isSticker {
self.maskImage = roundedCornersMaskImage(size: CGSize(width: floor(1080.0 * 0.97), height: floor(1080.0 * 0.97)))
} else if values.isAvatar {
self.maskImage = rectangleMaskImage(size: CGSize(width: floor(1080.0 * 0.97), height: floor(1080.0 * 0.97)))
}
if let drawing = values.drawing, let drawingImage = CIImage(image: drawing, options: [.colorSpace: self.colorSpace]) {
@ -224,6 +226,8 @@ public func makeEditorImageComposition(context: CIContext, postbox: Postbox, inp
var maskImage: CIImage?
if values.isSticker {
maskImage = roundedCornersMaskImage(size: CGSize(width: floor(1080.0 * 0.97), height: floor(1080.0 * 0.97)))
} else if values.isAvatar {
maskImage = rectangleMaskImage(size: CGSize(width: floor(1080.0 * 0.97), height: floor(1080.0 * 0.97)))
} else if let _ = outputDimensions {
maskImage = rectangleMaskImage(size: CGSize(width: 1080.0, height: 1080.0))
}
@ -264,7 +268,7 @@ private func makeEditorImageFrameComposition(context: CIContext, inputImage: CII
var mediaImage = inputImage.samplingLinear().transformed(by: CGAffineTransform(translationX: -inputImage.extent.midX, y: -inputImage.extent.midY))
if values.isStory || values.isSticker {
if values.isStory || values.isSticker || values.isAvatar {
resultImage = mediaImage.samplingLinear().composited(over: resultImage)
} else {
let initialScale = dimensions.width / mediaImage.extent.width

View File

@ -1808,10 +1808,11 @@ public func recommendedVideoExportConfiguration(values: MediaEditorValues, durat
useHEVC = false
} else {
if isAvatar {
width = 640
height = 640
width = 800
height = 800
frameRate = 30
useHEVC = false
values = values.withUpdatedQualityPreset(.profile)
} else if isSticker {
width = 512
height = 512
@ -1853,7 +1854,7 @@ public func recommendedVideoExportConfiguration(values: MediaEditorValues, durat
]
let audioSettings: [String: Any]
if isSticker {
if isSticker || isAvatar {
audioSettings = [:]
} else {
audioSettings = [

View File

@ -131,7 +131,7 @@ public final class MediaEditorVideoExport {
}
var composerDimensions: CGSize {
if self.values.isStory || self.values.isSticker {
if self.values.isStory || self.values.isSticker || self.values.isAvatar {
return CGSize(width: 1080.0, height: 1920.0)
} else {
let maxSize = CGSize(width: 1920.0, height: 1920.0)

View File

@ -435,7 +435,7 @@ final class VideoFinishPass: RenderPass {
y: canvasSize.height / 2.0 + values.cropOffset.y
)
self.isStory = values.isStory || values.isSticker
self.isStory = values.isStory || values.isSticker || values.isAvatar
self.isSticker = values.gradientColors?.first?.alpha == 0.0
self.mainPosition = VideoFinishPass.VideoPosition(position: position, size: self.mainPosition.size, scale: values.cropScale, rotation: values.cropRotation, mirroring: values.cropMirroring, baseScale: self.mainPosition.baseScale)

View File

@ -3271,6 +3271,9 @@ public final class MediaEditorScreenImpl: ViewController, MediaEditorScreen, UID
}
let mediaEditor = MediaEditor(context: self.context, mode: mediaEditorMode, subject: effectiveSubject.editorSubject, values: initialValues, hasHistogram: true)
if case .avatarEditor = controller.mode {
mediaEditor.setVideoIsMuted(true)
}
if let initialVideoPosition = controller.initialVideoPosition {
if controller.isEditingStoryCover {
mediaEditor.setCoverImageTimestamp(initialVideoPosition)

View File

@ -525,10 +525,8 @@ extension PeerInfoScreenImpl {
|> mapToSignal { exportSubject, duration in
return Signal<TelegramMediaResource?, UploadPeerPhotoError> { subscriber in
let configuration = recommendedVideoExportConfiguration(values: values, duration: duration, forceFullHd: true, frameRate: 60.0, isAvatar: true)
//let outputPath = NSTemporaryDirectory() + "\(Int64.random(in: 0 ..< .max)).mp4"
let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4")
let videoExport = MediaEditorVideoExport(postbox: context.account.postbox, subject: exportSubject, configuration: configuration, outputPath: tempFile.path, textScale: 2.0)
let _ = (videoExport.status
|> deliverOnMainQueue).startStandalone(next: { [weak self] status in
guard let self else {

View File

@ -2396,8 +2396,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
var mode: ContactSelectionControllerMode = .generic
var currentBirthdays: [EnginePeer.Id: TelegramBirthday]?
if case let .starGiftTransfer(birthdays, _, _, _, _) = source {
mode = .starsGifting(birthdays: birthdays, hasActions: false, showSelf: false)
if case let .starGiftTransfer(birthdays, _, _, _, _, showSelf) = source {
mode = .starsGifting(birthdays: birthdays, hasActions: false, showSelf: showSelf)
currentBirthdays = birthdays
} else if case let .chatList(birthdays) = source {
mode = .starsGifting(birthdays: birthdays, hasActions: true, showSelf: true)
@ -2411,7 +2411,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
var allowChannelsInSearch = false
let contactOptions: Signal<[ContactListAdditionalOption], NoError>
if case let .starGiftTransfer(_, _, _, _, canExportDate) = source {
if case let .starGiftTransfer(_, _, _, _, canExportDate, _) = source {
allowChannelsInSearch = true
var subtitle: String?
if let canExportDate {
@ -2560,7 +2560,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
presentExportAlertImpl = { [weak controller] in
guard let controller, case let .starGiftTransfer(_, reference, gift, _, canExportDate) = source, let canExportDate else {
guard let controller, case let .starGiftTransfer(_, reference, gift, _, canExportDate, _) = source, let canExportDate else {
return
}
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
@ -2604,7 +2604,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
presentTransferAlertImpl = { [weak controller] peer in
guard let controller, case let .starGiftTransfer(_, _, gift, transferStars, _) = source else {
guard let controller, case let .starGiftTransfer(_, _, gift, transferStars, _, _) = source else {
return
}
let alertController = giftTransferAlertController(context: context, gift: gift, peer: peer, transferStars: transferStars, commit: { [weak controller] in