mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Add chat translation suggestion
This commit is contained in:
parent
a02ece5c0e
commit
a235246c49
@ -167,6 +167,8 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
||||
case audioTranscriptionSuggestion = 33
|
||||
case clearStorageDismissedTipSize = 34
|
||||
case dismissedTrendingEmojiPacks = 35
|
||||
case audioRateOptionsTip = 36
|
||||
case translationSuggestion = 37
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let v = ValueBoxKey(length: 4)
|
||||
@ -359,6 +361,14 @@ private struct ApplicationSpecificNoticeKeys {
|
||||
static func dismissedTrendingEmojiPacks() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedTrendingEmojiPacks.key)
|
||||
}
|
||||
|
||||
static func translationSuggestionNotice() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.translationSuggestion.key)
|
||||
}
|
||||
|
||||
static func audioRateOptionsTip() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.audioRateOptionsTip.key)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificNotice {
|
||||
@ -1207,22 +1217,84 @@ public struct ApplicationSpecificNotice {
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementAudioTranscriptionSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||
return accountManager.transaction { transaction -> Int in
|
||||
public static func incrementAudioTranscriptionSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int32 = 1) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
var currentValue: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.audioTranscriptionSuggestion())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += Int32(count)
|
||||
currentValue += count
|
||||
|
||||
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.audioTranscriptionSuggestion(), entry)
|
||||
}
|
||||
|
||||
return Int(previousValue)
|
||||
return previousValue
|
||||
}
|
||||
}
|
||||
|
||||
public static func translationSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<(Int32, Int32), NoError> {
|
||||
return accountManager.noticeEntry(key: ApplicationSpecificNoticeKeys.translationSuggestionNotice())
|
||||
|> map { view -> (Int32, Int32) in
|
||||
if let value = view.value?.get(ApplicationSpecificTimestampAndCounterNotice.self) {
|
||||
return (value.counter, value.timestamp)
|
||||
} else {
|
||||
return (0, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementTranslationSuggestion(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int32 = 1, timestamp: Int32) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
var currentValue: Int32 = 0
|
||||
var currentTimestamp: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.translationSuggestionNotice())?.get(ApplicationSpecificTimestampAndCounterNotice.self) {
|
||||
currentValue = value.counter
|
||||
currentTimestamp = value.timestamp
|
||||
}
|
||||
|
||||
if currentTimestamp > timestamp {
|
||||
return Int32(currentValue)
|
||||
} else {
|
||||
let previousValue = currentValue
|
||||
currentValue = max(0, Int32(currentValue + count))
|
||||
|
||||
if let entry = CodableEntry(ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp)) {
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.translationSuggestionNotice(), entry)
|
||||
}
|
||||
|
||||
return Int32(previousValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func getAudioRateOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.audioRateOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
return value.value
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementAudioRateOptionsTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int32 = 1) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
var currentValue: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.audioRateOptionsTip())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += count
|
||||
|
||||
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.audioRateOptionsTip(), entry)
|
||||
}
|
||||
return previousValue
|
||||
}
|
||||
}
|
||||
|
||||
public static func reset(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Void, NoError> {
|
||||
return accountManager.transaction { transaction -> Void in
|
||||
}
|
||||
|
@ -3550,7 +3550,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let f = {
|
||||
let _ = (context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { sharedData in
|
||||
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
let translationSettings: TranslationSettings
|
||||
if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) {
|
||||
translationSettings = current
|
||||
@ -3565,6 +3568,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
let (_, language) = canTranslateText(context: context, text: text.string, showTranslate: translationSettings.showTranslate, showTranslateIfTopical: showTranslateIfTopical, ignoredLanguages: translationSettings.ignoredLanguages)
|
||||
|
||||
let _ = ApplicationSpecificNotice.incrementTranslationSuggestion(accountManager: context.sharedContext.accountManager, timestamp: Int32(Date().timeIntervalSince1970)).start()
|
||||
|
||||
let controller = TranslateScreen(context: context, text: text.string, canCopy: canCopy, fromLanguage: language)
|
||||
controller.pushController = { [weak self] c in
|
||||
self?.effectiveNavigationController?._keepModalDismissProgress = true
|
||||
@ -6717,9 +6722,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.translationStateDisposable = (combineLatest(
|
||||
queue: .concurrentDefaultQueue(),
|
||||
isPremium,
|
||||
isHidden
|
||||
) |> mapToSignal { isPremium, isHidden -> Signal<ChatPresentationTranslationState?, NoError> in
|
||||
if isPremium && !isHidden {
|
||||
isHidden,
|
||||
ApplicationSpecificNotice.translationSuggestion(accountManager: self.context.sharedContext.accountManager)
|
||||
) |> mapToSignal { isPremium, isHidden, counterAndTimestamp -> Signal<ChatPresentationTranslationState?, NoError> in
|
||||
var maybeSuggestPremium = false
|
||||
if counterAndTimestamp.0 >= 3 {
|
||||
maybeSuggestPremium = true
|
||||
}
|
||||
if (isPremium || maybeSuggestPremium) && !isHidden {
|
||||
return chatTranslationState(context: context, peerId: peerId)
|
||||
|> map { translationState -> ChatPresentationTranslationState? in
|
||||
if let translationState, !translationState.fromLang.isEmpty {
|
||||
|
@ -16,6 +16,8 @@ import MoreButtonNode
|
||||
import ContextUI
|
||||
import TranslateUI
|
||||
import TelegramUIPreferences
|
||||
import TelegramNotices
|
||||
import PremiumUI
|
||||
|
||||
final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
private let context: AccountContext
|
||||
@ -26,7 +28,8 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
private let buttonIconNode: ASImageNode
|
||||
private let buttonTextNode: ImmediateTextNode
|
||||
private let moreButton: MoreButtonNode
|
||||
|
||||
private let closeButton: HighlightableButtonNode
|
||||
|
||||
private var theme: PresentationTheme?
|
||||
|
||||
private var chatInterfaceState: ChatPresentationInterfaceState?
|
||||
@ -47,6 +50,11 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
|
||||
self.moreButton = MoreButtonNode(theme: context.sharedContext.currentPresentationData.with { $0 }.theme)
|
||||
self.moreButton.iconNode.enqueueState(.more, animated: false)
|
||||
self.moreButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||
|
||||
self.closeButton = HighlightableButtonNode()
|
||||
self.closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0)
|
||||
self.closeButton.displaysAsynchronously = false
|
||||
|
||||
super.init()
|
||||
|
||||
@ -65,6 +73,9 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
strongSelf.morePressed(node: strongSelf.moreButton.contextSourceNode, gesture: gesture)
|
||||
}
|
||||
}
|
||||
|
||||
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
|
||||
self.addSubnode(self.closeButton)
|
||||
}
|
||||
|
||||
func animateOut() {
|
||||
@ -90,6 +101,7 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
self.buttonIconNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
|
||||
self.moreButton.theme = interfaceState.theme
|
||||
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
|
||||
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelEncircledCloseIconImage(interfaceState.theme), for: [])
|
||||
}
|
||||
|
||||
if themeUpdated || isEnabledUpdated {
|
||||
@ -139,6 +151,17 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
let moreButtonSize = self.moreButton.measure(CGSize(width: 100.0, height: panelHeight))
|
||||
self.moreButton.frame = CGRect(origin: CGPoint(x: width - contentRightInset - moreButtonSize.width, y: floorToScreenPixels((panelHeight - moreButtonSize.height) / 2.0)), size: moreButtonSize)
|
||||
|
||||
let closeButtonSize = self.closeButton.measure(CGSize(width: 100.0, height: 100.0))
|
||||
self.closeButton.frame: CGRect(origin: CGPoint(x: width - contentRightInset - closeButtonSize.width, y: floorToScreenPixels((panelHeight - closeButtonSize.height) / 2.0)), size: closeButtonSize)
|
||||
|
||||
if interfaceState.isPremium {
|
||||
self.moreButton.isHidden = false
|
||||
self.closeButton.isHidden = true
|
||||
} else {
|
||||
self.moreButton.isHidden = true
|
||||
self.closeButton.isHidden = false
|
||||
}
|
||||
|
||||
let buttonPadding: CGFloat = 10.0
|
||||
let buttonSpacing: CGFloat = 10.0
|
||||
let buttonTextSize = self.buttonTextNode.updateLayout(CGSize(width: width - contentRightInset - moreButtonSize.width, height: panelHeight))
|
||||
@ -154,12 +177,30 @@ final class ChatTranslationPanelNode: ASDisplayNode {
|
||||
return panelHeight
|
||||
}
|
||||
|
||||
@objc private func closePressed() {
|
||||
let _ = ApplicationSpecificNotice.incrementTranslationSuggestion(accountManager: self.context.sharedContext.accountManager, count: -100, timestamp: Int32(Date().timeIntervalSince1970) + 60 * 60 * 24 * 7).start()
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
guard let translationState = self.chatInterfaceState?.translationState else {
|
||||
return
|
||||
}
|
||||
|
||||
self.interfaceInteraction?.toggleTranslation(translationState.isEnabled ? .original : .translated)
|
||||
let isPremium = self.chatInterfaceState?.isPremium ?? false
|
||||
if isPremium {
|
||||
self.interfaceInteraction?.toggleTranslation(translationState.isEnabled ? .original : .translated)
|
||||
} else if !translationState.isEnabled {
|
||||
let context = self.context
|
||||
var replaceImpl: ((ViewController) -> Void)?
|
||||
let controller = PremiumDemoScreen(context: context, subject: .translation, action: {
|
||||
let controller = PremiumIntroScreen(context: context, source: .translation)
|
||||
replaceImpl?(controller)
|
||||
})
|
||||
replaceImpl = { [weak controller] c in
|
||||
controller?.replace(with: c)
|
||||
}
|
||||
self.interfaceInteraction?.chatController()?.push(controller)
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func morePressed(node: ContextReferenceContentNode, gesture: ContextGesture?) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user