This commit is contained in:
Isaac 2026-02-12 17:58:56 +04:00
commit 955d69472c
21 changed files with 180 additions and 87 deletions

View file

@ -1244,7 +1244,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-484987010] = { return Api.Updates.parse_updatesTooLong($0) }
dict[1648005024] = { return Api.UrlAuthResult.parse_urlAuthResultAccepted($0) }
dict[-1445536993] = { return Api.UrlAuthResult.parse_urlAuthResultDefault($0) }
dict[855293722] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
dict[-948574935] = { return Api.UrlAuthResult.parse_urlAuthResultRequest($0) }
dict[829899656] = { return Api.User.parse_user($0) }
dict[-742634630] = { return Api.User.parse_userEmpty($0) }
dict[-1607745218] = { return Api.UserFull.parse_userFull($0) }

View file

@ -556,7 +556,8 @@ public extension Api {
public var platform: String?
public var ip: String?
public var region: String?
public init(flags: Int32, bot: Api.User, domain: String, browser: String?, platform: String?, ip: String?, region: String?) {
public var matchCodes: [String]?
public init(flags: Int32, bot: Api.User, domain: String, browser: String?, platform: String?, ip: String?, region: String?, matchCodes: [String]?) {
self.flags = flags
self.bot = bot
self.domain = domain
@ -564,6 +565,7 @@ public extension Api {
self.platform = platform
self.ip = ip
self.region = region
self.matchCodes = matchCodes
}
}
case urlAuthResultAccepted(Cons_urlAuthResultAccepted)
@ -588,7 +590,7 @@ public extension Api {
break
case .urlAuthResultRequest(let _data):
if boxed {
buffer.appendInt32(855293722)
buffer.appendInt32(-948574935)
}
serializeInt32(_data.flags, buffer: buffer, boxed: false)
_data.bot.serialize(buffer, true)
@ -605,6 +607,13 @@ public extension Api {
if Int(_data.flags) & Int(1 << 2) != 0 {
serializeString(_data.region!, buffer: buffer, boxed: false)
}
if Int(_data.flags) & Int(1 << 3) != 0 {
buffer.appendInt32(481674261)
buffer.appendInt32(Int32(_data.matchCodes!.count))
for item in _data.matchCodes! {
serializeString(item, buffer: buffer, boxed: false)
}
}
break
}
}
@ -616,7 +625,7 @@ public extension Api {
case .urlAuthResultDefault:
return ("urlAuthResultDefault", [])
case .urlAuthResultRequest(let _data):
return ("urlAuthResultRequest", [("flags", _data.flags as Any), ("bot", _data.bot as Any), ("domain", _data.domain as Any), ("browser", _data.browser as Any), ("platform", _data.platform as Any), ("ip", _data.ip as Any), ("region", _data.region as Any)])
return ("urlAuthResultRequest", [("flags", _data.flags as Any), ("bot", _data.bot as Any), ("domain", _data.domain as Any), ("browser", _data.browser as Any), ("platform", _data.platform as Any), ("ip", _data.ip as Any), ("region", _data.region as Any), ("matchCodes", _data.matchCodes as Any)])
}
}
@ -664,6 +673,12 @@ public extension Api {
if Int(_1!) & Int(1 << 2) != 0 {
_7 = parseString(reader)
}
var _8: [String]?
if Int(_1!) & Int(1 << 3) != 0 {
if let _ = reader.readInt32() {
_8 = Api.parseVector(reader, elementSignature: -1255641564, elementType: String.self)
}
}
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
@ -671,8 +686,9 @@ public extension Api {
let _c5 = (Int(_1!) & Int(1 << 2) == 0) || _5 != nil
let _c6 = (Int(_1!) & Int(1 << 2) == 0) || _6 != nil
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
return Api.UrlAuthResult.urlAuthResultRequest(Cons_urlAuthResultRequest(flags: _1!, bot: _2!, domain: _3!, browser: _4, platform: _5, ip: _6, region: _7))
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
return Api.UrlAuthResult.urlAuthResultRequest(Cons_urlAuthResultRequest(flags: _1!, bot: _2!, domain: _3!, browser: _4, platform: _5, ip: _6, region: _7, matchCodes: _8))
}
else {
return nil

View file

@ -5192,9 +5192,9 @@ public extension Api.functions.messages {
}
}
public extension Api.functions.messages {
static func acceptUrlAuth(flags: Int32, peer: Api.InputPeer?, msgId: Int32?, buttonId: Int32?, url: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.UrlAuthResult>) {
static func acceptUrlAuth(flags: Int32, peer: Api.InputPeer?, msgId: Int32?, buttonId: Int32?, url: String?, matchCode: String?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.UrlAuthResult>) {
let buffer = Buffer()
buffer.appendInt32(-1322487515)
buffer.appendInt32(1738797278)
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {
peer!.serialize(buffer, true)
@ -5208,7 +5208,10 @@ public extension Api.functions.messages {
if Int(flags) & Int(1 << 2) != 0 {
serializeString(url!, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "messages.acceptUrlAuth", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("buttonId", String(describing: buttonId)), ("url", String(describing: url))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UrlAuthResult? in
if Int(flags) & Int(1 << 4) != 0 {
serializeString(matchCode!, buffer: buffer, boxed: false)
}
return (FunctionDescription(name: "messages.acceptUrlAuth", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("buttonId", String(describing: buttonId)), ("url", String(describing: url)), ("matchCode", String(describing: matchCode))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.UrlAuthResult? in
let reader = BufferReader(buffer)
var result: Api.UrlAuthResult?
if let signature = reader.readInt32() {
@ -9460,22 +9463,6 @@ public extension Api.functions.messages {
})
}
}
public extension Api.functions.messages {
static func toggleChatCustomRanks(peer: Api.InputPeer, enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
let buffer = Buffer()
buffer.appendInt32(874013158)
peer.serialize(buffer, true)
enabled.serialize(buffer, true)
return (FunctionDescription(name: "messages.toggleChatCustomRanks", parameters: [("peer", String(describing: peer)), ("enabled", String(describing: enabled))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in
let reader = BufferReader(buffer)
var result: Api.Updates?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Updates
}
return result
})
}
}
public extension Api.functions.messages {
static func toggleDialogFilterTags(enabled: Api.Bool) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
let buffer = Buffer()

View file

@ -59,9 +59,6 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
if (flags & Int32(1 << 25)) != 0 {
groupFlags.insert(.copyProtectionEnabled)
}
if (flags & Int32(1 << 19)) != 0 {
groupFlags.insert(.customRanksEnabled)
}
return TelegramGroup(id: PeerId(namespace: Namespaces.Peer.CloudGroup, id: PeerId.Id._internalFromInt64Value(id)), title: title, photo: imageRepresentationsForApiChatPhoto(photo), participantCount: Int(participantsCount), role: role, membership: left ? .Left : .Member, flags: groupFlags, defaultBannedRights: defaultBannedRights.flatMap(TelegramChatBannedRights.init(apiBannedRights:)), migrationReference: migrationReference, creationDate: date, version: Int(version))
case let .chatEmpty(chatEmptyData):
let id = chatEmptyData.id
@ -152,9 +149,6 @@ func parseTelegramGroupOrChannel(chat: Api.Chat) -> Peer? {
if (flags2 & Int32(1 << 19)) != 0 {
channelFlags.insert(.displayForumAsTabs)
}
if (flags2 & Int32(1 << 20)) != 0 {
channelFlags.insert(.customRanksEnabled)
}
var storiesHidden: Bool?
if flags2 & (1 << 2) == 0 { // stories_hidden_min
if flags2 & (1 << 1) != 0 {

View file

@ -809,7 +809,7 @@ func messageTextEntitiesFromApiEntities(_ entities: [Api.MessageEntity]) -> [Mes
} else {
dateFormat = nil
}
format = .full(timeFormat: timeFormat, dateFormat: dateFormat)
format = .full(timeFormat: timeFormat, dateFormat: dateFormat, dayOfWeek: (flags & (1 << 5)) != 0)
}
result.append(MessageTextEntity(range: Int(offset) ..< Int(offset + length), type: .FormattedDate(format: format, date: date)))
}

View file

@ -21,6 +21,8 @@ public enum TelegramChannelPermission {
case editStories
case deleteStories
case manageDirect
case editRank
case manageRanks
}
public extension TelegramChannel {
@ -261,6 +263,23 @@ public extension TelegramChannel {
} else {
return false
}
case .editRank:
if let adminRights = self.adminRights, adminRights.rights.contains(.canManageRanks) {
return true
}
if let bannedRights = self.bannedRights, bannedRights.flags.contains(.banEditRank) {
return false
}
if let defaultBannedRights = self.defaultBannedRights, defaultBannedRights.flags.contains(.banEditRank) {
return false
}
return true
case .manageRanks:
if let adminRights = self.adminRights {
return adminRights.rights.contains(.canManageRanks)
} else {
return false
}
}
}

View file

@ -59,7 +59,7 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa
switch format {
case .relative:
flags |= 1 << 0
case let .full(timeFormat, dateFormat):
case let .full(timeFormat, dateFormat, dayOfWeek):
switch timeFormat {
case .short:
flags |= 1 << 1
@ -76,6 +76,9 @@ func apiEntitiesFromMessageTextEntities(_ entities: [MessageTextEntity], associa
default:
break
}
if dayOfWeek {
flags |= 1 << 5
}
default:
break
}

View file

@ -73,6 +73,17 @@ public enum GroupParticipant: PostboxCoding, Equatable {
}
}
public var rank: String? {
switch self {
case let .admin(_, _, _, rank):
return rank
case let .member(_, _, _, rank):
return rank
case let .creator(_, rank):
return rank
}
}
func withUpdated(rank: String?) -> GroupParticipant {
switch self {
case let .member(id, invitedBy, invitedAt, _):

View file

@ -185,7 +185,6 @@ public struct TelegramChannelFlags: OptionSet {
public static let autoTranslateEnabled = TelegramChannelFlags(rawValue: 1 << 12)
public static let isMonoforum = TelegramChannelFlags(rawValue: 1 << 13)
public static let displayForumAsTabs = TelegramChannelFlags(rawValue: 1 << 14)
public static let customRanksEnabled = TelegramChannelFlags(rawValue: 1 << 15)
}
public final class TelegramChannel: Peer, Equatable {

View file

@ -28,9 +28,10 @@ public struct TelegramChatAdminRightsFlags: OptionSet, Hashable {
public static let canEditStories = TelegramChatAdminRightsFlags(rawValue: 1 << 15)
public static let canDeleteStories = TelegramChatAdminRightsFlags(rawValue: 1 << 16)
public static let canManageDirect = TelegramChatAdminRightsFlags(rawValue: 1 << 17)
public static let canManageRanks = TelegramChatAdminRightsFlags(rawValue: 1 << 18)
public static var all: TelegramChatAdminRightsFlags {
return [.canChangeInfo, .canPostMessages, .canEditMessages, .canDeleteMessages, .canBanUsers, .canInviteUsers, .canPinMessages, .canAddAdmins, .canBeAnonymous, .canManageCalls, .canManageTopics, .canPostStories, .canEditStories, .canDeleteStories]
return [.canChangeInfo, .canPostMessages, .canEditMessages, .canDeleteMessages, .canBanUsers, .canInviteUsers, .canPinMessages, .canAddAdmins, .canBeAnonymous, .canManageCalls, .canManageTopics, .canPostStories, .canEditStories, .canDeleteStories, .canManageRanks]
}
public static var allChannel: TelegramChatAdminRightsFlags {
@ -48,7 +49,8 @@ public struct TelegramChatAdminRightsFlags: OptionSet, Hashable {
.canAddAdmins,
.canPostStories,
.canEditStories,
.canDeleteStories
.canDeleteStories,
.canManageRanks
]
public static let internal_broadcastSpecific: TelegramChatAdminRightsFlags = [

View file

@ -32,6 +32,7 @@ public struct TelegramChatBannedRightsFlags: OptionSet, Hashable {
public static let banSendVoice = TelegramChatBannedRightsFlags(rawValue: 1 << 23)
public static let banSendFiles = TelegramChatBannedRightsFlags(rawValue: 1 << 24)
public static let banSendText = TelegramChatBannedRightsFlags(rawValue: 1 << 25)
public static let banEditRank = TelegramChatBannedRightsFlags(rawValue: 1 << 26)
}
public struct TelegramChatBannedRights: PostboxCoding, Equatable {

View file

@ -16,7 +16,7 @@ public enum MessageTextEntityType: Equatable {
}
case relative
case full(timeFormat: TimeFormat?, dateFormat: DateFormat?)
case full(timeFormat: TimeFormat?, dateFormat: DateFormat?, dayOfWeek: Bool)
public init(rawValue: Int32) {
if (rawValue & (1 << 0)) != 0 {
@ -38,7 +38,7 @@ public enum MessageTextEntityType: Equatable {
} else {
dateFormat = nil
}
self = .full(timeFormat: timeFormat, dateFormat: dateFormat)
self = .full(timeFormat: timeFormat, dateFormat: dateFormat, dayOfWeek: (rawValue & (1 << 5)) != 0)
}
}
@ -47,7 +47,7 @@ public enum MessageTextEntityType: Equatable {
switch self {
case .relative:
rawValue |= 1 << 0
case let .full(timeFormat, dateFormat):
case let .full(timeFormat, dateFormat, dayOfWeek):
switch timeFormat {
case .short:
rawValue |= 1 << 1
@ -64,6 +64,9 @@ public enum MessageTextEntityType: Equatable {
default:
break
}
if dayOfWeek {
rawValue |= 1 << 5
}
}
return rawValue
}

View file

@ -283,7 +283,7 @@ func _internal_acceptMessageActionUrlAuth(account: Account, subject: MessageActi
|> mapToSignal { peer -> Signal<Api.UrlAuthResult?, MTRpcError> in
if let inputPeer = apiInputPeer(peer) {
let flags: Int32 = 1 << 1
return account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: inputPeer, msgId: messageId.id, buttonId: buttonId, url: nil))
return account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: inputPeer, msgId: messageId.id, buttonId: buttonId, url: nil, matchCode: nil))
|> map(Optional.init)
} else {
return .single(nil)
@ -291,7 +291,7 @@ func _internal_acceptMessageActionUrlAuth(account: Account, subject: MessageActi
}
case let .url(url):
flags |= (1 << 2)
request = account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: nil, msgId: nil, buttonId: nil, url: url))
request = account.network.request(Api.functions.messages.acceptUrlAuth(flags: flags, peer: nil, msgId: nil, buttonId: nil, url: url, matchCode: nil))
|> map(Optional.init)
}

View file

@ -2372,8 +2372,22 @@ private final class ProfileGiftsContextImpl {
self.pushState()
}
func insertStarGifts(gifts: [ProfileGiftsContext.State.StarGift]) {
self.gifts.insert(contentsOf: gifts, at: 0)
func insertStarGifts(gifts: [ProfileGiftsContext.State.StarGift], afterPinned: Bool = false) {
if afterPinned {
var added = false
for index in 0 ..< self.gifts.count {
if !self.gifts[index].pinnedToTop {
added = true
self.gifts.insert(contentsOf: gifts, at: index)
break
}
}
if !added {
self.gifts.append(contentsOf: gifts)
}
} else {
self.gifts.insert(contentsOf: gifts, at: 0)
}
self.pushState()
let peerId = self.peerId
@ -2387,7 +2401,21 @@ private final class ProfileGiftsContextImpl {
} else {
updatedGifts = []
}
updatedGifts.insert(contentsOf: gifts, at: 0)
if afterPinned {
var added = false
for index in 0 ..< updatedGifts.count {
if !updatedGifts[index].pinnedToTop {
added = true
updatedGifts.insert(contentsOf: gifts, at: index)
break
}
}
if !added {
updatedGifts.append(contentsOf: gifts)
}
} else {
updatedGifts.insert(contentsOf: gifts, at: 0)
}
updatedCount += Int32(gifts.count)
if let entry = CodableEntry(CachedProfileGifts(gifts: updatedGifts, count: updatedCount, notificationsEnabled: nil)) {
transaction.putItemCacheEntry(id: giftsEntryId(peerId: peerId, collectionId: collectionId), entry: entry)
@ -3087,9 +3115,9 @@ public final class ProfileGiftsContext {
}
}
public func insertStarGifts(gifts: [ProfileGiftsContext.State.StarGift]) {
public func insertStarGifts(gifts: [ProfileGiftsContext.State.StarGift], afterPinned: Bool = false) {
self.impl.with { impl in
impl.insertStarGifts(gifts: gifts)
impl.insertStarGifts(gifts: gifts, afterPinned: afterPinned)
}
}

View file

@ -4,35 +4,55 @@ import SwiftSignalKit
import TelegramApi
import MtProtoKit
func _internal_toggleChatCustomRanks(account: Account, peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
return account.postbox.transaction { transaction -> Signal<Void, NoError> in
if let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.toggleChatCustomRanks(peer: inputPeer, enabled: enabled ? .boolTrue : .boolFalse))
|> `catch` { _ in
return .complete()
}
|> map { updates -> Void in
account.stateManager.addUpdates(updates)
}
} else {
return .complete()
}
} |> switchToLatest
}
public enum UpdateChatRankError {
case generic
case changeForbidden
case chatAdminRequired
case chatCreatorRequired
case notParticipant
}
func _internal_updateChatRank(account: Account, peerId: PeerId, userId: PeerId, rank: String?) -> Signal<Never, UpdateChatRankError> {
return account.postbox.transaction { transaction -> Signal<Void, UpdateChatRankError> in
func _internal_updateChatRank(account: Account, peerId: PeerId, userId: PeerId, rank: String?) -> Signal<(ChannelParticipant?, RenderedChannelParticipant)?, UpdateChatRankError> {
return account.postbox.transaction { transaction -> Signal<(ChannelParticipant?, RenderedChannelParticipant)?, UpdateChatRankError> in
if let user = transaction.getPeer(userId), let inputUser = apiInputPeer(user), let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) {
return account.network.request(Api.functions.messages.editChatParticipantRank(peer: inputPeer, participant: inputUser, rank: rank ?? ""))
|> mapError { _ -> UpdateChatRankError in
return .generic
|> mapError { error -> UpdateChatRankError in
if error.errorDescription == "CHAT_ADMIN_REQUIRED" {
return .chatAdminRequired
} else if error.errorDescription == "CHAT_CREATOR_REQUIRED" {
return .chatCreatorRequired
} else if error.errorDescription == "USER_NOT_PARTICIPANT" {
return .notParticipant
} else if error.errorDescription == "RANK_CHANGE_FORBIDDEN" {
return .changeForbidden
} else {
return .generic
}
}
|> map { updates -> Void in
|> mapToSignal { updates -> Signal<(ChannelParticipant?, RenderedChannelParticipant)?, UpdateChatRankError> in
account.stateManager.addUpdates(updates)
if peerId.namespace == Namespaces.Peer.CloudGroup {
return account.postbox.transaction { transaction -> (ChannelParticipant?, RenderedChannelParticipant)? in
transaction.updatePeerCachedData(peerIds: [peerId], update: { peerId, current in
if let current = current as? CachedGroupData, let participants = current.participants {
var updatedParticipants = participants.participants
if let index = updatedParticipants.firstIndex(where: { $0.peerId == userId }) {
updatedParticipants[index] = updatedParticipants[index].withUpdated(rank: rank)
}
return current.withUpdatedParticipants(CachedGroupParticipants(participants: updatedParticipants, version: participants.version + 2))
} else {
return current
}
})
return nil
}
|> castError(UpdateChatRankError.self)
} else {
let participant: ChannelParticipant = .member(id: userId, invitedAt: Int32(Date().timeIntervalSince1970), adminInfo: nil, banInfo: nil, rank: rank, subscriptionUntilDate: nil)
let timestamp = Int32(Date().timeIntervalSince1970)
return .single((participant, RenderedChannelParticipant(participant: participant, peer: user, presences: [userId: TelegramUserPresence(status: .present(until: timestamp + 60), lastActivity: timestamp)])))
}
}
} else {
return .fail(.generic)
@ -40,7 +60,6 @@ func _internal_updateChatRank(account: Account, peerId: PeerId, userId: PeerId,
}
|> mapError { _ -> UpdateChatRankError in }
|> switchToLatest
|> ignoreValues
}

View file

@ -616,12 +616,8 @@ public extension TelegramEngine {
public func getFutureCreatorAfterLeave(peerId: EnginePeer.Id) -> Signal<EnginePeer?, NoError> {
return _internal_getFutureCreatorAfterLeave(account: self.account, peerId: peerId)
}
public func toggleChatCustomRanks(peerId: PeerId, enabled: Bool) -> Signal<Void, NoError> {
return _internal_toggleChatCustomRanks(account: self.account, peerId: peerId, enabled: enabled)
}
public func updateChatRank(account: Account, peerId: PeerId, userId: PeerId, rank: String?) -> Signal<Never, UpdateChatRankError> {
public func updateChatRank(peerId: PeerId, userId: PeerId, rank: String?) -> Signal<(ChannelParticipant?, RenderedChannelParticipant)?, UpdateChatRankError> {
return _internal_updateChatRank(account: account, peerId: peerId, userId: userId, rank: rank)
}

View file

@ -526,9 +526,6 @@ final class GiftSlotComponent: Component {
}
@objc private func buttonPressed() {
guard let _ = self.component?.removeAction else {
return
}
self.component?.action()
}
@ -630,7 +627,7 @@ final class GiftSlotComponent: Component {
)
),
environment: {},
containerSize: CGSize(width: availableSize.width, height: availableSize.height)
containerSize: CGSize(width: availableSize.width - 2.0 + UIScreenPixel, height: availableSize.height - 2.0 + UIScreenPixel)
)
let iconFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: iconSize)
if let iconView = icon.view {

View file

@ -430,7 +430,12 @@ private final class CraftGiftPageContent: Component {
transition.setAlpha(view: titleView, alpha: 1.0)
}
let giftTitle = "\(component.gift.title) #\(formatCollectibleNumber(component.gift.number, dateTimeFormat: environment.dateTimeFormat))"
var selectedMainGift = component.gift
if component.selectedGiftIds[0] != selectedMainGift.id, let id = component.selectedGiftIds[0], let gift = self.giftMap[id]?.gift {
selectedMainGift = gift
}
let giftTitle = "\(selectedMainGift.title) #\(formatCollectibleNumber(selectedMainGift.number, dateTimeFormat: environment.dateTimeFormat))"
let descriptionFont = Font.regular(13.0)
let descriptionBoldFont = Font.semibold(13.0)
@ -1160,7 +1165,7 @@ private final class CraftGiftPageContent: Component {
context: component.context,
craftContext: component.craftContext,
resaleContext: resaleContext,
gift: component.gift,
gift: selectedMainGift,
genericGift: genericGift,
selectedGiftIds: Set(component.selectedGiftIds.values),
starsTopUpOptions: component.starsTopUpOptionsPromise.get(),
@ -1219,7 +1224,7 @@ private final class CraftGiftPageContent: Component {
navigationController.view.addSubview(ConfettiView(frame: navigationController.view.bounds))
}
Queue.mainQueue().after(0.5) {
controller.profileGiftsContext?.insertStarGifts(gifts: [gift])
controller.profileGiftsContext?.insertStarGifts(gifts: [gift], afterPinned: true)
}
}
controller.view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.35, removeOnCompletion: false, completion: { _ in
@ -1257,7 +1262,7 @@ private final class CraftGiftPageContent: Component {
GiftCompositionComponent(
context: component.context,
theme: environment.theme,
subject: .unique(nil, component.gift),
subject: .unique(nil, selectedMainGift),
animationOffset: nil,
animationScale: nil,
displayAnimationStars: false,
@ -1621,8 +1626,13 @@ private final class SheetContainerComponent: CombinedComponent {
}
}
var selectedMainGift = component.gift
if state.selectedGiftIds[0] != selectedMainGift.id, let id = state.selectedGiftIds[0], let gift = externalState.giftsMap[id]?.gift {
selectedMainGift = gift
}
var buttonColor = colors.3
if state.displayInfo, let backdropAttribute = component.gift.attributes.first(where: { attribute in
if state.displayInfo, let backdropAttribute = selectedMainGift.attributes.first(where: { attribute in
if case .backdrop = attribute {
return true
} else {
@ -1637,7 +1647,7 @@ private final class SheetContainerComponent: CombinedComponent {
backgroundColor = environment.theme.list.plainBackgroundColor
}
let giftTitle = "\(component.gift.title) #\(formatCollectibleNumber(component.gift.number, dateTimeFormat: environment.dateTimeFormat))"
let giftTitle = "\(selectedMainGift.title) #\(formatCollectibleNumber(selectedMainGift.number, dateTimeFormat: environment.dateTimeFormat))"
let buttonContent: AnyComponentWithIdentity<Empty>
if state.displayInfo {

View file

@ -692,7 +692,10 @@ private final class GiftUpgradeVariantsScreenComponent: Component {
self.isPlaying = false
for attribute in selectedAttributes {
switch attribute {
case .model:
case let .model(_, _, _, crafted):
if crafted {
self.displayCraftableModels = true
}
self.selectedModel = attribute
case .pattern:
self.selectedSymbol = attribute

View file

@ -30,7 +30,8 @@ public func stringForEntityFormattedDate(timestamp: Int32, format: MessageTextEn
return strings.FormattedDate_InDays(Int32(round(Float(value) / (24 * 60 * 60))))
}
}
case let .full(timeFormat, dateFormat):
case let .full(timeFormat, dateFormat, dayOfWeek):
let _ = dayOfWeek
var string = ""
if let dateFormat {
switch dateFormat {

View file

@ -300,6 +300,7 @@ public func generateTextEntities(_ text: String, enabledTypes: EnabledEntityType
type = .Url
} else if result.resultType == NSTextCheckingResult.CheckingType.date, let date = result.date?.timeIntervalSince1970 {
#if DEBUG
var dayOfWeek = false
var format: MessageTextEntityType.DateTimeFormat?
if text.contains("[rel]") {
format = .relative
@ -316,8 +317,11 @@ public func generateTextEntities(_ text: String, enabledTypes: EnabledEntityType
} else if text.contains("[ld]") {
dateFormat = .long
}
if text.contains("[d]") {
dayOfWeek = true
}
if timeFormat != nil || dateFormat != nil {
format = .full(timeFormat: timeFormat, dateFormat: dateFormat)
format = .full(timeFormat: timeFormat, dateFormat: dateFormat, dayOfWeek: dayOfWeek)
}
type = .FormattedDate(format: format, date: Int32(date))
#else