Various improvements

This commit is contained in:
Ilya Laktyushin 2023-02-25 18:00:45 +04:00
parent 96496aabd9
commit 441e102b0d
23 changed files with 215 additions and 94 deletions

View File

@ -8911,8 +8911,9 @@ Sorry for the inconvenience.";
"ChatList.EmptyChatListWithArchive" = "All of your chats are archived.";
"Conversation.AudioRateTooltip15X" = "Audio will play at 1.5X speed.";
"Conversation.AudioRateTooltip15X" = "Audio will play at 1.5x speed.";
"Conversation.AudioRateOptionsTooltip" = "Long tap for more speed values.";
"Conversation.AudioRateTooltipCustom" = "Audio will play at %@x speed.";
"ImportStickerPack.EmojiCount_1" = "%@ Emoji";
"ImportStickerPack.EmojiCount_any" = "%@ Emojis";
@ -8936,3 +8937,5 @@ Sorry for the inconvenience.";
"ChatList.ReadAll" = "Read All";
"ChatList.ClearSavedMessagesConfirmation" = "Are you sure you want to delete all your saved messages?";
"Conversation.Translation.Settings" = "Settings";

View File

@ -751,6 +751,7 @@ public protocol SharedAccountContext: AnyObject {
var immediateExperimentalUISettings: ExperimentalUISettings { get }
var currentInAppNotificationSettings: Atomic<InAppNotificationSettings> { get }
var currentMediaInputSettings: Atomic<MediaInputSettings> { get }
var currentStickerSettings: Atomic<StickerSettings> { get }
var energyUsageSettings: EnergyUsageSettings { get }

View File

@ -2715,7 +2715,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
mediaAccessoryPanel.setRate = { [weak self] rate, changeType in
guard let strongSelf = self else {
return
}
@ -2756,10 +2756,25 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
rate = 2.0
} else {
text = nil
rate = nil
let value = String(format: "%0.1f", baseRate.doubleValue)
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
if case let .sliderCommit(previousValue, newValue) = changeType {
if newValue > previousValue {
rate = .infinity
} else if newValue < previousValue {
rate = -.infinity
} else {
rate = nil
}
} else {
rate = nil
}
}
if let rate, let text, !fromMenu {
var showTooltip = true
if case .sliderChange = changeType {
showTooltip = false
}
if let rate, let text, showTooltip {
controller.present(
UndoOverlayController(
presentationData: presentationData,

View File

@ -615,16 +615,8 @@ final class ChatImageGalleryItemNode: ZoomableContentGalleryItemNode {
func setFile(context: AccountContext, userLocation: MediaResourceUserLocation, fileReference: FileMediaReference) {
if self.contextAndMedia == nil || !self.contextAndMedia!.1.media.isEqual(to: fileReference.media) {
if var largestSize = fileReference.media.dimensions {
var displaySize = largestSize.cgSize.dividedByScreenScale()
if let previewDimensions = largestImageRepresentation(fileReference.media.previewRepresentations)?.dimensions {
let previewAspect = CGFloat(previewDimensions.width) / CGFloat(previewDimensions.height)
let aspect = displaySize.width / displaySize.height
if abs(previewAspect - 1.0 / aspect) < 0.1 {
displaySize = CGSize(width: displaySize.height, height: displaySize.width)
largestSize = PixelDimensions(width: largestSize.height, height: largestSize.width)
}
}
if let largestSize = fileReference.media.dimensions {
let displaySize = largestSize.cgSize.dividedByScreenScale()
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets()))()
/*if largestSize.width > 2600 || largestSize.height > 2600 {

View File

@ -1904,19 +1904,23 @@ public func channelVisibilityController(context: AccountContext, updatedPresenta
}
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
let text: String
if case .broadcast = peer.info {
text = presentationData.strings.Channel_Edit_PrivatePublicLinkAlert
if !updatedAddressNameValue.isEmpty {
_ = (ApplicationSpecificNotice.getSetPublicChannelLink(accountManager: context.sharedContext.accountManager) |> deliverOnMainQueue).start(next: { showAlert in
if showAlert {
let text: String
if case .broadcast = peer.info {
text = presentationData.strings.Channel_Edit_PrivatePublicLinkAlert
} else {
text = presentationData.strings.Group_Edit_PrivatePublicLinkAlert
}
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
text = presentationData.strings.Group_Edit_PrivatePublicLinkAlert
invokeAction()
}
presentControllerImpl?(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: invokeAction)]), nil)
} else {
invokeAction()
}
})
})
} else {
invokeAction()
}
} else {
switch mode {
case .initialSetup:

View File

@ -465,8 +465,15 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
if let languages = translationSettings.ignoredLanguages {
ignoredLanguages = languages
} else {
if let activeLanguage = activeLanguageCode, supportedTranslationLanguages.contains(activeLanguage) {
ignoredLanguages = [activeLanguage]
if var activeLanguage = activeLanguageCode {
let rawSuffix = "-raw"
if activeLanguage.hasSuffix(rawSuffix) {
activeLanguage = String(activeLanguage.dropLast(rawSuffix.count))
}
if supportedTranslationLanguages.contains(activeLanguage) {
ignoredLanguages = [activeLanguage]
}
}
let systemLanguages = systemLanguageCodes()
for systemLanguage in systemLanguages {

View File

@ -77,13 +77,17 @@ private func translationSettingsControllerEntries(theme: PresentationTheme, stri
if let ignoredLanguages = settings.ignoredLanguages {
selectedLanguages = Set(ignoredLanguages)
} else {
var langCode = strings.baseLanguageCode
if langCode == "nb" {
langCode = "no"
} else if langCode == "pt-br" {
langCode = "pt"
var activeLanguage = strings.baseLanguageCode
let rawSuffix = "-raw"
if activeLanguage.hasSuffix(rawSuffix) {
activeLanguage = String(activeLanguage.dropLast(rawSuffix.count))
}
selectedLanguages = Set([langCode])
if activeLanguage == "nb" {
activeLanguage = "no"
} else if activeLanguage == "pt-br" {
activeLanguage = "pt"
}
selectedLanguages = Set([activeLanguage])
for language in systemLanguageCodes() {
selectedLanguages.insert(language)
}
@ -114,7 +118,11 @@ public func translationSettingsController(context: AccountContext) -> ViewContro
let actionsDisposable = DisposableSet()
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let interfaceLanguageCode = presentationData.strings.baseLanguageCode
var interfaceLanguageCode = presentationData.strings.baseLanguageCode
let rawSuffix = "-raw"
if interfaceLanguageCode.hasSuffix(rawSuffix) {
interfaceLanguageCode = String(interfaceLanguageCode.dropLast(rawSuffix.count))
}
let arguments = TranslationSettingsControllerArguments(context: context, updateLanguageSelected: { code, value in
let _ = updateTranslationSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in
@ -185,7 +193,12 @@ public func translationSettingsController(context: AccountContext) -> ViewContro
if let ignoredLanguages = settings.ignoredLanguages {
selectedLanguages = Set(ignoredLanguages)
} else {
selectedLanguages = Set([presentationData.strings.baseLanguageCode])
var activeLanguage = presentationData.strings.baseLanguageCode
let rawSuffix = "-raw"
if activeLanguage.hasSuffix(rawSuffix) {
activeLanguage = String(activeLanguage.dropLast(rawSuffix.count))
}
selectedLanguages = Set([activeLanguage])
for language in systemLanguageCodes() {
selectedLanguages.insert(language)
}

View File

@ -174,7 +174,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
public var tapAction: (() -> Void)?
public var close: (() -> Void)?
public var setRate: ((AudioPlaybackRate, Bool) -> Void)?
public var setRate: ((AudioPlaybackRate, MediaNavigationAccessoryPanel.ChangeType) -> Void)?
public var togglePlayPause: (() -> Void)?
public var playPrevious: (() -> Void)?
public var playNext: (() -> Void)?
@ -500,7 +500,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
} else {
nextRate = .x2
}
self.setRate?(nextRate, false)
self.setRate?(nextRate, .preset)
let frame = self.rateButton.view.convert(self.rateButton.bounds, to: nil)
@ -527,8 +527,10 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
private func contextMenuSpeedItems(dismiss: @escaping () -> Void) -> Signal<[ContextMenuItem], NoError> {
var items: [ContextMenuItem] = []
items.append(.custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: self.playbackBaseRate?.doubleValue ?? 1.0, valueChanged: { [weak self] newValue, finished in
self?.setRate?(AudioPlaybackRate(newValue), true)
let previousValue = self.playbackBaseRate?.doubleValue ?? 1.0
items.append(.custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: previousValue, valueChanged: { [weak self] newValue, finished in
let type: MediaNavigationAccessoryPanel.ChangeType = finished ? .sliderCommit(previousValue, newValue) : .sliderChange
self?.setRate?(AudioPlaybackRate(newValue), type)
if finished {
dismiss()
}
@ -547,7 +549,7 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
}, action: { [weak self] _, f in
f(.default)
self?.setRate?(rate, true)
self?.setRate?(rate, .preset)
})))
}

View File

@ -10,8 +10,14 @@ import TelegramPresentationData
public final class MediaNavigationAccessoryPanel: ASDisplayNode {
public let containerNode: MediaNavigationAccessoryContainerNode
public enum ChangeType {
case preset
case sliderChange
case sliderCommit(CGFloat, CGFloat)
}
public var close: (() -> Void)?
public var setRate: ((AudioPlaybackRate, Bool) -> Void)?
public var setRate: ((AudioPlaybackRate, ChangeType) -> Void)?
public var togglePlayPause: (() -> Void)?
public var tapAction: (() -> Void)?
public var playPrevious: (() -> Void)?
@ -34,8 +40,8 @@ public final class MediaNavigationAccessoryPanel: ASDisplayNode {
close()
}
}
self.containerNode.headerNode.setRate = { [weak self] rate, fromMenu in
self?.setRate?(rate, fromMenu)
self.containerNode.headerNode.setRate = { [weak self] rate, type in
self?.setRate?(rate, type)
}
self.containerNode.headerNode.togglePlayPause = { [weak self] in
if let strongSelf = self, let togglePlayPause = strongSelf.togglePlayPause {

View File

@ -669,7 +669,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
mediaAccessoryPanel.setRate = { [weak self] rate, changeType in
guard let strongSelf = self else {
return
}
@ -709,10 +709,25 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
rate = 2.0
} else {
text = nil
rate = nil
let value = String(format: "%0.1f", baseRate.doubleValue)
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
if case let .sliderCommit(previousValue, newValue) = changeType {
if newValue > previousValue {
rate = .infinity
} else if newValue < previousValue {
rate = -.infinity
} else {
rate = nil
}
} else {
rate = nil
}
}
if let rate, let text, !fromMenu {
var showTooltip = true
if case .sliderChange = changeType {
showTooltip = false
}
if let rate, let text, showTooltip {
strongSelf.present(
UndoOverlayController(
presentationData: presentationData,

View File

@ -218,15 +218,17 @@ public final class InitialPresentationDataAndSettings {
public let callListSettings: CallListSettings
public let inAppNotificationSettings: InAppNotificationSettings
public let mediaInputSettings: MediaInputSettings
public let stickerSettings: StickerSettings
public let experimentalUISettings: ExperimentalUISettings
public init(presentationData: PresentationData, automaticMediaDownloadSettings: MediaAutoDownloadSettings, autodownloadSettings: AutodownloadSettings, callListSettings: CallListSettings, inAppNotificationSettings: InAppNotificationSettings, mediaInputSettings: MediaInputSettings, experimentalUISettings: ExperimentalUISettings) {
public init(presentationData: PresentationData, automaticMediaDownloadSettings: MediaAutoDownloadSettings, autodownloadSettings: AutodownloadSettings, callListSettings: CallListSettings, inAppNotificationSettings: InAppNotificationSettings, mediaInputSettings: MediaInputSettings, stickerSettings: StickerSettings, experimentalUISettings: ExperimentalUISettings) {
self.presentationData = presentationData
self.automaticMediaDownloadSettings = automaticMediaDownloadSettings
self.autodownloadSettings = autodownloadSettings
self.callListSettings = callListSettings
self.inAppNotificationSettings = inAppNotificationSettings
self.mediaInputSettings = mediaInputSettings
self.stickerSettings = stickerSettings
self.experimentalUISettings = experimentalUISettings
}
}
@ -242,6 +244,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
var mediaInputSettings: PreferencesEntry?
var experimentalUISettings: PreferencesEntry?
var contactSynchronizationSettings: PreferencesEntry?
var stickerSettings: PreferencesEntry?
init(
localizationSettings: PreferencesEntry?,
@ -252,7 +255,8 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
inAppNotificationSettings: PreferencesEntry?,
mediaInputSettings: PreferencesEntry?,
experimentalUISettings: PreferencesEntry?,
contactSynchronizationSettings: PreferencesEntry?
contactSynchronizationSettings: PreferencesEntry?,
stickerSettings: PreferencesEntry?
) {
self.localizationSettings = localizationSettings
self.presentationThemeSettings = presentationThemeSettings
@ -263,6 +267,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
self.mediaInputSettings = mediaInputSettings
self.experimentalUISettings = experimentalUISettings
self.contactSynchronizationSettings = contactSynchronizationSettings
self.stickerSettings = stickerSettings
}
}
@ -276,6 +281,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
let mediaInputSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.mediaInputSettings)
let experimentalUISettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings)
let contactSynchronizationSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.contactSynchronizationSettings)
let stickerSettings = transaction.getSharedData(ApplicationSpecificSharedDataKeys.stickerSettings)
return InternalData(
localizationSettings: localizationSettings,
@ -286,7 +292,8 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
inAppNotificationSettings: inAppNotificationSettings,
mediaInputSettings: mediaInputSettings,
experimentalUISettings: experimentalUISettings,
contactSynchronizationSettings: contactSynchronizationSettings
contactSynchronizationSettings: contactSynchronizationSettings,
stickerSettings: stickerSettings
)
}
|> deliverOn(Queue(name: "PresentationData-Load", qos: .userInteractive))
@ -340,6 +347,13 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
mediaInputSettings = MediaInputSettings.defaultSettings
}
let stickerSettings: StickerSettings
if let value = internalData.stickerSettings?.get(StickerSettings.self) {
stickerSettings = value
} else {
stickerSettings = StickerSettings.defaultSettings
}
let experimentalUISettings: ExperimentalUISettings = internalData.experimentalUISettings?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings
let contactSettings: ContactSynchronizationSettings = internalData.contactSynchronizationSettings?.get(ContactSynchronizationSettings.self) ?? ContactSynchronizationSettings.defaultSettings
@ -385,7 +399,7 @@ public func currentPresentationDataAndSettings(accountManager: AccountManager<Te
let chatBubbleCorners = PresentationChatBubbleCorners(mainRadius: CGFloat(themeSettings.chatBubbleSettings.mainRadius), auxiliaryRadius: CGFloat(themeSettings.chatBubbleSettings.auxiliaryRadius), mergeBubbleCorners: themeSettings.chatBubbleSettings.mergeBubbleCorners)
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, reduceMotion: themeSettings.reduceMotion, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, experimentalUISettings: experimentalUISettings)
return InitialPresentationDataAndSettings(presentationData: PresentationData(strings: stringsValue, theme: theme, autoNightModeTriggered: autoNightModeTriggered, chatWallpaper: effectiveChatWallpaper, chatFontSize: chatFontSize, chatBubbleCorners: chatBubbleCorners, listsFontSize: listsFontSize, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, nameSortOrder: nameSortOrder, reduceMotion: themeSettings.reduceMotion, largeEmoji: themeSettings.largeEmoji), automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, callListSettings: callListSettings, inAppNotificationSettings: inAppNotificationSettings, mediaInputSettings: mediaInputSettings, stickerSettings: stickerSettings, experimentalUISettings: experimentalUISettings)
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -604,7 +604,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.automaticMediaDownloadSettings = context.sharedContext.currentAutomaticMediaDownloadSettings
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: false)
self.stickerSettings = ChatInterfaceStickerSettings(loopAnimatedStickers: context.sharedContext.currentStickerSettings.with { $0 }.loopAnimatedStickers)
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: mode, chatLocation: chatLocation, subject: subject, peerNearbyData: peerNearbyData, greetingData: context.prefetchManager?.preloadedGreetingSticker, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
self.presentationInterfaceStatePromise = ValuePromise(self.presentationInterfaceState)
@ -10116,7 +10116,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let locale = Locale(identifier: languageCode)
let fromLanguage: String = locale.localizedString(forLanguageCode: langCode) ?? ""
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: presentationData.strings.Conversation_Translation_AddedToDoNotTranslateText(fromLanguage).string, round: false, undoText: "Settings"), elevatedLayout: false, animateInAsReplacement: false, action: { [weak self] action in
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .image(image: generateTintedImage(image: UIImage(bundleImageName: "Chat/Title Panels/Translate"), color: .white)!, title: nil, text: presentationData.strings.Conversation_Translation_AddedToDoNotTranslateText(fromLanguage).string, round: false, undoText: presentationData.strings.Conversation_Translation_Settings), elevatedLayout: false, animateInAsReplacement: false, action: { [weak self] action in
if case .undo = action, let strongSelf = self {
let controller = translationSettingsController(context: strongSelf.context)
controller.navigationPresentation = .modal
@ -15632,7 +15632,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.dismiss()
let navigateToLocation: NavigateToChatControllerParams.Location
if let threadId = messages.first?.threadId {
if let message = messages.first, let threadId = message.threadId, threadId != 1 || (message.peers[message.id.peerId] as? TelegramChannel)?.flags.contains(.isForum) == true {
navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false))
} else {
navigateToLocation = .peer(peer)

View File

@ -1074,9 +1074,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
let isCopyProtected = chatPresentationInterfaceState.copyProtectionEnabled || message.isCopyProtected()
if !messageText.isEmpty || (resourceAvailable && isImage) || diceEmoji != nil {
let isCopyProtected = chatPresentationInterfaceState.copyProtectionEnabled || message.isCopyProtected()
if !isExpired {
if !isPoll {
if !isCopyProtected {
@ -1183,35 +1182,35 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
})))
}
}
if resourceAvailable, !message.containsSecretMedia, !chatPresentationInterfaceState.copyProtectionEnabled, !message.isCopyProtected() {
var mediaReference: AnyMediaReference?
var isVideo = false
for media in message.media {
if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) {
mediaReference = ImageMediaReference.standalone(media: image).abstract
break
} else if let file = media as? TelegramMediaFile, file.isVideo {
mediaReference = FileMediaReference.standalone(media: file).abstract
isVideo = true
break
}
}
if let mediaReference = mediaReference {
actions.append(.action(ContextMenuActionItem(text: isVideo ? chatPresentationInterfaceState.strings.Gallery_SaveVideo : chatPresentationInterfaceState.strings.Gallery_SaveImage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
let _ = (saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: mediaReference)
|> deliverOnMainQueue).start(completed: {
Queue.mainQueue().after(0.2) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
controllerInteraction.presentControllerInCurrent(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: isVideo ? presentationData.strings.Gallery_VideoSaved : presentationData.strings.Gallery_ImageSaved), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), nil)
}
})
f(.default)
})))
}
if resourceAvailable, !message.containsSecretMedia && !isCopyProtected {
var mediaReference: AnyMediaReference?
var isVideo = false
for media in message.media {
if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) {
mediaReference = ImageMediaReference.standalone(media: image).abstract
break
} else if let file = media as? TelegramMediaFile, file.isVideo {
mediaReference = FileMediaReference.standalone(media: file).abstract
isVideo = true
break
}
}
if let mediaReference = mediaReference {
actions.append(.action(ContextMenuActionItem(text: isVideo ? chatPresentationInterfaceState.strings.Gallery_SaveVideo : chatPresentationInterfaceState.strings.Gallery_SaveImage, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Save"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
let _ = (saveToCameraRoll(context: context, postbox: context.account.postbox, userLocation: .peer(message.id.peerId), mediaReference: mediaReference)
|> deliverOnMainQueue).start(completed: {
Queue.mainQueue().after(0.2) {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
controllerInteraction.presentControllerInCurrent(UndoOverlayController(presentationData: presentationData, content: .mediaSaved(text: isVideo ? presentationData.strings.Gallery_VideoSaved : presentationData.strings.Gallery_ImageSaved), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return true }), nil)
}
})
f(.default)
})))
}
}
var downloadableMediaResourceInfos: [String] = []

View File

@ -1034,7 +1034,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
if item.associatedData.isCopyProtectionEnabled || item.message.isCopyProtected() {
needsShareButton = false
if hasCommentButton(item: item) {
} else {
needsShareButton = false
}
}
}

View File

@ -53,7 +53,7 @@ private final class ChatMessageBubbleClippingNode: ASDisplayNode {
}
}
private func hasCommentButton(item: ChatMessageItem) -> Bool {
func hasCommentButton(item: ChatMessageItem) -> Bool {
let firstMessage = item.content.firstMessage
var hasDiscussion = false
@ -4541,6 +4541,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
for contentNode in self.contentNodes {
if let contentNode = contentNode as? ChatMessageFileBubbleContentNode {
return contentNode.interactiveFileNode.hasExpandedAudioTranscription
} else if let contentNode = contentNode as? ChatMessageInstantVideoBubbleContentNode {
return contentNode.hasExpandedAudioTranscription
}
}
return false

View File

@ -23,6 +23,14 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
private var audioTranscriptionState: AudioTranscriptionButtonComponent.TranscriptionState = .collapsed
var hasExpandedAudioTranscription: Bool {
if case .expanded = self.audioTranscriptionState {
return true
} else {
return false
}
}
override var visibility: ListViewItemNodeVisibility {
didSet {
var wasVisible = false

View File

@ -505,7 +505,10 @@ class ChatMessageStickerItemNode: ChatMessageItemView {
}
if item.associatedData.isCopyProtectionEnabled || item.message.isCopyProtected() {
needsShareButton = false
if hasCommentButton(item: item) {
} else {
needsShareButton = false
}
}
}

View File

@ -262,7 +262,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
strongSelf.context.sharedContext.mediaManager.setPlaylist(nil, type: type, control: SharedMediaPlayerControlAction.playback(.pause))
}
}
mediaAccessoryPanel.setRate = { [weak self] rate, fromMenu in
mediaAccessoryPanel.setRate = { [weak self] rate, changeType in
guard let strongSelf = self else {
return
}
@ -289,7 +289,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
}
return true
})
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String?
let rate: CGFloat?
@ -303,10 +303,25 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
text = presentationData.strings.Conversation_AudioRateTooltipSpeedUp
rate = 2.0
} else {
text = nil
rate = nil
let value = String(format: "%0.1f", baseRate.doubleValue)
text = presentationData.strings.Conversation_AudioRateTooltipCustom(value).string
if case let .sliderCommit(previousValue, newValue) = changeType {
if newValue > previousValue {
rate = .infinity
} else if newValue < previousValue {
rate = -.infinity
} else {
rate = nil
}
} else {
rate = nil
}
}
if let rate, let text, !fromMenu {
var showTooltip = true
if case .sliderChange = changeType {
showTooltip = false
}
if let rate, let text, showTooltip {
controller.present(
UndoOverlayController(
presentationData: presentationData,

View File

@ -1105,7 +1105,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese
}))
}
if user.botInfo != nil, !user.isVerified {
if user.botInfo != nil {
items[.peerInfo]!.append(PeerInfoScreenActionItem(id: 6, text: presentationData.strings.ReportPeer_Report, action: {
interaction.openReport(.default)
}))

View File

@ -163,6 +163,9 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public let currentMediaInputSettings: Atomic<MediaInputSettings>
private var mediaInputSettingsDisposable: Disposable?
public let currentStickerSettings: Atomic<StickerSettings>
private var stickerSettingsDisposable: Disposable?
private let automaticMediaDownloadSettingsDisposable = MetaDisposable()
private var immediateExperimentalUISettingsValue = Atomic<ExperimentalUISettings>(value: ExperimentalUISettings.defaultSettings)
@ -237,6 +240,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
self.currentAutomaticMediaDownloadSettings = initialPresentationDataAndSettings.automaticMediaDownloadSettings
self.currentAutodownloadSettings = Atomic(value: initialPresentationDataAndSettings.autodownloadSettings)
self.currentMediaInputSettings = Atomic(value: initialPresentationDataAndSettings.mediaInputSettings)
self.currentStickerSettings = Atomic(value: initialPresentationDataAndSettings.stickerSettings)
self.currentInAppNotificationSettings = Atomic(value: initialPresentationDataAndSettings.inAppNotificationSettings)
let presentationData: Signal<PresentationData, NoError> = .single(initialPresentationDataAndSettings.presentationData)
@ -348,6 +352,15 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}
})
self.stickerSettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.stickerSettings])
|> deliverOnMainQueue).start(next: { [weak self] sharedData in
if let strongSelf = self {
if let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.stickerSettings]?.get(StickerSettings.self) {
let _ = strongSelf.currentStickerSettings.swap(settings)
}
}
})
let immediateExperimentalUISettingsValue = self.immediateExperimentalUISettingsValue
let _ = immediateExperimentalUISettingsValue.swap(initialPresentationDataAndSettings.experimentalUISettings)
self.experimentalUISettingsDisposable = (self.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.experimentalUISettings])

View File

@ -546,7 +546,11 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.iconCheckNode = nil
let animationName: String
if rate == 1.5 {
if rate == .infinity {
animationName = "anim_voicefast"
} else if rate == -.infinity {
animationName = "anim_voiceslow"
} else if rate == 1.5 {
animationName = "anim_voice1_5x"
} else if rate == 2.0 {
animationName = "anim_voice2x"