Various fixes

This commit is contained in:
Ilya Laktyushin 2023-10-27 16:43:54 +04:00
parent f9f5aa683c
commit be556a3b5e
11 changed files with 102 additions and 40 deletions

View File

@ -10151,12 +10151,14 @@ Sorry for the inconvenience.";
"NameColor.UnsavedChanges.Apply" = "Apply";
"NameColor.YourColorUpdated" = "Your name color has been updated.";
"NameColor.ChannelColorUpdated" = "Channel name color has been updated.";
"Chat.ErrorQuoteOutdatedTitle" = "Quote Outdated";
"Chat.ErrorQuoteOutdatedText" = "**%@** updated the message you are quoting. Edit your quote to make it up-to-date.";
"Chat.ErrorQuoteOutdatedActionEdit" = "Edit";
"Premium.BoostByGiftDescription" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()";
"Premium.BoostByGiftDescription2" = "Boost your channel by gifting your subscribers Telegram Premium. [Get boosts >]()";
"ChatContextMenu.QuoteSelectionTip" = "Hold on a word, then move cursor to select more| text to quote.";
@ -10415,3 +10417,5 @@ Sorry for the inconvenience.";
"ChannelBoost.BoostAgain" = "Boost Again";
"Settings.New" = "NEW";
"ChannelBoost.Or" = "or";

View File

@ -968,6 +968,7 @@ public enum PremiumIntroSource {
case storiesExpirationDurations
case storiesSuggestedReactions
case channelBoost(EnginePeer.Id)
case nameColor
}
public enum PremiumDemoSubject {

View File

@ -175,23 +175,42 @@ public func PremiumBoostScreen(
replaceController?.dismiss(animated: true)
}
} else if let boost = occupiedBoosts.first, let occupiedPeer = boost.peer {
let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: {
currentMyBoostCount += 1
myBoostCount += 1
let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot])
|> deliverOnMainQueue).startStandalone(completed: { [weak controller] in
let _ = (updatedState.get()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak controller] state in
guard let state else {
return
}
let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount)
controller?.updateSubject(subject, count: count)
if let cooldown = boost.cooldownUntil {
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
let timeout = cooldown - currentTime
let valueText = timeIntervalString(strings: presentationData.strings, value: timeout, usage: .afterTime, preferLowerValue: false)
let controller = textAlertController(
sharedContext: context.sharedContext,
updatedPresentationData: nil,
title: presentationData.strings.ChannelBoost_Error_BoostTooOftenTitle,
text: presentationData.strings.ChannelBoost_Error_BoostTooOftenText(valueText).string,
actions: [
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})
],
parseMarkdown: true
)
presentController(controller)
} else {
let replaceController = replaceBoostConfirmationController(context: context, fromPeers: [occupiedPeer], toPeer: peer, commit: {
currentMyBoostCount += 1
myBoostCount += 1
let _ = (context.engine.peers.applyChannelBoost(peerId: peerId, slots: [boost.slot])
|> deliverOnMainQueue).startStandalone(completed: { [weak controller] in
let _ = (updatedState.get()
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak controller] state in
guard let state else {
return
}
let (subject, count) = state.displayData(peer: peer, isCurrent: isCurrent, canBoostAgain: canBoostAgain, myBoostCount: myBoostCount, currentMyBoostCount: currentMyBoostCount)
controller?.updateSubject(subject, count: count)
})
})
})
})
presentController(replaceController)
presentController(replaceController)
}
} else {
dismissImpl?()
}
} else {
if isPremium {

View File

@ -233,6 +233,12 @@ public enum PremiumSource: Equatable {
} else {
return false
}
case .nameColor:
if case .nameColor = rhs {
return true
} else {
return false
}
}
}
@ -270,6 +276,7 @@ public enum PremiumSource: Equatable {
case storiesExpirationDurations
case storiesSuggestedReactions
case channelBoost(EnginePeer.Id)
case nameColor
var identifier: String? {
switch self {
@ -343,6 +350,8 @@ public enum PremiumSource: Equatable {
return "stories__suggested_reactions"
case let .channelBoost(peerId):
return "channel_boost__\(peerId.id._internalGetInt64Value())"
case .nameColor:
return "name_color"
}
}
}

View File

@ -1541,7 +1541,7 @@ private final class LimitSheetContent: CombinedComponent {
var additionalContentHeight: CGFloat = 0.0
if case let .storiesChannelBoost(_, _, _, _, _, _, link, _, _) = component.subject, link != nil, let openGift = component.openGift {
let orText = orText.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))),
component: MultilineTextComponent(text: .plain(NSAttributedString(string: environment.strings.ChannelBoost_Or, font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
transition: .immediate
)
@ -1571,7 +1571,7 @@ private final class LimitSheetContent: CombinedComponent {
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, environment.theme)
}
let giftString = environment.strings.Premium_BoostByGiftDescription
let giftString = environment.strings.Premium_BoostByGiftDescription2
let giftAttributedString = parseMarkdownIntoAttributedString(giftString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {

View File

@ -125,12 +125,12 @@ private func generateRingImage(nameColor: PeerNameColors.Colors) -> UIImage? {
})
}
private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? {
return generateImage(CGSize(width: 40.0, height: 40.0), rotatedContext: { size, context in
let bounds = CGRect(origin: CGPoint(), size: size)
func generatePeerNameColorImage(nameColor: PeerNameColors.Colors, bounds: CGSize = CGSize(width: 40.0, height: 40.0), size: CGSize = CGSize(width: 40.0, height: 40.0)) -> UIImage? {
return generateImage(bounds, rotatedContext: { contextSize, context in
let bounds = CGRect(origin: CGPoint(), size: contextSize)
context.clear(bounds)
let circleBounds = bounds
let circleBounds = CGRect(origin: CGPoint(x: floorToScreenPixels((bounds.width - size.width) / 2.0), y: floorToScreenPixels((bounds.height - size.height) / 2.0)), size: size)
context.addEllipse(in: circleBounds)
context.clip()
@ -139,24 +139,26 @@ private func generateFillImage(nameColor: PeerNameColors.Colors) -> UIImage? {
context.fill(circleBounds)
if let thirdColor = nameColor.tertiary {
context.move(to: CGPoint(x: size.width, y: 0.0))
context.addLine(to: CGPoint(x: size.width, y: size.height))
context.addLine(to: CGPoint(x: 0.0, y: size.height))
context.move(to: CGPoint(x: contextSize.width, y: 0.0))
context.addLine(to: CGPoint(x: contextSize.width, y: contextSize.height))
context.addLine(to: CGPoint(x: 0.0, y: contextSize.height))
context.closePath()
context.setFillColor(nameColor.main.cgColor)
context.fillPath()
context.setFillColor(thirdColor.cgColor)
context.translateBy(x: size.width / 2.0, y: size.height / 2.0)
context.translateBy(x: contextSize.width / 2.0, y: contextSize.height / 2.0)
context.rotate(by: .pi / 4.0)
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -9.0, y: -9.0), size: CGSize(width: 18.0, height: 18.0)), cornerRadius: 4.0)
let rectSide = size.width / 40.0 * 18.0
let rectCornerRadius = round(size.width / 40.0 * 4.0)
let path = UIBezierPath(roundedRect: CGRect(origin: CGPoint(x: -rectSide / 2.0, y: -rectSide / 2.0), size: CGSize(width: rectSide, height: rectSide)), cornerRadius: rectCornerRadius)
context.addPath(path.cgPath)
context.fillPath()
} else {
context.move(to: .zero)
context.addLine(to: CGPoint(x: size.width, y: 0.0))
context.addLine(to: CGPoint(x: 0.0, y: size.height))
context.addLine(to: CGPoint(x: contextSize.width, y: 0.0))
context.addLine(to: CGPoint(x: 0.0, y: contextSize.height))
context.closePath()
context.setFillColor(nameColor.main.cgColor)
context.fillPath()
@ -230,7 +232,7 @@ private final class PeerNameColorIconItemNode : ListViewItemNode {
strongSelf.item = item
if updatedAccentColor {
strongSelf.fillNode.image = generateFillImage(nameColor: item.colors)
strongSelf.fillNode.image = generatePeerNameColorImage(nameColor: item.colors)
strongSelf.ringNode.image = generateRingImage(nameColor: item.colors)
}

View File

@ -280,6 +280,8 @@ public func PeerNameColorScreen(
statePromise.set(stateValue.modify { f($0) })
}
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
var presentImpl: ((ViewController) -> Void)?
var pushImpl: ((ViewController) -> Void)?
var dismissImpl: (() -> Void)?
@ -416,7 +418,7 @@ public func PeerNameColorScreen(
elevatedLayout: false,
action: { action in
if case .info = action {
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .storiesSuggestedReactions, forceDark: false, dismissed: nil)
let controller = context.sharedContext.makePremiumIntroController(context: context, source: .nameColor, forceDark: false, dismissed: nil)
pushImpl?(controller)
}
return true
@ -550,7 +552,7 @@ public func PeerNameColorScreen(
return attemptNavigationImpl?(f) ?? true
}
attemptNavigationImpl = { f in
if !context.isPremium {
if case .account = subject, !context.isPremium {
f()
return true
}
@ -583,19 +585,21 @@ public func PeerNameColorScreen(
return
}
let state = stateValue.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let nameColor = state.updatedNameColor ?? peer.nameColor
let backgroundEmojiId = state.updatedBackgroundEmojiId ?? peer.backgroundEmojiId
let colors = context.peerNameColors.get(nameColor ?? .blue, dark: presentationData.theme.overallDarkAppearance)
switch subject {
case .account:
let _ = context.engine.accountData.updateNameColorAndEmoji(nameColor: nameColor ?? .blue, backgroundEmojiId: backgroundEmojiId ?? 0).startStandalone()
if let navigationController = controller?.navigationController as? NavigationController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
Queue.mainQueue().after(0.25) {
if let lastController = navigationController.viewControllers.last as? ViewController {
let tipController = UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.NameColor_YourColorUpdated, timeout: nil, customUndoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })
let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_YourColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })
lastController.present(tipController, in: .window(.root))
}
}
@ -627,10 +631,10 @@ public func PeerNameColorScreen(
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
presentImpl?(UndoOverlayController(presentationData: presentationData, content: .linkCopied(text: presentationData.strings.ChannelBoost_BoostLinkCopied), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false }))
return true
}, openStats: nil, openGift: {
}, openStats: nil, openGift: premiumConfiguration.giveawayGiftsPurchaseAvailable ? {
let controller = createGiveawayController(context: context, peerId: peerId, subject: .generic)
pushImpl?(controller)
})
} : nil)
pushImpl?(controller)
HapticFeedback().impact(.light)
@ -644,6 +648,15 @@ public func PeerNameColorScreen(
return updatedState
}
}, completed: {
if let navigationController = controller?.navigationController as? NavigationController {
Queue.mainQueue().after(0.25) {
if let lastController = navigationController.viewControllers.last as? ViewController {
let tipController = UndoOverlayController(presentationData: presentationData, content: .image(image: generatePeerNameColorImage(nameColor: colors, bounds: CGSize(width: 32.0, height: 32.0), size: CGSize(width: 22.0, height: 22.0))!, title: nil, text: presentationData.strings.NameColor_ChannelColorUpdated, round: false, undoText: nil), elevatedLayout: false, position: .bottom, animateInAsReplacement: false, action: { _ in return false })
lastController.present(tipController, in: .window(.root))
}
}
}
dismissImpl?()
})
}

View File

@ -514,7 +514,7 @@ private final class StoryContainerScreenComponent: Component {
var apply = true
let currentTime = CACurrentMediaTime()
if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.1 {
if let previousTime = self.previousSeekTime, currentTime - previousTime < 0.15 {
apply = false
}
if apply {

View File

@ -496,7 +496,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
let botsKey = ValueBoxKey(length: 8)
botsKey.setInt64(0, value: 0)
var iconLoaded: [EnginePeer.Id: Bool] = [:]
let iconLoaded = Atomic<[EnginePeer.Id: Bool]>(value: [:])
let bots = context.engine.data.subscribe(TelegramEngine.EngineData.Item.ItemCache.Item(collectionId: Namespaces.CachedItemCollection.attachMenuBots, id: botsKey))
|> mapToSignal { entry -> Signal<[AttachMenuBot], NoError> in
let bots: [AttachMenuBots.Bot] = entry?.get(AttachMenuBots.self)?.bots ?? []
@ -512,7 +512,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
if let peer = PeerReference(peer._asPeer()), let icon = bot.icons[.iOSSettingsStatic] {
let fileReference: FileMediaReference = .attachBot(peer: peer, media: icon)
let signal: Signal<AttachMenuBot?, NoError>
if let _ = iconLoaded[peer.id] {
if let _ = iconLoaded.with({ $0 })[peer.id] {
signal = .single(resultBot)
} else {
signal = .single(nil)
@ -523,7 +523,11 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id,
return resultBot
}
|> afterNext { _ in
iconLoaded[peer.id] = true
let _ = iconLoaded.modify { current in
var updated = current
updated[peer.id] = true
return updated
}
}
)
}

View File

@ -1744,6 +1744,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
mappedSource = .storiesSuggestedReactions
case let .channelBoost(peerId):
mappedSource = .channelBoost(peerId)
case .nameColor:
mappedSource = .nameColor
}
let controller = PremiumIntroScreen(context: context, source: mappedSource, forceDark: forceDark)
controller.wasDismissed = dismissed

View File

@ -207,7 +207,15 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
for message in messages {
if message.effectivelyIncoming(context.account.peerId), message.text.count >= 10 {
var text = String(message.text.prefix(256))
if var entities = message.textEntitiesAttribute?.entities.filter({ [.Pre, .Code, .Url, .Email, .Mention, .Hashtag, .BotCommand].contains($0.type) }) {
if var entities = message.textEntitiesAttribute?.entities.filter({
if [.Code, .Url, .Email, .Mention, .Hashtag, .BotCommand].contains($0.type) {
return true
} else if case .Pre = $0.type {
return true
} else {
return false
}
}) {
entities = entities.sorted(by: { $0.range.lowerBound > $1.range.lowerBound })
var ranges: [Range<String.Index>] = []
for entity in entities {