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
d09c539298
commit
5659120fa9
@ -12466,3 +12466,9 @@ Sorry for the inconvenience.";
|
||||
"WebApp.MinimizedTitleFormat" = "%1$@ & %2$@";
|
||||
"WebApp.MinimizedTitle.Others_1" = "%@ Other";
|
||||
"WebApp.MinimizedTitle.Others_any" = "%@ Others";
|
||||
|
||||
"Stars.SendStars.Title" = "Send Stars";
|
||||
"Stars.SendStars.AmountTitle" = "ENTER AMOUNT";
|
||||
"Stars.SendStars.AmountPlaceholder" = "Stars Amount";
|
||||
"Stars.SendStars.AmountInfo" = "Send %@ or more to highlight your profile in the TOP 3 supporters of this message.";
|
||||
"Stars.SendStars.SendStars" = "Confirm and Send";
|
||||
|
@ -153,6 +153,13 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
open var minimizedContainer: MinimizedContainer? {
|
||||
didSet {
|
||||
self.minimizedContainer?.navigationController = self
|
||||
self.minimizedContainer?.willMaximize = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isMaximizing = true
|
||||
self.updateContainersNonReentrant(transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1576,7 +1583,6 @@ open class NavigationController: UINavigationController, ContainableController,
|
||||
self.updateContainersNonReentrant(transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
|
||||
|
||||
self.minimizedContainer?.removeFromSupernode()
|
||||
self.minimizedContainer = minimizedContainer
|
||||
|
||||
|
@ -133,9 +133,10 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
|
||||
private struct SelectionState: Equatable {
|
||||
let selected: Bool
|
||||
let index: Int?
|
||||
let count: Int
|
||||
}
|
||||
private let selectionPromise = ValuePromise<SelectionState>(SelectionState(selected: false, count: 0))
|
||||
private let selectionPromise = ValuePromise<SelectionState>(SelectionState(selected: false, index: nil, count: 0))
|
||||
private let spoilerDisposable = MetaDisposable()
|
||||
var spoilerNode: SpoilerOverlayNode?
|
||||
var priceNode: PriceNode?
|
||||
@ -256,14 +257,16 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
|
||||
if let interaction = self.interaction, let selectionState = interaction.selectionState {
|
||||
let selected = selectionState.isIdentifierSelected(self.identifier)
|
||||
var selectionIndex: Int?
|
||||
if let selectableItem = self.selectableItem {
|
||||
let index = selectionState.index(of: selectableItem)
|
||||
if index != NSNotFound {
|
||||
self.checkNode?.content = .counter(Int(index))
|
||||
selectionIndex = Int(index)
|
||||
}
|
||||
}
|
||||
self.checkNode?.setSelected(selected, animated: animated)
|
||||
self.selectionPromise.set(SelectionState(selected: selected, count: selectionState.selectedItems().count))
|
||||
self.selectionPromise.set(SelectionState(selected: selected, index: selectionIndex, count: selectionState.selectedItems().count))
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,7 +295,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
self.durationNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.draftNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
self.priceNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
if animateSpoilerNode {
|
||||
if animateSpoilerNode || self.priceNode != nil {
|
||||
self.spoilerNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
}
|
||||
}
|
||||
@ -573,7 +576,7 @@ final class MediaPickerGridItemNode: GridItemNode {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.updateHasSpoiler(hasSpoiler, price: selectionState.selected ? price : nil, isSingle: selectionState.count == 1)
|
||||
strongSelf.updateHasSpoiler(hasSpoiler, price: selectionState.selected ? price : nil, isSingle: selectionState.count == 1 || selectionState.index == 1)
|
||||
}))
|
||||
|
||||
if self.currentDraftState != nil {
|
||||
|
@ -185,7 +185,7 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
self.didSetupSpoiler = true
|
||||
}
|
||||
|
||||
if hasSpoiler || price != nil {
|
||||
if hasSpoiler {
|
||||
if self.spoilerNode == nil {
|
||||
let spoilerNode = SpoilerOverlayNode(enableAnimations: self.enableAnimations)
|
||||
self.insertSubnode(spoilerNode, aboveSubnode: self.imageNode)
|
||||
@ -499,6 +499,8 @@ final class PriceNode: ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.isUserInteractionEnabled = false
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.backgroundNode.addSubnode(self.lockNode)
|
||||
self.backgroundNode.addSubnode(self.iconNode)
|
||||
@ -890,11 +892,24 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
self.reorderFeedback = HapticFeedback()
|
||||
}
|
||||
self.reorderFeedback?.impact()
|
||||
|
||||
let priceTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
for (_, node) in self.priceNodes {
|
||||
priceTransition.updateAlpha(node: node, alpha: 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
private func endReordering(point: CGPoint?) {
|
||||
if let reorderNode = self.reorderNode {
|
||||
self.reorderNode = nil
|
||||
|
||||
let completion = {
|
||||
let priceTransition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||
for (_, node) in self.priceNodes {
|
||||
node.supernode?.view.bringSubviewToFront(node.view)
|
||||
priceTransition.updateAlpha(node: node, alpha: 1.0)
|
||||
}
|
||||
}
|
||||
|
||||
if let itemNode = reorderNode.itemNode, let point = point {
|
||||
var targetNode: MediaPickerSelectedItemNode?
|
||||
@ -910,11 +925,13 @@ final class MediaPickerSelectedListNode: ASDisplayNode, ASScrollViewDelegate, AS
|
||||
}
|
||||
reorderNode.animateCompletion(completion: { [weak reorderNode] in
|
||||
reorderNode?.removeFromSupernode()
|
||||
completion()
|
||||
})
|
||||
self.reorderFeedback?.tap()
|
||||
} else {
|
||||
reorderNode.removeFromSupernode()
|
||||
reorderNode.itemNode?.isHidden = false
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ public struct CachedChannelFlags: OptionSet {
|
||||
public static let translationHidden = CachedChannelFlags(rawValue: 1 << 8)
|
||||
public static let adsRestricted = CachedChannelFlags(rawValue: 1 << 9)
|
||||
public static let canViewRevenue = CachedChannelFlags(rawValue: 1 << 10)
|
||||
public static let paidMediaAllowed = CachedChannelFlags(rawValue: 1 << 11)
|
||||
}
|
||||
|
||||
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
|
||||
|
@ -1096,6 +1096,34 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
}
|
||||
|
||||
public struct PaidMediaAllowed: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Bool
|
||||
|
||||
fileprivate var id: EnginePeer.Id
|
||||
public var mapKey: EnginePeer.Id {
|
||||
return self.id
|
||||
}
|
||||
|
||||
public init(id: EnginePeer.Id) {
|
||||
self.id = id
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .cachedPeerData(peerId: self.id)
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? CachedPeerDataView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
if let cachedData = view.cachedPeerData as? CachedChannelData {
|
||||
return cachedData.flags.contains(.paidMediaAllowed)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct BoostsToUnrestrict: TelegramEngineDataItem, TelegramEngineMapKeyDataItem, PostboxViewDataItem {
|
||||
public typealias Result = Int32?
|
||||
|
||||
|
@ -589,6 +589,9 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
if (flags2 & Int32(1 << 12)) != 0 {
|
||||
channelFlags.insert(.canViewRevenue)
|
||||
}
|
||||
if (flags2 & Int32(1 << 14)) != 0 {
|
||||
channelFlags.insert(.paidMediaAllowed)
|
||||
}
|
||||
|
||||
let sendAsPeerId = defaultSendAs?.peerId
|
||||
|
||||
|
@ -2948,7 +2948,13 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
contentSize.height += totalContentNodesHeight
|
||||
|
||||
if let paidContent = item.message.media.first(where: { $0 is TelegramMediaPaidContent }) as? TelegramMediaPaidContent, let media = paidContent.extendedMedia.first {
|
||||
var isLocked = false
|
||||
if case .preview = media {
|
||||
isLocked = true
|
||||
} else if item.presentationData.isPreview {
|
||||
isLocked = true
|
||||
}
|
||||
if isLocked {
|
||||
let sizeAndApply = unlockButtonLayout(ChatMessageUnlockMediaNode.Arguments(
|
||||
presentationData: item.presentationData,
|
||||
strings: item.presentationData.strings,
|
||||
|
@ -1140,11 +1140,21 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
|
||||
if let extendedMedia {
|
||||
switch extendedMedia {
|
||||
case let .preview(_, immediateThumbnailData, _):
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
media = thumbnailMedia
|
||||
case let .full(fullMedia):
|
||||
case let .preview(_, immediateThumbnailData, _):
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
media = thumbnailMedia
|
||||
case let .full(fullMedia):
|
||||
if presentationData.isPreview {
|
||||
if let image = fullMedia as? TelegramMediaImage {
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: image.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
media = thumbnailMedia
|
||||
} else if let video = fullMedia as? TelegramMediaFile {
|
||||
let thumbnailMedia = TelegramMediaImage(imageId: MediaId(namespace: 0, id: 0), representations: [], immediateThumbnailData: video.immediateThumbnailData, reference: nil, partialReference: nil, flags: [])
|
||||
media = thumbnailMedia
|
||||
}
|
||||
} else {
|
||||
media = fullMedia
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1475,7 +1485,7 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
extendedMedia = paidContent.extendedMedia[selectedMediaIndex]
|
||||
}
|
||||
}
|
||||
if let extendedMedia, case let .full(fullMedia) = extendedMedia {
|
||||
if let extendedMedia, case let .full(fullMedia) = extendedMedia, !presentationData.isPreview {
|
||||
isExtendedMedia = true
|
||||
media = fullMedia
|
||||
}
|
||||
@ -2366,6 +2376,11 @@ public final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTr
|
||||
icon = .lock
|
||||
}
|
||||
displaySpoiler = true
|
||||
} else if let _ = extendedMedia, isPreview {
|
||||
if let invoice, invoice.currency != "XTR" {
|
||||
icon = .lock
|
||||
}
|
||||
displaySpoiler = true
|
||||
} else if message.attributes.contains(where: { $0 is MediaSpoilerMessageAttribute }) {
|
||||
displaySpoiler = true
|
||||
} else if isSecretMedia {
|
||||
|
@ -193,7 +193,7 @@ public final class DrawingMessageRenderer {
|
||||
mainRadius: presentationData.chatBubbleCorners.mainRadius,
|
||||
auxiliaryRadius: presentationData.chatBubbleCorners.auxiliaryRadius,
|
||||
mergeBubbleCorners: presentationData.chatBubbleCorners.mergeBubbleCorners,
|
||||
hasTails: false
|
||||
hasTails: !self.isLink
|
||||
)
|
||||
|
||||
let avatarHeaderItem: ListViewItemHeader?
|
||||
|
@ -716,7 +716,7 @@ public class MinimizedContainerImpl: ASDisplayNode, MinimizedContainer, ASScroll
|
||||
itemFrame = effectiveItemFrame
|
||||
itemTransform = effectiveItemTransform
|
||||
|
||||
itemNode.isCovered = index == self.items.count - 2
|
||||
itemNode.isCovered = index <= self.items.count - 2
|
||||
}
|
||||
|
||||
itemNode.bounds = CGRect(origin: .zero, size: itemFrame.size)
|
||||
|
@ -643,7 +643,7 @@ public final class StarsImageComponent: Component {
|
||||
}
|
||||
|
||||
var totalLabelWidth: CGFloat = 0.0
|
||||
let labelSpacing: CGFloat = 3.0
|
||||
let labelSpacing: CGFloat = 4.0
|
||||
let lockView: UIImageView
|
||||
if let current = self.lockView {
|
||||
lockView = current
|
||||
|
@ -129,6 +129,14 @@ private final class SheetContent: CombinedComponent {
|
||||
|
||||
minAmount = 1
|
||||
maxAmount = configuration.maxPaidMediaAmount
|
||||
case .reaction:
|
||||
titleString = environment.strings.Stars_SendStars_Title
|
||||
amountTitle = environment.strings.Stars_SendStars_AmountTitle
|
||||
amountPlaceholder = environment.strings.Stars_SendStars_AmountPlaceholder
|
||||
|
||||
minAmount = 1
|
||||
//TODO:
|
||||
maxAmount = configuration.maxPaidMediaAmount
|
||||
}
|
||||
|
||||
let title = title.update(
|
||||
@ -142,7 +150,16 @@ private final class SheetContent: CombinedComponent {
|
||||
contentSize.height += title.size.height
|
||||
contentSize.height += 40.0
|
||||
|
||||
if case let .withdraw(starsState) = component.mode {
|
||||
let balance: Int64?
|
||||
if case .reaction = component.mode {
|
||||
balance = state.balance
|
||||
} else if case let .withdraw(starsState) = component.mode {
|
||||
balance = starsState.balances.availableBalance
|
||||
} else {
|
||||
balance = nil
|
||||
}
|
||||
|
||||
if let balance {
|
||||
let balanceTitle = balanceTitle.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
@ -158,7 +175,7 @@ private final class SheetContent: CombinedComponent {
|
||||
let balanceValue = balanceValue.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: presentationStringsFormattedNumber(Int32(starsState.balances.availableBalance), environment.dateTimeFormat.groupingSeparator),
|
||||
string: presentationStringsFormattedNumber(Int32(balance), environment.dateTimeFormat.groupingSeparator),
|
||||
font: Font.semibold(16.0),
|
||||
textColor: theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
@ -185,17 +202,18 @@ private final class SheetContent: CombinedComponent {
|
||||
)
|
||||
}
|
||||
|
||||
let amountFont = Font.regular(13.0)
|
||||
let amountTextColor = theme.list.freeTextColor
|
||||
let amountMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: amountFont, textColor: amountTextColor), bold: MarkdownAttributeSet(font: amountFont, textColor: amountTextColor), link: MarkdownAttributeSet(font: amountFont, textColor: theme.list.itemAccentColor), linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
})
|
||||
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== environment.theme {
|
||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||
}
|
||||
let amountFooter: AnyComponent<Empty>?
|
||||
if case .paidMedia = component.mode {
|
||||
let amountFont = Font.regular(13.0)
|
||||
let amountTextColor = theme.list.freeTextColor
|
||||
let amountMarkdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: amountFont, textColor: amountTextColor), bold: MarkdownAttributeSet(font: amountFont, textColor: amountTextColor), link: MarkdownAttributeSet(font: amountFont, textColor: theme.list.itemAccentColor), linkAttribute: { contents in
|
||||
return (TelegramTextAttributes.URL, contents)
|
||||
})
|
||||
switch component.mode {
|
||||
case .paidMedia:
|
||||
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_PaidContent_AmountInfo, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== environment.theme {
|
||||
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Contact List/SubtitleArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||
}
|
||||
if let range = amountInfoString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
|
||||
amountInfoString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: amountInfoString.string))
|
||||
}
|
||||
@ -214,7 +232,13 @@ private final class SheetContent: CombinedComponent {
|
||||
component.context.sharedContext.openExternalUrl(context: component.context, urlContext: .generic, url: strings.Stars_PaidContent_AmountInfo_URL, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {})
|
||||
}
|
||||
))
|
||||
} else {
|
||||
case let .reaction(starsToTop):
|
||||
let amountInfoString = NSMutableAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SendStars_AmountInfo("\(starsToTop ?? 0)").string, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||
amountFooter = AnyComponent(MultilineTextComponent(
|
||||
text: .plain(amountInfoString),
|
||||
maximumNumberOfLines: 0
|
||||
))
|
||||
default:
|
||||
amountFooter = nil
|
||||
}
|
||||
|
||||
@ -296,7 +320,7 @@ private final class SheetContent: CombinedComponent {
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
|
||||
),
|
||||
isEnabled: true,
|
||||
isEnabled: (state.amount ?? 0) > 0,
|
||||
displaysProgress: false,
|
||||
action: { [weak state] in
|
||||
if let controller = controller() as? StarsWithdrawScreen, let amount = state?.amount {
|
||||
@ -328,33 +352,56 @@ private final class SheetContent: CombinedComponent {
|
||||
|
||||
final class State: ComponentState {
|
||||
private let context: AccountContext
|
||||
private let mode: StarsWithdrawScreen.Mode
|
||||
|
||||
fileprivate var amount: Int64?
|
||||
|
||||
fileprivate var balance: Int64?
|
||||
private var stateDisposable: Disposable?
|
||||
|
||||
var cachedCloseImage: (UIImage, PresentationTheme)?
|
||||
var cachedStarImage: (UIImage, PresentationTheme)?
|
||||
var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
amount: Int64?
|
||||
mode: StarsWithdrawScreen.Mode
|
||||
) {
|
||||
self.context = context
|
||||
self.mode = mode
|
||||
|
||||
var amount: Int64?
|
||||
switch mode {
|
||||
case let .withdraw(stats):
|
||||
amount = stats.balances.availableBalance
|
||||
case let .paidMedia(initialValue):
|
||||
amount = initialValue
|
||||
case .reaction:
|
||||
amount = nil
|
||||
}
|
||||
|
||||
self.amount = amount
|
||||
|
||||
super.init()
|
||||
|
||||
if case .reaction = self.mode, let starsContext = context.starsContext {
|
||||
self.stateDisposable = (starsContext.state
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] state in
|
||||
if let self, let balance = state?.balance {
|
||||
self.balance = balance
|
||||
self.updated()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.stateDisposable?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
func makeState() -> State {
|
||||
var amount: Int64?
|
||||
switch self.mode {
|
||||
case let .withdraw(stats):
|
||||
amount = stats.balances.availableBalance
|
||||
case let .paidMedia(initialValue):
|
||||
amount = initialValue
|
||||
}
|
||||
return State(context: self.context, amount: amount)
|
||||
return State(context: self.context, mode: self.mode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -449,6 +496,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
||||
public enum Mode: Equatable {
|
||||
case withdraw(StarsRevenueStats)
|
||||
case paidMedia(Int64?)
|
||||
case reaction(Int64?)
|
||||
}
|
||||
|
||||
private let context: AccountContext
|
||||
@ -638,12 +686,11 @@ private final class AmountFieldComponent: Component {
|
||||
|
||||
if let component = self.component {
|
||||
let amount: Int64?
|
||||
if !newText.isEmpty, let value = Int64(newText) {
|
||||
if !newText.isEmpty, let value = Int64(normalizeArabicNumeralString(newText, type: .western)) {
|
||||
amount = value
|
||||
} else {
|
||||
amount = nil
|
||||
}
|
||||
|
||||
if let amount, let maxAmount = component.maxValue, amount > maxAmount {
|
||||
textField.text = "\(maxAmount)"
|
||||
self.textChanged(self.textField)
|
||||
|
Loading…
x
Reference in New Issue
Block a user