mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Web app improvements
This commit is contained in:
parent
c0bb57c850
commit
7f7cb498bb
@ -30,6 +30,7 @@ swift_library(
|
||||
"//submodules/ContextUI:ContextUI",
|
||||
"//submodules/ManagedAnimationNode:ManagedAnimationNode",
|
||||
"//submodules/PhotoResources:PhotoResources",
|
||||
"//submodules/MediaResources:MediaResources",
|
||||
"//submodules/SemanticStatusNode:SemanticStatusNode",
|
||||
"//submodules/Components/AnimatedStickerComponent:AnimatedStickerComponent",
|
||||
],
|
||||
|
@ -15,6 +15,7 @@ import ChatTextLinkEditUI
|
||||
import PhotoResources
|
||||
import AnimatedStickerComponent
|
||||
import SemanticStatusNode
|
||||
import MediaResources
|
||||
|
||||
private let buttonSize = CGSize(width: 88.0, height: 49.0)
|
||||
private let smallButtonWidth: CGFloat = 69.0
|
||||
@ -79,7 +80,7 @@ private final class IconComponent: Component {
|
||||
self.image = nil
|
||||
}
|
||||
|
||||
self.disposable = (svgIconImageFile(account: component.account, fileReference: fileReference, fetched: true)
|
||||
self.disposable = (svgIconImageFile(account: component.account, fileReference: fileReference)
|
||||
|> runOn(Queue.concurrentDefaultQueue())
|
||||
|> deliverOnMainQueue).start(next: { [weak self] transform in
|
||||
let arguments = TransformImageArguments(corners: ImageCorners(), imageSize: availableSize, boundingSize: availableSize, intrinsicInsets: UIEdgeInsets())
|
||||
@ -809,7 +810,27 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
|
||||
for (name, file) in iconFiles {
|
||||
if [.default, .iOSAnimated, .placeholder].contains(name) {
|
||||
if self.iconDisposables[file.fileId] == nil, let peer = PeerReference(peer) {
|
||||
self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start()
|
||||
if case .placeholder = name {
|
||||
let account = self.context.account
|
||||
let path = account.postbox.mediaBox.cachedRepresentationCompletePath(file.resource.id, representation: CachedPreparedSvgRepresentation())
|
||||
if !FileManager.default.fileExists(atPath: path) {
|
||||
let accountFullSizeData = Signal<(Data?, Bool), NoError> { subscriber in
|
||||
let accountResource = account.postbox.mediaBox.cachedResourceRepresentation(file.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true)
|
||||
|
||||
let fetchedFullSize = fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: .media(media: .attachBot(peer: peer, media: file), resource: file.resource))
|
||||
let fetchedFullSizeDisposable = fetchedFullSize.start()
|
||||
let fullSizeDisposable = accountResource.start()
|
||||
|
||||
return ActionDisposable {
|
||||
fetchedFullSizeDisposable.dispose()
|
||||
fullSizeDisposable.dispose()
|
||||
}
|
||||
}
|
||||
self.iconDisposables[file.fileId] = accountFullSizeData.start()
|
||||
}
|
||||
} else {
|
||||
self.iconDisposables[file.fileId] = freeMediaFileInteractiveFetched(account: self.context.account, fileReference: .attachBot(peer: peer, media: file)).start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -344,3 +344,23 @@ public final class CachedPreparedPatternWallpaperRepresentation: CachedMediaReso
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final class CachedPreparedSvgRepresentation: CachedMediaResourceRepresentation {
|
||||
public let keepDuration: CachedMediaRepresentationKeepDuration = .general
|
||||
|
||||
public var uniqueId: String {
|
||||
return "prepared-svg"
|
||||
}
|
||||
|
||||
public init() {
|
||||
}
|
||||
|
||||
public func isEqual(to: CachedMediaResourceRepresentation) -> Bool {
|
||||
if to is CachedPreparedSvgRepresentation {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2283,13 +2283,14 @@ public func instantPageImageFile(account: Account, fileReference: FileMediaRefer
|
||||
}
|
||||
}
|
||||
|
||||
public func svgIconImageFile(account: Account, fileReference: FileMediaReference, stickToTop: Bool = false, fetched: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
return chatMessageFileDatas(account: account, fileReference: fileReference, progressive: false, fetched: false)
|
||||
public func svgIconImageFile(account: Account, fileReference: FileMediaReference, stickToTop: Bool = false) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
|
||||
let data = account.postbox.mediaBox.cachedResourceRepresentation(fileReference.media.resource, representation: CachedPreparedSvgRepresentation(), complete: false, fetch: true)
|
||||
|
||||
return data
|
||||
|> map { value in
|
||||
let fullSizePath = value._1
|
||||
let fullSizeComplete = value._2
|
||||
let fullSizePath = value.path
|
||||
let fullSizeComplete = value.complete
|
||||
return { arguments in
|
||||
// assertNotOnMainThread()
|
||||
let context = DrawingContext(size: arguments.drawingSize, clear: true)
|
||||
|
||||
let drawingRect = arguments.drawingRect
|
||||
@ -2298,12 +2299,12 @@ public func svgIconImageFile(account: Account, fileReference: FileMediaReference
|
||||
var fullSizeImage: UIImage?
|
||||
let imageOrientation: UIImage.Orientation = .up
|
||||
|
||||
if let fullSizePath = fullSizePath {
|
||||
if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) {
|
||||
fullSizeImage = drawSvgImage(data, stickToTop ? CGSize.zero : CGSize(width: 90.0, height: 90.0), .clear, .black, false)
|
||||
if let image = fullSizeImage {
|
||||
fittedSize = image.size.aspectFitted(arguments.boundingSize)
|
||||
}
|
||||
if fullSizeComplete, let data = try? Data(contentsOf: URL(fileURLWithPath: fullSizePath)) {
|
||||
fullSizeImage = renderPreparedImage(data, CGSize.zero, .clear, UIScreenScale)
|
||||
|
||||
// fullSizeImage = drawSvgImage(data, stickToTop ? CGSize.zero : CGSize(width: 90.0, height: 90.0), .clear, .black, false)
|
||||
if let image = fullSizeImage {
|
||||
fittedSize = image.size.aspectFitted(arguments.boundingSize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NSData * _Nullable prepareSvgImage(NSData * _Nonnull data);
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size);
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor * _Nonnull backgroundColor, CGFloat scale);
|
||||
|
||||
UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor * _Nullable backgroundColor, UIColor * _Nullable foregroundColor, bool opaque);
|
||||
|
||||
|
@ -358,11 +358,11 @@ UIImage * _Nullable drawSvgImage(NSData * _Nonnull data, CGSize size, UIColor *b
|
||||
|
||||
@end
|
||||
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size) {
|
||||
UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size, UIColor *backgroundColor, CGFloat scale) {
|
||||
NSDate *startTime = [NSDate date];
|
||||
|
||||
UIColor *foregroundColor = [UIColor whiteColor];
|
||||
UIColor *backgroundColor = [UIColor blackColor];
|
||||
|
||||
|
||||
int32_t ptr = 0;
|
||||
int32_t width;
|
||||
@ -377,17 +377,27 @@ UIImage * _Nullable renderPreparedImage(NSData * _Nonnull data, CGSize size) {
|
||||
[data getBytes:&height range:NSMakeRange(ptr, sizeof(height))];
|
||||
ptr += sizeof(height);
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, true, 1.0);
|
||||
if (CGSizeEqualToSize(size, CGSizeZero)) {
|
||||
size = CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
bool isTransparent = [backgroundColor isEqual:[UIColor clearColor]];
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, !isTransparent, scale);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
if (isTransparent) {
|
||||
CGContextClearRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
} else {
|
||||
CGContextSetFillColorWithColor(context, backgroundColor.CGColor);
|
||||
CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height));
|
||||
}
|
||||
|
||||
CGSize svgSize = CGSizeMake(width, height);
|
||||
CGSize drawingSize = aspectFillSize(svgSize, size);
|
||||
|
||||
CGFloat scale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height));
|
||||
CGFloat renderScale = MAX(size.width / MAX(1.0, svgSize.width), size.height / MAX(1.0, svgSize.height));
|
||||
|
||||
CGContextScaleCTM(context, scale, scale);
|
||||
CGContextScaleCTM(context, renderScale, renderScale);
|
||||
CGContextTranslateCTM(context, (size.width - drawingSize.width) / 2.0, (size.height - drawingSize.height) / 2.0);
|
||||
|
||||
while (ptr < data.length) {
|
||||
|
@ -279,6 +279,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
private var bankCardDisposable: MetaDisposable?
|
||||
private var hasActiveGroupCallDisposable: Disposable?
|
||||
private var sendAsPeersDisposable: Disposable?
|
||||
private let preloadAttachBotIconsDisposables = DisposableSet()
|
||||
|
||||
private let editingMessage = ValuePromise<Float?>(nil, ignoreRepeated: true)
|
||||
private let startingBot = ValuePromise<Bool>(false, ignoreRepeated: true)
|
||||
@ -4828,6 +4829,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.nextChannelToReadDisposable?.dispose()
|
||||
self.inviteRequestsDisposable.dispose()
|
||||
self.sendAsPeersDisposable?.dispose()
|
||||
self.preloadAttachBotIconsDisposables.dispose()
|
||||
}
|
||||
|
||||
public func updatePresentationMode(_ mode: ChatControllerPresentationMode) {
|
||||
@ -9053,6 +9055,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}).start())
|
||||
}
|
||||
}
|
||||
|
||||
self.preloadAttachBotIcons()
|
||||
}
|
||||
|
||||
if let _ = self.focusOnSearchAfterAppearance {
|
||||
@ -15711,6 +15715,23 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func preloadAttachBotIcons() {
|
||||
let _ = (self.context.engine.messages.attachMenuBots()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] bots in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
for bot in bots {
|
||||
for (name, file) in bot.icons {
|
||||
if [.iOSAnimated].contains(name), let peer = PeerReference(bot.peer) {
|
||||
strongSelf.preloadAttachBotIconsDisposables.add(freeMediaFileInteractiveFetched(account: strongSelf.context.account, fileReference: .attachBot(peer: peer, media: file)).start())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {
|
||||
|
@ -137,6 +137,14 @@ public func fetchCachedResourceRepresentation(account: Account, resource: MediaR
|
||||
}
|
||||
return fetchPreparedPatternWallpaperRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
} else if let representation = representation as? CachedPreparedSvgRepresentation {
|
||||
return account.postbox.mediaBox.resourceData(resource, option: .complete(waitUntilFetchStatus: false))
|
||||
|> mapToSignal { data -> Signal<CachedMediaResourceRepresentationResult, NoError> in
|
||||
if !data.complete {
|
||||
return .complete()
|
||||
}
|
||||
return fetchPreparedSvgRepresentation(resource: resource, resourceData: data, representation: representation)
|
||||
}
|
||||
}
|
||||
return .never()
|
||||
}
|
||||
@ -755,3 +763,18 @@ private func fetchPreparedPatternWallpaperRepresentation(resource: MediaResource
|
||||
return EmptyDisposable
|
||||
}) |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
||||
private func fetchPreparedSvgRepresentation(resource: MediaResource, resourceData: MediaResourceData, representation: CachedPreparedSvgRepresentation) -> Signal<CachedMediaResourceRepresentationResult, NoError> {
|
||||
return Signal({ subscriber in
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: resourceData.path), options: [.mappedIfSafe]) {
|
||||
if let data = prepareSvgImage(data) {
|
||||
let path = NSTemporaryDirectory() + "\(Int64.random(in: Int64.min ... Int64.max))"
|
||||
let url = URL(fileURLWithPath: path)
|
||||
let _ = try? data.write(to: url)
|
||||
subscriber.putNext(.temporaryPath(path))
|
||||
subscriber.putCompletion()
|
||||
}
|
||||
}
|
||||
return EmptyDisposable
|
||||
}) |> runOn(Queue.concurrentDefaultQueue())
|
||||
}
|
||||
|
@ -337,6 +337,11 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
|
||||
if state.textExpanded {
|
||||
if let fromLanguage = state.fromLanguage, state.availableSpeakLanguages.contains(fromLanguage) {
|
||||
var checkColor = theme.list.itemCheckColors.foregroundColor
|
||||
if checkColor.rgb == theme.list.itemPrimaryTextColor.rgb {
|
||||
checkColor = theme.list.plainBackgroundColor
|
||||
}
|
||||
|
||||
let originalSpeakButton = originalSpeakButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(ZStack([
|
||||
@ -346,7 +351,7 @@ private final class TranslateScreenComponent: CombinedComponent {
|
||||
))),
|
||||
AnyComponentWithIdentity(id: "a", component: AnyComponent(PlayPauseIconComponent(
|
||||
state: state.isSpeakingOriginalText ? .pause : .play,
|
||||
tintColor: theme.list.itemCheckColors.foregroundColor,
|
||||
tintColor: checkColor,
|
||||
size: CGSize(width: 18.0, height: 18.0)
|
||||
))),
|
||||
])),
|
||||
|
@ -531,7 +531,7 @@ private func patternWallpaperImageInternal(fullSizeData: Data?, fullSizeComplete
|
||||
var image: UIImage?
|
||||
if let fullSizeData = fullSizeData {
|
||||
if mode == .screen {
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale))
|
||||
image = renderPreparedImage(fullSizeData, CGSize(width: size.width * context.scale, height: size.height * context.scale), .black, 1.0)
|
||||
} else {
|
||||
image = UIImage(data: fullSizeData)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user