Various Improvements

This commit is contained in:
Ilya Laktyushin 2022-01-22 20:54:32 +03:00
parent 241f78ddd9
commit 5154356e38
24 changed files with 339 additions and 94 deletions

View File

@ -115,7 +115,9 @@ public final class CallListController: TelegramBaseController {
self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle
self.tabBarItem.image = icon
self.tabBarItem.selectedImage = icon
self.tabBarItem.animationName = "TabCalls"
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabCalls"
}
}
self.segmentedTitleView.indexUpdated = { [weak self] index in
@ -166,6 +168,11 @@ public final class CallListController: TelegramBaseController {
self.segmentedTitleView.index = index
self.tabBarItem.title = self.presentationData.strings.Calls_TabTitle
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabCalls"
} else {
self.tabBarItem.animationName = nil
}
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
switch self.mode {
case .tab:

View File

@ -2,6 +2,7 @@ import Foundation
import AsyncDisplayKit
import Display
import AVFoundation
import SwiftSignalKit
private final class CameraPreviewNodeLayerNullAction: NSObject, CAAction {
@objc func run(forKey event: String, object anObject: Any, arguments dict: [AnyHashable : Any]?) {
@ -16,16 +17,25 @@ private final class CameraPreviewNodeLayer: AVSampleBufferDisplayLayer {
public final class CameraPreviewNode: ASDisplayNode {
private var displayLayer: AVSampleBufferDisplayLayer
private let fadeNode: ASDisplayNode
private var fadedIn = false
public override init() {
self.displayLayer = AVSampleBufferDisplayLayer()
self.displayLayer.videoGravity = .resizeAspectFill
self.fadeNode = ASDisplayNode()
self.fadeNode.backgroundColor = .black
self.fadeNode.isUserInteractionEnabled = false
super.init()
self.clipsToBounds = true
self.layer.addSublayer(self.displayLayer)
self.addSubnode(self.fadeNode)
}
func prepare() {
@ -36,6 +46,14 @@ public final class CameraPreviewNode: ASDisplayNode {
func enqueue(_ sampleBuffer: CMSampleBuffer) {
self.displayLayer.enqueue(sampleBuffer)
if !self.fadedIn {
self.fadedIn = true
Queue.mainQueue().after(0.2) {
self.fadeNode.alpha = 0.0
self.fadeNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
}
}
}
override public func layout() {
@ -46,5 +64,6 @@ public final class CameraPreviewNode: ASDisplayNode {
self.displayLayer.setAffineTransform(transform)
self.displayLayer.frame = self.bounds
self.fadeNode.frame = self.bounds
}
}

View File

@ -206,8 +206,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
self.tabBarItem.image = icon
self.tabBarItem.selectedImage = icon
self.tabBarItem.animationName = "TabChats"
self.tabBarItem.animationOffset = CGPoint(x: 0.0, y: UIScreenPixel)
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabChats"
self.tabBarItem.animationOffset = CGPoint(x: 0.0, y: UIScreenPixel)
}
let leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
leftBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Edit
@ -520,6 +522,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.DialogList_Title, style: .plain, target: nil, action: nil)
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back
self.navigationItem.backBarButtonItem = backBarButtonItem
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabChats"
} else {
self.tabBarItem.animationName = nil
}
} else {
let backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
backBarButtonItem.accessibilityLabel = self.presentationData.strings.Common_Back

View File

@ -192,7 +192,9 @@ public class ContactsController: ViewController {
self.tabBarItem.image = icon
self.tabBarItem.selectedImage = icon
self.tabBarItem.animationName = "TabContacts"
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabContacts"
}
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
@ -281,6 +283,11 @@ public class ContactsController: ViewController {
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
self.title = self.presentationData.strings.Contacts_Title
self.tabBarItem.title = self.presentationData.strings.Contacts_Title
if !self.presentationData.reduceMotion {
self.tabBarItem.animationName = "TabContacts"
} else {
self.tabBarItem.animationName = nil
}
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
if self.navigationItem.rightBarButtonItem != nil {
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationAddIcon(self.presentationData.theme), style: .plain, target: self, action: #selector(self.addPressed))

View File

@ -143,7 +143,7 @@ final class GameControllerNode: ViewControllerTracingNode {
if eventName == "share_game" || eventName == "share_score" {
if let (botPeer, gameName) = self.shareData(), let addressName = botPeer.addressName, !addressName.isEmpty, !gameName.isEmpty {
if eventName == "share_score" {
self.present(ShareController(context: self.context, subject: .fromExternal({ [weak self] peerIds, text, account in
self.present(ShareController(context: self.context, subject: .fromExternal({ [weak self] peerIds, text, account, _ in
if let strongSelf = self {
let signals = peerIds.map { TelegramEngine(account: account).messages.forwardGameWithScore(messageId: strongSelf.message.id, to: $0, as: nil) }
return .single(.preparing)

View File

@ -1,6 +1,7 @@
import Foundation
import UIKit
import Postbox
import TelegramCore
enum StickerVerificationStatus {
case loading
@ -9,10 +10,39 @@ enum StickerVerificationStatus {
}
public class ImportStickerPack {
public enum StickerPackType {
case image
case animation
case video
var importType: CreateStickerSetType {
switch self {
case .image:
return .image
case .animation:
return .animation
case .video:
return .video
}
}
}
public class Sticker: Equatable {
public enum Content {
case image(Data)
case animation(Data)
case video(Data, String)
}
var mimeType: String {
switch self.content {
case .image:
return "image/png"
case .animation:
return "application/x-tgsticker"
case let .video(_, mimeType):
return mimeType
}
}
public static func == (lhs: ImportStickerPack.Sticker, rhs: ImportStickerPack.Sticker) -> Bool {
@ -32,9 +62,7 @@ public class ImportStickerPack {
var data: Data {
switch self.content {
case let .image(data):
return data
case let .animation(data):
case let .image(data), let .animation(data), let .video(data, _):
return data
}
}
@ -49,7 +77,7 @@ public class ImportStickerPack {
}
public let software: String
public let isAnimated: Bool
public let type: StickerPackType
public let thumbnail: Sticker?
public let stickers: [Sticker]
@ -59,20 +87,33 @@ public class ImportStickerPack {
}
self.software = json["software"] as? String ?? ""
let isAnimated = json["isAnimated"] as? Bool ?? false
self.isAnimated = isAnimated
let isVideo = json["isVideo"] as? Bool ?? false
let type: StickerPackType
if isAnimated {
type = .animation
} else if isVideo {
type = .video
} else {
type = .image
}
self.type = type
func parseSticker(_ sticker: [String: Any]) -> Sticker? {
if let dataString = sticker["data"] as? String, let mimeType = sticker["mimeType"] as? String, let data = Data(base64Encoded: dataString) {
var content: Sticker.Content?
switch mimeType.lowercased() {
case "image/png":
if !isAnimated {
if case .image = type {
content = .image(data)
}
case "application/x-tgsticker":
if isAnimated {
if case .animation = type {
content = .animation(data)
}
case "video/webm", "image/webp", "image/gif":
if case .video = type {
content = .video(data, mimeType)
}
default:
break
}

View File

@ -79,7 +79,8 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
Queue.mainQueue().after(0.1) {
self.controllerNode.updateStickerPack(self.stickerPack, verifiedStickers: Set(), declinedStickers: Set(), uploadedStickerResources: [:])
if self.stickerPack.isAnimated {
if case .image = self.stickerPack.type {
} else {
let _ = (self.context.account.postbox.loadedPeerWithId(self.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let strongSelf = self else {
@ -89,13 +90,13 @@ public final class ImportStickerPackController: ViewController, StandalonePresen
var signals: [Signal<(UUID, StickerVerificationStatus, MediaResource?), NoError>] = []
for sticker in strongSelf.stickerPack.stickers {
if let resource = strongSelf.controllerNode.stickerResources[sticker.uuid] {
signals.append(strongSelf.context.engine.stickers.uploadSticker(peer: peer, resource: resource, alt: sticker.emojis.first ?? "", dimensions: PixelDimensions(width: 512, height: 512), isAnimated: true)
signals.append(strongSelf.context.engine.stickers.uploadSticker(peer: peer, resource: resource, alt: sticker.emojis.first ?? "", dimensions: PixelDimensions(width: 512, height: 512), mimeType: sticker.mimeType)
|> map { result -> (UUID, StickerVerificationStatus, MediaResource?) in
switch result {
case .progress:
return (sticker.uuid, .loading, nil)
case let .complete(resource, mimeType):
if mimeType == "application/x-tgsticker" {
if ["application/x-tgsticker", "video/webm"].contains(mimeType) {
return (sticker.uuid, .verified, resource)
} else {
return (sticker.uuid, .declined, nil)

View File

@ -607,9 +607,9 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
if let localResource = item.stickerItem.resource {
self.context.account.postbox.mediaBox.copyResourceData(from: localResource.id, to: resource.id)
}
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions, mimeType: item.stickerItem.mimeType))
} else if let resource = item.stickerItem.resource {
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions))
stickers.append(ImportSticker(resource: resource, emojis: item.stickerItem.emojis, dimensions: dimensions, mimeType: item.stickerItem.mimeType))
}
}
var thumbnailSticker: ImportSticker?
@ -620,7 +620,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
}
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
self.context.account.postbox.mediaBox.storeResourceData(resource.id, data: thumbnail.data)
thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions)
thumbnailSticker = ImportSticker(resource: resource, emojis: [], dimensions: dimensions, mimeType: thumbnail.mimeType)
}
let firstStickerItem = thumbnailSticker ?? stickers.first
@ -631,13 +631,17 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.2, curve: .easeInOut))
}
self.disposable.set((self.context.engine.stickers.createStickerSet(title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnailSticker, isAnimated: stickerPack.isAnimated, software: stickerPack.software)
self.disposable.set((self.context.engine.stickers.createStickerSet(title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnailSticker, type: stickerPack.type.importType, software: stickerPack.software)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self {
if case let .complete(info, items) = status {
if let (_, _, count) = strongSelf.progress {
strongSelf.progress = (1.0, count, count)
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: !stickerPack.isAnimated, synchronous: true, completion: {})
var animated = false
if case .image = stickerPack.type {
animated = true
}
strongSelf.radialStatus.transitionToState(.progress(color: strongSelf.presentationData.theme.list.itemAccentColor, lineWidth: 6.0, value: 1.0, cancelEnabled: false, animateRotation: false), animated: animated, synchronous: true, completion: {})
if let (layout, navigationBarHeight) = strongSelf.containerLayout {
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
}
@ -675,7 +679,7 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
Queue.mainQueue().after(1.0) {
var firstItem: StickerPackItem?
if let firstStickerItem = firstStickerItem, let resource = firstStickerItem.resource as? TelegramMediaResource {
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: stickerPack.isAnimated ? "application/x-tgsticker": "image/png", size: nil, attributes: [.FileName(fileName: stickerPack.isAnimated ? "sticker.tgs" : "sticker.png"), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
firstItem = StickerPackItem(index: ItemCollectionItemIndex(index: 0, id: 0), file: TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: firstStickerItem.mimeType, size: nil, attributes: [.FileName(fileName: ""), .ImageSize(size: firstStickerItem.dimensions)]), indexKeys: [])
}
strongSelf.presentInGlobalOverlay?(UndoOverlayController(presentationData: strongSelf.presentationData, content: .stickersModified(title: strongSelf.presentationData.strings.StickerPackActionInfo_AddedTitle, text: strongSelf.presentationData.strings.StickerPackActionInfo_AddedText(info.title).string, undo: false, info: info, topItem: firstItem ?? items.first, context: strongSelf.context), elevatedLayout: false, action: { action in
if case .info = action {
@ -781,11 +785,16 @@ final class ImportStickerPackControllerNode: ViewControllerTracingNode, UIScroll
item.resource = resource
self.stickerResources[item.uuid] = resource
}
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item, isVerified: !item.isAnimated || verifiedStickers.contains(item.uuid)))
var isInitiallyVerified = false
if case .image = item.content {
isInitiallyVerified = true
}
updatedItems.append(StickerPackPreviewGridEntry(index: updatedItems.count, stickerItem: item, isVerified: isInitiallyVerified || verifiedStickers.contains(item.uuid)))
}
self.pendingItems = updatedItems
if stickerPack.isAnimated {
if case .image = stickerPack.type {
} else {
self.stickerPackReady = stickerPack.stickers.count == (verifiedStickers.count + declinedStickers.count) && updatedItems.count > 0
}

View File

@ -11,6 +11,7 @@ import AnimatedStickerNode
import TelegramAnimatedStickerNode
import TelegramPresentationData
import ShimmerEffect
import SoftwareVideo
final class StickerPackPreviewInteraction {
var previewedItem: ImportStickerPack.Sticker?
@ -60,6 +61,7 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
private var isVerified: Bool?
private let imageNode: ASImageNode
private var animationNode: AnimatedStickerNode?
private var videoNode: VideoStickerNode?
private var placeholderNode: ShimmerEffectNode?
private var theme: PresentationTheme?
@ -145,6 +147,39 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
let placeholderNode = ShimmerEffectNode()
self.placeholderNode = placeholderNode
self.addSubnode(placeholderNode)
if let (absoluteRect, containerSize) = self.absoluteLocation {
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
}
}
case .video:
self.imageNode.isHidden = true
if isVerified {
let videoNode = VideoStickerNode()
self.videoNode = videoNode
if let resource = stickerItem.resource as? TelegramMediaResource {
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
}
if let placeholderNode = self.placeholderNode {
self.placeholderNode = nil
placeholderNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak placeholderNode] _ in
placeholderNode?.removeFromSupernode()
})
self.insertSubnode(videoNode, belowSubnode: placeholderNode)
} else {
self.addSubnode(videoNode)
}
videoNode.update(isPlaying: self.isVisibleInGrid && self.interaction?.playAnimatedStickers ?? true)
} else {
let placeholderNode = ShimmerEffectNode()
self.placeholderNode = placeholderNode
self.addSubnode(placeholderNode)
if let (absoluteRect, containerSize) = self.absoluteLocation {
placeholderNode.updateAbsoluteRect(absoluteRect, within: containerSize)
@ -175,6 +210,11 @@ final class StickerPackPreviewGridItemNode: GridItemNode {
animationNode.updateLayout(size: imageSize)
}
if let videoNode = self.videoNode {
videoNode.frame = CGRect(origin: CGPoint(x: floor((bounds.size.width - imageSize.width) / 2.0), y: (bounds.size.height - imageSize.height) / 2.0), size: imageSize)
videoNode.updateLayout(size: imageSize)
}
if let placeholderNode = self.placeholderNode, let theme = self.theme {
placeholderNode.update(backgroundColor: theme.list.itemBlocksBackgroundColor, foregroundColor: theme.list.mediaPlaceholderColor, shimmeringColor: theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.4), shapes: [.roundedRect(rect: CGRect(origin: CGPoint(), size: imageSize), cornerRadius: 11.0)], horizontal: true, size: imageSize)
placeholderNode.frame = self.imageNode.frame

View File

@ -9,6 +9,7 @@ import StickerResources
import AnimatedStickerNode
import TelegramAnimatedStickerNode
import ContextUI
import SoftwareVideo
public final class StickerPreviewPeekContent: PeekControllerContent {
let account: Account
@ -57,6 +58,7 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
private var textNode: ASTextNode
private var imageNode: ASImageNode
private var animationNode: AnimatedStickerNode?
private var videoNode: VideoStickerNode?
private var containerLayout: (ContainerViewLayout, CGFloat)?
@ -79,6 +81,16 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
self.animationNode?.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil))
}
self.animationNode?.visibility = true
case .video:
let videoNode = VideoStickerNode()
self.videoNode = videoNode
if let resource = item.resource as? TelegramMediaResource {
let dummyFile = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 1), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "video/webm", size: resource.size ?? 1, attributes: [.Video(duration: 1, size: PixelDimensions(width: 100, height: 100), flags: [])])
videoNode.update(account: account, fileReference: .standalone(media: dummyFile))
}
videoNode.update(isPlaying: true)
}
if case let .image(data) = item.content, let image = UIImage(data: data) {
self.imageNode.image = image
@ -89,7 +101,9 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
self.isUserInteractionEnabled = false
if let animationNode = self.animationNode {
if let videoNode = self.videoNode {
self.addSubnode(videoNode)
} else if let animationNode = self.animationNode {
self.addSubnode(animationNode)
} else {
self.addSubnode(self.imageNode)
@ -108,7 +122,10 @@ private final class StickerPreviewPeekContentNode: ASDisplayNode, PeekController
self.imageNode.frame = imageFrame
if let animationNode = self.animationNode {
if let videoNode = self.videoNode {
videoNode.frame = imageFrame
videoNode.updateLayout(size: imageFrame.size)
} else if let animationNode = self.animationNode {
animationNode.frame = imageFrame
animationNode.updateLayout(size: imageFrame.size)
}

View File

@ -59,22 +59,29 @@ public class InvisibleInkDustNode: ASDisplayNode {
public var isRevealed = false
private var exploding = false
public init(textNode: TextNode?) {
self.textNode = textNode
self.emitterNode = ASDisplayNode()
self.emitterNode.isUserInteractionEnabled = false
self.emitterNode.clipsToBounds = true
self.textMaskNode = ASDisplayNode()
self.textMaskNode.isUserInteractionEnabled = false
self.textSpotNode = ASImageNode()
self.textSpotNode.contentMode = .scaleToFill
self.textSpotNode.isUserInteractionEnabled = false
self.emitterMaskNode = ASDisplayNode()
self.emitterSpotNode = ASImageNode()
self.emitterSpotNode.contentMode = .scaleToFill
self.emitterSpotNode.isUserInteractionEnabled = false
self.emitterMaskFillNode = ASDisplayNode()
self.emitterMaskFillNode.backgroundColor = .white
self.emitterMaskFillNode.isUserInteractionEnabled = false
super.init()
@ -135,7 +142,7 @@ public class InvisibleInkDustNode: ASDisplayNode {
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tap(_:))))
}
public func update(revealed: Bool) {
public func update(revealed: Bool, animated: Bool = true) {
guard self.isRevealed != revealed, let textNode = self.textNode else {
return
}
@ -143,13 +150,18 @@ public class InvisibleInkDustNode: ASDisplayNode {
self.isRevealed = revealed
if revealed {
let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .linear)
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .linear) : .immediate
transition.updateAlpha(node: self, alpha: 0.0)
transition.updateAlpha(node: textNode, alpha: 1.0)
} else {
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .linear)
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .linear) : .immediate
transition.updateAlpha(node: self, alpha: 1.0)
transition.updateAlpha(node: textNode, alpha: 0.0)
if self.exploding {
self.exploding = false
self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
}
}
}
@ -159,6 +171,7 @@ public class InvisibleInkDustNode: ASDisplayNode {
}
self.isRevealed = true
self.exploding = true
let position = gestureRecognizer.location(in: self.view)
self.emitterLayer?.setValue(true, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
@ -214,6 +227,7 @@ public class InvisibleInkDustNode: ASDisplayNode {
}
Queue.mainQueue().after(0.8 * UIView.animationDurationFactor()) {
self.exploding = false
self.emitterLayer?.setValue(false, forKeyPath: "emitterBehaviors.fingerAttractor.enabled")
self.textSpotNode.layer.removeAllAnimations()

View File

@ -61,7 +61,7 @@ public enum ShareControllerSubject {
case image([ImageRepresentationWithReference])
case media(AnyMediaReference)
case mapMedia(TelegramMediaMap)
case fromExternal(([PeerId], String, Account) -> Signal<ShareControllerExternalStatus, NoError>)
case fromExternal(([PeerId], String, Account, Bool) -> Signal<ShareControllerExternalStatus, NoError>)
}
private enum ExternalShareItem {
@ -503,7 +503,7 @@ public final class ShareController: ViewController {
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forceTheme: self.forceTheme, fromPublicChannel: fromPublicChannel, segmentedValues: self.segmentedValues)
self.controllerNode.completed = self.completed
self.controllerNode.present = { [weak self] c in
self?.presentInGlobalOverlay(c, with: nil)
self?.present(c, in: .window(.root))
}
self.controllerNode.dismiss = { [weak self] shared in
self?.dismissed?(shared)
@ -623,7 +623,7 @@ public final class ShareController: ViewController {
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
}
case let .fromExternal(f):
return f(peerIds, text, strongSelf.currentAccount)
return f(peerIds, text, strongSelf.currentAccount, silently)
|> map { state -> ShareState in
switch state {
case .preparing:

View File

@ -191,29 +191,35 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
self.actionButtonNode.contextAction = { [weak self] node, gesture in
if let strongSelf = self, let context = strongSelf.context, let node = node as? ContextReferenceContentNode {
let presentationData = strongSelf.presentationData
let fromForeignApp = strongSelf.fromForeignApp
let items: Signal<ContextController.Items, NoError> =
strongSelf.showNames.get()
|> map { showNamesValue in
return ContextController.Items(content: .list([
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowSendersName, icon: { theme in
if showNamesValue {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, _ in
self?.showNames.set(true)
})),
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideSendersName, icon: { theme in
if !showNamesValue {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, _ in
self?.showNames.set(false)
})),
.separator,
var items: [ContextMenuItem] = []
if !fromForeignApp {
items.append(contentsOf: [
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowSendersName, icon: { theme in
if showNamesValue {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, _ in
self?.showNames.set(true)
})),
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideSendersName, icon: { theme in
if !showNamesValue {
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor)
} else {
return nil
}
}, action: { _, _ in
self?.showNames.set(false)
})),
.separator,
])
}
items.append(contentsOf: [
.action(ContextMenuActionItem(text: presentationData.strings.Conversation_SendMessage_SendSilently, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Menu/SilentIcon"), color: theme.contextMenu.primaryColor) }, action: { _, f in
f(.default)
if let strongSelf = self {
@ -225,8 +231,9 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
if let strongSelf = self {
strongSelf.send(showNames: showNamesValue, silently: false)
}
})),
]))
}))
])
return ContextController.Items(content: .list(items))
}
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .reference(ShareContextReferenceContentSource(sourceNode: node, customPosition: CGPoint(x: 0.0, y: -116.0))), items: items, gesture: gesture)
contextController.immediateItemsTransitionAnimation = true

View File

@ -365,7 +365,7 @@ public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [
})
}
public func sentShareItems(account: Account, to peerIds: [PeerId], items: [PreparedShareItemContent]) -> Signal<Float, Void> {
public func sentShareItems(account: Account, to peerIds: [PeerId], items: [PreparedShareItemContent], silently: Bool) -> Signal<Float, Void> {
var messages: [EnqueueMessage] = []
var groupingKey: Int64?
var mediaTypes: (photo: Int, video: Int, music: Int, other: Int) = (0, 0, 0, 0)
@ -401,15 +401,20 @@ public func sentShareItems(account: Account, to peerIds: [PeerId], items: [Prepa
groupingKey = Int64.random(in: Int64.min ... Int64.max)
}
var attributes: [MessageAttribute] = []
if silently {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
var mediaMessages: [EnqueueMessage] = []
for item in items {
switch item {
case let .text(text):
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
messages.append(.message(text: text, attributes: attributes, mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil, correlationId: nil))
case let .media(media):
switch media {
case let .media(reference):
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: reference, replyToMessageId: nil, localGroupingKey: groupingKey, correlationId: nil)
let message: EnqueueMessage = .message(text: "", attributes: attributes, mediaReference: reference, replyToMessageId: nil, localGroupingKey: groupingKey, correlationId: nil)
messages.append(message)
mediaMessages.append(message)

View File

@ -723,7 +723,9 @@ class TabBarNode: ASDisplayNode {
let previousSelectedIndex = self.selectedIndex
self.itemSelected(closestNode.0, longTap, [container.imageNode.imageNode, container.imageNode.textImageNode, container.badgeContainerNode])
if previousSelectedIndex != closestNode.0 {
container.imageNode.animationNode.play()
if let selectedIndex = self.selectedIndex, let _ = self.tabBarItems[selectedIndex].item.animationName {
container.imageNode.animationNode.play()
}
}
}
}

View File

@ -284,7 +284,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
}
switch message {
case let .message(_, _, _, replyToMessageId, _, _):
case let .message(_, attributes, _, replyToMessageId, _, _):
if let replyToMessageId = replyToMessageId, replyToMessageId.peerId != peerId, let replyMessage = transaction.getMessage(replyToMessageId) {
var canBeForwarded = true
if replyMessage.id.namespace != Namespaces.Message.Cloud {
@ -297,7 +297,7 @@ func enqueueMessages(transaction: Transaction, account: Account, peerId: PeerId,
}
}
if canBeForwarded {
updatedMessages.append((true, .forward(source: replyToMessageId, grouping: .none, attributes: [], correlationId: nil)))
updatedMessages.append((true, .forward(source: replyToMessageId, grouping: .none, attributes: attributes, correlationId: nil)))
}
}
case let .forward(sourceId, _, _, _):

View File

@ -33,7 +33,7 @@ private func uploadedSticker(postbox: Postbox, network: Network, resource: Media
}
}
func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, mimeType: String) -> Signal<UploadStickerStatus, UploadStickerError> {
guard let inputPeer = apiInputPeer(peer) else {
return .fail(.generic)
}
@ -53,7 +53,7 @@ func _internal_uploadSticker(account: Account, peer: Peer, resource: MediaResour
var attributes: [Api.DocumentAttribute] = []
attributes.append(.documentAttributeSticker(flags: 0, alt: alt, stickerset: .inputStickerSetEmpty, maskCoords: nil))
attributes.append(.documentAttributeImageSize(w: dimensions.width, h: dimensions.height))
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: file, thumb: nil, mimeType: isAnimated ? "application/x-tgsticker": "image/png", attributes: attributes, stickers: nil, ttlSeconds: nil)))
return account.network.request(Api.functions.messages.uploadMedia(peer: inputPeer, media: Api.InputMedia.inputMediaUploadedDocument(flags: flags, file: file, thumb: nil, mimeType: mimeType, attributes: attributes, stickers: nil, ttlSeconds: nil)))
|> mapError { _ -> UploadStickerError in return .generic }
|> mapToSignal { media -> Signal<UploadStickerStatus, UploadStickerError> in
switch media {
@ -81,11 +81,13 @@ public struct ImportSticker {
public let resource: MediaResource
let emojis: [String]
public let dimensions: PixelDimensions
public let mimeType: String
public init(resource: MediaResource, emojis: [String], dimensions: PixelDimensions) {
public init(resource: MediaResource, emojis: [String], dimensions: PixelDimensions, mimeType: String) {
self.resource = resource
self.emojis = emojis
self.dimensions = dimensions
self.mimeType = mimeType
}
}
@ -94,7 +96,13 @@ public enum CreateStickerSetStatus {
case complete(StickerPackCollectionInfo, [StickerPackItem])
}
func _internal_createStickerSet(account: Account, title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
public enum CreateStickerSetType {
case image
case animation
case video
}
func _internal_createStickerSet(account: Account, title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, type: CreateStickerSetType, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return account.postbox.loadedPeerWithId(account.peerId)
|> castError(CreateStickerSetError.self)
|> mapToSignal { peer -> Signal<CreateStickerSetStatus, CreateStickerSetError> in
@ -108,9 +116,9 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
}
for sticker in stickers {
if let resource = sticker.resource as? CloudDocumentMediaResource {
uploadStickers.append(.single(.complete(resource, isAnimated ? "application/x-tgsticker": "image/png")))
uploadStickers.append(.single(.complete(resource, sticker.mimeType)))
} else {
uploadStickers.append(_internal_uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, isAnimated: isAnimated)
uploadStickers.append(_internal_uploadSticker(account: account, peer: peer, resource: sticker.resource, alt: sticker.emojis.first ?? "", dimensions: sticker.dimensions, mimeType: sticker.mimeType)
|> mapError { _ -> CreateStickerSetError in
return .generic
})
@ -126,7 +134,7 @@ func _internal_createStickerSet(account: Account, title: String, shortName: Stri
}
if resources.count == stickers.count {
var flags: Int32 = 0
if isAnimated {
if case .animation = type {
flags |= (1 << 1)
}
var inputStickers: [Api.InputStickerSetItem] = []

View File

@ -69,12 +69,12 @@ public extension TelegramEngine {
return _internal_stickerPacksAttachedToMedia(account: self.account, media: media)
}
public func uploadSticker(peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, isAnimated: Bool) -> Signal<UploadStickerStatus, UploadStickerError> {
return _internal_uploadSticker(account: self.account, peer: peer, resource: resource, alt: alt, dimensions: dimensions, isAnimated: isAnimated)
public func uploadSticker(peer: Peer, resource: MediaResource, alt: String, dimensions: PixelDimensions, mimeType: String) -> Signal<UploadStickerStatus, UploadStickerError> {
return _internal_uploadSticker(account: self.account, peer: peer, resource: resource, alt: alt, dimensions: dimensions, mimeType: mimeType)
}
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, isAnimated: Bool, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, isAnimated: isAnimated, software: software)
public func createStickerSet(title: String, shortName: String, stickers: [ImportSticker], thumbnail: ImportSticker?, type: CreateStickerSetType, software: String?) -> Signal<CreateStickerSetStatus, CreateStickerSetError> {
return _internal_createStickerSet(account: self.account, title: title, shortName: shortName, stickers: stickers, thumbnail: thumbnail, type: type, software: software)
}
public func getStickerSetShortNameSuggestion(title: String) -> Signal<String?, NoError> {

View File

@ -52,6 +52,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
private let lineNode: AnimatedNavigationStripeNode
private let titleNode: AnimatedCountLabelNode
private let textNode: TextNode
private var spoilerTextNode: TextNode?
private var dustNode: InvisibleInkDustNode?
private let imageNode: TransformImageNode
@ -71,6 +72,15 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
private let queue = Queue()
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let containerResult = self.contentTextContainer.hitTest(point.offsetBy(dx: -self.contentTextContainer.frame.minX, dy: -self.contentTextContainer.frame.minY), with: event)
if containerResult?.asyncdisplaykit_node === self.dustNode, self.dustNode?.isRevealed == false {
return containerResult
}
let result = super.hitTest(point, with: event)
return result
}
init(context: AccountContext) {
self.context = context
@ -270,6 +280,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
self.currentMessage = interfaceState.pinnedMessage
if let currentMessage = self.currentMessage, let currentLayout = self.currentLayout {
self.dustNode?.update(revealed: false, animated: false)
self.enqueueTransition(width: currentLayout.0, panelHeight: panelHeight, leftInset: currentLayout.1, rightInset: currentLayout.2, transition: .immediate, animation: messageUpdatedAnimation, pinnedMessage: currentMessage, theme: interfaceState.theme, strings: interfaceState.strings, nameDisplayOrder: interfaceState.nameDisplayOrder, dateTimeFormat: interfaceState.dateTimeFormat, accountPeerId: self.context.account.peerId, firstTime: previousMessageWasNil, isReplyThread: isReplyThread)
}
}
@ -352,6 +363,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
let makeTitleLayout = self.titleNode.asyncLayout()
let makeTextLayout = TextNode.asyncLayout(self.textNode)
let makeSpoilerTextLayout = TextNode.asyncLayout(self.spoilerTextNode)
let imageNodeLayout = self.imageNode.asyncLayout()
let previousMediaReference = self.previousMediaReference
@ -476,7 +488,15 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
messageText = NSAttributedString(string: foldLineBreaks(textString), font: textFont, textColor: message.media.isEmpty || message.media.first is TelegramMediaWebpage ? theme.chat.inputPanel.primaryTextColor : theme.chat.inputPanel.secondaryTextColor)
}
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: messageText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0)))
let textConstrainedSize = CGSize(width: width - textLineInset - contentLeftInset - rightInset - textRightInset, height: CGFloat.greatestFiniteMagnitude)
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: messageText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0)))
let spoilerTextLayoutAndApply: (TextNodeLayout, () -> TextNode)?
if !textLayout.spoilers.isEmpty {
spoilerTextLayoutAndApply = makeSpoilerTextLayout(TextNodeLayoutArguments(attributedString: messageText, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0), displaySpoilers: true))
} else {
spoilerTextLayoutAndApply = nil
}
Queue.mainQueue().async {
if let strongSelf = self {
@ -485,28 +505,47 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
strongSelf.previousMediaReference = updatedMediaReference
animationTransition.updateFrameAdditive(node: strongSelf.contentTextContainer, frame: CGRect(origin: CGPoint(x: contentLeftInset + textLineInset, y: 0.0), size: CGSize()))
animationTransition.updateFrameAdditive(node: strongSelf.contentTextContainer, frame: CGRect(origin: CGPoint(x: contentLeftInset + textLineInset, y: 0.0), size: CGSize(width: width, height: panelHeight)))
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 5.0), size: titleLayout.size)
let textFrame = CGRect(origin: CGPoint(x: 0.0, y: 23.0), size: textLayout.size)
strongSelf.textNode.frame = textFrame
if !textLayout.spoilers.isEmpty {
if let (_, spoilerTextApply) = spoilerTextLayoutAndApply {
let spoilerTextNode = spoilerTextApply()
if strongSelf.spoilerTextNode == nil {
spoilerTextNode.alpha = 0.0
spoilerTextNode.isUserInteractionEnabled = false
spoilerTextNode.contentMode = .topLeft
spoilerTextNode.contentsScale = UIScreenScale
spoilerTextNode.displaysAsynchronously = false
strongSelf.contentTextContainer.insertSubnode(spoilerTextNode, aboveSubnode: strongSelf.textNode)
strongSelf.spoilerTextNode = spoilerTextNode
}
strongSelf.spoilerTextNode?.frame = textFrame
let dustNode: InvisibleInkDustNode
if let current = strongSelf.dustNode {
dustNode = current
} else {
dustNode = InvisibleInkDustNode(textNode: nil)
dustNode.isUserInteractionEnabled = false
dustNode = InvisibleInkDustNode(textNode: spoilerTextNode)
strongSelf.dustNode = dustNode
strongSelf.contentTextContainer.insertSubnode(dustNode, aboveSubnode: strongSelf.textNode)
strongSelf.contentTextContainer.insertSubnode(dustNode, aboveSubnode: spoilerTextNode)
}
dustNode.frame = textFrame.insetBy(dx: -3.0, dy: -3.0).offsetBy(dx: 0.0, dy: 3.0)
dustNode.update(size: dustNode.frame.size, color: theme.chat.inputPanel.secondaryTextColor, textColor: theme.chat.inputPanel.primaryTextColor, rects: textLayout.spoilers.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) }, wordRects: textLayout.spoilerWords.map { $0.1.offsetBy(dx: 3.0, dy: 3.0).insetBy(dx: 1.0, dy: 1.0) })
} else if let dustNode = strongSelf.dustNode {
dustNode.removeFromSupernode()
strongSelf.dustNode = nil
} else if let spoilerTextNode = strongSelf.spoilerTextNode {
strongSelf.spoilerTextNode = nil
spoilerTextNode.removeFromSupernode()
if let dustNode = strongSelf.dustNode {
strongSelf.dustNode = nil
dustNode.removeFromSupernode()
}
}
let lineFrame = CGRect(origin: CGPoint(x: contentLeftInset, y: 0.0), size: CGSize(width: 2.0, height: panelHeight))

View File

@ -2167,7 +2167,13 @@ private class MessageContentNode: ASDisplayNode, ContentNode {
}
}
func renderVideo(context: AccountContext, backgroundImage: UIImage, media: TelegramMediaFile, videoFrame: CGRect, completion: @escaping (URL?) -> Void) {
private enum RenderVideoResult {
case progress(Float)
case completion(URL)
case error
}
private func renderVideo(context: AccountContext, backgroundImage: UIImage, media: TelegramMediaFile, videoFrame: CGRect, completion: @escaping (URL?) -> Void) {
let _ = (fetchMediaData(context: context, postbox: context.account.postbox, mediaReference: AnyMediaReference.standalone(media: media))
|> deliverOnMainQueue).start(next: { value, isImage in
guard case let .data(data) = value, data.complete else {

View File

@ -227,7 +227,7 @@ func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedMedia: B
nativeGenerator(_1, _2, _3, nil)
})
if let parentController = parentController {
parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, text, account in
parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, text, account, silently in
return legacyAssetPickerEnqueueMessages(account: account, signals: signals!)
|> `catch` { _ -> Signal<[LegacyAssetPickerEnqueueMessage], NoError> in
return .single([])

View File

@ -5,6 +5,7 @@ import AccountContext
import TextFormat
import UIKit
import AppBundle
import TelegramStringFormatting
enum PeerInfoScreenLabeledValueTextColor {
case primary
@ -284,16 +285,23 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
self.labelNode.attributedText = NSAttributedString(string: item.label, font: Font.regular(14.0), textColor: presentationData.theme.list.itemPrimaryTextColor)
var text = item.text
let maxNumberOfLines: Int
switch item.textBehavior {
case .singleLine:
maxNumberOfLines = 1
self.textNode.maximumNumberOfLines = maxNumberOfLines
self.textNode.cutout = nil
self.textNode.maximumNumberOfLines = 1
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
case let .multiLine(maxLines, enabledEntities):
self.textNode.maximumNumberOfLines = self.isExpanded ? maxLines : 3
// self.textNode.cutout = self.isExpanded ? nil : TextNodeCutout(bottomRight: CGSize(width: expandSize.width + 4.0, height: expandSize.height))
if !self.isExpanded {
text = trimToLineCount(text, lineCount: 3)
}
maxNumberOfLines = self.isExpanded ? maxLines : 3
self.textNode.maximumNumberOfLines = maxNumberOfLines
if enabledEntities.isEmpty {
self.textNode.attributedText = NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: textColorValue)
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(17.0), textColor: textColorValue)
} else {
let fontSize: CGFloat = 17.0
@ -304,8 +312,8 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
let boldItalicFont = Font.semiboldItalic(fontSize)
let titleFixedFont = Font.monospace(fontSize)
let entities = generateTextEntities(item.text, enabledTypes: enabledEntities)
self.textNode.attributedText = stringWithAppliedEntities(item.text, entities: entities, baseColor: textColorValue, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont)
let entities = generateTextEntities(text, enabledTypes: enabledEntities)
self.textNode.attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: textColorValue, linkColor: presentationData.theme.list.itemAccentColor, baseFont: baseFont, linkFont: linkFont, boldFont: boldFont, italicFont: italicFont, boldItalicFont: boldItalicFont, fixedFont: titleFixedFont, blockQuoteFont: baseFont)
}
}
@ -328,7 +336,14 @@ private final class PeerInfoScreenLabeledValueItemNode: PeerInfoScreenItemNode {
let textLayout = self.textNode.updateLayoutInfo(CGSize(width: width - sideInset * 2.0 - additionalSideInset, height: .greatestFiniteMagnitude))
let textSize = textLayout.size
if case .multiLine = item.textBehavior, textLayout.truncated, !self.isExpanded {
var displayMore = false
if !self.isExpanded {
if textLayout.truncated || text.count < item.text.count {
displayMore = true
}
}
if case .multiLine = item.textBehavior, displayMore {
self.expandBackgroundNode.isHidden = false
self.expandNode.isHidden = false
self.expandButonNode.isHidden = false

View File

@ -7213,7 +7213,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
if accountTabBarAvatarBadge > 0 {
otherAccountsBadge = compactNumericCountString(Int(accountTabBarAvatarBadge), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator)
}
return (presentationData.strings.Settings_Title, accountTabBarAvatar?.0 ?? icon, accountTabBarAvatar?.1 ?? icon, notificationsWarning || phoneNumberWarning || passwordWarning ? "!" : otherAccountsBadge, accountTabBarAvatar != nil)
return (presentationData.strings.Settings_Title, accountTabBarAvatar?.0 ?? icon, accountTabBarAvatar?.1 ?? icon, notificationsWarning || phoneNumberWarning || passwordWarning ? "!" : otherAccountsBadge, accountTabBarAvatar != nil || presentationData.reduceMotion)
}
self.tabBarItemDisposable = (tabBarItem |> deliverOnMainQueue).start(next: { [weak self] title, image, selectedImage, badgeValue, isAvatar in

View File

@ -348,8 +348,8 @@ public class ShareRootControllerImpl {
} |> runOn(Queue.mainQueue())
}
let sentItems: ([PeerId], [PreparedShareItemContent], Account) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, contents, account in
let sentItems = sentShareItems(account: account, to: peerIds, items: contents)
let sentItems: ([PeerId], [PreparedShareItemContent], Account, Bool) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, contents, account, silently in
let sentItems = sentShareItems(account: account, to: peerIds, items: contents, silently: silently)
|> `catch` { _ -> Signal<
Float, NoError> in
return .complete()
@ -361,7 +361,7 @@ public class ShareRootControllerImpl {
|> then(.single(.done))
}
let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account in
let shareController = ShareController(context: context, subject: .fromExternal({ peerIds, additionalText, account, silently in
if let strongSelf = self, let inputItems = strongSelf.getExtensionContext()?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty {
let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)!
return preparedShareItems(account: account, to: peerIds[0], dataItems: rawSignals, additionalText: additionalText)
@ -381,10 +381,10 @@ public class ShareRootControllerImpl {
case let .userInteractionRequired(value):
return requestUserInteraction(value)
|> mapToSignal { contents -> Signal<ShareControllerExternalStatus, NoError> in
return sentItems(peerIds, contents, account)
return sentItems(peerIds, contents, account, silently)
}
case let .done(contents):
return sentItems(peerIds, contents, account)
return sentItems(peerIds, contents, account, silently)
}
}
} else {