mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit 'fe49c781343bb09f09f2eb1e8351fbbd6e6ae334'
This commit is contained in:
commit
e8cf06d3be
@ -1,6 +1,6 @@
|
|||||||
#import <FFMpegBinding/FFMpegAVCodec.h>
|
#import <FFMpegBinding/FFMpegAVCodec.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavcodec/avcodec.h>
|
#import "libavcodec/avcodec.h"
|
||||||
|
|
||||||
@interface FFMpegAVCodec () {
|
@interface FFMpegAVCodec () {
|
||||||
AVCodec const *_impl;
|
AVCodec const *_impl;
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
#import <FFMpegBinding/FFMpegAVFrame.h>
|
#import <FFMpegBinding/FFMpegAVFrame.h>
|
||||||
#import <FFMpegBinding/FFMpegAVCodec.h>
|
#import <FFMpegBinding/FFMpegAVCodec.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
#import <third_party/ffmpeg/libavcodec/avcodec.h>
|
#import "libavcodec/avcodec.h"
|
||||||
|
|
||||||
static enum AVPixelFormat getPreferredPixelFormat(__unused AVCodecContext *ctx, __unused const enum AVPixelFormat *pix_fmts) {
|
static enum AVPixelFormat getPreferredPixelFormat(__unused AVCodecContext *ctx, __unused const enum AVPixelFormat *pix_fmts) {
|
||||||
return AV_PIX_FMT_VIDEOTOOLBOX;
|
return AV_PIX_FMT_VIDEOTOOLBOX;
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#import <FFMpegBinding/FFMpegPacket.h>
|
#import <FFMpegBinding/FFMpegPacket.h>
|
||||||
#import <FFMpegBinding/FFMpegAVCodecContext.h>
|
#import <FFMpegBinding/FFMpegAVCodecContext.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavcodec/avcodec.h>
|
#import "libavcodec/avcodec.h"
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
int FFMpegCodecIdH264 = AV_CODEC_ID_H264;
|
int FFMpegCodecIdH264 = AV_CODEC_ID_H264;
|
||||||
int FFMpegCodecIdHEVC = AV_CODEC_ID_HEVC;
|
int FFMpegCodecIdHEVC = AV_CODEC_ID_HEVC;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#import <FFMpegBinding/FFMpegAVFrame.h>
|
#import <FFMpegBinding/FFMpegAVFrame.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
@interface FFMpegAVFrame () {
|
@interface FFMpegAVFrame () {
|
||||||
AVFrame *_impl;
|
AVFrame *_impl;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
int FFMPEG_CONSTANT_AVERROR_EOF = AVERROR_EOF;
|
int FFMPEG_CONSTANT_AVERROR_EOF = AVERROR_EOF;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#import <FFMpegBinding/FFMpegGlobals.h>
|
#import <FFMpegBinding/FFMpegGlobals.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
@implementation FFMpegGlobals
|
@implementation FFMpegGlobals
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
#import <FFMpegBinding/FFMpegLiveMuxer.h>
|
#import <FFMpegBinding/FFMpegLiveMuxer.h>
|
||||||
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
||||||
|
|
||||||
#include <third_party/ffmpeg/libavutil/timestamp.h>
|
#include "libavutil/timestamp.h"
|
||||||
#include <third_party/ffmpeg/libavformat/avformat.h>
|
#include "libavformat/avformat.h"
|
||||||
#include <third_party/ffmpeg/libavcodec/avcodec.h>
|
#include "libavcodec/avcodec.h"
|
||||||
#include <third_party/ffmpeg/libswresample/swresample.h>
|
#include "libswresample/swresample.h"
|
||||||
|
|
||||||
#define MOV_TIMESCALE 1000
|
#define MOV_TIMESCALE 1000
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#import <FFMpegBinding/FFMpegAVCodecContext.h>
|
#import <FFMpegBinding/FFMpegAVCodecContext.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavcodec/avcodec.h>
|
#import "libavcodec/avcodec.h"
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
|
|
||||||
@interface FFMpegPacket () {
|
@interface FFMpegPacket () {
|
||||||
AVPacket *_impl;
|
AVPacket *_impl;
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
#import <FFMpegBinding/FFMpegAVIOContext.h>
|
||||||
|
|
||||||
#include <third_party/ffmpeg/libavutil/timestamp.h>
|
#include "libavutil/timestamp.h"
|
||||||
#include <third_party/ffmpeg/libavformat/avformat.h>
|
#include "libavformat/avformat.h"
|
||||||
#include <third_party/ffmpeg/libavcodec/avcodec.h>
|
#include "libavcodec/avcodec.h"
|
||||||
|
|
||||||
#define MOV_TIMESCALE 1000
|
#define MOV_TIMESCALE 1000
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
#import <FFMpegBinding/FFMpegAVFrame.h>
|
#import <FFMpegBinding/FFMpegAVFrame.h>
|
||||||
|
|
||||||
#import <third_party/ffmpeg/libavformat/avformat.h>
|
#import "libavformat/avformat.h"
|
||||||
#import <third_party/ffmpeg/libavcodec/avcodec.h>
|
#import "libavcodec/avcodec.h"
|
||||||
#import <third_party/ffmpeg/libswresample/swresample.h>
|
#import "libswresample/swresample.h"
|
||||||
|
|
||||||
@interface FFMpegSWResample () {
|
@interface FFMpegSWResample () {
|
||||||
int _sourceSampleRate;
|
int _sourceSampleRate;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
#import <FFMpegBinding/FFMpegVideoWriter.h>
|
#import <FFMpegBinding/FFMpegVideoWriter.h>
|
||||||
#import <FFMpegBinding/FFMpegAVFrame.h>
|
#import <FFMpegBinding/FFMpegAVFrame.h>
|
||||||
|
|
||||||
#include <third_party/ffmpeg/libavformat/avformat.h>
|
#include "libavformat/avformat.h"
|
||||||
#include <third_party/ffmpeg/libavcodec/avcodec.h>
|
#include "libavcodec/avcodec.h"
|
||||||
#include <third_party/ffmpeg/libavutil/imgutils.h>
|
#include "libavutil/imgutils.h"
|
||||||
|
|
||||||
@interface FFMpegVideoWriter ()
|
@interface FFMpegVideoWriter ()
|
||||||
|
|
||||||
|
@ -53,6 +53,19 @@ private func chatInputStateString(attributedString: NSAttributedString) -> NSAtt
|
|||||||
}
|
}
|
||||||
if let value = attributes[.font], let font = value as? UIFont {
|
if let value = attributes[.font], let font = value as? UIFont {
|
||||||
let fontName = font.fontName.lowercased()
|
let fontName = font.fontName.lowercased()
|
||||||
|
if fontName.hasPrefix(".sfui") {
|
||||||
|
let traits = font.fontDescriptor.symbolicTraits
|
||||||
|
if traits.contains(.traitMonoSpace) {
|
||||||
|
string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range)
|
||||||
|
} else {
|
||||||
|
if traits.contains(.traitBold) {
|
||||||
|
string.addAttribute(ChatTextInputAttributes.bold, value: true as NSNumber, range: range)
|
||||||
|
}
|
||||||
|
if traits.contains(.traitItalic) {
|
||||||
|
string.addAttribute(ChatTextInputAttributes.italic, value: true as NSNumber, range: range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if fontName.contains("bolditalic") {
|
if fontName.contains("bolditalic") {
|
||||||
string.addAttribute(ChatTextInputAttributes.bold, value: true as NSNumber, range: range)
|
string.addAttribute(ChatTextInputAttributes.bold, value: true as NSNumber, range: range)
|
||||||
string.addAttribute(ChatTextInputAttributes.italic, value: true as NSNumber, range: range)
|
string.addAttribute(ChatTextInputAttributes.italic, value: true as NSNumber, range: range)
|
||||||
@ -64,6 +77,7 @@ private func chatInputStateString(attributedString: NSAttributedString) -> NSAtt
|
|||||||
string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range)
|
string.addAttribute(ChatTextInputAttributes.monospace, value: true as NSNumber, range: range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if let value = attributes[.backgroundColor] as? UIColor, value.rgb == UIColor.gray.rgb {
|
if let value = attributes[.backgroundColor] as? UIColor, value.rgb == UIColor.gray.rgb {
|
||||||
string.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: range)
|
string.addAttribute(ChatTextInputAttributes.spoiler, value: true as NSNumber, range: range)
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,7 @@ swift_library(
|
|||||||
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
"//submodules/MediaPlayer:UniversalMediaPlayer",
|
||||||
"//submodules/TelegramVoip:TelegramVoip",
|
"//submodules/TelegramVoip:TelegramVoip",
|
||||||
"//submodules/DeviceAccess:DeviceAccess",
|
"//submodules/DeviceAccess:DeviceAccess",
|
||||||
|
"//submodules/Utils/DeviceModel",
|
||||||
"//submodules/WatchCommon/Host:WatchCommon",
|
"//submodules/WatchCommon/Host:WatchCommon",
|
||||||
"//submodules/BuildConfig:BuildConfig",
|
"//submodules/BuildConfig:BuildConfig",
|
||||||
"//submodules/BuildConfigExtra:BuildConfigExtra",
|
"//submodules/BuildConfigExtra:BuildConfigExtra",
|
||||||
|
@ -295,10 +295,6 @@ public func canAddMessageReactions(message: Message) -> Bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let story = media as? TelegramMediaStory {
|
|
||||||
if story.isMention {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -559,7 +559,7 @@ public final class GiftItemComponent: Component {
|
|||||||
let price: String
|
let price: String
|
||||||
switch component.subject {
|
switch component.subject {
|
||||||
case let .premium(_, priceValue), let .starGift(_, priceValue):
|
case let .premium(_, priceValue), let .starGift(_, priceValue):
|
||||||
if priceValue.containsEmoji {
|
if priceValue.contains("#") {
|
||||||
buttonColor = component.theme.overallDarkAppearance ? UIColor(rgb: 0xffc337) : UIColor(rgb: 0xd3720a)
|
buttonColor = component.theme.overallDarkAppearance ? UIColor(rgb: 0xffc337) : UIColor(rgb: 0xd3720a)
|
||||||
if !component.isSoldOut {
|
if !component.isSoldOut {
|
||||||
starsColor = UIColor(rgb: 0xffbe27)
|
starsColor = UIColor(rgb: 0xffbe27)
|
||||||
@ -867,10 +867,12 @@ public final class GiftItemComponent: Component {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
let dateTimeFormat = component.context.sharedContext.currentPresentationData.with { $0 }.dateTimeFormat
|
let dateTimeFormat = component.context.sharedContext.currentPresentationData.with { $0 }.dateTimeFormat
|
||||||
let labelText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("#\(presentationStringsFormattedNumber(Int32(resellPrice), dateTimeFormat.groupingSeparator))", attributes: attributes))
|
let labelText = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString("# \(presentationStringsFormattedNumber(Int32(resellPrice), dateTimeFormat.groupingSeparator))", attributes: attributes))
|
||||||
if let range = labelText.string.range(of: "#") {
|
let range = (labelText.string as NSString).range(of: "#")
|
||||||
labelText.addAttribute(NSAttributedString.Key.font, value: Font.semibold(10.0), range: NSRange(range, in: labelText.string))
|
if range.location != NSNotFound {
|
||||||
labelText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: true)), range: NSRange(range, in: labelText.string))
|
labelText.addAttribute(NSAttributedString.Key.font, value: Font.semibold(10.0), range: range)
|
||||||
|
labelText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: true)), range: range)
|
||||||
|
labelText.addAttribute(.kern, value: -1.5, range: NSRange(location: range.upperBound, length: 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
let resellSize = self.reselLabel.update(
|
let resellSize = self.reselLabel.update(
|
||||||
@ -1048,11 +1050,13 @@ private final class ButtonContentComponent: Component {
|
|||||||
self.componentState = state
|
self.componentState = state
|
||||||
|
|
||||||
let attributedText = NSMutableAttributedString(string: component.text, font: Font.semibold(11.0), textColor: component.color)
|
let attributedText = NSMutableAttributedString(string: component.text, font: Font.semibold(11.0), textColor: component.color)
|
||||||
let range = (attributedText.string as NSString).range(of: "⭐️")
|
let range = (attributedText.string as NSString).range(of: "#")
|
||||||
if range.location != NSNotFound {
|
if range.location != NSNotFound {
|
||||||
attributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: component.tinted)), range: range)
|
attributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: component.tinted)), range: range)
|
||||||
attributedText.addAttribute(.font, value: Font.semibold(15.0), range: range)
|
attributedText.addAttribute(.font, value: Font.semibold(component.tinted ? 14.0 : 15.0), range: range)
|
||||||
attributedText.addAttribute(.baselineOffset, value: 2.0, range: NSRange(location: range.upperBound, length: attributedText.length - range.upperBound))
|
attributedText.addAttribute(.baselineOffset, value: -3.0, range: range)
|
||||||
|
attributedText.addAttribute(.baselineOffset, value: 1.5, range: NSRange(location: range.upperBound + 1, length: attributedText.length - range.upperBound - 1))
|
||||||
|
attributedText.addAttribute(.kern, value: -1.5, range: NSRange(location: range.upperBound, length: 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleSize = self.title.update(
|
let titleSize = self.title.update(
|
||||||
|
@ -412,12 +412,12 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
if let availability = gift.availability, availability.remains == 0, let minResaleStars = availability.minResaleStars {
|
if let availability = gift.availability, availability.remains == 0, let minResaleStars = availability.minResaleStars {
|
||||||
let priceString = presentationStringsFormattedNumber(Int32(minResaleStars), environment.dateTimeFormat.groupingSeparator)
|
let priceString = presentationStringsFormattedNumber(Int32(minResaleStars), environment.dateTimeFormat.groupingSeparator)
|
||||||
if let resaleConfiguration = self.resaleConfiguration, minResaleStars == resaleConfiguration.starGiftResaleMaxAmount || availability.resale == 1 {
|
if let resaleConfiguration = self.resaleConfiguration, minResaleStars == resaleConfiguration.starGiftResaleMaxAmount || availability.resale == 1 {
|
||||||
subject = .starGift(gift: gift, price: "⭐️ \(priceString)")
|
subject = .starGift(gift: gift, price: "# \(priceString)")
|
||||||
} else {
|
} else {
|
||||||
subject = .starGift(gift: gift, price: "⭐️ \(priceString)+")
|
subject = .starGift(gift: gift, price: "# \(priceString)+")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
subject = .starGift(gift: gift, price: "⭐️ \(presentationStringsFormattedNumber(Int32(gift.price), environment.dateTimeFormat.groupingSeparator))")
|
subject = .starGift(gift: gift, price: "# \(presentationStringsFormattedNumber(Int32(gift.price), environment.dateTimeFormat.groupingSeparator))")
|
||||||
}
|
}
|
||||||
case let .unique(gift):
|
case let .unique(gift):
|
||||||
subject = .uniqueGift(gift: gift, price: nil)
|
subject = .uniqueGift(gift: gift, price: nil)
|
||||||
@ -1567,6 +1567,9 @@ final class GiftOptionsScreenComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if disallowedGifts.contains(.unique) && gift.availability?.remains == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ final class GiftStoreScreenComponent: Component {
|
|||||||
color: ribbonColor
|
color: ribbonColor
|
||||||
)
|
)
|
||||||
|
|
||||||
let subject: GiftItemComponent.Subject = .uniqueGift(gift: uniqueGift, price: "⭐️\(presentationStringsFormattedNumber(Int32(uniqueGift.resellStars ?? 0), environment.dateTimeFormat.groupingSeparator))")
|
let subject: GiftItemComponent.Subject = .uniqueGift(gift: uniqueGift, price: "# \(presentationStringsFormattedNumber(Int32(uniqueGift.resellStars ?? 0), environment.dateTimeFormat.groupingSeparator))")
|
||||||
let _ = visibleItem.update(
|
let _ = visibleItem.update(
|
||||||
transition: itemTransition,
|
transition: itemTransition,
|
||||||
component: AnyComponent(
|
component: AnyComponent(
|
||||||
|
@ -309,6 +309,16 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
let context = self.context
|
let context = self.context
|
||||||
let action = {
|
let action = {
|
||||||
if gifts {
|
if gifts {
|
||||||
|
let profileGifts = ProfileGiftsContext(account: context.account, peerId: peer.id)
|
||||||
|
let _ = (profileGifts.state
|
||||||
|
|> filter { state in
|
||||||
|
if case .ready = state.dataState {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak navigationController] _ in
|
||||||
if let profileController = context.sharedContext.makePeerInfoController(
|
if let profileController = context.sharedContext.makePeerInfoController(
|
||||||
context: context,
|
context: context,
|
||||||
updatedPresentationData: nil,
|
updatedPresentationData: nil,
|
||||||
@ -318,8 +328,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||||||
fromChat: false,
|
fromChat: false,
|
||||||
requestsContext: nil
|
requestsContext: nil
|
||||||
) {
|
) {
|
||||||
navigationController.pushViewController(profileController)
|
navigationController?.pushViewController(profileController)
|
||||||
}
|
}
|
||||||
|
let _ = profileGifts
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||||
navigationController: navigationController,
|
navigationController: navigationController,
|
||||||
|
@ -230,7 +230,7 @@ public enum MediaCropOrientation: Int32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class MediaEditorValues: Codable, Equatable {
|
public final class MediaEditorValues: Codable, Equatable, CustomStringConvertible {
|
||||||
public static func == (lhs: MediaEditorValues, rhs: MediaEditorValues) -> Bool {
|
public static func == (lhs: MediaEditorValues, rhs: MediaEditorValues) -> Bool {
|
||||||
if lhs.peerId != rhs.peerId {
|
if lhs.peerId != rhs.peerId {
|
||||||
return false
|
return false
|
||||||
@ -1010,6 +1010,114 @@ public final class MediaEditorValues: Codable, Equatable {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var description: String {
|
||||||
|
var components: [String] = []
|
||||||
|
|
||||||
|
components.append("originalDimensions: \(self.originalDimensions.width)x\(self.originalDimensions.height)")
|
||||||
|
|
||||||
|
if self.cropOffset != .zero {
|
||||||
|
components.append("cropOffset: \(cropOffset)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let cropRect = self.cropRect {
|
||||||
|
components.append("cropRect: \(cropRect)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.cropScale != 1.0 {
|
||||||
|
components.append("cropScale: \(self.cropScale)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.cropRotation != 0.0 {
|
||||||
|
components.append("cropRotation: \(self.cropRotation)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.cropMirroring {
|
||||||
|
components.append("cropMirroring: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let cropOrientation = self.cropOrientation {
|
||||||
|
components.append("cropOrientation: \(cropOrientation)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let gradientColors = self.gradientColors, !gradientColors.isEmpty {
|
||||||
|
components.append("gradientColors: \(gradientColors.count) colors")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let videoTrimRange = self.videoTrimRange {
|
||||||
|
components.append("videoTrimRange: \(videoTrimRange.lowerBound) - \(videoTrimRange.upperBound)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.videoIsMuted {
|
||||||
|
components.append("videoIsMuted: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.videoIsFullHd {
|
||||||
|
components.append("videoIsFullHd: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.videoIsMirrored {
|
||||||
|
components.append("videoIsMirrored: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let videoVolume = self.videoVolume, videoVolume != 1.0 {
|
||||||
|
components.append("videoVolume: \(videoVolume)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let additionalVideoPath = self.additionalVideoPath {
|
||||||
|
components.append("additionalVideo: \(additionalVideoPath)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let position = self.additionalVideoPosition {
|
||||||
|
components.append("additionalVideoPosition: \(position)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let scale = self.additionalVideoScale {
|
||||||
|
components.append("additionalVideoScale: \(scale)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rotation = self.additionalVideoRotation {
|
||||||
|
components.append("additionalVideoRotation: \(rotation)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.additionalVideoPositionChanges.isEmpty {
|
||||||
|
components.append("additionalVideoPositionChanges: \(additionalVideoPositionChanges.count) changes")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.collage.isEmpty {
|
||||||
|
components.append("collage: \(collage.count) items")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.nightTheme {
|
||||||
|
components.append("nightTheme: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.drawing != nil {
|
||||||
|
components.append("drawing: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.maskDrawing != nil {
|
||||||
|
components.append("maskDrawing: true")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.entities.isEmpty {
|
||||||
|
components.append("entities: \(self.entities.count) items")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.toolValues.isEmpty {
|
||||||
|
components.append("toolValues: \(self.toolValues.count) tools")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let audioTrack = self.audioTrack {
|
||||||
|
components.append("audioTrack: \(audioTrack.path)")
|
||||||
|
}
|
||||||
|
|
||||||
|
if let qualityPreset = self.qualityPreset {
|
||||||
|
components.append("qualityPreset: \(qualityPreset)")
|
||||||
|
}
|
||||||
|
|
||||||
|
return "MediaEditorValues(\(components.joined(separator: ", ")))"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct TintValue: Equatable, Codable {
|
public struct TintValue: Equatable, Codable {
|
||||||
|
@ -264,6 +264,11 @@ public final class MediaEditorVideoExport {
|
|||||||
self.outputPath = outputPath
|
self.outputPath = outputPath
|
||||||
self.textScale = textScale
|
self.textScale = textScale
|
||||||
|
|
||||||
|
Logger.shared.log("VideoExport", "Init")
|
||||||
|
Logger.shared.log("VideoExport", "Subject: \(subject)")
|
||||||
|
Logger.shared.log("VideoExport", "Output Path: \(outputPath)")
|
||||||
|
Logger.shared.log("VideoExport", "Configuration: \(configuration)")
|
||||||
|
|
||||||
if FileManager.default.fileExists(atPath: outputPath) {
|
if FileManager.default.fileExists(atPath: outputPath) {
|
||||||
try? FileManager.default.removeItem(atPath: outputPath)
|
try? FileManager.default.removeItem(atPath: outputPath)
|
||||||
}
|
}
|
||||||
@ -297,6 +302,9 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setup() {
|
private func setup() {
|
||||||
|
Logger.shared.log("VideoExport", "Setting up")
|
||||||
|
|
||||||
|
|
||||||
var mainAsset: AVAsset?
|
var mainAsset: AVAsset?
|
||||||
|
|
||||||
var signals: [Signal<Input, NoError>] = []
|
var signals: [Signal<Input, NoError>] = []
|
||||||
@ -948,11 +956,6 @@ public final class MediaEditorVideoExport {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// if !writer.appendVideoBuffer(sampleBuffer) {
|
|
||||||
// writer.markVideoAsFinished()
|
|
||||||
// return false
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -983,17 +986,21 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func start() {
|
private func start() {
|
||||||
|
Logger.shared.log("VideoExport", "Start")
|
||||||
guard self.internalStatus == .idle, let writer = self.writer else {
|
guard self.internalStatus == .idle, let writer = self.writer else {
|
||||||
|
Logger.shared.log("VideoExport", "Failed with invalid state")
|
||||||
self.statusValue = .failed(.invalid)
|
self.statusValue = .failed(.invalid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard writer.startWriting() else {
|
guard writer.startWriting() else {
|
||||||
|
Logger.shared.log("VideoExport", "Failed on startWriting")
|
||||||
self.statusValue = .failed(.writing(nil))
|
self.statusValue = .failed(.writing(nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if let reader = self.reader, !reader.startReading() {
|
if let reader = self.reader, !reader.startReading() {
|
||||||
|
Logger.shared.log("VideoExport", "Failed on startReading")
|
||||||
self.statusValue = .failed(.reading(nil))
|
self.statusValue = .failed(.reading(nil))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -1067,6 +1074,7 @@ public final class MediaEditorVideoExport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cancelled {
|
if cancelled {
|
||||||
|
Logger.shared.log("VideoExport", "Cancelled")
|
||||||
try? FileManager.default.removeItem(at: outputUrl)
|
try? FileManager.default.removeItem(at: outputUrl)
|
||||||
self.internalStatus = .finished
|
self.internalStatus = .finished
|
||||||
self.statusValue = .failed(.cancelled)
|
self.statusValue = .failed(.cancelled)
|
||||||
@ -1108,6 +1116,7 @@ public final class MediaEditorVideoExport {
|
|||||||
let exportDuration = end - self.startTimestamp
|
let exportDuration = end - self.startTimestamp
|
||||||
print("video processing took \(exportDuration)s")
|
print("video processing took \(exportDuration)s")
|
||||||
if duration.seconds > 0 {
|
if duration.seconds > 0 {
|
||||||
|
Logger.shared.log("VideoExport", "Completed with path \(self.outputPath)")
|
||||||
Logger.shared.log("VideoExport", "Video processing took \(exportDuration / duration.seconds)")
|
Logger.shared.log("VideoExport", "Video processing took \(exportDuration / duration.seconds)")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -184,7 +184,9 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var scheduledAnimateIn = false
|
||||||
public func willAnimateIn() {
|
public func willAnimateIn() {
|
||||||
|
self.scheduledAnimateIn = true
|
||||||
for (_, layer) in self.iconLayers {
|
for (_, layer) in self.iconLayers {
|
||||||
layer.opacity = 0.0
|
layer.opacity = 0.0
|
||||||
}
|
}
|
||||||
@ -194,6 +196,7 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
guard let _ = self.currentSize, let component = self.component else {
|
guard let _ = self.currentSize, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
self.scheduledAnimateIn = false
|
||||||
|
|
||||||
for (_, layer) in self.iconLayers {
|
for (_, layer) in self.iconLayers {
|
||||||
layer.opacity = 1.0
|
layer.opacity = 1.0
|
||||||
@ -319,8 +322,12 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
self.iconLayers[id] = iconLayer
|
self.iconLayers[id] = iconLayer
|
||||||
self.layer.addSublayer(iconLayer)
|
self.layer.addSublayer(iconLayer)
|
||||||
|
|
||||||
|
if self.scheduledAnimateIn {
|
||||||
|
iconLayer.opacity = 0.0
|
||||||
|
} else {
|
||||||
iconLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
iconLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
iconLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
|
iconLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
|
||||||
|
}
|
||||||
|
|
||||||
iconLayer.startAnimations(index: index)
|
iconLayer.startAnimations(index: index)
|
||||||
}
|
}
|
||||||
@ -349,7 +356,10 @@ public final class PeerInfoGiftsCoverComponent: Component {
|
|||||||
iconTransition.setPosition(layer: iconLayer, position: absolutePosition)
|
iconTransition.setPosition(layer: iconLayer, position: absolutePosition)
|
||||||
iconLayer.updateRotation(effectiveAngle, transition: iconTransition)
|
iconLayer.updateRotation(effectiveAngle, transition: iconTransition)
|
||||||
iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction))
|
iconTransition.setScale(layer: iconLayer, scale: iconPosition.scale * (1.0 - itemScaleFraction))
|
||||||
|
|
||||||
|
if !self.scheduledAnimateIn {
|
||||||
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
|
iconTransition.setAlpha(layer: iconLayer, alpha: 1.0 - itemScaleFraction)
|
||||||
|
}
|
||||||
|
|
||||||
index += 1
|
index += 1
|
||||||
}
|
}
|
||||||
|
@ -488,7 +488,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
|
|
||||||
switch product.gift {
|
switch product.gift {
|
||||||
case let .generic(gift):
|
case let .generic(gift):
|
||||||
subject = .starGift(gift: gift, price: "⭐️ \(gift.price)")
|
subject = .starGift(gift: gift, price: "# \(gift.price)")
|
||||||
peer = product.fromPeer.flatMap { .peer($0) } ?? .anonymous
|
peer = product.fromPeer.flatMap { .peer($0) } ?? .anonymous
|
||||||
|
|
||||||
if let availability = gift.availability {
|
if let availability = gift.availability {
|
||||||
|
@ -117,6 +117,8 @@ public final class TabSelectorComponent: Component {
|
|||||||
private let selectionView: UIImageView
|
private let selectionView: UIImageView
|
||||||
private var visibleItems: [AnyHashable: VisibleItem] = [:]
|
private var visibleItems: [AnyHashable: VisibleItem] = [:]
|
||||||
|
|
||||||
|
private var didInitiallyScroll = false
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
override init(frame: CGRect) {
|
||||||
self.selectionView = UIImageView()
|
self.selectionView = UIImageView()
|
||||||
|
|
||||||
@ -238,11 +240,15 @@ public final class TabSelectorComponent: Component {
|
|||||||
)),
|
)),
|
||||||
effectAlignment: .center,
|
effectAlignment: .center,
|
||||||
minSize: nil,
|
minSize: nil,
|
||||||
action: { [weak self] in
|
action: { [weak self, weak itemView] in
|
||||||
guard let self, let component = self.component else {
|
guard let self, let component = self.component else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
component.setSelectedId(itemId)
|
component.setSelectedId(itemId)
|
||||||
|
|
||||||
|
if let view = itemView?.title.view, allowScroll && self.contentSize.width > self.bounds.width {
|
||||||
|
self.scrollRectToVisible(view.frame.insetBy(dx: -64.0, dy: 0.0), animated: true)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
animateScale: !isLineSelection
|
animateScale: !isLineSelection
|
||||||
)),
|
)),
|
||||||
@ -336,11 +342,15 @@ public final class TabSelectorComponent: Component {
|
|||||||
self.selectionView.alpha = 0.0
|
self.selectionView.alpha = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
self.contentSize = CGSize(width: contentWidth, height: baseHeight + verticalInset * 2.0)
|
let contentSize = CGSize(width: contentWidth, height: baseHeight + verticalInset * 2.0)
|
||||||
|
if self.contentSize != contentSize {
|
||||||
|
self.contentSize = contentSize
|
||||||
|
}
|
||||||
self.disablesInteractiveTransitionGestureRecognizer = contentWidth > availableSize.width
|
self.disablesInteractiveTransitionGestureRecognizer = contentWidth > availableSize.width
|
||||||
|
|
||||||
if let selectedBackgroundRect, self.bounds.width > 0.0 {
|
if let selectedBackgroundRect, self.bounds.width > 0.0 && !self.didInitiallyScroll {
|
||||||
self.scrollRectToVisible(selectedBackgroundRect.insetBy(dx: -spacing, dy: 0.0), animated: false)
|
self.scrollRectToVisible(selectedBackgroundRect.insetBy(dx: -spacing, dy: 0.0), animated: false)
|
||||||
|
self.didInitiallyScroll = true
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGSize(width: min(contentWidth, availableSize.width), height: baseHeight + verticalInset * 2.0)
|
return CGSize(width: min(contentWidth, availableSize.width), height: baseHeight + verticalInset * 2.0)
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"images" : [
|
|
||||||
{
|
|
||||||
"filename" : "ic_qrcode.pdf",
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
@ -1,4 +1,5 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
import UniformTypeIdentifiers
|
||||||
import UIKit
|
import UIKit
|
||||||
import Display
|
import Display
|
||||||
import AsyncDisplayKit
|
import AsyncDisplayKit
|
||||||
@ -44,6 +45,7 @@ import TelegramNotices
|
|||||||
import AnimatedCountLabelNode
|
import AnimatedCountLabelNode
|
||||||
import TelegramStringFormatting
|
import TelegramStringFormatting
|
||||||
import TextNodeWithEntities
|
import TextNodeWithEntities
|
||||||
|
import DeviceModel
|
||||||
|
|
||||||
private let accessoryButtonFont = Font.medium(14.0)
|
private let accessoryButtonFont = Font.medium(14.0)
|
||||||
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
|
private let counterFont = Font.with(size: 14.0, design: .regular, traits: [.monospacedNumbers])
|
||||||
@ -4473,11 +4475,15 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
var attributedString: NSAttributedString?
|
var attributedString: NSAttributedString?
|
||||||
if let data = pasteboard.data(forPasteboardType: "private.telegramtext"), let value = chatInputStateStringFromAppSpecificString(data: data) {
|
if let data = pasteboard.data(forPasteboardType: "private.telegramtext"), let value = chatInputStateStringFromAppSpecificString(data: data) {
|
||||||
attributedString = value
|
attributedString = value
|
||||||
} else if let data = pasteboard.data(forPasteboardType: kUTTypeRTF as String) {
|
} else if let data = pasteboard.data(forPasteboardType: "public.rtf") {
|
||||||
attributedString = chatInputStateStringFromRTF(data, type: NSAttributedString.DocumentType.rtf)
|
attributedString = chatInputStateStringFromRTF(data, type: NSAttributedString.DocumentType.rtf)
|
||||||
} else if let data = pasteboard.data(forPasteboardType: "com.apple.flat-rtfd") {
|
} else if let data = pasteboard.data(forPasteboardType: "com.apple.flat-rtfd") {
|
||||||
|
if let _ = pasteboard.data(forPasteboardType: "com.apple.notes.richtext"), DeviceModel.current.isIpad, let htmlData = pasteboard.data(forPasteboardType: "public.html") {
|
||||||
|
attributedString = chatInputStateStringFromRTF(htmlData, type: NSAttributedString.DocumentType.html)
|
||||||
|
} else {
|
||||||
attributedString = chatInputStateStringFromRTF(data, type: NSAttributedString.DocumentType.rtfd)
|
attributedString = chatInputStateStringFromRTF(data, type: NSAttributedString.DocumentType.rtfd)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let attributedString = attributedString {
|
if let attributedString = attributedString {
|
||||||
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
self.interfaceInteraction?.updateTextInputStateAndMode { current, inputMode in
|
||||||
|
@ -76,10 +76,14 @@ public struct ChatTranslationState: Codable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func cachedChatTranslationState(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?) -> Signal<ChatTranslationState?, NoError> {
|
private func cachedChatTranslationState(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?) -> Signal<ChatTranslationState?, NoError> {
|
||||||
let key = EngineDataBuffer(length: 8)
|
let key: EngineDataBuffer
|
||||||
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
|
||||||
if let threadId {
|
if let threadId {
|
||||||
|
key = EngineDataBuffer(length: 16)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
key.setInt64(8, value: threadId)
|
key.setInt64(8, value: threadId)
|
||||||
|
} else {
|
||||||
|
key = EngineDataBuffer(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
return engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.translationState, id: key))
|
return engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.translationState, id: key))
|
||||||
@ -89,10 +93,14 @@ private func cachedChatTranslationState(engine: TelegramEngine, peerId: EnginePe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateChatTranslationState(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?, state: ChatTranslationState?) -> Signal<Never, NoError> {
|
private func updateChatTranslationState(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?, state: ChatTranslationState?) -> Signal<Never, NoError> {
|
||||||
let key = EngineDataBuffer(length: 8)
|
let key: EngineDataBuffer
|
||||||
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
|
||||||
if let threadId {
|
if let threadId {
|
||||||
|
key = EngineDataBuffer(length: 16)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
key.setInt64(8, value: threadId)
|
key.setInt64(8, value: threadId)
|
||||||
|
} else {
|
||||||
|
key = EngineDataBuffer(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
if let state {
|
if let state {
|
||||||
@ -103,10 +111,14 @@ private func updateChatTranslationState(engine: TelegramEngine, peerId: EnginePe
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func updateChatTranslationStateInteractively(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?, _ f: @escaping (ChatTranslationState?) -> ChatTranslationState?) -> Signal<Never, NoError> {
|
public func updateChatTranslationStateInteractively(engine: TelegramEngine, peerId: EnginePeer.Id, threadId: Int64?, _ f: @escaping (ChatTranslationState?) -> ChatTranslationState?) -> Signal<Never, NoError> {
|
||||||
let key = EngineDataBuffer(length: 8)
|
let key: EngineDataBuffer
|
||||||
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
|
||||||
if let threadId {
|
if let threadId {
|
||||||
|
key = EngineDataBuffer(length: 16)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
key.setInt64(8, value: threadId)
|
key.setInt64(8, value: threadId)
|
||||||
|
} else {
|
||||||
|
key = EngineDataBuffer(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.id._internalGetInt64Value())
|
||||||
}
|
}
|
||||||
|
|
||||||
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.translationState, id: key))
|
return engine.data.get(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: ApplicationSpecificItemCacheCollectionId.translationState, id: key))
|
||||||
|
@ -828,7 +828,11 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let webView = self.webView {
|
if let webView = self.webView {
|
||||||
var scrollInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0)
|
let inputHeight = self.validLayout?.0.inputHeight ?? 0.0
|
||||||
|
|
||||||
|
let intrinsicBottomInset = layout.intrinsicInsets.bottom > 40.0 ? layout.intrinsicInsets.bottom : 0.0
|
||||||
|
|
||||||
|
var scrollInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: max(inputHeight, intrinsicBottomInset), right: 0.0)
|
||||||
var frameBottomInset: CGFloat = 0.0
|
var frameBottomInset: CGFloat = 0.0
|
||||||
if scrollInset.bottom > 40.0 {
|
if scrollInset.bottom > 40.0 {
|
||||||
frameBottomInset = scrollInset.bottom
|
frameBottomInset = scrollInset.bottom
|
||||||
@ -842,11 +846,11 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
self.updateWebViewWhenStable = true
|
self.updateWebViewWhenStable = true
|
||||||
}
|
}
|
||||||
|
|
||||||
var bottomInset = layout.intrinsicInsets.bottom + layout.additionalInsets.bottom
|
var viewportBottomInset = max(frameBottomInset, scrollInset.bottom)
|
||||||
if let inputHeight = self.validLayout?.0.inputHeight, inputHeight > 44.0 {
|
if (self.validLayout?.0.inputHeight ?? 0.0) < 44.0 {
|
||||||
bottomInset = max(bottomInset, inputHeight)
|
viewportBottomInset += layout.additionalInsets.bottom
|
||||||
}
|
}
|
||||||
let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: topInset), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - topInset - bottomInset)))
|
let viewportFrame = CGRect(origin: CGPoint(x: layout.safeInsets.left, y: topInset), size: CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right, height: max(1.0, layout.size.height - topInset - viewportBottomInset)))
|
||||||
|
|
||||||
if webView.scrollView.contentInset != scrollInset {
|
if webView.scrollView.contentInset != scrollInset {
|
||||||
webView.scrollView.contentInset = scrollInset
|
webView.scrollView.contentInset = scrollInset
|
||||||
@ -1061,6 +1065,10 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||||||
} else {
|
} else {
|
||||||
self.lastExpansionTimestamp = currentTimestamp
|
self.lastExpansionTimestamp = currentTimestamp
|
||||||
controller.requestAttachmentMenuExpansion()
|
controller.requestAttachmentMenuExpansion()
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.4) {
|
||||||
|
self.webView?.setNeedsLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case "web_app_close":
|
case "web_app_close":
|
||||||
controller.dismiss()
|
controller.dismiss()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user