Skip to content

Commit c026f5a

Browse files
committed
Various fixes
1 parent 3f12448 commit c026f5a

File tree

4 files changed

+246
-82
lines changed

4 files changed

+246
-82
lines changed

submodules/TelegramCore/Sources/TelegramEngine/Payments/StarGifts.swift

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1150,9 +1150,33 @@ private final class ProfileGiftsContextImpl {
11501150
self.actionDisposable.set(
11511151
_internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: added).startStrict()
11521152
)
1153+
11531154
if let index = self.gifts.firstIndex(where: { $0.reference == reference }) {
1154-
self.gifts[index] = self.gifts[index].withSavedToProfile(added)
1155+
if !added && self.gifts[index].pinnedToTop {
1156+
let pinnedGifts = self.gifts.filter { $0.pinnedToTop && $0.reference != reference }
1157+
let existingGifts = Set(pinnedGifts.compactMap { $0.reference })
1158+
1159+
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
1160+
for gift in self.gifts {
1161+
if let reference = gift.reference, existingGifts.contains(reference) {
1162+
continue
1163+
}
1164+
var gift = gift
1165+
if gift.reference == reference {
1166+
gift = gift.withPinnedToTop(false).withSavedToProfile(false)
1167+
}
1168+
updatedGifts.append(gift)
1169+
}
1170+
updatedGifts.sort { lhs, rhs in
1171+
lhs.date > rhs.date
1172+
}
1173+
updatedGifts.insert(contentsOf: pinnedGifts, at: 0)
1174+
self.gifts = updatedGifts
1175+
} else {
1176+
self.gifts[index] = self.gifts[index].withSavedToProfile(added)
1177+
}
11551178
}
1179+
11561180
if let index = self.filteredGifts.firstIndex(where: { $0.reference == reference }) {
11571181
self.filteredGifts[index] = self.filteredGifts[index].withSavedToProfile(added)
11581182
if !self.filter.contains(.hidden) && !added {
@@ -1164,9 +1188,14 @@ private final class ProfileGiftsContextImpl {
11641188

11651189
func updateStarGiftPinnedToTop(reference: StarGiftReference, pinnedToTop: Bool) {
11661190
var pinnedGifts = self.gifts.filter { $0.pinnedToTop }
1191+
var saveToProfile = false
11671192
if var gift = self.gifts.first(where: { $0.reference == reference }) {
11681193
gift = gift.withPinnedToTop(pinnedToTop)
11691194
if pinnedToTop {
1195+
if !gift.savedToProfile {
1196+
gift = gift.withSavedToProfile(true)
1197+
saveToProfile = true
1198+
}
11701199
pinnedGifts.append(gift)
11711200
} else {
11721201
pinnedGifts.removeAll(where: { $0.reference == reference })
@@ -1192,22 +1221,35 @@ private final class ProfileGiftsContextImpl {
11921221
}
11931222
self.pushState()
11941223

1224+
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference })
1225+
1226+
if saveToProfile {
1227+
signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true)
1228+
|> then(signal)
1229+
}
1230+
11951231
self.actionDisposable.set(
1196-
_internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference }).startStrict(completed: { [weak self] in
1232+
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
11971233
self?.reload()
11981234
})
11991235
)
12001236
}
12011237

12021238
public func updatePinnedToTopStarGifts(references: [StarGiftReference]) {
12031239
let existingGifts = Set(references)
1240+
var saveSignals: [Signal<Never, NoError>] = []
12041241
let currentPinnedGifts = self.gifts.filter { gift in
12051242
if let reference = gift.reference {
12061243
return existingGifts.contains(reference)
12071244
} else {
12081245
return false
12091246
}
1210-
}.map { $0.withPinnedToTop(true) }
1247+
}.map { gift in
1248+
if !gift.savedToProfile, let reference = gift.reference {
1249+
saveSignals.append(_internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true))
1250+
}
1251+
return gift.withPinnedToTop(true).withSavedToProfile(true)
1252+
}
12111253

12121254
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
12131255
for gift in self.gifts {
@@ -1231,8 +1273,15 @@ private final class ProfileGiftsContextImpl {
12311273

12321274
self.pushState()
12331275

1276+
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference })
1277+
if !saveSignals.isEmpty {
1278+
signal = combineLatest(saveSignals)
1279+
|> ignoreValues
1280+
|> then(signal)
1281+
}
1282+
12341283
self.actionDisposable.set(
1235-
_internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference }).startStrict(completed: { [weak self] in
1284+
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
12361285
self?.reload()
12371286
})
12381287
)

submodules/TelegramUI/Components/Gifts/GiftItemComponent/Sources/GiftItemComponent.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ public final class GiftItemComponent: Component {
664664

665665
var iconBackgroundSize: CGSize?
666666
if component.isEditing {
667-
if !component.isPinned {
667+
if !component.isPinned && backgroundColor != nil {
668668
iconBackgroundSize = CGSize(width: 48.0, height: 48.0)
669669
}
670670
} else {
@@ -710,7 +710,7 @@ public final class GiftItemComponent: Component {
710710
iconBackground.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
711711
}
712712

713-
if component.isPinned || component.isEditing {
713+
if component.isPinned || (component.isEditing && backgroundColor != nil) {
714714
let pinnedIcon: UIImageView
715715
if let currentIcon = self.pinnedIcon {
716716
pinnedIcon = currentIcon

submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoPaneContainerNode.swift

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
4343

4444
private let titleNode: ImmediateTextNode
4545
private let buttonNode: HighlightTrackingButtonNode
46-
private var iconLayers: [InlineStickerItemLayer] = []
46+
private var iconLayers: [AnyHashable: InlineStickerItemLayer] = [:]
4747

4848
private var isSelected: Bool = false
49+
private var icons: [ProfileGiftsContext.State.StarGift] = []
50+
private var titleWidth: CGFloat?
4951

5052
init(pressed: @escaping () -> Void) {
5153
self.pressed = pressed
@@ -67,27 +69,53 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
6769
self.pressed()
6870
}
6971

70-
func updateText(context: AccountContext, title: String, icons: [TelegramMediaFile] = [], isSelected: Bool, presentationData: PresentationData) {
72+
func updateText(context: AccountContext, title: String, icons: [ProfileGiftsContext.State.StarGift] = [], isSelected: Bool, presentationData: PresentationData) {
7173
self.isSelected = isSelected
7274
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor)
75+
self.icons = icons
7376

7477
if !icons.isEmpty {
75-
if self.iconLayers.isEmpty {
76-
for icon in icons {
77-
let iconSize = CGSize(width: 18.0, height: 18.0)
78+
var validIds = Set<AnyHashable>()
79+
var index = 0
80+
for icon in icons {
81+
let id: AnyHashable
82+
if let reference = icon.reference {
83+
id = reference
84+
} else {
85+
id = index
86+
}
87+
validIds.insert(id)
88+
89+
let iconSize = CGSize(width: 18.0, height: 18.0)
90+
if let _ = self.iconLayers[id] {
91+
92+
} else {
93+
var file: TelegramMediaFile?
94+
switch icon.gift {
95+
case let .generic(gift):
96+
file = gift.file
97+
case let .unique(gift):
98+
for attribute in gift.attributes {
99+
if case let .model(_, fileValue, _) = attribute {
100+
file = fileValue
101+
}
102+
}
103+
}
104+
guard let file else {
105+
continue
106+
}
78107

79108
let emoji = ChatTextInputTextCustomEmojiAttribute(
80109
interactivelySelectedFromPackId: nil,
81-
fileId: icon.fileId.id,
82-
file: icon
110+
fileId: file.fileId.id,
111+
file: file
83112
)
84-
85113
let animationLayer = InlineStickerItemLayer(
86114
context: .account(context),
87115
userLocation: .other,
88116
attemptSynchronousLoad: false,
89117
emoji: emoji,
90-
file: icon,
118+
file: file,
91119
cache: context.animationCache,
92120
renderer: context.animationRenderer,
93121
unique: true,
@@ -96,12 +124,30 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
96124
loopCount: 1
97125
)
98126
animationLayer.isVisibleForAnimations = true
99-
self.iconLayers.append(animationLayer)
127+
self.iconLayers[id] = animationLayer
100128
self.layer.addSublayer(animationLayer)
129+
130+
animationLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
131+
animationLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
132+
}
133+
index += 1
134+
}
135+
136+
var removeIds: [AnyHashable] = []
137+
for (id, layer) in self.iconLayers {
138+
if !validIds.contains(id) {
139+
removeIds.append(id)
140+
layer.animateScale(from: 1.0, to: 0.01, duration: 0.25, removeOnCompletion: false)
141+
layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
142+
layer.removeFromSuperlayer()
143+
})
101144
}
102145
}
146+
for id in removeIds {
147+
self.iconLayers.removeValue(forKey: id)
148+
}
103149
} else {
104-
for layer in self.iconLayers {
150+
for (_, layer) in self.iconLayers {
105151
layer.removeFromSuperlayer()
106152
}
107153
self.iconLayers.removeAll()
@@ -115,24 +161,54 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
115161
}
116162

117163
func updateLayout(height: CGFloat) -> CGFloat {
118-
var totalWidth: CGFloat = 0.0
119164
let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
165+
let iconSize = CGSize(width: 18.0, height: 18.0)
166+
let spacing: CGFloat = 1.0
167+
120168
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
121-
totalWidth = titleSize.width
169+
self.titleWidth = titleSize.width
122170

171+
var totalWidth = titleSize.width
123172
if !self.iconLayers.isEmpty {
124173
totalWidth += 2.0
125-
let iconSize = CGSize(width: 18.0, height: 18.0)
126-
let spacing: CGFloat = 1.0
127-
for iconlayer in self.iconLayers {
128-
iconlayer.frame = CGRect(origin: CGPoint(x: totalWidth, y: 15.0), size: iconSize)
129-
totalWidth += iconSize.width + spacing
130-
}
174+
totalWidth += (iconSize.width + spacing) * CGFloat(self.iconLayers.count)
131175
totalWidth -= spacing
132176
}
177+
178+
self.layoutIcons(transition: .animated(duration: 0.3, curve: .spring))
179+
133180
return totalWidth
134181
}
135182

183+
func layoutIcons(transition: ContainedViewLayoutTransition) {
184+
guard let titleWidth = self.titleWidth else {
185+
return
186+
}
187+
let iconSize = CGSize(width: 18.0, height: 18.0)
188+
let spacing: CGFloat = 1.0
189+
190+
var origin = CGPoint(x: titleWidth + 2.0, y: 15.0)
191+
192+
var index = 0
193+
for icon in self.icons {
194+
let id: AnyHashable
195+
if let reference = icon.reference {
196+
id = reference
197+
} else {
198+
id = index
199+
}
200+
if let layer = self.iconLayers[id] {
201+
var iconTransition = transition
202+
if layer.frame.width.isZero {
203+
iconTransition = .immediate
204+
}
205+
iconTransition.updateFrame(layer: layer, frame: CGRect(origin: origin, size: iconSize))
206+
}
207+
origin.x += iconSize.width + spacing
208+
index += 1
209+
}
210+
}
211+
136212
func updateArea(size: CGSize, sideInset: CGFloat) {
137213
self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height))
138214
}
@@ -141,7 +217,7 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
141217
struct PeerInfoPaneSpecifier: Equatable {
142218
var key: PeerInfoPaneKey
143219
var title: String
144-
var icons: [TelegramMediaFile]
220+
var icons: [ProfileGiftsContext.State.StarGift]
145221
}
146222

147223
private func interpolateFrame(from fromValue: CGRect, to toValue: CGRect, t: CGFloat) -> CGRect {
@@ -1189,7 +1265,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
11891265

11901266
self.tabsContainerNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in
11911267
let title: String
1192-
var icons: [TelegramMediaFile] = []
1268+
var icons: [ProfileGiftsContext.State.StarGift] = []
11931269
switch key {
11941270
case .stories:
11951271
title = presentationData.strings.PeerInfo_PaneStories
@@ -1223,19 +1299,9 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
12231299
title = presentationData.strings.PeerInfo_SavedMessagesTabTitle
12241300
case .gifts:
12251301
title = presentationData.strings.PeerInfo_PaneGifts
1226-
icons = data?.profileGiftsContext?.currentState?.gifts.prefix(3).compactMap { gift in
1227-
switch gift.gift {
1228-
case let .generic(gift):
1229-
return gift.file
1230-
case let .unique(gift):
1231-
for attribute in gift.attributes {
1232-
if case let .model(_, file, _) = attribute {
1233-
return file
1234-
}
1235-
}
1236-
return nil
1237-
}
1238-
} ?? []
1302+
if let gifts = data?.profileGiftsContext?.currentState?.gifts.prefix(3) {
1303+
icons = Array(gifts)
1304+
}
12391305
}
12401306
return PeerInfoPaneSpecifier(key: key, title: title, icons: icons)
12411307
}, selectedPane: self.currentPaneKey, disableSwitching: disableTabSwitching, transitionFraction: self.transitionFraction, transition: transition)

0 commit comments

Comments
 (0)