Various Improvements

This commit is contained in:
Ilya Laktyushin 2021-09-13 21:45:57 +03:00
parent 5fb5c433bc
commit 330dc4c17e
9 changed files with 143 additions and 46 deletions

View File

@ -6715,12 +6715,15 @@ Sorry for the inconvenience.";
"UserInfo.ChangeColors" = "Change Colors"; "UserInfo.ChangeColors" = "Change Colors";
"Conversation.Theme.Title" = "Select Theme"; "Conversation.Theme.Title" = "Select Theme";
"Conversation.Theme.Subtitle" = "Theme will be also applied for %@";
"Conversation.Theme.Apply" = "Apply Theme"; "Conversation.Theme.Apply" = "Apply Theme";
"Conversation.Theme.NoTheme" = "No\nTheme"; "Conversation.Theme.NoTheme" = "No\nTheme";
"Conversation.Theme.Reset" = "Reset Theme for This Chat"; "Conversation.Theme.Reset" = "Reset Theme for This Chat";
"Conversation.Theme.DontSetTheme" = "Do Not Set Theme"; "Conversation.Theme.DontSetTheme" = "Do Not Set Theme";
"Conversation.Theme.SwitchToDark" = "Switch to dark appearance"; "Conversation.Theme.SwitchToDark" = "Switch to dark appearance";
"Conversation.Theme.SwitchToLight" = "Switch to light appearance"; "Conversation.Theme.SwitchToLight" = "Switch to light appearance";
"Conversation.Theme.PreviewDark" = "Tap to see how chat will appear to\n%@ when using night mode.";
"Conversation.Theme.PreviewLight" = "Tap to see how chat will appear to\n%@ when using day mode.";
"Conversation.Theme.DismissAlert" = "Do you want to apply the selected theme to the chat?"; "Conversation.Theme.DismissAlert" = "Do you want to apply the selected theme to the chat?";
"Conversation.Theme.DismissAlertApply" = "Apply"; "Conversation.Theme.DismissAlertApply" = "Apply";

View File

@ -104,6 +104,37 @@ public final class ApplicationSpecificTimestampNotice: NoticeEntry {
} }
} }
public final class ApplicationSpecificTimestampAndCounterNotice: NoticeEntry {
public let counter: Int32
public let timestamp: Int32
public init(counter: Int32, timestamp: Int32) {
self.counter = counter
self.timestamp = timestamp
}
public init(decoder: PostboxDecoder) {
self.counter = decoder.decodeInt32ForKey("v", orElse: 0)
self.timestamp = decoder.decodeInt32ForKey("t", orElse: 0)
}
public func encode(_ encoder: PostboxEncoder) {
encoder.encodeInt32(self.counter, forKey: "v")
encoder.encodeInt32(self.timestamp, forKey: "t")
}
public func isEqual(to: NoticeEntry) -> Bool {
if let to = to as? ApplicationSpecificTimestampAndCounterNotice {
if self.counter != to.counter || self.timestamp != to.timestamp {
return false
}
return true
} else {
return false
}
}
}
public final class ApplicationSpecificInt64ArrayNotice: NoticeEntry { public final class ApplicationSpecificInt64ArrayNotice: NoticeEntry {
public let values: [Int64] public let values: [Int64]
@ -167,9 +198,10 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
case locationProximityAlertTip = 20 case locationProximityAlertTip = 20
case nextChatSuggestionTip = 21 case nextChatSuggestionTip = 21
case dismissedTrendingStickerPacks = 22 case dismissedTrendingStickerPacks = 22
case chatSpecificThemesDarkPreviewTip = 23
case chatForwardOptionsTip = 24 case chatForwardOptionsTip = 24
case messageViewsPrivacyTips = 25 case messageViewsPrivacyTips = 25
case chatSpecificThemeLightPreviewTip = 26
case chatSpecificThemeDarkPreviewTip = 27
var key: ValueBoxKey { var key: ValueBoxKey {
let v = ValueBoxKey(length: 4) let v = ValueBoxKey(length: 4)
@ -314,8 +346,12 @@ private struct ApplicationSpecificNoticeKeys {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedTrendingStickerPacks.key) return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.dismissedTrendingStickerPacks.key)
} }
static func chatSpecificThemesDarkPreviewTip() -> NoticeEntryKey { static func chatSpecificThemeLightPreviewTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemesDarkPreviewTip.key) return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemeLightPreviewTip.key)
}
static func chatSpecificThemeDarkPreviewTip() -> NoticeEntryKey {
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.chatSpecificThemeDarkPreviewTip.key)
} }
static func chatForwardOptionsTip() -> NoticeEntryKey { static func chatForwardOptionsTip() -> NoticeEntryKey {
@ -850,26 +886,51 @@ public struct ApplicationSpecificNotice {
} }
} }
public static func getChatSpecificThemesDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> { public static func getChatSpecificThemeLightPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<(Int32, Int32), NoError> {
return accountManager.transaction { transaction -> Int32 in return accountManager.transaction { transaction -> (Int32, Int32) in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip()) as? ApplicationSpecificCounterNotice { if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice {
return value.value return (value.counter, value.timestamp)
} else { } else {
return 0 return (0, 0)
} }
} }
} }
public static func incrementChatSpecificThemesDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> { public static func incrementChatSpecificThemeLightPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1, timestamp: Int32) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0 var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip()) as? ApplicationSpecificCounterNotice { if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice {
currentValue = value.value currentValue = value.counter
} }
let previousValue = currentValue let previousValue = currentValue
currentValue += Int32(count) currentValue += Int32(count)
transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemesDarkPreviewTip(), ApplicationSpecificCounterNotice(value: currentValue)) transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeLightPreviewTip(), ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp))
return Int(previousValue)
}
}
public static func getChatSpecificThemeDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<(Int32, Int32), NoError> {
return accountManager.transaction { transaction -> (Int32, Int32) in
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice {
return (value.counter, value.timestamp)
} else {
return (0, 0)
}
}
}
public static func incrementChatSpecificThemeDarkPreviewTip(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1, timestamp: Int32) -> Signal<Int, NoError> {
return accountManager.transaction { transaction -> Int in
var currentValue: Int32 = 0
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip()) as? ApplicationSpecificTimestampAndCounterNotice {
currentValue = value.counter
}
let previousValue = currentValue
currentValue += Int32(count)
transaction.setNotice(ApplicationSpecificNoticeKeys.chatSpecificThemeDarkPreviewTip(), ApplicationSpecificTimestampAndCounterNotice(counter: currentValue, timestamp: timestamp))
return Int(previousValue) return Int(previousValue)
} }

View File

@ -13436,7 +13436,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
let selectedEmoticon: String? let selectedEmoticon: String?
if let cachedData = cachedData as? CachedUserData { if let cachedData = cachedData as? CachedUserData {
selectedEmoticon = cachedData.themeEmoticon selectedEmoticon = cachedData.themeEmoticon
@ -13448,7 +13448,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
selectedEmoticon = nil selectedEmoticon = nil
} }
let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, previewTheme: { [weak self] emoticon, dark in let controller = ChatThemeScreen(context: context, updatedPresentationData: strongSelf.updatedPresentationData, animatedEmojiStickers: animatedEmojiStickers, initiallySelectedEmoticon: selectedEmoticon, peerName: strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer?.compactDisplayTitle ?? "", previewTheme: { [weak self] emoticon, dark in
if let strongSelf = self { if let strongSelf = self {
strongSelf.presentCrossfadeSnapshot(delay: 0.2) strongSelf.presentCrossfadeSnapshot(delay: 0.2)
strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark))) strongSelf.themeEmoticonAndDarkAppearancePreviewPromise.set(.single((emoticon, dark)))

View File

@ -289,13 +289,13 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
actionTitle = item.presentationData.strings.Conversation_ViewGroup actionTitle = item.presentationData.strings.Conversation_ViewGroup
case "telegram_message": case "telegram_message":
actionTitle = item.presentationData.strings.Conversation_ViewMessage actionTitle = item.presentationData.strings.Conversation_ViewMessage
case "telegram_voicechat": case "telegram_voicechat", "telegram_videochat", "telegram_livestream":
if let channel = item.message.peers[item.message.id.peerId] as? TelegramChannel, case let .broadcast = channel.info { if type == "telegram_livestream" {
title = item.presentationData.strings.Conversation_LiveStream title = item.presentationData.strings.Conversation_LiveStream
} else { } else {
title = item.presentationData.strings.Conversation_VoiceChat title = item.presentationData.strings.Conversation_VoiceChat
} }
if webpage.url.contains("voicechat=") { if webpage.url.contains("voicechat=") || webpage.url.contains("videochat=") || webpage.url.contains("livestream=") {
actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsSpeaker actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsSpeaker
} else { } else {
actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsListener actionTitle = item.presentationData.strings.Conversation_JoinVoiceChatAsListener

View File

@ -530,7 +530,7 @@ final class ChatThemeScreen: ViewController {
private let context: AccountContext private let context: AccountContext
private let animatedEmojiStickers: [String: [StickerPackItem]] private let animatedEmojiStickers: [String: [StickerPackItem]]
private let initiallySelectedEmoticon: String? private let initiallySelectedEmoticon: String?
private let dismissByTapOutside: Bool private let peerName: String
private let previewTheme: (String?, Bool?) -> Void private let previewTheme: (String?, Bool?) -> Void
private let completion: (String?) -> Void private let completion: (String?) -> Void
@ -547,12 +547,12 @@ final class ChatThemeScreen: ViewController {
} }
} }
init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, dismissByTapOutside: Bool = true, previewTheme: @escaping (String?, Bool?) -> Void, completion: @escaping (String?) -> Void) { init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, peerName: String, previewTheme: @escaping (String?, Bool?) -> Void, completion: @escaping (String?) -> Void) {
self.context = context self.context = context
self.presentationData = updatedPresentationData.initial self.presentationData = updatedPresentationData.initial
self.animatedEmojiStickers = animatedEmojiStickers self.animatedEmojiStickers = animatedEmojiStickers
self.initiallySelectedEmoticon = initiallySelectedEmoticon self.initiallySelectedEmoticon = initiallySelectedEmoticon
self.dismissByTapOutside = dismissByTapOutside self.peerName = peerName
self.previewTheme = previewTheme self.previewTheme = previewTheme
self.completion = completion self.completion = completion
@ -582,7 +582,7 @@ final class ChatThemeScreen: ViewController {
} }
override public func loadDisplayNode() { override public func loadDisplayNode() {
self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, controller: self, animatedEmojiStickers: self.animatedEmojiStickers, initiallySelectedEmoticon: self.initiallySelectedEmoticon, dismissByTapOutside: self.dismissByTapOutside) self.displayNode = ChatThemeScreenNode(context: self.context, presentationData: self.presentationData, controller: self, animatedEmojiStickers: self.animatedEmojiStickers, initiallySelectedEmoticon: self.initiallySelectedEmoticon, peerName: self.peerName)
self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl self.controllerNode.passthroughHitTestImpl = self.passthroughHitTestImpl
self.controllerNode.previewTheme = { [weak self] emoticon, dark in self.controllerNode.previewTheme = { [weak self] emoticon, dark in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -675,7 +675,6 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
private let context: AccountContext private let context: AccountContext
private var presentationData: PresentationData private var presentationData: PresentationData
private weak var controller: ChatThemeScreen? private weak var controller: ChatThemeScreen?
private let dismissByTapOutside: Bool
private let dimNode: ASDisplayNode private let dimNode: ASDisplayNode
private let wrappingScrollNode: ASScrollNode private let wrappingScrollNode: ASScrollNode
@ -697,6 +696,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
private var enqueuedTransitions: [ThemeSettingsThemeItemNodeTransition] = [] private var enqueuedTransitions: [ThemeSettingsThemeItemNodeTransition] = []
private var initialized = false private var initialized = false
private let peerName: String
private let initiallySelectedEmoticon: String? private let initiallySelectedEmoticon: String?
private var selectedEmoticon: String? { private var selectedEmoticon: String? {
didSet { didSet {
@ -722,14 +723,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
var dismiss: (() -> Void)? var dismiss: (() -> Void)?
var cancel: (() -> Void)? var cancel: (() -> Void)?
init(context: AccountContext, presentationData: PresentationData, controller: ChatThemeScreen, animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, dismissByTapOutside: Bool) { init(context: AccountContext, presentationData: PresentationData, controller: ChatThemeScreen, animatedEmojiStickers: [String: [StickerPackItem]], initiallySelectedEmoticon: String?, peerName: String) {
self.context = context self.context = context
self.controller = controller self.controller = controller
self.initiallySelectedEmoticon = initiallySelectedEmoticon self.initiallySelectedEmoticon = initiallySelectedEmoticon
self.peerName = peerName
self.selectedEmoticon = initiallySelectedEmoticon self.selectedEmoticon = initiallySelectedEmoticon
self.selectedEmoticonPromise = ValuePromise(initiallySelectedEmoticon) self.selectedEmoticonPromise = ValuePromise(initiallySelectedEmoticon)
self.presentationData = presentationData self.presentationData = presentationData
self.dismissByTapOutside = dismissByTapOutside
self.wrappingScrollNode = ASScrollNode() self.wrappingScrollNode = ASScrollNode()
self.wrappingScrollNode.view.alwaysBounceVertical = true self.wrappingScrollNode.view.alwaysBounceVertical = true
@ -754,6 +755,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor let backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor
let textColor = self.presentationData.theme.actionSheet.primaryTextColor let textColor = self.presentationData.theme.actionSheet.primaryTextColor
let secondaryTextColor = self.presentationData.theme.actionSheet.secondaryTextColor
let blurStyle: UIBlurEffect.Style = self.presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark let blurStyle: UIBlurEffect.Style = self.presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark
self.effectNode = ASDisplayNode(viewBlock: { self.effectNode = ASDisplayNode(viewBlock: {
@ -763,11 +765,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.contentBackgroundNode = ASDisplayNode() self.contentBackgroundNode = ASDisplayNode()
self.contentBackgroundNode.backgroundColor = backgroundColor self.contentBackgroundNode.backgroundColor = backgroundColor
let title = self.presentationData.strings.Conversation_Theme_Title
self.titleNode = ASTextNode() self.titleNode = ASTextNode()
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.bold(17.0), textColor: textColor) self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.Conversation_Theme_Title, font: Font.semibold(16.0), textColor: textColor)
self.textNode = ImmediateTextNode() self.textNode = ImmediateTextNode()
self.textNode.attributedText = NSAttributedString(string: self.presentationData.strings.Conversation_Theme_Subtitle(peerName).string, font: Font.regular(12.0), textColor: secondaryTextColor)
self.cancelButton = HighlightableButtonNode() self.cancelButton = HighlightableButtonNode()
self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal) self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal)
@ -850,6 +852,11 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
doneButtonTitle = strongSelf.presentationData.strings.Conversation_Theme_Apply doneButtonTitle = strongSelf.presentationData.strings.Conversation_Theme_Apply
} }
strongSelf.doneButton.title = doneButtonTitle strongSelf.doneButton.title = doneButtonTitle
strongSelf.themeSelectionsCount += 1
if strongSelf.themeSelectionsCount == 2 {
strongSelf.maybePresentPreviewTooltip()
}
} }
} }
let previousEntries = strongSelf.entries ?? [] let previousEntries = strongSelf.entries ?? []
@ -945,7 +952,8 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
let previousTheme = self.presentationData.theme let previousTheme = self.presentationData.theme
self.presentationData = presentationData self.presentationData = presentationData
self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor) self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.semibold(16.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
self.textNode.attributedText = NSAttributedString(string: self.textNode.attributedText?.string ?? "", font: Font.regular(12.0), textColor: self.presentationData.theme.actionSheet.secondaryTextColor)
if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout { if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
@ -1009,7 +1017,7 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.previewTheme?(self.selectedEmoticon, isDarkAppearance) self.previewTheme?(self.selectedEmoticon, isDarkAppearance)
self.isDarkAppearance = isDarkAppearance self.isDarkAppearance = isDarkAppearance
let _ = ApplicationSpecificNotice.incrementChatSpecificThemesDarkPreviewTip(accountManager: self.context.sharedContext.accountManager, count: 3).start() let _ = ApplicationSpecificNotice.incrementChatSpecificThemeDarkPreviewTip(accountManager: self.context.sharedContext.accountManager, count: 3, timestamp: Int32(Date().timeIntervalSince1970)).start()
} }
private func animateCrossfade(animateIcon: Bool = true) { private func animateCrossfade(animateIcon: Bool = true) {
@ -1068,20 +1076,40 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
self.bounds = targetBounds self.bounds = targetBounds
self.dimNode.position = dimPosition self.dimNode.position = dimPosition
}) })
}
private var themeSelectionsCount = 0
private var displayedPreviewTooltip = false
private func maybePresentPreviewTooltip() {
guard !self.displayedPreviewTooltip, !self.animatedOut else {
return
}
let frame = self.switchThemeButton.view.convert(self.switchThemeButton.bounds, to: self.view) let frame = self.switchThemeButton.view.convert(self.switchThemeButton.bounds, to: self.view)
let currentTimestamp = Int32(Date().timeIntervalSince1970)
let _ = (ApplicationSpecificNotice.getChatSpecificThemesDarkPreviewTip(accountManager: self.context.sharedContext.accountManager) let isDark = self.presentationData.theme.overallDarkAppearance
|> deliverOnMainQueue).start(next: { [weak self] count in
if let strongSelf = self, count < 3 { let signal: Signal<(Int32, Int32), NoError>
Queue.mainQueue().after(1.0) { if isDark {
if !strongSelf.animatedOut { signal = ApplicationSpecificNotice.getChatSpecificThemeLightPreviewTip(accountManager: self.context.sharedContext.accountManager)
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, text: strongSelf.presentationData.theme.overallDarkAppearance ? strongSelf.presentationData.strings.Conversation_Theme_SwitchToLight : strongSelf.presentationData.strings.Conversation_Theme_SwitchToDark, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in } else {
return .dismiss(consume: false) signal = ApplicationSpecificNotice.getChatSpecificThemeDarkPreviewTip(accountManager: self.context.sharedContext.accountManager)
})) }
let _ = ApplicationSpecificNotice.incrementChatSpecificThemesDarkPreviewTip(accountManager: strongSelf.context.sharedContext.accountManager).start() let _ = (signal
} |> deliverOnMainQueue).start(next: { [weak self] count, timestamp in
if let strongSelf = self, count < 2 && currentTimestamp > timestamp + 24 * 60 * 60 {
strongSelf.displayedPreviewTooltip = true
strongSelf.present?(TooltipScreen(account: strongSelf.context.account, text: isDark ? strongSelf.presentationData.strings.Conversation_Theme_PreviewLight(strongSelf.peerName).string : strongSelf.presentationData.strings.Conversation_Theme_PreviewDark(strongSelf.peerName).string, style: .default, icon: nil, location: .point(frame.offsetBy(dx: 3.0, dy: 6.0), .bottom), displayDuration: .custom(3.0), inset: 3.0, shouldDismissOnTouch: { _ in
return .dismiss(consume: false)
}))
if isDark {
let _ = ApplicationSpecificNotice.incrementChatSpecificThemeLightPreviewTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start()
} else {
let _ = ApplicationSpecificNotice.incrementChatSpecificThemeDarkPreviewTip(accountManager: strongSelf.context.sharedContext.accountManager, timestamp: currentTimestamp).start()
} }
} }
}) })
@ -1157,10 +1185,14 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
transition.updateFrame(node: self.wrappingScrollNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: self.wrappingScrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
let titleSize = self.titleNode.measure(CGSize(width: width, height: titleHeight)) let titleSize = self.titleNode.measure(CGSize(width: width - 90.0, height: titleHeight))
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 18.0), size: titleSize) let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 11.0 + UIScreenPixel), size: titleSize)
transition.updateFrame(node: self.titleNode, frame: titleFrame) transition.updateFrame(node: self.titleNode, frame: titleFrame)
let textSize = self.textNode.updateLayout(CGSize(width: width - 90.0, height: titleHeight))
let textFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - textSize.width) / 2.0), y: 31.0), size: textSize)
transition.updateFrame(node: self.textNode, frame: textFrame)
let switchThemeSize = CGSize(width: 44.0, height: 44.0) let switchThemeSize = CGSize(width: 44.0, height: 44.0)
let switchThemeFrame = CGRect(origin: CGPoint(x: 3.0, y: 6.0), size: switchThemeSize) let switchThemeFrame = CGRect(origin: CGPoint(x: 3.0, y: 6.0), size: switchThemeSize)
transition.updateFrame(node: self.switchThemeButton, frame: switchThemeFrame) transition.updateFrame(node: self.switchThemeButton, frame: switchThemeFrame)

View File

@ -28,6 +28,7 @@ private var telegramUIDeclaredEncodables: Void = {
declareEncodable(ApplicationSpecificVariantNotice.self, f: { ApplicationSpecificVariantNotice(decoder: $0) }) declareEncodable(ApplicationSpecificVariantNotice.self, f: { ApplicationSpecificVariantNotice(decoder: $0) })
declareEncodable(ApplicationSpecificCounterNotice.self, f: { ApplicationSpecificCounterNotice(decoder: $0) }) declareEncodable(ApplicationSpecificCounterNotice.self, f: { ApplicationSpecificCounterNotice(decoder: $0) })
declareEncodable(ApplicationSpecificTimestampNotice.self, f: { ApplicationSpecificTimestampNotice(decoder: $0) }) declareEncodable(ApplicationSpecificTimestampNotice.self, f: { ApplicationSpecificTimestampNotice(decoder: $0) })
declareEncodable(ApplicationSpecificTimestampAndCounterNotice.self, f: { ApplicationSpecificTimestampAndCounterNotice(decoder: $0) })
declareEncodable(ApplicationSpecificInt64ArrayNotice.self, f: { ApplicationSpecificInt64ArrayNotice(decoder: $0) }) declareEncodable(ApplicationSpecificInt64ArrayNotice.self, f: { ApplicationSpecificInt64ArrayNotice(decoder: $0) })
declareEncodable(CallListSettings.self, f: { CallListSettings(decoder: $0) }) declareEncodable(CallListSettings.self, f: { CallListSettings(decoder: $0) })
declareEncodable(VoiceCallSettings.self, f: { VoiceCallSettings(decoder: $0) }) declareEncodable(VoiceCallSettings.self, f: { VoiceCallSettings(decoder: $0) })

View File

@ -624,10 +624,10 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
game = value game = value
} else if queryItem.name == "post" { } else if queryItem.name == "post" {
post = value post = value
} else if queryItem.name == "voicechat" { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
voiceChat = value voiceChat = value
} }
} else if queryItem.name == "voicechat" { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
voiceChat = "" voiceChat = ""
} }
} }

View File

@ -49,7 +49,7 @@ private let validUrlSet: CharacterSet = {
var set = CharacterSet(charactersIn: "a".unicodeScalars.first! ... "z".unicodeScalars.first!) var set = CharacterSet(charactersIn: "a".unicodeScalars.first! ... "z".unicodeScalars.first!)
set.insert(charactersIn: "A".unicodeScalars.first! ... "Z".unicodeScalars.first!) set.insert(charactersIn: "A".unicodeScalars.first! ... "Z".unicodeScalars.first!)
set.insert(charactersIn: "0".unicodeScalars.first! ... "9".unicodeScalars.first!) set.insert(charactersIn: "0".unicodeScalars.first! ... "9".unicodeScalars.first!)
set.insert(charactersIn: ".?!@#$^&%*+=,:;'\"`<>()[]{}/\\|~ ") set.insert(charactersIn: ".?!@#$^&%*-+=,:;'\"`<>()[]{}/\\|~ ")
return set return set
}() }()

View File

@ -136,10 +136,10 @@ public func parseInternalUrl(query: String) -> ParsedInternalUrl? {
return .peerName(peerName, .groupBotStart(value)) return .peerName(peerName, .groupBotStart(value))
} else if queryItem.name == "game" { } else if queryItem.name == "game" {
return nil return nil
} else if queryItem.name == "voicechat" { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(value)) return .peerName(peerName, .voiceChat(value))
} }
} else if queryItem.name == "voicechat" { } else if ["voicechat", "videochat", "livestream"].contains(queryItem.name) {
return .peerName(peerName, .voiceChat(nil)) return .peerName(peerName, .voiceChat(nil))
} }
} }