mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-22 13:34:44 +00:00
UI improvements and API update
This commit is contained in:
parent
e55e22e074
commit
dd366395c1
@ -1274,6 +1274,18 @@ public final class ChatListNode: ListView {
|
||||
let previousActivities = Atomic<ChatListNodePeerInputActivities?>(value: nil)
|
||||
self.activityStatusesDisposable = (context.account.allPeerInputActivities()
|
||||
|> mapToSignal { activitiesByPeerId -> Signal<[EnginePeer.Id: [(EnginePeer, PeerInputActivity)]], NoError> in
|
||||
var activitiesByPeerId = activitiesByPeerId
|
||||
for key in activitiesByPeerId.keys {
|
||||
activitiesByPeerId[key]?.removeAll(where: { _, activity in
|
||||
switch activity {
|
||||
case .interactingWithEmoji:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var foundAllPeers = true
|
||||
var cachedResult: [EnginePeer.Id: [(EnginePeer, PeerInputActivity)]] = [:]
|
||||
previousPeerCache.with { dict -> Void in
|
||||
|
@ -360,7 +360,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1678949555] = { return Api.InputWebDocument.parse_inputWebDocument($0) }
|
||||
dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) }
|
||||
dict[-1036396922] = { return Api.InputWebFileLocation.parse_inputWebFileLocation($0) }
|
||||
dict[1475721060] = { return Api.Invoice.parse_invoice($0) }
|
||||
dict[1048946971] = { return Api.Invoice.parse_invoice($0) }
|
||||
dict[-1059185703] = { return Api.JSONObjectValue.parse_jsonObjectValue($0) }
|
||||
dict[-146520221] = { return Api.JSONValue.parse_jsonArray($0) }
|
||||
dict[-952869270] = { return Api.JSONValue.parse_jsonBool($0) }
|
||||
@ -918,7 +918,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
|
||||
dict[-1600596305] = { return Api.help.PassportConfig.parse_passportConfig($0) }
|
||||
dict[-1078332329] = { return Api.help.PassportConfig.parse_passportConfigNotModified($0) }
|
||||
dict[1065019118] = { return Api.help.PremiumPromo.parse_premiumPromo($0) }
|
||||
dict[-533328101] = { return Api.help.PremiumPromo.parse_premiumPromo($0) }
|
||||
dict[-1942390465] = { return Api.help.PromoData.parse_promoData($0) }
|
||||
dict[-1728664459] = { return Api.help.PromoData.parse_promoDataEmpty($0) }
|
||||
dict[235081943] = { return Api.help.RecentMeUrls.parse_recentMeUrls($0) }
|
||||
|
@ -212,13 +212,13 @@ public extension Api.help {
|
||||
}
|
||||
public extension Api.help {
|
||||
enum PremiumPromo: TypeConstructorDescription {
|
||||
case premiumPromo(statusText: String, statusEntities: [Api.MessageEntity], videoSections: [String], videos: [Api.Document])
|
||||
case premiumPromo(statusText: String, statusEntities: [Api.MessageEntity], videoSections: [String], videos: [Api.Document], currency: String, monthlyAmount: Int64)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .premiumPromo(let statusText, let statusEntities, let videoSections, let videos):
|
||||
case .premiumPromo(let statusText, let statusEntities, let videoSections, let videos, let currency, let monthlyAmount):
|
||||
if boxed {
|
||||
buffer.appendInt32(1065019118)
|
||||
buffer.appendInt32(-533328101)
|
||||
}
|
||||
serializeString(statusText, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(481674261)
|
||||
@ -236,14 +236,16 @@ public extension Api.help {
|
||||
for item in videos {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
serializeString(currency, buffer: buffer, boxed: false)
|
||||
serializeInt64(monthlyAmount, buffer: buffer, boxed: false)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .premiumPromo(let statusText, let statusEntities, let videoSections, let videos):
|
||||
return ("premiumPromo", [("statusText", String(describing: statusText)), ("statusEntities", String(describing: statusEntities)), ("videoSections", String(describing: videoSections)), ("videos", String(describing: videos))])
|
||||
case .premiumPromo(let statusText, let statusEntities, let videoSections, let videos, let currency, let monthlyAmount):
|
||||
return ("premiumPromo", [("statusText", String(describing: statusText)), ("statusEntities", String(describing: statusEntities)), ("videoSections", String(describing: videoSections)), ("videos", String(describing: videos)), ("currency", String(describing: currency)), ("monthlyAmount", String(describing: monthlyAmount))])
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,12 +264,18 @@ public extension Api.help {
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Document.self)
|
||||
}
|
||||
var _5: String?
|
||||
_5 = parseString(reader)
|
||||
var _6: Int64?
|
||||
_6 = reader.readInt64()
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 {
|
||||
return Api.help.PremiumPromo.premiumPromo(statusText: _1!, statusEntities: _2!, videoSections: _3!, videos: _4!)
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.help.PremiumPromo.premiumPromo(statusText: _1!, statusEntities: _2!, videoSections: _3!, videos: _4!, currency: _5!, monthlyAmount: _6!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -6350,13 +6350,13 @@ public extension Api.functions.payments {
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func requestRecurrentPayment(userId: Int64, recurrentInitCharge: String, invoiceMedia: Api.InputMedia) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
static func requestRecurringPayment(userId: Api.InputUser, recurringInitCharge: String, invoiceMedia: Api.InputMedia) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1329030023)
|
||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||
serializeString(recurrentInitCharge, buffer: buffer, boxed: false)
|
||||
buffer.appendInt32(342791565)
|
||||
userId.serialize(buffer, true)
|
||||
serializeString(recurringInitCharge, buffer: buffer, boxed: false)
|
||||
invoiceMedia.serialize(buffer, true)
|
||||
return (FunctionDescription(name: "payments.requestRecurrentPayment", parameters: [("userId", String(describing: userId)), ("recurrentInitCharge", String(describing: recurrentInitCharge)), ("invoiceMedia", String(describing: invoiceMedia))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
return (FunctionDescription(name: "payments.requestRecurringPayment", parameters: [("userId", String(describing: userId)), ("recurringInitCharge", String(describing: recurringInitCharge)), ("invoiceMedia", String(describing: invoiceMedia))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Updates?
|
||||
if let signature = reader.readInt32() {
|
||||
|
@ -898,13 +898,13 @@ public extension Api {
|
||||
}
|
||||
public extension Api {
|
||||
enum Invoice: TypeConstructorDescription {
|
||||
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], maxTipAmount: Int64?, suggestedTipAmounts: [Int64]?, recurrentTermsUrl: String?)
|
||||
case invoice(flags: Int32, currency: String, prices: [Api.LabeledPrice], maxTipAmount: Int64?, suggestedTipAmounts: [Int64]?, recurringTermsUrl: String?)
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurrentTermsUrl):
|
||||
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurringTermsUrl):
|
||||
if boxed {
|
||||
buffer.appendInt32(1475721060)
|
||||
buffer.appendInt32(1048946971)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeString(currency, buffer: buffer, boxed: false)
|
||||
@ -919,15 +919,15 @@ public extension Api {
|
||||
for item in suggestedTipAmounts! {
|
||||
serializeInt64(item, buffer: buffer, boxed: false)
|
||||
}}
|
||||
if Int(flags) & Int(1 << 9) != 0 {serializeString(recurrentTermsUrl!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 9) != 0 {serializeString(recurringTermsUrl!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurrentTermsUrl):
|
||||
return ("invoice", [("flags", String(describing: flags)), ("currency", String(describing: currency)), ("prices", String(describing: prices)), ("maxTipAmount", String(describing: maxTipAmount)), ("suggestedTipAmounts", String(describing: suggestedTipAmounts)), ("recurrentTermsUrl", String(describing: recurrentTermsUrl))])
|
||||
case .invoice(let flags, let currency, let prices, let maxTipAmount, let suggestedTipAmounts, let recurringTermsUrl):
|
||||
return ("invoice", [("flags", String(describing: flags)), ("currency", String(describing: currency)), ("prices", String(describing: prices)), ("maxTipAmount", String(describing: maxTipAmount)), ("suggestedTipAmounts", String(describing: suggestedTipAmounts)), ("recurringTermsUrl", String(describing: recurringTermsUrl))])
|
||||
}
|
||||
}
|
||||
|
||||
@ -955,7 +955,7 @@ public extension Api {
|
||||
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 9) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!, maxTipAmount: _4, suggestedTipAmounts: _5, recurrentTermsUrl: _6)
|
||||
return Api.Invoice.invoice(flags: _1!, currency: _2!, prices: _3!, maxTipAmount: _4, suggestedTipAmounts: _5, recurringTermsUrl: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -54,7 +54,7 @@ private func updatePremiumPromoConfiguration(transaction: Transaction, _ f: (Pre
|
||||
private extension PremiumPromoConfiguration {
|
||||
init(apiPremiumPromo: Api.help.PremiumPromo) {
|
||||
switch apiPremiumPromo {
|
||||
case let .premiumPromo(statusText, statusEntities, videoSections, videoFiles):
|
||||
case let .premiumPromo(statusText, statusEntities, videoSections, videoFiles, _, _):
|
||||
self.status = statusText
|
||||
self.statusEntities = messageTextEntitiesFromApiEntities(statusEntities)
|
||||
|
||||
|
@ -41,9 +41,10 @@ public final class AudioTranscriptionButtonComponent: Component {
|
||||
private var component: AudioTranscriptionButtonComponent?
|
||||
|
||||
private let backgroundLayer: SimpleLayer
|
||||
private var inProgressLayer: SimpleShapeLayer?
|
||||
private let animationView: ComponentHostView<Empty>
|
||||
|
||||
private var progressAnimationView: ComponentHostView<Empty>?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundLayer = SimpleLayer()
|
||||
self.animationView = ComponentHostView<Empty>()
|
||||
@ -76,53 +77,20 @@ public final class AudioTranscriptionButtonComponent: Component {
|
||||
if self.component?.transcriptionState != component.transcriptionState {
|
||||
switch component.transcriptionState {
|
||||
case .inProgress:
|
||||
if self.inProgressLayer == nil {
|
||||
let inProgressLayer = SimpleShapeLayer()
|
||||
inProgressLayer.isOpaque = false
|
||||
inProgressLayer.backgroundColor = nil
|
||||
inProgressLayer.fillColor = nil
|
||||
inProgressLayer.lineCap = .round
|
||||
inProgressLayer.lineWidth = 1.0
|
||||
|
||||
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(), size: CGSize(width: 30.0, height: 30.0)), cornerRadius: 9.0).cgPath
|
||||
inProgressLayer.path = path
|
||||
|
||||
self.inProgressLayer = inProgressLayer
|
||||
|
||||
inProgressLayer.didEnterHierarchy = { [weak inProgressLayer] in
|
||||
guard let inProgressLayer = inProgressLayer else {
|
||||
return
|
||||
}
|
||||
let endAnimation = CABasicAnimation(keyPath: "strokeEnd")
|
||||
endAnimation.fromValue = CGFloat(0.0) as NSNumber
|
||||
endAnimation.toValue = CGFloat(1.0) as NSNumber
|
||||
endAnimation.duration = 1.25
|
||||
endAnimation.timingFunction = CAMediaTimingFunction(name: .easeOut)
|
||||
endAnimation.fillMode = .forwards
|
||||
endAnimation.repeatCount = .infinity
|
||||
inProgressLayer.add(endAnimation, forKey: "strokeEnd")
|
||||
|
||||
let startAnimation = CABasicAnimation(keyPath: "strokeStart")
|
||||
startAnimation.fromValue = CGFloat(0.0) as NSNumber
|
||||
startAnimation.toValue = CGFloat(1.0) as NSNumber
|
||||
startAnimation.duration = 1.25
|
||||
startAnimation.timingFunction = CAMediaTimingFunction(name: .easeIn)
|
||||
startAnimation.fillMode = .forwards
|
||||
startAnimation.repeatCount = .infinity
|
||||
inProgressLayer.add(startAnimation, forKey: "strokeStart")
|
||||
}
|
||||
|
||||
self.layer.addSublayer(inProgressLayer)
|
||||
if self.progressAnimationView == nil {
|
||||
let progressAnimationView = ComponentHostView<Empty>()
|
||||
self.progressAnimationView = progressAnimationView
|
||||
self.addSubview(progressAnimationView)
|
||||
}
|
||||
default:
|
||||
if let inProgressLayer = self.inProgressLayer {
|
||||
self.inProgressLayer = nil
|
||||
if let progressAnimationView = self.progressAnimationView {
|
||||
self.progressAnimationView = nil
|
||||
if case .none = transition.animation {
|
||||
inProgressLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak inProgressLayer] _ in
|
||||
inProgressLayer?.removeFromSuperlayer()
|
||||
progressAnimationView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak progressAnimationView] _ in
|
||||
progressAnimationView?.removeFromSuperview()
|
||||
})
|
||||
} else {
|
||||
inProgressLayer.removeFromSuperlayer()
|
||||
progressAnimationView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -162,13 +130,29 @@ public final class AudioTranscriptionButtonComponent: Component {
|
||||
}
|
||||
|
||||
self.backgroundLayer.backgroundColor = component.theme.bubble.withWallpaper.reactionInactiveBackground.cgColor
|
||||
self.inProgressLayer?.strokeColor = foregroundColor.cgColor
|
||||
|
||||
self.component = component
|
||||
|
||||
self.backgroundLayer.frame = CGRect(origin: CGPoint(), size: size)
|
||||
if let inProgressLayer = self.inProgressLayer {
|
||||
inProgressLayer.frame = CGRect(origin: CGPoint(), size: size)
|
||||
if let progressAnimationView = self.progressAnimationView {
|
||||
let progressFrame = CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0)
|
||||
let _ = progressAnimationView.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(LottieAnimationComponent(
|
||||
animation: LottieAnimationComponent.Animation(
|
||||
name: "voicets_progress",
|
||||
colors: [
|
||||
"Rectangle 60.Rectangle 60.Stroke 1": foregroundColor
|
||||
],
|
||||
mode: .animating(loop: true)
|
||||
),
|
||||
size: progressFrame.size
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: progressFrame.size
|
||||
)
|
||||
|
||||
progressAnimationView.frame = progressFrame
|
||||
}
|
||||
|
||||
return CGSize(width: min(availableSize.width, size.width), height: min(availableSize.height, size.height))
|
||||
|
@ -0,0 +1 @@
|
||||
{"v":"5.8.1","fr":60,"ip":0,"op":120,"w":320,"h":320,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Rectangle 60","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":270,"ix":10},"p":{"a":0,"k":[160,160,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[-100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.863,-1.693],[0,-5.04],[0,0],[-0.981,-1.925],[-1.693,-0.863],[-5.04,0],[0,0],[-1.925,0.981],[-0.863,1.693],[0,5.04],[0,0],[0.981,1.925],[1.693,0.863],[5.04,0],[0,0],[1.925,-0.981]],"o":[[-0.981,1.925],[0,0],[0,5.04],[0.863,1.693],[1.925,0.981],[0,0],[5.04,0],[1.693,-0.863],[0.981,-1.925],[0,0],[0,-5.04],[-0.863,-1.693],[-1.925,-0.981],[0,0],[-5.04,0],[-1.693,0.863]],"v":[[-14.019,-10.086],[-15,-0.6],[-15,0.6],[-14.019,10.086],[-10.086,14.019],[-0.6,15],[0.6,15],[10.086,14.019],[14.019,10.086],[15,0.6],[15,-0.6],[14.019,-10.086],[10.086,-14.019],[0.6,-15],[-0.6,-15],[-10.086,-14.019]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0,0,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1.33,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[1000,1000],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 60","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":59,"s":[95]},{"t":119,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":59,"s":[25]},{"t":119,"s":[99]}],"ix":2},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[30]},{"t":119,"s":[389]}],"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]}
|
@ -155,7 +155,7 @@ public func generateChatInputTextEntities(_ text: NSAttributedString, maxAnimate
|
||||
if !emoji.isEmpty && emoji.isSingleEmoji {
|
||||
let mappedRange = NSRange(substringRange, in: text.string)
|
||||
|
||||
entities.append(MessageTextEntity(range: mappedRange.lowerBound ..< mappedRange.upperBound, type: .AnimatedEmoji))
|
||||
entities.append(MessageTextEntity(range: mappedRange.lowerBound ..< mappedRange.upperBound, type: .AnimatedEmoji(nil)))
|
||||
|
||||
count += 1
|
||||
if count >= maxAnimatedEmojisInText {
|
||||
|
Loading…
x
Reference in New Issue
Block a user