Various improvements

This commit is contained in:
Ilya Laktyushin 2023-01-24 22:29:00 +04:00
parent e695f61bc7
commit 7d11ba5d5e
33 changed files with 588 additions and 277 deletions

View File

@ -32,13 +32,15 @@ public final class AvatarVideoNode: ASDisplayNode {
private let playbackStartDisposable = MetaDisposable()
private var videoLoopCount = 0
private var size = CGSize(width: 60.0, height: 60.0)
private var validLayout: (CGSize, CGFloat)?
private var internalSize = CGSize(width: 60.0, height: 60.0)
public init(context: AccountContext) {
self.context = context
self.backgroundNode = ASImageNode()
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.isHidden = true
super.init()
@ -60,16 +62,15 @@ public final class AvatarVideoNode: ASDisplayNode {
}
}
private var didAppear = false
private func setupAnimation() {
guard let animationFile = self.animationFile else {
return
}
let itemNativeFitSize = CGSize(width: 128.0, height: 128.0)
let size = CGSize(width: self.size.width * 0.67, height: self.size.height * 0.67)
let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((self.size.width - size.width) / 2.0), y: floorToScreenPixels((self.size.height - size.height) / 2.0)), size: size)
let itemNativeFitSize = self.internalSize.width > 100.0 ? CGSize(width: 256.0, height: 256.0) : CGSize(width: 128.0, height: 128.0)
let animationData = EntityKeyboardAnimationData(file: animationFile)
let itemLayer = EmojiPagerContentComponent.View.ItemLayer(
item: EmojiPagerContentComponent.Item(
@ -89,109 +90,77 @@ public final class AvatarVideoNode: ASDisplayNode {
blurredBadgeColor: .clear,
accentIconColor: .white,
pointSize: itemNativeFitSize,
onUpdateDisplayPlaceholder: { displayPlaceholder, _ in
if !displayPlaceholder {
print()
}
// guard let strongSelf = self else {
// return
// }
// if displayPlaceholder {
// if let itemLayer = strongSelf.visibleItemLayers[itemId] {
// let placeholderView: EmojiPagerContentComponent.View.ItemPlaceholderView
// if let current = strongSelf.visibleItemPlaceholderViews[itemId] {
// placeholderView = current
// } else {
// placeholderView = EmojiPagerContentComponent.View.ItemPlaceholderView(
// context: context,
// dimensions: item.file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0),
// immediateThumbnailData: item.file.immediateThumbnailData,
// shimmerView: nil,//strongSelf.shimmerHostView,
// color: theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.08),
// size: itemNativeFitSize
// )
// strongSelf.visibleItemPlaceholderViews[itemId] = placeholderView
// strongSelf.view.insertSubview(placeholderView, at: 0)
// }
// placeholderView.frame = itemLayer.frame
// placeholderView.update(size: placeholderView.bounds.size)
//
// strongSelf.updateShimmerIfNeeded()
// }
// } else {
// if let placeholderView = strongSelf.visibleItemPlaceholderViews[itemId] {
// strongSelf.visibleItemPlaceholderViews.removeValue(forKey: itemId)
//
// if duration > 0.0 {
// placeholderView.layer.opacity = 0.0
// placeholderView.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, completion: { [weak self, weak placeholderView] _ in
// guard let strongSelf = self else {
// return
// }
// placeholderView?.removeFromSuperview()
// strongSelf.updateShimmerIfNeeded()
// })
// } else {
// placeholderView.removeFromSuperview()
// strongSelf.updateShimmerIfNeeded()
// }
// }
// }
onUpdateDisplayPlaceholder: { _, _ in
}
)
itemLayer.onContentsUpdate = { [weak self] in
self?.backgroundNode.isHidden = false
if let self {
if !self.didAppear {
self.didAppear = true
Queue.mainQueue().after(0.15) {
self.backgroundNode.isHidden = false
}
}
}
}
itemLayer.layerTintColor = UIColor.white.cgColor
itemLayer.frame = itemFrame
itemLayer.isVisibleForAnimations = true
itemLayer.isVisibleForAnimations = self.visibility
self.itemLayer = itemLayer
self.backgroundNode.layer.addSublayer(itemLayer)
if let (size, cornerRadius) = self.validLayout {
self.updateLayout(size: size, cornerRadius: cornerRadius, transition: .immediate)
}
}
public func update(markup: TelegramMediaImage.EmojiMarkup, size: CGSize) {
guard markup != self.emojiMarkup else {
return
}
self.emojiMarkup = markup
self.internalSize = size
let colors = markup.backgroundColors.map { UInt32(bitPattern: $0) }
if colors.count == 1 {
backgroundNode.backgroundColor = UIColor(rgb: colors.first!)
self.backgroundNode.image = nil
} else if colors.count == 2 {
self.backgroundNode.image = generateGradientImage(size: size, colors: colors.map { UIColor(rgb: $0) }, locations: [0.0, 1.0])!
} else {
self.backgroundNode.image = GradientBackgroundNode.generatePreview(size: size, colors: colors.map { UIColor(rgb: $0) })
}
self.backgroundNode.isHidden = true
switch markup.content {
case let .emoji(fileId):
self.fileDisposable = (self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId])
|> deliverOnMainQueue).start(next: { [weak self] files in
if let strongSelf = self, let file = files.values.first {
strongSelf.animationFile = file
strongSelf.setupAnimation()
}
})
case let .sticker(packReference, fileId):
self.fileDisposable = (self.context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: false)
|> map { pack -> TelegramMediaFile? in
if case let .result(_, items, _) = pack, let item = items.first(where: { $0.file.fileId.id == fileId }) {
return item.file
}
return nil
}
|> deliverOnMainQueue).start(next: { [weak self] file in
if let strongSelf = self, let file {
strongSelf.animationFile = file
strongSelf.setupAnimation()
}
})
}
}
public func update(peer: EnginePeer, photo: TelegramMediaImage, size: CGSize) {
self.size = size
self.internalSize = size
if let markup = photo.emojiMarkup {
if markup != self.emojiMarkup {
self.emojiMarkup = markup
let colors = markup.backgroundColors.map { UInt32(bitPattern: $0) }
let backgroundImage: UIImage
if colors.count == 1 {
backgroundImage = generateSingleColorImage(size: size, color: UIColor(rgb: colors.first!))!
} else if colors.count == 2 {
backgroundImage = generateGradientImage(size: size, colors: colors.map { UIColor(rgb: $0) }, locations: [0.0, 1.0])!
} else {
backgroundImage = GradientBackgroundNode.generatePreview(size: size, colors: colors.map { UIColor(rgb: $0) })
}
self.backgroundNode.image = backgroundImage
self.backgroundNode.isHidden = true
switch markup.content {
case let .emoji(fileId):
self.fileDisposable = (self.context.engine.stickers.resolveInlineStickers(fileIds: [fileId])
|> deliverOnMainQueue).start(next: { [weak self] files in
if let strongSelf = self, let file = files.values.first {
strongSelf.animationFile = file
strongSelf.setupAnimation()
}
})
case let .sticker(packReference, fileId):
self.fileDisposable = (self.context.engine.stickers.loadedStickerPack(reference: packReference, forceActualized: false)
|> map { pack -> TelegramMediaFile? in
if case let .result(_, items, _) = pack, let item = items.first(where: { $0.file.fileId.id == fileId }) {
return item.file
}
return nil
}
|> deliverOnMainQueue).start(next: { [weak self] file in
if let strongSelf = self, let file {
strongSelf.animationFile = file
strongSelf.setupAnimation()
}
})
}
}
self.update(markup: markup, size: size)
} else if let video = smallestVideoRepresentation(photo.videoRepresentations), let peerReference = PeerReference(peer._asPeer()) {
self.backgroundNode.image = nil
@ -205,7 +174,9 @@ public final class AvatarVideoNode: ASDisplayNode {
}
}
private var visibility = false
public func updateVisibility(_ isVisible: Bool) {
self.visibility = isVisible
if isVisible, let videoContent = self.videoContent, self.videoLoopCount != maxVideoLoopCount {
if self.videoNode == nil {
let context = self.context
@ -262,9 +233,11 @@ public final class AvatarVideoNode: ASDisplayNode {
self.videoNode = nil
videoNode.removeFromSupernode()
}
self.itemLayer?.isVisibleForAnimations = isVisible
}
public func updateLayout(size: CGSize, cornerRadius: CGFloat, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, cornerRadius)
self.layer.cornerRadius = cornerRadius
self.backgroundNode.frame = CGRect(origin: .zero, size: size)
@ -273,6 +246,12 @@ public final class AvatarVideoNode: ASDisplayNode {
videoNode.frame = CGRect(origin: .zero, size: size)
videoNode.updateLayout(size: size, transition: transition)
}
if let itemLayer = self.itemLayer {
let itemSize = CGSize(width: size.width * 0.67, height: size.height * 0.67)
let itemFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - itemSize.width) / 2.0), y: floorToScreenPixels((size.height - itemSize.height) / 2.0)), size: itemSize)
itemLayer.frame = itemFrame
}
}
public func resetPlayback() {

View File

@ -1710,7 +1710,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
}
}
if let hasUsername = groupType.hasUsername {
if hasUsername != (channel.addressName != nil) {
if hasUsername != (!(channel.addressName ?? "").isEmpty) {
return false
}
}
@ -1738,8 +1738,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
return false
}
}
if let hasUsername = channelType.hasUsername, hasUsername {
if hasUsername != (channel.addressName != nil) {
if let hasUsername = channelType.hasUsername {
if hasUsername != (!(channel.addressName ?? "").isEmpty) {
return false
}
}

View File

@ -1802,7 +1802,7 @@ public final class ChatListNode: ListView {
}
}
if let hasUsername = groupType.hasUsername {
if hasUsername != (channel.addressName != nil) {
if hasUsername != (!(channel.addressName ?? "").isEmpty) {
return false
}
}
@ -1831,8 +1831,8 @@ public final class ChatListNode: ListView {
return false
}
}
if let hasUsername = channelType.hasUsername, hasUsername {
if hasUsername != (channel.addressName != nil) {
if let hasUsername = channelType.hasUsername {
if hasUsername != (!(channel.addressName ?? "").isEmpty) {
return false
}
}

View File

@ -65,6 +65,11 @@ public struct ContextMenuActionItemIconSource {
}
}
public enum ContextMenuActionItemIconPosition {
case left
case right
}
public enum ContextMenuActionBadgeColor {
case accent
case inactive
@ -102,6 +107,7 @@ public final class ContextMenuActionItem {
public let badge: ContextMenuActionBadge?
public let icon: (PresentationTheme) -> UIImage?
public let iconSource: ContextMenuActionItemIconSource?
public let iconPosition: ContextMenuActionItemIconPosition
public let animationName: String?
public let textIcon: (PresentationTheme) -> UIImage?
public let textLinkAction: () -> Void
@ -117,6 +123,7 @@ public final class ContextMenuActionItem {
badge: ContextMenuActionBadge? = nil,
icon: @escaping (PresentationTheme) -> UIImage?,
iconSource: ContextMenuActionItemIconSource? = nil,
iconPosition: ContextMenuActionItemIconPosition = .right,
animationName: String? = nil,
textIcon: @escaping (PresentationTheme) -> UIImage? = { _ in return nil },
textLinkAction: @escaping () -> Void = {},
@ -132,6 +139,7 @@ public final class ContextMenuActionItem {
badge: badge,
icon: icon,
iconSource: iconSource,
iconPosition: iconPosition,
animationName: animationName,
textIcon: textIcon,
textLinkAction: textLinkAction,
@ -153,6 +161,7 @@ public final class ContextMenuActionItem {
badge: ContextMenuActionBadge? = nil,
icon: @escaping (PresentationTheme) -> UIImage?,
iconSource: ContextMenuActionItemIconSource? = nil,
iconPosition: ContextMenuActionItemIconPosition = .right,
animationName: String? = nil,
textIcon: @escaping (PresentationTheme) -> UIImage? = { _ in return nil },
textLinkAction: @escaping () -> Void = {},
@ -167,6 +176,7 @@ public final class ContextMenuActionItem {
self.badge = badge
self.icon = icon
self.iconSource = iconSource
self.iconPosition = iconPosition
self.animationName = animationName
self.textIcon = textIcon
self.textLinkAction = textLinkAction

View File

@ -549,8 +549,11 @@ public class Window1 {
var keyboardHeight: CGFloat
if keyboardFrame.isEmpty || keyboardFrame.maxY < screenHeight {
if isTablet && screenHeight - keyboardFrame.maxY < 5.0 {
if inPopover || (isTablet && screenHeight - keyboardFrame.maxY < 5.0) {
keyboardHeight = max(0.0, screenHeight - keyboardFrame.minY)
if inPopover && !keyboardHeight.isZero {
keyboardHeight = max(0.0, keyboardHeight - popoverDelta)
}
} else {
keyboardHeight = 0.0
}

View File

@ -3013,22 +3013,7 @@ public class DrawingScreen: ViewController, TGPhotoDrawingInterfaceController, U
return TGPaintingData(drawing: drawingData, entitiesData: entitiesData, image: image, stillImage: stillImage, hasAnimation: hasAnimatedEntities, stickers: stickers)
}
public func resultImage() -> UIImage! {
let image = generateImage(self.drawingView.imageSize, contextGenerator: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
if let cgImage = self.drawingView.drawingImage?.cgImage {
context.draw(cgImage, in: bounds)
}
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -size.width / 2.0, y: -size.height / 2.0)
self.entitiesView.layer.render(in: context)
}, opaque: false, scale: 1.0)
return image
}
public func animateOut(_ completion: @escaping (() -> Void)) {
self.selectionContainerView.alpha = 0.0

View File

@ -27,6 +27,8 @@ typedef enum
@property (nonatomic, readonly) NSTimeInterval trimEndValue;
@property (nonatomic, readonly) TGMediaVideoConversionPreset preset;
@property (nonatomic, readonly) int64_t stickerPackId;
@property (nonatomic, readonly) int64_t stickerPackAccessHash;
@property (nonatomic, readonly) int64_t documentId;
@property (nonatomic, strong, readonly) NSArray *colors;
@ -43,6 +45,7 @@ typedef enum
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize preset:(TGMediaVideoConversionPreset)preset;
+ (instancetype)editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)values preset:(TGMediaVideoConversionPreset)preset;
+ (instancetype)editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)values preset:(TGMediaVideoConversionPreset)preset documentId:(int64_t)documentId colors:(NSArray *)colors;
+ (instancetype)editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)values preset:(TGMediaVideoConversionPreset)preset stickerPackId:(int64_t)stickerPackId stickerPackAccessHash:(int64_t)stickerPackAccessHash documentId:(int64_t)documentId colors:(NSArray *)colors;
+ (instancetype)editAdjustmentsWithDictionary:(NSDictionary *)dictionary;
+ (instancetype)editAdjustmentsWithOriginalSize:(CGSize)originalSize

View File

@ -151,6 +151,29 @@ const NSTimeInterval TGVideoEditMaximumGifDuration = 30.5;
return adjustments;
}
+ (instancetype)editAdjustmentsWithPhotoEditorValues:(PGPhotoEditorValues *)values preset:(TGMediaVideoConversionPreset)preset stickerPackId:(int64_t)stickerPackId stickerPackAccessHash:(int64_t)stickerPackAccessHash documentId:(int64_t)documentId colors:(NSArray *)colors {
TGVideoEditAdjustments *adjustments = [[[self class] alloc] init];
adjustments->_originalSize = values.originalSize;
CGRect cropRect = values.cropRect;
if (CGRectIsEmpty(cropRect)) {
cropRect = CGRectMake(0.0f, 0.0f, values.originalSize.width, values.originalSize.height);
}
adjustments->_cropRect = cropRect;
adjustments->_cropOrientation = values.cropOrientation;
adjustments->_cropRotation = values.cropRotation;
adjustments->_cropLockedAspectRatio = values.cropLockedAspectRatio;
adjustments->_cropMirrored = values.cropMirrored;
adjustments->_paintingData = [values.paintingData dataForAnimation];
adjustments->_sendAsGif = true;
adjustments->_preset = preset;
adjustments->_stickerPackId = stickerPackId;
adjustments->_stickerPackAccessHash = stickerPackAccessHash;
adjustments->_documentId = documentId;
adjustments->_colors = colors;
return adjustments;
}
- (instancetype)editAdjustmentsWithPreset:(TGMediaVideoConversionPreset)preset maxDuration:(NSTimeInterval)maxDuration
{
TGVideoEditAdjustments *adjustments = [[[self class] alloc] init];

View File

@ -25,6 +25,7 @@ swift_library(
"//submodules/GalleryUI:GalleryUI",
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/AccountContext:AccountContext",
"//submodules/AvatarVideoNode:AvatarVideoNode",
],
visibility = [
"//visibility:public",

View File

@ -0,0 +1,150 @@
import Foundation
import UIKit
import Display
import SwiftSignalKit
private let phrases = [
"Вітаю",
"你好",
"Hello",
"سلام",
"Bonjour",
"Guten tag",
"שלום",
"नमस्ते",
"Ciao",
"こんにちは",
"Hei",
"Olá",
"Привет",
"Zdravo",
"Hola",
"Привіт",
"Salom",
"Halo"
]
private var activeCount = 13
private let referenceWidth: CGFloat = 1180
private let positions: [CGPoint] = [
CGPoint(x: 315.0, y: 83.0),
CGPoint(x: 676.0, y: 18.0),
CGPoint(x: 880.0, y: 130.0),
CGPoint(x: 90.0, y: 214.0),
CGPoint(x: 550.0, y: 150.0),
CGPoint(x: 1130.0, y: 220.0),
CGPoint(x: 220.0, y: 440.0),
CGPoint(x: 1080.0, y: 350.0),
CGPoint(x: 85.0, y: 630.0),
CGPoint(x: 1180.0, y: 550.0),
CGPoint(x: 150.0, y: 810.0),
CGPoint(x: 1010.0, y: 770.0),
CGPoint(x: 40.0, y: 1000.0),
CGPoint(x: 1130.0, y: 1000.0)
]
final class HelloView: UIView, PhoneDemoDecorationView {
private var activePhrases = Set<Int>()
private var activePositions = Set<Int>()
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupAnimations() {
guard self.activePhrases.isEmpty else {
return
}
var ids: [Int] = []
for i in 0 ..< phrases.count {
ids.append(i)
}
ids.shuffle()
let phraseIds = Array(self.availablePhraseIds()).shuffled()
let positionIds = Array(self.availablePositionIds()).shuffled()
for i in 0 ..< activeCount {
let delay: Double = Double.random(in: 0.0 ..< 0.8)
Queue.mainQueue().after(delay) {
self.spawnPhrase(phraseIds[i], positionIndex: positionIds[i])
}
}
}
func availablePhraseIds() -> Set<Int> {
var ids = Set<Int>()
for i in 0 ..< phrases.count {
ids.insert(i)
}
for id in self.activePhrases {
ids.remove(id)
}
return ids
}
func availablePositionIds() -> Set<Int> {
var ids = Set<Int>()
for i in 0 ..< positions.count {
ids.insert(i)
}
for id in self.activePositions {
ids.remove(id)
}
return ids
}
func spawnNextPhrase() {
let phraseIds = Array(self.availablePhraseIds()).shuffled()
let positionIds = Array(self.availablePositionIds()).shuffled()
if let phrase = phraseIds.first, let position = positionIds.first {
self.spawnPhrase(phrase, positionIndex: position)
}
}
func spawnPhrase(_ index: Int, positionIndex: Int) {
let view = UILabel()
view.alpha = 0.0
view.text = phrases[index]
view.font = Font.with(size: 24.0, design: .round, weight: .semibold, traits: [])
view.textColor = UIColor(rgb: 0xffffff, alpha: CGFloat.random(in: 0.4 ... 0.6))
view.layer.compositingFilter = "softLightBlendMode"
view.sizeToFit()
view.center = self.positionForIndex(positionIndex)
self.activePhrases.insert(index)
self.activePositions.insert(positionIndex)
let duration: Double = Double.random(in: 1.75...2.25)
view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view] _ in
self.activePhrases.remove(index)
self.activePositions.remove(positionIndex)
view?.removeFromSuperview()
self.spawnNextPhrase()
})
view.layer.animateScale(from: CGFloat.random(in: 0.4 ..< 0.6), to: CGFloat.random(in: 0.9 ..< 1.2), duration: duration, removeOnCompletion: false)
self.addSubview(view)
}
func positionForIndex(_ index: Int) -> CGPoint {
var position = positions[index]
let spread: CGPoint = CGPoint(x: 30.0, y: 5.0)
position.x = (self.frame.width - self.frame.height) / 2.0 + position.x / referenceWidth * self.frame.height + CGFloat.random(in: -spread.x ... spread.x)
position.y = position.y / referenceWidth * self.frame.height + CGFloat.random(in: -spread.y ... spread.y)
return position
}
func setVisible(_ visible: Bool) {
self.setupAnimations()
}
func resetAnimation() {
}
}

View File

@ -138,6 +138,21 @@ private final class PhoneView: UIView {
}
}
var model: PhoneDemoComponent.Model = .notch {
didSet {
if self.model != oldValue {
switch self.model {
case .notch:
self.borderView.image = phoneBorderImage
self.shimmerBorderView.image = phoneBorderMaskImage
case .island:
self.borderView.image = phoneBorderImage14
self.shimmerBorderView.image = phoneBorderMaskImage14
}
}
}
}
override init(frame: CGRect) {
self.contentContainerView = UIView()
self.contentContainerView.clipsToBounds = true
@ -355,21 +370,30 @@ final class PhoneDemoComponent: Component {
case fasterStars
case badgeStars
case emoji
case hello
}
enum Model {
case notch
case island
}
let context: AccountContext
let position: Position
let model: Model
let videoFile: TelegramMediaFile?
let decoration: BackgroundDecoration
public init(
context: AccountContext,
position: PhoneDemoComponent.Position,
model: Model = .notch,
videoFile: TelegramMediaFile?,
decoration: BackgroundDecoration = .none
) {
self.context = context
self.position = position
self.model = model
self.videoFile = videoFile
self.decoration = decoration
}
@ -381,6 +405,9 @@ final class PhoneDemoComponent: Component {
if lhs.position != rhs.position {
return false
}
if lhs.model != rhs.model {
return false
}
if lhs.videoFile != rhs.videoFile {
return false
}
@ -452,6 +479,7 @@ final class PhoneDemoComponent: Component {
self.containerView.frame = CGRect(origin: .zero, size: availableSize)
self.decorationContainerView.frame = CGRect(origin: CGPoint(x: -availableSize.width * 0.5, y: 0.0), size: CGSize(width: availableSize.width * 2.0, height: availableSize.height))
self.phoneView.bounds = CGRect(origin: .zero, size: phoneSize)
self.phoneView.model = component.model
switch component.decoration {
case .none:
@ -504,6 +532,13 @@ final class PhoneDemoComponent: Component {
self.decorationView = starsView
self.decorationContainerView.addSubview(starsView)
}
case .hello:
if let _ = self.decorationView as? HelloView {
} else {
let starsView = HelloView(frame: self.decorationContainerView.bounds)
self.decorationView = starsView
self.decorationContainerView.addSubview(starsView)
}
}
self.phoneView.setup(context: component.context, videoFile: component.videoFile, position: component.position)

View File

@ -909,9 +909,12 @@ private final class DemoSheetContent: CombinedComponent {
id: PremiumDemoScreen.Subject.translation,
component: AnyComponent(
PageComponent(
content: AnyComponent(AppIconsDemoComponent(
content: AnyComponent(PhoneDemoComponent(
context: component.context,
appIcons: appIcons
position: .top,
model: .island,
videoFile: configuration.videos["translations"],
decoration: .hello
)),
title: strings.Premium_Translation,
text: isStandalone ? strings.Premium_TranslationStandaloneInfo : strings.Premium_TranslationInfo,

View File

@ -250,7 +250,7 @@ public enum PremiumSource: Equatable {
return "deeplink"
}
case .translation:
return "translation"
return "translations"
}
}
}
@ -329,7 +329,7 @@ enum PremiumPerk: CaseIterable {
case .emojiStatus:
return "emoji_status"
case .translation:
return "translation"
return "translations"
}
}
@ -428,7 +428,7 @@ enum PremiumPerk: CaseIterable {
case .emojiStatus:
return "Premium/Perk/Status"
case .translation:
return "Premium/Perk/Status"
return "Premium/Perk/Translation"
}
}
}
@ -1492,7 +1492,8 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent {
UIColor(rgb: 0x5A6EEE),
UIColor(rgb: 0x548DFF),
UIColor(rgb: 0x54A3FF),
UIColor(rgb: 0x54bdff)
UIColor(rgb: 0x54bdff),
UIColor(rgb: 0x71c8ff)
]
let accountContext = context.component.context

View File

@ -1184,6 +1184,26 @@ public class PremiumLimitsListScreen: ViewController {
)
)
availableItems[.translation] = DemoPagerComponent.Item(
AnyComponentWithIdentity(
id: PremiumDemoScreen.Subject.translation,
component: AnyComponent(
PageComponent(
content: AnyComponent(PhoneDemoComponent(
context: context,
position: .top,
model: .island,
videoFile: configuration.videos["translations"],
decoration: .hello
)),
title: strings.Premium_Translation,
text: isStandalone ? strings.Premium_TranslationStandaloneInfo : strings.Premium_TranslationInfo,
textColor: textColor
)
)
)
)
if let order = controller.order {
var items: [DemoPagerComponent.Item] = order.compactMap { availableItems[$0] }
let index: Int

View File

@ -70,47 +70,8 @@ final class SwirlStarsView: UIView, PhoneDemoDecorationView {
animation.fillMode = .forwards
animation.repeatCount = .infinity
node.addAnimation(animation, forKey: "rotation")
self.setupMovementAnimation()
}
func setupMovementAnimation() {
guard let node = self.sceneView.scene?.rootNode.childNode(withName: "star", recursively: false) else {
return
}
node.position = SCNVector3(3.5, 0.0, -2.0)
let firstPath = UIBezierPath()
firstPath.move(to: CGPoint(x: 3.5, y: -2.0))
firstPath.addLine(to: CGPoint(x: -15.5, y: 15.5))
let firstAction = SCNAction.moveAlong(path: firstPath, duration: 2.0)
SCNTransaction.begin()
SCNTransaction.animationDuration = 2.0
node.runAction(firstAction)
SCNTransaction.completionBlock = { [weak self, weak node] in
Queue.mainQueue().after(2.2, {
node?.position = SCNVector3(0.0, 0.0, -3.0)
let secondPath = UIBezierPath()
secondPath.move(to: CGPoint(x: 0.0, y: -3.0))
secondPath.addLine(to: CGPoint(x: 15.5, y: 20.0))
let secondAction = SCNAction.moveAlong(path: secondPath, duration: 2.0)
SCNTransaction.begin()
SCNTransaction.animationDuration = 2.0
node?.runAction(secondAction)
SCNTransaction.completionBlock = { [weak self] in
Queue.mainQueue().after(2.2, {
self?.setupMovementAnimation()
})
}
SCNTransaction.commit()
})
}
SCNTransaction.commit()
}
func resetAnimation() {
}
@ -120,85 +81,3 @@ final class SwirlStarsView: UIView, PhoneDemoDecorationView {
self.sceneView.frame = CGRect(origin: .zero, size: frame.size)
}
}
extension UIBezierPath {
var elements: [PathElement] {
var pathElements = [PathElement]()
withUnsafeMutablePointer(to: &pathElements) { elementsPointer in
cgPath.apply(info: elementsPointer) { (userInfo, nextElementPointer) in
let nextElement = PathElement(element: nextElementPointer.pointee)
let elementsPointer = userInfo!.assumingMemoryBound(to: [PathElement].self)
elementsPointer.pointee.append(nextElement)
}
}
return pathElements
}
}
enum PathElement {
case moveToPoint(CGPoint)
case addLineToPoint(CGPoint)
case addQuadCurveToPoint(CGPoint, CGPoint)
case addCurveToPoint(CGPoint, CGPoint, CGPoint)
case closeSubpath
init(element: CGPathElement) {
switch element.type {
case .moveToPoint:
self = .moveToPoint(element.points[0])
case .addLineToPoint:
self = .addLineToPoint(element.points[0])
case .addQuadCurveToPoint:
self = .addQuadCurveToPoint(element.points[0], element.points[1])
case .addCurveToPoint:
self = .addCurveToPoint(element.points[0], element.points[1], element.points[2])
case .closeSubpath:
self = .closeSubpath
@unknown default:
self = .closeSubpath
}
}
}
public extension SCNAction {
class func moveAlong(path: UIBezierPath, duration animationDuration: Double) -> SCNAction {
let points = path.elements
var actions = [SCNAction]()
for point in points {
switch point {
case .moveToPoint(let a):
let moveAction = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration)
actions.append(moveAction)
break
case .addCurveToPoint(let a, let b, let c):
let moveAction1 = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration)
let moveAction2 = SCNAction.move(to: SCNVector3(b.x, 0, b.y), duration: animationDuration)
let moveAction3 = SCNAction.move(to: SCNVector3(c.x, 0, c.y), duration: animationDuration)
actions.append(moveAction1)
actions.append(moveAction2)
actions.append(moveAction3)
break
case .addLineToPoint(let a):
let moveAction = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration)
actions.append(moveAction)
break
case .addQuadCurveToPoint(let a, let b):
let moveAction1 = SCNAction.move(to: SCNVector3(a.x, 0, a.y), duration: animationDuration)
let moveAction2 = SCNAction.move(to: SCNVector3(b.x, 0, b.y), duration: animationDuration)
actions.append(moveAction1)
actions.append(moveAction2)
break
default:
let moveAction = SCNAction.move(to: SCNVector3(0, 0, 0), duration: animationDuration)
actions.append(moveAction)
break
}
}
return SCNAction.sequence(actions)
}
}

View File

@ -496,7 +496,9 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
}
}
entries.append(.doNotTranslate(text: presentationData.strings.Localization_DoNotTranslate, value: value))
if showTranslate || translateChats {
entries.append(.doNotTranslate(text: presentationData.strings.Localization_DoNotTranslate, value: value))
}
if showTranslate {
entries.append(.translateInfo(text: ignoredLanguages.count > 1 ? presentationData.strings.Localization_DoNotTranslateManyInfo : presentationData.strings.Localization_DoNotTranslateInfo))

View File

@ -199,6 +199,9 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
@objc internal func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
var updated = textField.text ?? ""
updated.replaceSubrange(updated.index(updated.startIndex, offsetBy: range.lowerBound) ..< updated.index(updated.startIndex, offsetBy: range.upperBound), with: string)
if updated.hasPrefix("#") {
updated.removeFirst()
}
if updated.count <= 6 && updated.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789abcdefABCDEF").inverted) == nil {
textField.text = updated.uppercased()
textField.textColor = self.theme.chat.inputPanel.inputTextColor

View File

@ -1291,9 +1291,23 @@ final class AvatarEditorScreenComponent: Component {
entity.position = CGPoint(x: drawingSize.width / 2.0, y: drawingSize.height / 2.0)
entity.scale = 3.3
var documentId: Int64 = 0
if case let .file(file) = entity.content, file.isCustomEmoji {
documentId = file.fileId.id
var fileId: Int64 = 0
var stickerPackId: Int64 = 0
var stickerPackAccessHash: Int64 = 0
if case let .file(file) = entity.content {
if file.isCustomEmoji {
fileId = file.fileId.id
} else if file.isAnimatedSticker {
for attribute in file.attributes {
if case let .Sticker(_, packReference, _) = attribute, let packReference, case let .id(id, accessHash) = packReference {
fileId = file.fileId.id
stickerPackId = id
stickerPackAccessHash = accessHash
break
}
}
}
}
let colors: [NSNumber] = state.selectedBackground.colors.map { Int32(bitPattern: $0) as NSNumber }
@ -1337,9 +1351,15 @@ final class AvatarEditorScreenComponent: Component {
}, opaque: false)!
if entity.isAnimated {
controller.videoCompletion(combinedImage, tempUrl, TGVideoEditAdjustments(photoEditorValues: adjustments, preset: preset, documentId: documentId, colors: colors), { [weak controller] in
controller?.dismiss()
})
if stickerPackId != 0 {
controller.videoCompletion(combinedImage, tempUrl, TGVideoEditAdjustments(photoEditorValues: adjustments, preset: preset, stickerPackId: stickerPackId, stickerPackAccessHash: stickerPackAccessHash, documentId: fileId, colors: colors), { [weak controller] in
controller?.dismiss()
})
} else {
controller.videoCompletion(combinedImage, tempUrl, TGVideoEditAdjustments(photoEditorValues: adjustments, preset: preset, documentId: fileId, colors: colors), { [weak controller] in
controller?.dismiss()
})
}
} else {
controller.imageCompletion(combinedImage, { [weak controller] in
controller?.dismiss()
@ -1436,6 +1456,16 @@ public final class AvatarEditorScreen: ViewControllerComponentContainer {
self.navigationItem.leftBarButtonItem = UIBarButtonItem(customView: UIView())
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
self.scrollToTop = { [weak self] in
if let self {
if let view = self.node.hostView.findTaggedView(tag: EmojiPagerContentComponent.Tag(id: AnyHashable("emoji"))) as? EmojiPagerContentComponent.View {
view.scrollToTop()
} else if let view = self.node.hostView.findTaggedView(tag: EmojiPagerContentComponent.Tag(id: AnyHashable("emoji"))) as? EmojiPagerContentComponent.View {
view.scrollToTop()
}
}
}
}
required public init(coder aDecoder: NSCoder) {

View File

@ -1140,6 +1140,9 @@ private class ColorInputFieldNode: ASDisplayNode, UITextFieldDelegate {
@objc internal func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
var updated = textField.text ?? ""
updated.replaceSubrange(updated.index(updated.startIndex, offsetBy: range.lowerBound) ..< updated.index(updated.startIndex, offsetBy: range.upperBound), with: string)
if updated.hasPrefix("#") {
updated.removeFirst()
}
if updated.count <= 6 && updated.rangeOfCharacter(from: CharacterSet(charactersIn: "0123456789abcdefABCDEF").inverted) == nil {
textField.text = updated.uppercased()
textField.textColor = self.theme.chat.inputPanel.inputTextColor

View File

@ -3878,7 +3878,7 @@ public final class EmojiPagerContentComponent: Component {
}
}
private func scrollToTop() {
public func scrollToTop() {
guard let _ = self.component, let _ = self.pagerEnvironment, let itemLayout = self.itemLayout else {
return
}
@ -5061,7 +5061,7 @@ public final class EmojiPagerContentComponent: Component {
self.visibleSearchHeader?.endEditing(true)
}
}
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if self.ignoreScrolling {
return

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "translatepremium.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,125 @@
%PDF-1.7
1 0 obj
<< >>
endobj
2 0 obj
<< /Length 3 0 R >>
stream
/DeviceRGB CS
/DeviceRGB cs
q
1.000000 0.000000 -0.000000 1.000000 10.920044 10.255630 cm
1.000000 1.000000 1.000000 scn
5.750232 15.581270 m
5.426097 15.905405 4.900570 15.905405 4.576435 15.581270 c
4.252300 15.257134 4.252300 14.731607 4.576435 14.407473 c
6.743102 12.240807 l
7.067237 11.916671 7.592764 11.916671 7.916899 12.240807 c
8.241034 12.564941 8.241034 13.090468 7.916899 13.414603 c
5.750232 15.581270 l
h
12.746666 11.491037 m
10.580000 11.491037 l
4.080000 11.491037 l
1.913333 11.491037 l
1.454937 11.491037 1.083333 11.119434 1.083333 10.661037 c
1.083333 10.202641 1.454937 9.831038 1.913333 9.831038 c
3.267690 9.831038 l
3.397668 6.842636 4.247280 4.446305 5.928415 2.763829 c
4.622104 2.096912 2.938897 1.741038 0.830000 1.741038 c
0.371604 1.741038 0.000000 1.369434 0.000000 0.911038 c
0.000000 0.452641 0.371604 0.081038 0.830000 0.081038 c
3.431095 0.081038 5.621857 0.582098 7.330002 1.650631 c
9.038148 0.582098 11.228905 0.081038 13.830000 0.081038 c
14.288396 0.081038 14.660000 0.452641 14.660000 0.911038 c
14.660000 1.369434 14.288396 1.741038 13.830000 1.741038 c
11.721103 1.741038 10.037899 2.096912 8.731588 2.763829 c
10.412724 4.446305 11.262332 6.842636 11.392309 9.831038 c
12.746666 9.831038 l
13.205063 9.831038 13.576666 10.202641 13.576666 10.661037 c
13.576666 11.119434 13.205063 11.491037 12.746666 11.491037 c
h
7.104398 3.935437 m
5.818785 5.221051 5.057345 7.146626 4.929302 9.831038 c
9.730699 9.831038 l
9.602655 7.146626 8.841215 5.221051 7.555602 3.935437 c
7.482480 3.862315 7.407287 3.790889 7.330002 3.721178 c
7.252717 3.790889 7.177521 3.862315 7.104398 3.935437 c
h
f*
n
Q
q
1.000000 0.000000 -0.000000 1.000000 4.419800 5.891495 cm
1.000000 1.000000 1.000000 scn
6.473423 13.172696 m
6.345813 13.484631 6.042246 13.688431 5.705219 13.688431 c
5.368191 13.688431 5.064625 13.484631 4.937015 13.172696 c
0.062015 1.256029 l
-0.111549 0.831761 0.091686 0.347124 0.515953 0.173560 c
0.940221 -0.000004 1.424859 0.203231 1.598423 0.627499 c
3.160168 4.445098 l
8.250270 4.445098 l
9.812015 0.627499 l
9.985579 0.203231 10.470217 -0.000004 10.894484 0.173560 c
11.318751 0.347124 11.521987 0.831761 11.348423 1.256029 c
6.473423 13.172696 l
h
7.571179 6.105098 m
5.705219 10.666334 l
3.839258 6.105098 l
7.571179 6.105098 l
h
f*
n
Q
endstream
endobj
3 0 obj
2291
endobj
4 0 obj
<< /Annots []
/Type /Page
/MediaBox [ 0.000000 0.000000 30.000000 30.000000 ]
/Resources 1 0 R
/Contents 2 0 R
/Parent 5 0 R
>>
endobj
5 0 obj
<< /Kids [ 4 0 R ]
/Count 1
/Type /Pages
>>
endobj
6 0 obj
<< /Pages 5 0 R
/Type /Catalog
>>
endobj
xref
0 7
0000000000 65535 f
0000000010 00000 n
0000000034 00000 n
0000002381 00000 n
0000002404 00000 n
0000002577 00000 n
0000002651 00000 n
trailer
<< /ID [ (some) (id) ]
/Root 6 0 R
/Size 7
>>
startxref
2710
%%EOF

View File

@ -1944,9 +1944,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let dismissedTranslationPanelNode = dismissedTranslationPanelNode {
var dismissedPanelFrame = dismissedTranslationPanelNode.frame
dismissedPanelFrame.origin.y = -dismissedPanelFrame.size.height
transition.updateFrame(node: dismissedTranslationPanelNode, frame: dismissedPanelFrame, completion: { [weak dismissedTranslationPanelNode] _ in
transition.updateAlpha(node: dismissedTranslationPanelNode, alpha: 0.0, completion: { [weak dismissedTranslationPanelNode] _ in
dismissedTranslationPanelNode?.removeFromSupernode()
})
dismissedTranslationPanelNode.animateOut()
}
if let dismissedImportStatusPanelNode = dismissedImportStatusPanelNode {

View File

@ -1249,7 +1249,8 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
parentMessage: item.message,
constrainedSize: CGSize(width: availableContentWidth, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer,
associatedData: item.associatedData
))
}

View File

@ -2011,7 +2011,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
parentMessage: item.message,
constrainedSize: CGSize(width: maximumNodeWidth - layoutConstants.text.bubbleInsets.left - layoutConstants.text.bubbleInsets.right, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer,
associatedData: item.associatedData
))
replyInfoSizeApply = (sizeAndApply.0, { synchronousLoads in sizeAndApply.1(synchronousLoads) })

View File

@ -469,7 +469,8 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD
parentMessage: item.message,
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer,
associatedData: item.associatedData
))
}
} else if let _ = attribute as? InlineBotMessageAttribute {

View File

@ -350,7 +350,8 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
parentMessage: item.message,
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer,
associatedData: item.associatedData
))
}
}

View File

@ -32,6 +32,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
let constrainedSize: CGSize
let animationCache: AnimationCache?
let animationRenderer: MultiAnimationRenderer?
let associatedData: ChatMessageItemAssociatedData
init(
presentationData: ChatPresentationData,
@ -42,7 +43,8 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
parentMessage: Message,
constrainedSize: CGSize,
animationCache: AnimationCache?,
animationRenderer: MultiAnimationRenderer?
animationRenderer: MultiAnimationRenderer?,
associatedData: ChatMessageItemAssociatedData
) {
self.presentationData = presentationData
self.strings = strings
@ -53,6 +55,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
self.constrainedSize = constrainedSize
self.animationCache = animationCache
self.animationRenderer = animationRenderer
self.associatedData = associatedData
}
}
@ -165,7 +168,20 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
let messageText: NSAttributedString
if isText {
let entities = (arguments.message.textEntitiesAttribute?.entities ?? []).filter { entity in
var text = arguments.message.text
var messageEntities = arguments.message.textEntitiesAttribute?.entities ?? []
if let translateToLanguage = arguments.associatedData.translateToLanguage, !text.isEmpty {
for attribute in arguments.message.attributes {
if let attribute = attribute as? TranslationMessageAttribute, !attribute.text.isEmpty, attribute.toLang == translateToLanguage {
text = attribute.text
messageEntities = attribute.entities
break
}
}
}
let entities = messageEntities.filter { entity in
if case .Spoiler = entity.type {
return true
} else if case .CustomEmoji = entity.type {
@ -175,9 +191,9 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
}
}
if entities.count > 0 {
messageText = stringWithAppliedEntities(trimToLineCount(arguments.message.text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: arguments.message)
messageText = stringWithAppliedEntities(trimToLineCount(text, lineCount: 1), entities: entities, baseColor: textColor, linkColor: textColor, baseFont: textFont, linkFont: textFont, boldFont: textFont, italicFont: textFont, boldItalicFont: textFont, fixedFont: textFont, blockQuoteFont: textFont, underlineLinks: false, message: arguments.message)
} else {
messageText = NSAttributedString(string: textString.string, font: textFont, textColor: textColor)
messageText = NSAttributedString(string: text, font: textFont, textColor: textColor)
}
} else {
messageText = NSAttributedString(string: textString.string, font: textFont, textColor: textColor)

View File

@ -677,7 +677,8 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
parentMessage: item.message,
constrainedSize: CGSize(width: availableWidth, height: CGFloat.greatestFiniteMagnitude),
animationCache: item.controllerInteraction.presentationContext.animationCache,
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer
animationRenderer: item.controllerInteraction.presentationContext.animationRenderer,
associatedData: item.associatedData
))
}

View File

@ -48,6 +48,8 @@ final class ChatTranslationPanelNode: ASDisplayNode {
super.init()
self.clipsToBounds = true
self.addSubnode(self.separatorNode)
self.addSubnode(self.button)
self.addSubnode(self.moreButton)
@ -63,6 +65,10 @@ final class ChatTranslationPanelNode: ASDisplayNode {
}
}
func animateOut() {
self.layer.animateBounds(from: self.bounds, to: self.bounds.offsetBy(dx: 0.0, dy: self.bounds.size.height), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
}
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
let previousIsEnabled = self.chatInterfaceState?.translationState?.isEnabled
self.chatInterfaceState = interfaceState
@ -123,13 +129,14 @@ final class ChatTranslationPanelNode: ASDisplayNode {
let moreButtonSize = self.moreButton.measure(CGSize(width: 100.0, height: panelHeight))
self.moreButton.frame = CGRect(origin: CGPoint(x: width - contentRightInset - moreButtonSize.width, y: floorToScreenPixels((panelHeight - moreButtonSize.height) / 2.0)), size: moreButtonSize)
let buttonPadding: CGFloat = 10.0
let buttonSpacing: CGFloat = 10.0
let buttonTextSize = self.buttonTextNode.updateLayout(CGSize(width: width - contentRightInset - moreButtonSize.width, height: panelHeight))
if let icon = self.buttonIconNode.image {
let buttonSize = CGSize(width: buttonTextSize.width + icon.size.width + buttonSpacing, height: panelHeight)
let buttonSize = CGSize(width: buttonTextSize.width + icon.size.width + buttonSpacing + buttonPadding * 2.0, height: panelHeight)
self.button.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - buttonSize.width) / 2.0), y: 0.0), size: buttonSize)
self.buttonIconNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floorToScreenPixels((buttonSize.height - icon.size.height) / 2.0)), size: icon.size)
self.buttonTextNode.frame = CGRect(origin: CGPoint(x: icon.size.width + buttonSpacing, y: floorToScreenPixels((buttonSize.height - buttonTextSize.height) / 2.0)), size: buttonTextSize)
self.buttonIconNode.frame = CGRect(origin: CGPoint(x: buttonPadding, y: floorToScreenPixels((buttonSize.height - icon.size.height) / 2.0)), size: icon.size)
self.buttonTextNode.frame = CGRect(origin: CGPoint(x: buttonPadding + icon.size.width + buttonSpacing, y: floorToScreenPixels((buttonSize.height - buttonTextSize.height) / 2.0)), size: buttonTextSize)
}
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))

View File

@ -7092,10 +7092,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
let isSettings = self.isSettings
self.updateAvatarDisposable.set((signal
|> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
let markup: UploadPeerPhotoMarkup? = nil
var markup: UploadPeerPhotoMarkup? = nil
if isSettings {
// let fileId = adjustments?.documentId
// let backgroundColors = adjustments?.colors as? [Int32]
if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
markup = .sticker(packReference: .id(id: packId, accessHash: accessHash), fileId: fileId, backgroundColors: backgroundColors)
} else {
markup = .emoji(fileId: fileId, backgroundColors: backgroundColors)
}
}
if case .fallback = mode {
return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)

View File

@ -73,7 +73,7 @@ private enum ApplicationSpecificItemCacheCollectionIdValues: Int8 {
case visualMediaStoredState = 5
case cachedImageRecognizedContent = 6
case pendingInAppPurchaseState = 7
case translationState = 8
case translationState = 9
}
public struct ApplicationSpecificItemCacheCollectionId {

View File

@ -114,7 +114,17 @@ public func translateMessageIds(context: AccountContext, messageIds: [EngineMess
return context.account.postbox.transaction { transaction -> Signal<Void, NoError> in
var messageIdsToTranslate: [EngineMessage.Id] = []
for messageId in messageIds {
if let message = transaction.getMessage(messageId), !message.text.isEmpty, let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == toLang {
if let message = transaction.getMessage(messageId) {
if let replyAttribute = message.attributes.first(where: { $0 is ReplyMessageAttribute }) as? ReplyMessageAttribute, let replyMessage = message.associatedMessages[replyAttribute.messageId] {
if !replyMessage.text.isEmpty, let translation = replyMessage.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == toLang {
} else {
messageIdsToTranslate.append(replyMessage.id)
}
}
if !message.text.isEmpty, let translation = message.attributes.first(where: { $0 is TranslationMessageAttribute }) as? TranslationMessageAttribute, translation.toLang == toLang {
} else {
messageIdsToTranslate.append(messageId)
}
} else {
messageIdsToTranslate.append(messageId)
}
@ -151,7 +161,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
} else {
return .single(nil)
|> then(
context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 16, fixedCombinedReadStates: nil)
context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId: peerId, threadId: nil), index: .upperBound, anchorIndex: .upperBound, count: 32, fixedCombinedReadStates: nil)
|> filter { messageHistoryView -> Bool in
return messageHistoryView.0.entries.count > 1
}
@ -168,7 +178,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
if message.text.count > 10 {
let text = String(message.text.prefix(100))
languageRecognizer.processString(text)
let hypotheses = languageRecognizer.languageHypotheses(withMaximum: 3)
let hypotheses = languageRecognizer.languageHypotheses(withMaximum: 4)
languageRecognizer.reset()
let filteredLanguages = hypotheses.filter { supportedTranslationLanguages.contains($0.key.rawValue) }.sorted(by: { $0.value > $1.value })