mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
3f12448474
commit
c026f5af0b
@ -1150,9 +1150,33 @@ private final class ProfileGiftsContextImpl {
|
|||||||
self.actionDisposable.set(
|
self.actionDisposable.set(
|
||||||
_internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: added).startStrict()
|
_internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: added).startStrict()
|
||||||
)
|
)
|
||||||
|
|
||||||
if let index = self.gifts.firstIndex(where: { $0.reference == reference }) {
|
if let index = self.gifts.firstIndex(where: { $0.reference == reference }) {
|
||||||
|
if !added && self.gifts[index].pinnedToTop {
|
||||||
|
let pinnedGifts = self.gifts.filter { $0.pinnedToTop && $0.reference != reference }
|
||||||
|
let existingGifts = Set(pinnedGifts.compactMap { $0.reference })
|
||||||
|
|
||||||
|
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
|
||||||
|
for gift in self.gifts {
|
||||||
|
if let reference = gift.reference, existingGifts.contains(reference) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var gift = gift
|
||||||
|
if gift.reference == reference {
|
||||||
|
gift = gift.withPinnedToTop(false).withSavedToProfile(false)
|
||||||
|
}
|
||||||
|
updatedGifts.append(gift)
|
||||||
|
}
|
||||||
|
updatedGifts.sort { lhs, rhs in
|
||||||
|
lhs.date > rhs.date
|
||||||
|
}
|
||||||
|
updatedGifts.insert(contentsOf: pinnedGifts, at: 0)
|
||||||
|
self.gifts = updatedGifts
|
||||||
|
} else {
|
||||||
self.gifts[index] = self.gifts[index].withSavedToProfile(added)
|
self.gifts[index] = self.gifts[index].withSavedToProfile(added)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let index = self.filteredGifts.firstIndex(where: { $0.reference == reference }) {
|
if let index = self.filteredGifts.firstIndex(where: { $0.reference == reference }) {
|
||||||
self.filteredGifts[index] = self.filteredGifts[index].withSavedToProfile(added)
|
self.filteredGifts[index] = self.filteredGifts[index].withSavedToProfile(added)
|
||||||
if !self.filter.contains(.hidden) && !added {
|
if !self.filter.contains(.hidden) && !added {
|
||||||
@ -1164,9 +1188,14 @@ private final class ProfileGiftsContextImpl {
|
|||||||
|
|
||||||
func updateStarGiftPinnedToTop(reference: StarGiftReference, pinnedToTop: Bool) {
|
func updateStarGiftPinnedToTop(reference: StarGiftReference, pinnedToTop: Bool) {
|
||||||
var pinnedGifts = self.gifts.filter { $0.pinnedToTop }
|
var pinnedGifts = self.gifts.filter { $0.pinnedToTop }
|
||||||
|
var saveToProfile = false
|
||||||
if var gift = self.gifts.first(where: { $0.reference == reference }) {
|
if var gift = self.gifts.first(where: { $0.reference == reference }) {
|
||||||
gift = gift.withPinnedToTop(pinnedToTop)
|
gift = gift.withPinnedToTop(pinnedToTop)
|
||||||
if pinnedToTop {
|
if pinnedToTop {
|
||||||
|
if !gift.savedToProfile {
|
||||||
|
gift = gift.withSavedToProfile(true)
|
||||||
|
saveToProfile = true
|
||||||
|
}
|
||||||
pinnedGifts.append(gift)
|
pinnedGifts.append(gift)
|
||||||
} else {
|
} else {
|
||||||
pinnedGifts.removeAll(where: { $0.reference == reference })
|
pinnedGifts.removeAll(where: { $0.reference == reference })
|
||||||
@ -1192,8 +1221,15 @@ private final class ProfileGiftsContextImpl {
|
|||||||
}
|
}
|
||||||
self.pushState()
|
self.pushState()
|
||||||
|
|
||||||
|
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference })
|
||||||
|
|
||||||
|
if saveToProfile {
|
||||||
|
signal = _internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true)
|
||||||
|
|> then(signal)
|
||||||
|
}
|
||||||
|
|
||||||
self.actionDisposable.set(
|
self.actionDisposable.set(
|
||||||
_internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference }).startStrict(completed: { [weak self] in
|
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
||||||
self?.reload()
|
self?.reload()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -1201,13 +1237,19 @@ private final class ProfileGiftsContextImpl {
|
|||||||
|
|
||||||
public func updatePinnedToTopStarGifts(references: [StarGiftReference]) {
|
public func updatePinnedToTopStarGifts(references: [StarGiftReference]) {
|
||||||
let existingGifts = Set(references)
|
let existingGifts = Set(references)
|
||||||
|
var saveSignals: [Signal<Never, NoError>] = []
|
||||||
let currentPinnedGifts = self.gifts.filter { gift in
|
let currentPinnedGifts = self.gifts.filter { gift in
|
||||||
if let reference = gift.reference {
|
if let reference = gift.reference {
|
||||||
return existingGifts.contains(reference)
|
return existingGifts.contains(reference)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}.map { $0.withPinnedToTop(true) }
|
}.map { gift in
|
||||||
|
if !gift.savedToProfile, let reference = gift.reference {
|
||||||
|
saveSignals.append(_internal_updateStarGiftAddedToProfile(account: self.account, reference: reference, added: true))
|
||||||
|
}
|
||||||
|
return gift.withPinnedToTop(true).withSavedToProfile(true)
|
||||||
|
}
|
||||||
|
|
||||||
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
|
var updatedGifts: [ProfileGiftsContext.State.StarGift] = []
|
||||||
for gift in self.gifts {
|
for gift in self.gifts {
|
||||||
@ -1231,8 +1273,15 @@ private final class ProfileGiftsContextImpl {
|
|||||||
|
|
||||||
self.pushState()
|
self.pushState()
|
||||||
|
|
||||||
|
var signal = _internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference })
|
||||||
|
if !saveSignals.isEmpty {
|
||||||
|
signal = combineLatest(saveSignals)
|
||||||
|
|> ignoreValues
|
||||||
|
|> then(signal)
|
||||||
|
}
|
||||||
|
|
||||||
self.actionDisposable.set(
|
self.actionDisposable.set(
|
||||||
_internal_updateStarGiftsPinnedToTop(account: self.account, peerId: self.peerId, references: pinnedGifts.compactMap { $0.reference }).startStrict(completed: { [weak self] in
|
(signal |> deliverOn(self.queue)).startStrict(completed: { [weak self] in
|
||||||
self?.reload()
|
self?.reload()
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@ -664,7 +664,7 @@ public final class GiftItemComponent: Component {
|
|||||||
|
|
||||||
var iconBackgroundSize: CGSize?
|
var iconBackgroundSize: CGSize?
|
||||||
if component.isEditing {
|
if component.isEditing {
|
||||||
if !component.isPinned {
|
if !component.isPinned && backgroundColor != nil {
|
||||||
iconBackgroundSize = CGSize(width: 48.0, height: 48.0)
|
iconBackgroundSize = CGSize(width: 48.0, height: 48.0)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -710,7 +710,7 @@ public final class GiftItemComponent: Component {
|
|||||||
iconBackground.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
iconBackground.layer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if component.isPinned || component.isEditing {
|
if component.isPinned || (component.isEditing && backgroundColor != nil) {
|
||||||
let pinnedIcon: UIImageView
|
let pinnedIcon: UIImageView
|
||||||
if let currentIcon = self.pinnedIcon {
|
if let currentIcon = self.pinnedIcon {
|
||||||
pinnedIcon = currentIcon
|
pinnedIcon = currentIcon
|
||||||
|
@ -43,9 +43,11 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
|||||||
|
|
||||||
private let titleNode: ImmediateTextNode
|
private let titleNode: ImmediateTextNode
|
||||||
private let buttonNode: HighlightTrackingButtonNode
|
private let buttonNode: HighlightTrackingButtonNode
|
||||||
private var iconLayers: [InlineStickerItemLayer] = []
|
private var iconLayers: [AnyHashable: InlineStickerItemLayer] = [:]
|
||||||
|
|
||||||
private var isSelected: Bool = false
|
private var isSelected: Bool = false
|
||||||
|
private var icons: [ProfileGiftsContext.State.StarGift] = []
|
||||||
|
private var titleWidth: CGFloat?
|
||||||
|
|
||||||
init(pressed: @escaping () -> Void) {
|
init(pressed: @escaping () -> Void) {
|
||||||
self.pressed = pressed
|
self.pressed = pressed
|
||||||
@ -67,27 +69,53 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
|||||||
self.pressed()
|
self.pressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateText(context: AccountContext, title: String, icons: [TelegramMediaFile] = [], isSelected: Bool, presentationData: PresentationData) {
|
func updateText(context: AccountContext, title: String, icons: [ProfileGiftsContext.State.StarGift] = [], isSelected: Bool, presentationData: PresentationData) {
|
||||||
self.isSelected = isSelected
|
self.isSelected = isSelected
|
||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor)
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(14.0), textColor: isSelected ? presentationData.theme.list.itemAccentColor : presentationData.theme.list.itemSecondaryTextColor)
|
||||||
|
self.icons = icons
|
||||||
|
|
||||||
if !icons.isEmpty {
|
if !icons.isEmpty {
|
||||||
if self.iconLayers.isEmpty {
|
var validIds = Set<AnyHashable>()
|
||||||
|
var index = 0
|
||||||
for icon in icons {
|
for icon in icons {
|
||||||
|
let id: AnyHashable
|
||||||
|
if let reference = icon.reference {
|
||||||
|
id = reference
|
||||||
|
} else {
|
||||||
|
id = index
|
||||||
|
}
|
||||||
|
validIds.insert(id)
|
||||||
|
|
||||||
let iconSize = CGSize(width: 18.0, height: 18.0)
|
let iconSize = CGSize(width: 18.0, height: 18.0)
|
||||||
|
if let _ = self.iconLayers[id] {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
var file: TelegramMediaFile?
|
||||||
|
switch icon.gift {
|
||||||
|
case let .generic(gift):
|
||||||
|
file = gift.file
|
||||||
|
case let .unique(gift):
|
||||||
|
for attribute in gift.attributes {
|
||||||
|
if case let .model(_, fileValue, _) = attribute {
|
||||||
|
file = fileValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
guard let file else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
let emoji = ChatTextInputTextCustomEmojiAttribute(
|
let emoji = ChatTextInputTextCustomEmojiAttribute(
|
||||||
interactivelySelectedFromPackId: nil,
|
interactivelySelectedFromPackId: nil,
|
||||||
fileId: icon.fileId.id,
|
fileId: file.fileId.id,
|
||||||
file: icon
|
file: file
|
||||||
)
|
)
|
||||||
|
|
||||||
let animationLayer = InlineStickerItemLayer(
|
let animationLayer = InlineStickerItemLayer(
|
||||||
context: .account(context),
|
context: .account(context),
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
attemptSynchronousLoad: false,
|
attemptSynchronousLoad: false,
|
||||||
emoji: emoji,
|
emoji: emoji,
|
||||||
file: icon,
|
file: file,
|
||||||
cache: context.animationCache,
|
cache: context.animationCache,
|
||||||
renderer: context.animationRenderer,
|
renderer: context.animationRenderer,
|
||||||
unique: true,
|
unique: true,
|
||||||
@ -96,12 +124,30 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
|||||||
loopCount: 1
|
loopCount: 1
|
||||||
)
|
)
|
||||||
animationLayer.isVisibleForAnimations = true
|
animationLayer.isVisibleForAnimations = true
|
||||||
self.iconLayers.append(animationLayer)
|
self.iconLayers[id] = animationLayer
|
||||||
self.layer.addSublayer(animationLayer)
|
self.layer.addSublayer(animationLayer)
|
||||||
|
|
||||||
|
animationLayer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||||
|
animationLayer.animateScale(from: 0.01, to: 1.0, duration: 0.2)
|
||||||
}
|
}
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var removeIds: [AnyHashable] = []
|
||||||
|
for (id, layer) in self.iconLayers {
|
||||||
|
if !validIds.contains(id) {
|
||||||
|
removeIds.append(id)
|
||||||
|
layer.animateScale(from: 1.0, to: 0.01, duration: 0.25, removeOnCompletion: false)
|
||||||
|
layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||||
|
layer.removeFromSuperlayer()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removeIds {
|
||||||
|
self.iconLayers.removeValue(forKey: id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for layer in self.iconLayers {
|
for (_, layer) in self.iconLayers {
|
||||||
layer.removeFromSuperlayer()
|
layer.removeFromSuperlayer()
|
||||||
}
|
}
|
||||||
self.iconLayers.removeAll()
|
self.iconLayers.removeAll()
|
||||||
@ -115,24 +161,54 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func updateLayout(height: CGFloat) -> CGFloat {
|
func updateLayout(height: CGFloat) -> CGFloat {
|
||||||
var totalWidth: CGFloat = 0.0
|
|
||||||
let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
let titleSize = self.titleNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
|
||||||
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
|
||||||
totalWidth = titleSize.width
|
|
||||||
|
|
||||||
if !self.iconLayers.isEmpty {
|
|
||||||
totalWidth += 2.0
|
|
||||||
let iconSize = CGSize(width: 18.0, height: 18.0)
|
let iconSize = CGSize(width: 18.0, height: 18.0)
|
||||||
let spacing: CGFloat = 1.0
|
let spacing: CGFloat = 1.0
|
||||||
for iconlayer in self.iconLayers {
|
|
||||||
iconlayer.frame = CGRect(origin: CGPoint(x: totalWidth, y: 15.0), size: iconSize)
|
self.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((height - titleSize.height) / 2.0)), size: titleSize)
|
||||||
totalWidth += iconSize.width + spacing
|
self.titleWidth = titleSize.width
|
||||||
}
|
|
||||||
|
var totalWidth = titleSize.width
|
||||||
|
if !self.iconLayers.isEmpty {
|
||||||
|
totalWidth += 2.0
|
||||||
|
totalWidth += (iconSize.width + spacing) * CGFloat(self.iconLayers.count)
|
||||||
totalWidth -= spacing
|
totalWidth -= spacing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.layoutIcons(transition: .animated(duration: 0.3, curve: .spring))
|
||||||
|
|
||||||
return totalWidth
|
return totalWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func layoutIcons(transition: ContainedViewLayoutTransition) {
|
||||||
|
guard let titleWidth = self.titleWidth else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let iconSize = CGSize(width: 18.0, height: 18.0)
|
||||||
|
let spacing: CGFloat = 1.0
|
||||||
|
|
||||||
|
var origin = CGPoint(x: titleWidth + 2.0, y: 15.0)
|
||||||
|
|
||||||
|
var index = 0
|
||||||
|
for icon in self.icons {
|
||||||
|
let id: AnyHashable
|
||||||
|
if let reference = icon.reference {
|
||||||
|
id = reference
|
||||||
|
} else {
|
||||||
|
id = index
|
||||||
|
}
|
||||||
|
if let layer = self.iconLayers[id] {
|
||||||
|
var iconTransition = transition
|
||||||
|
if layer.frame.width.isZero {
|
||||||
|
iconTransition = .immediate
|
||||||
|
}
|
||||||
|
iconTransition.updateFrame(layer: layer, frame: CGRect(origin: origin, size: iconSize))
|
||||||
|
}
|
||||||
|
origin.x += iconSize.width + spacing
|
||||||
|
index += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func updateArea(size: CGSize, sideInset: CGFloat) {
|
func updateArea(size: CGSize, sideInset: CGFloat) {
|
||||||
self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height))
|
self.buttonNode.frame = CGRect(origin: CGPoint(x: -sideInset, y: 0.0), size: CGSize(width: size.width + sideInset * 2.0, height: size.height))
|
||||||
}
|
}
|
||||||
@ -141,7 +217,7 @@ final class PeerInfoPaneTabsContainerPaneNode: ASDisplayNode {
|
|||||||
struct PeerInfoPaneSpecifier: Equatable {
|
struct PeerInfoPaneSpecifier: Equatable {
|
||||||
var key: PeerInfoPaneKey
|
var key: PeerInfoPaneKey
|
||||||
var title: String
|
var title: String
|
||||||
var icons: [TelegramMediaFile]
|
var icons: [ProfileGiftsContext.State.StarGift]
|
||||||
}
|
}
|
||||||
|
|
||||||
private func interpolateFrame(from fromValue: CGRect, to toValue: CGRect, t: CGFloat) -> CGRect {
|
private func interpolateFrame(from fromValue: CGRect, to toValue: CGRect, t: CGFloat) -> CGRect {
|
||||||
@ -1189,7 +1265,7 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
|||||||
|
|
||||||
self.tabsContainerNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in
|
self.tabsContainerNode.update(size: CGSize(width: size.width - sideInset * 2.0, height: tabsHeight), presentationData: presentationData, paneList: availablePanes.map { key in
|
||||||
let title: String
|
let title: String
|
||||||
var icons: [TelegramMediaFile] = []
|
var icons: [ProfileGiftsContext.State.StarGift] = []
|
||||||
switch key {
|
switch key {
|
||||||
case .stories:
|
case .stories:
|
||||||
title = presentationData.strings.PeerInfo_PaneStories
|
title = presentationData.strings.PeerInfo_PaneStories
|
||||||
@ -1223,20 +1299,10 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
|||||||
title = presentationData.strings.PeerInfo_SavedMessagesTabTitle
|
title = presentationData.strings.PeerInfo_SavedMessagesTabTitle
|
||||||
case .gifts:
|
case .gifts:
|
||||||
title = presentationData.strings.PeerInfo_PaneGifts
|
title = presentationData.strings.PeerInfo_PaneGifts
|
||||||
icons = data?.profileGiftsContext?.currentState?.gifts.prefix(3).compactMap { gift in
|
if let gifts = data?.profileGiftsContext?.currentState?.gifts.prefix(3) {
|
||||||
switch gift.gift {
|
icons = Array(gifts)
|
||||||
case let .generic(gift):
|
|
||||||
return gift.file
|
|
||||||
case let .unique(gift):
|
|
||||||
for attribute in gift.attributes {
|
|
||||||
if case let .model(_, file, _) = attribute {
|
|
||||||
return file
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} ?? []
|
|
||||||
}
|
|
||||||
return PeerInfoPaneSpecifier(key: key, title: title, icons: icons)
|
return PeerInfoPaneSpecifier(key: key, title: title, icons: icons)
|
||||||
}, selectedPane: self.currentPaneKey, disableSwitching: disableTabSwitching, transitionFraction: self.transitionFraction, transition: transition)
|
}, selectedPane: self.currentPaneKey, disableSwitching: disableTabSwitching, transitionFraction: self.transitionFraction, transition: transition)
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var starsProducts: [ProfileGiftsContext.State.StarGift]?
|
private var starsProducts: [ProfileGiftsContext.State.StarGift]?
|
||||||
private var starsItems: [AnyHashable: (ProfileGiftsContext.State.StarGift, ComponentView<Empty>)] = [:]
|
private var starsItems: [AnyHashable: (StarGiftReference?, ComponentView<Empty>)] = [:]
|
||||||
private var resultsAreFiltered = false
|
private var resultsAreFiltered = false
|
||||||
private var resultsAreEmpty = false
|
private var resultsAreEmpty = false
|
||||||
|
|
||||||
@ -90,6 +90,13 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
private var reorderedReferencesPromise = ValuePromise<[StarGiftReference]?>(nil)
|
private var reorderedReferencesPromise = ValuePromise<[StarGiftReference]?>(nil)
|
||||||
|
|
||||||
|
private var reorderedPinnedReferences: Set<StarGiftReference>? {
|
||||||
|
didSet {
|
||||||
|
self.reorderedPinnedReferencesPromise.set(self.reorderedPinnedReferences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var reorderedPinnedReferencesPromise = ValuePromise<Set<StarGiftReference>?>(nil)
|
||||||
|
|
||||||
private var reorderRecognizer: ReorderGestureRecognizer?
|
private var reorderRecognizer: ReorderGestureRecognizer?
|
||||||
|
|
||||||
private let maxPinnedCount: Int
|
private let maxPinnedCount: Int
|
||||||
@ -136,17 +143,24 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
for reference in reorderedReferences {
|
for reference in reorderedReferences {
|
||||||
if let index = stateItems.firstIndex(where: { $0.reference == reference }) {
|
if let index = stateItems.firstIndex(where: { $0.reference == reference }) {
|
||||||
seenIds.insert(reference)
|
seenIds.insert(reference)
|
||||||
fixedStateItems.append(stateItems[index])
|
var item = stateItems[index]
|
||||||
|
if self.reorderedPinnedReferences?.contains(reference) == true, !item.pinnedToTop {
|
||||||
|
item = item.withPinnedToTop(true)
|
||||||
|
}
|
||||||
|
fixedStateItems.append(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for item in stateItems {
|
for item in stateItems {
|
||||||
if let reference = item.reference, !seenIds.contains(reference) {
|
if let reference = item.reference, !seenIds.contains(reference) {
|
||||||
|
var item = item
|
||||||
|
if self.reorderedPinnedReferences?.contains(reference) == true, !item.pinnedToTop {
|
||||||
|
item = item.withPinnedToTop(true)
|
||||||
|
}
|
||||||
fixedStateItems.append(item)
|
fixedStateItems.append(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stateItems = fixedStateItems
|
stateItems = fixedStateItems
|
||||||
//self.reorderedReferences = fixedStateItems.compactMap(\.reference)
|
|
||||||
}
|
}
|
||||||
self.starsProducts = stateItems
|
self.starsProducts = stateItems
|
||||||
self.pinnedReferences = Array(stateItems.filter { $0.pinnedToTop }.compactMap { $0.reference })
|
self.pinnedReferences = Array(stateItems.filter { $0.pinnedToTop }.compactMap { $0.reference })
|
||||||
@ -218,7 +232,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
private func item(at point: CGPoint) -> (AnyHashable, ComponentView<Empty>)? {
|
private func item(at point: CGPoint) -> (AnyHashable, ComponentView<Empty>)? {
|
||||||
let localPoint = self.scrollNode.view.convert(point, from: self.view)
|
let localPoint = self.scrollNode.view.convert(point, from: self.view)
|
||||||
for (id, visibleItem) in self.starsItems {
|
for (id, visibleItem) in self.starsItems {
|
||||||
if let view = visibleItem.1.view, view.frame.contains(localPoint) {
|
if let view = visibleItem.1.view, view.frame.contains(localPoint), let reference = visibleItem.0, self.pinnedReferences.contains(reference) {
|
||||||
return (id, visibleItem.1)
|
return (id, visibleItem.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,6 +272,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
|
|
||||||
Queue.mainQueue().after(1.0) {
|
Queue.mainQueue().after(1.0) {
|
||||||
self.reorderedReferences = nil
|
self.reorderedReferences = nil
|
||||||
|
self.reorderedPinnedReferences = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,7 +296,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
} else {
|
} else {
|
||||||
self.reorderingItem = nil
|
self.reorderingItem = nil
|
||||||
}
|
}
|
||||||
self.updateScrolling(transition: .spring(duration: 0.3))
|
self.updateScrolling(transition: item == nil ? .spring(duration: 0.3) : .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,9 +311,9 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
if visibleItem.1 === visibleReorderingItem.1 {
|
if visibleItem.1 === visibleReorderingItem.1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if let view = visibleItem.1.view, view.frame.contains(targetPosition), let reorderItem = self.starsItems[id]?.0 {
|
if let view = visibleItem.1.view, view.frame.contains(targetPosition), let reorderItemReference = self.starsItems[id]?.0 {
|
||||||
if let targetIndex = starsProducts.firstIndex(where: { $0.reference == visibleItem.0.reference }) {
|
if let targetIndex = starsProducts.firstIndex(where: { $0.reference == visibleItem.0 }) {
|
||||||
self.reorderIfPossible(item: reorderItem, toIndex: targetIndex)
|
self.reorderIfPossible(reference: reorderItemReference, toIndex: targetIndex)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -307,7 +322,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func reorderIfPossible(item: ProfileGiftsContext.State.StarGift, toIndex: Int) {
|
private func reorderIfPossible(reference: StarGiftReference, toIndex: Int) {
|
||||||
if let items = self.starsProducts {
|
if let items = self.starsProducts {
|
||||||
var toIndex = toIndex
|
var toIndex = toIndex
|
||||||
|
|
||||||
@ -322,7 +337,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
return item.reference
|
return item.reference
|
||||||
}
|
}
|
||||||
|
|
||||||
if let reference = item.reference, let fromIndex = ids.firstIndex(of: reference) {
|
if let fromIndex = ids.firstIndex(of: reference) {
|
||||||
if fromIndex < toIndex {
|
if fromIndex < toIndex {
|
||||||
ids.insert(reference, at: toIndex + 1)
|
ids.insert(reference, at: toIndex + 1)
|
||||||
ids.remove(at: fromIndex)
|
ids.remove(at: fromIndex)
|
||||||
@ -401,7 +416,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
visibleItem = current
|
visibleItem = current
|
||||||
} else {
|
} else {
|
||||||
visibleItem = ComponentView()
|
visibleItem = ComponentView()
|
||||||
self.starsItems[itemId] = (product, visibleItem)
|
self.starsItems[itemId] = (product.reference, visibleItem)
|
||||||
itemTransition = .immediate
|
itemTransition = .immediate
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,11 +465,38 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
isEditing: self.isReordering,
|
isEditing: self.isReordering,
|
||||||
mode: .profile,
|
mode: .profile,
|
||||||
action: { [weak self] in
|
action: { [weak self] in
|
||||||
guard let self else {
|
guard let self, let presentationData = self.currentParams?.presentationData else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if self.isReordering {
|
if self.isReordering {
|
||||||
|
if !product.pinnedToTop, let reference = product.reference, let items = self.starsProducts {
|
||||||
|
if self.pinnedReferences.count >= self.maxPinnedCount {
|
||||||
|
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.PeerInfo_Gifts_ToastPinLimit_Text(Int32(self.maxPinnedCount)), timeout: nil, customUndoText: nil), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var reorderedPinnedReferences = Set<StarGiftReference>()
|
||||||
|
if let current = self.reorderedPinnedReferences {
|
||||||
|
reorderedPinnedReferences = current
|
||||||
|
}
|
||||||
|
reorderedPinnedReferences.insert(reference)
|
||||||
|
self.reorderedPinnedReferences = reorderedPinnedReferences
|
||||||
|
|
||||||
|
if let maxPinnedIndex = items.lastIndex(where: { $0.pinnedToTop }) {
|
||||||
|
var reorderedReferences: [StarGiftReference]
|
||||||
|
if let current = self.reorderedReferences {
|
||||||
|
reorderedReferences = current
|
||||||
|
} else {
|
||||||
|
let ids = items.compactMap { item -> StarGiftReference? in
|
||||||
|
return item.reference
|
||||||
|
}
|
||||||
|
reorderedReferences = ids
|
||||||
|
}
|
||||||
|
reorderedReferences.removeAll(where: { $0 == reference })
|
||||||
|
reorderedReferences.insert(reference, at: maxPinnedIndex + 1)
|
||||||
|
self.reorderedReferences = reorderedReferences
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let controller = GiftViewScreen(
|
let controller = GiftViewScreen(
|
||||||
context: self.context,
|
context: self.context,
|
||||||
@ -517,10 +559,15 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var itemFrame = itemFrame
|
var itemFrame = itemFrame
|
||||||
|
var isReordering = false
|
||||||
if let reorderingItem = self.reorderingItem, itemId == reorderingItem.id {
|
if let reorderingItem = self.reorderingItem, itemId == reorderingItem.id {
|
||||||
itemFrame = itemFrame.size.centered(around: reorderingItem.position)
|
itemFrame = itemFrame.size.centered(around: reorderingItem.position)
|
||||||
|
isReordering = true
|
||||||
}
|
}
|
||||||
|
if itemView.layer.animation(forKey: "position") != nil && !isReordering {
|
||||||
|
} else {
|
||||||
itemTransition.setFrame(view: itemView, frame: itemFrame)
|
itemTransition.setFrame(view: itemView, frame: itemFrame)
|
||||||
|
}
|
||||||
|
|
||||||
if self.isReordering && product.pinnedToTop {
|
if self.isReordering && product.pinnedToTop {
|
||||||
if itemView.layer.animation(forKey: "shaking_position") == nil {
|
if itemView.layer.animation(forKey: "shaking_position") == nil {
|
||||||
@ -933,6 +980,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
|
|
||||||
var items: [ContextMenuItem] = []
|
var items: [ContextMenuItem] = []
|
||||||
if canManage {
|
if canManage {
|
||||||
|
if case .unique = gift.gift {
|
||||||
items.append(.action(ContextMenuActionItem(text: gift.pinnedToTop ? strings.PeerInfo_Gifts_Context_Unpin : strings.PeerInfo_Gifts_Context_Pin , icon: { theme in generateTintedImage(image: UIImage(bundleImageName: gift.pinnedToTop ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
items.append(.action(ContextMenuActionItem(text: gift.pinnedToTop ? strings.PeerInfo_Gifts_Context_Unpin : strings.PeerInfo_Gifts_Context_Pin , icon: { theme in generateTintedImage(image: UIImage(bundleImageName: gift.pinnedToTop ? "Chat/Context Menu/Unpin" : "Chat/Context Menu/Pin"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||||
c?.dismiss(completion: { [weak self] in
|
c?.dismiss(completion: { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
@ -961,6 +1009,7 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
|
|||||||
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: !pinnedToTop ? "anim_toastunpin" : "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
self.parentController?.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: !pinnedToTop ? "anim_toastunpin" : "anim_toastpin", scale: 0.06, colors: [:], title: toastTitle, text: toastText, customUndoText: nil, timeout: 5), elevatedLayout: true, animateInAsReplacement: false, action: { _ in return false }), in: .window(.root))
|
||||||
})
|
})
|
||||||
})))
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
if canReorder {
|
if canReorder {
|
||||||
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_Reorder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
items.append(.action(ContextMenuActionItem(text: strings.PeerInfo_Gifts_Context_Reorder, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/ReorderItems"), color: theme.contextMenu.primaryColor) }, action: { [weak self] c, f in
|
||||||
|
Loading…
x
Reference in New Issue
Block a user