Various Improvements

This commit is contained in:
Ilya Laktyushin 2021-03-21 17:27:32 +05:00
parent 20570dc5f1
commit 5f4c70a4c4
36 changed files with 5175 additions and 4948 deletions

View File

@ -6038,7 +6038,6 @@ Sorry for the inconvenience.";
"Conversation.ForwardTooltip.TwoChats.Many" = "Messages forwarded to **%@** and **%@**"; "Conversation.ForwardTooltip.TwoChats.Many" = "Messages forwarded to **%@** and **%@**";
"Conversation.ForwardTooltip.ManyChats.One" = "Message forwarded to **%@** and %@ others"; "Conversation.ForwardTooltip.ManyChats.One" = "Message forwarded to **%@** and %@ others";
"Conversation.ForwardTooltip.ManyChats.Many" = "Messages forwarded to **%@** and %@ others"; "Conversation.ForwardTooltip.ManyChats.Many" = "Messages forwarded to **%@** and %@ others";
"Conversation.ForwardTooltip.SavedMessages.One" = "Message forwarded to **Saved Messages**"; "Conversation.ForwardTooltip.SavedMessages.One" = "Message forwarded to **Saved Messages**";
"Conversation.ForwardTooltip.SavedMessages.Many" = "Messages forwarded to **Saved Messages**"; "Conversation.ForwardTooltip.SavedMessages.Many" = "Messages forwarded to **Saved Messages**";
@ -6299,3 +6298,13 @@ Sorry for the inconvenience.";
"VoiceChat.ForwardTooltip.ManyChats" = "Invite link forwarded to **%@** and %@ others"; "VoiceChat.ForwardTooltip.ManyChats" = "Invite link forwarded to **%@** and %@ others";
"GroupRemoved.ViewChannelInfo" = "View Channel"; "GroupRemoved.ViewChannelInfo" = "View Channel";
"UserInfo.ContactForwardTooltip.Chat.One" = "Contact forwarded to **%@**";
"UserInfo.ContactForwardTooltip.TwoChats.One" = "Contact forwarded to **%@** and **%@**";
"UserInfo.ContactForwardTooltip.ManyChats.One" = "Contact forwarded to **%@** and %@ others";
"UserInfo.ContactForwardTooltip.SavedMessages.One" = "Contact forwarded to **Saved Messages**";
"UserInfo.LinkForwardTooltip.Chat.One" = "Link forwarded to **%@**";
"UserInfo.LinkForwardTooltip.TwoChats.One" = "Link forwarded to **%@** and **%@**";
"UserInfo.LinkForwardTooltip.ManyChats.One" = "Link forwarded to **%@** and %@ others";
"UserInfo.LinkForwardTooltip.SavedMessages.One" = "Link forwarded to **Saved Messages**";

View File

@ -608,7 +608,7 @@ public protocol SharedAccountContext: class {
func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void) func openExternalUrl(context: AccountContext, urlContext: OpenURLContext, url: String, forceExternal: Bool, presentationData: PresentationData, navigationController: NavigationController?, dismissInput: @escaping () -> Void)
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>) -> Signal<ChatAvailableMessageActions, NoError> func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>) -> Signal<ChatAvailableMessageActions, NoError>
func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message], peers: [PeerId: Peer]) -> Signal<ChatAvailableMessageActions, NoError> func chatAvailableMessageActions(postbox: Postbox, accountPeerId: PeerId, messageIds: Set<MessageId>, messages: [MessageId: Message], peers: [PeerId: Peer]) -> Signal<ChatAvailableMessageActions, NoError>
func resolveUrl(account: Account, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError>
func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?)
func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void) func openAddContact(context: AccountContext, firstName: String, lastName: String, phoneNumber: String, label: String, present: @escaping (ViewController, Any?) -> Void, pushController: @escaping (ViewController) -> Void, completed: @escaping () -> Void)
func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) func openAddPersonContact(context: AccountContext, peerId: PeerId, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void)

View File

@ -534,7 +534,7 @@ public final class ChatImportActivityScreen: ViewController {
self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: floor(36.0 * maxK), design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor) self.radialStatusText.attributedText = NSAttributedString(string: "\(Int(effectiveProgress * 100.0))%", font: Font.with(size: floor(36.0 * maxK), design: .round, weight: .semibold), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude)) let radialStatusTextSize = self.radialStatusText.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes))))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor) self.progressText.attributedText = NSAttributedString(string: "\(dataSizeString(Int(effectiveProgress * CGFloat(self.totalBytes)), formatting: DataSizeStringFormatting(presentationData: self.presentationData))) of \(dataSizeString(Int(1.0 * CGFloat(self.totalBytes)), formatting: DataSizeStringFormatting(presentationData: self.presentationData)))", font: Font.semibold(17.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
let progressTextSize = self.progressText.updateLayout(CGSize(width: layout.size.width - 16.0 * 2.0, height: .greatestFiniteMagnitude)) let progressTextSize = self.progressText.updateLayout(CGSize(width: layout.size.width - 16.0 * 2.0, height: .greatestFiniteMagnitude))
switch self.state { switch self.state {

View File

@ -160,11 +160,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_message", peerId: peer.id, data: .dictionary(["msg_id": .number(Double(messageId.id))])) addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_message", peerId: peer.id, data: .dictionary(["msg_id": .number(Double(messageId.id))]))
} }
}, openUrl: { [weak self] url in }, openUrl: { [weak self] url in
openUserGeneratedUrl(context: context, url: url, concealed: false, present: { c in openUserGeneratedUrl(context: context, peerId: nil, url: url, concealed: false, present: { c in
present(c, nil) present(c, nil)
}, openResolved: { [weak self] resolved in }, openResolved: { [weak self] resolved in
context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, openPeer: { peerId, navigation in context.sharedContext.openResolvedUrl(resolved, context: context, urlContext: .generic, navigationController: navigationController, openPeer: { peerId, navigation in
// self?.openPeer(peerId: peerId, navigation: navigation)
}, sendFile: nil, }, sendFile: nil,
sendSticker: nil, sendSticker: nil,
requestMessageActionUrlAuth: nil, requestMessageActionUrlAuth: nil,

View File

@ -965,7 +965,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
} }
let resolvedMessage = .single(nil) let resolvedMessage = .single(nil)
|> then(context.sharedContext.resolveUrl(account: context.account, url: finalQuery, skipUrlAuth: true) |> then(context.sharedContext.resolveUrl(context: context, peerId: nil, url: finalQuery, skipUrlAuth: true)
|> mapToSignal { resolvedUrl -> Signal<Message?, NoError> in |> mapToSignal { resolvedUrl -> Signal<Message?, NoError> in
if case let .channelMessage(_, messageId) = resolvedUrl { if case let .channelMessage(_, messageId) = resolvedUrl {
return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId) return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId)

View File

@ -7,8 +7,8 @@ import TextFormat
import RadialStatusNode import RadialStatusNode
import AppBundle import AppBundle
private let font = Font.regular(11.0) private let font = Font.with(size: 11.0, design: .regular, weight: .regular, traits: [.monospacedNumbers])
private let boldFont = Font.semibold(11.0) private let boldFont = Font.with(size: 11.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
public enum ChatMessageInteractiveMediaDownloadState: Equatable { public enum ChatMessageInteractiveMediaDownloadState: Equatable {
case remote case remote

View File

@ -226,6 +226,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
} }
func setFetchStatusSignal(_ fetchStatus: Signal<MediaResourceStatus, NoError>?, strings: PresentationStrings, decimalSeparator: String, fileSize: Int?) { func setFetchStatusSignal(_ fetchStatus: Signal<MediaResourceStatus, NoError>?, strings: PresentationStrings, decimalSeparator: String, fileSize: Int?) {
let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator)
if let fileSize = fileSize { if let fileSize = fileSize {
if let fetchStatus = fetchStatus { if let fetchStatus = fetchStatus {
self.fetchStatusDisposable.set((fetchStatus self.fetchStatusDisposable.set((fetchStatus
@ -234,9 +235,9 @@ final class ChatVideoGalleryItemScrubberView: UIView {
var text: String var text: String
switch status { switch status {
case .Remote: case .Remote:
text = dataSizeString(fileSize, forceDecimal: true, decimalSeparator: decimalSeparator) text = dataSizeString(fileSize, forceDecimal: true, formatting: formatting)
case let .Fetching(_, progress): case let .Fetching(_, progress):
text = strings.DownloadingStatus(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, decimalSeparator: decimalSeparator), dataSizeString(fileSize, forceDecimal: true, decimalSeparator: decimalSeparator)).0 text = strings.DownloadingStatus(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, formatting: formatting), dataSizeString(fileSize, forceDecimal: true, formatting: formatting)).0
default: default:
text = "" text = ""
} }
@ -248,7 +249,7 @@ final class ChatVideoGalleryItemScrubberView: UIView {
} }
})) }))
} else { } else {
self.infoNode.attributedText = NSAttributedString(string: dataSizeString(fileSize, forceDecimal: true, decimalSeparator: decimalSeparator), font: textFont, textColor: .white) self.infoNode.attributedText = NSAttributedString(string: dataSizeString(fileSize, forceDecimal: true, formatting: formatting), font: textFont, textColor: .white)
} }
} else { } else {
self.infoNode.attributedText = nil self.infoNode.attributedText = nil

View File

@ -171,7 +171,7 @@ final class ChatAnimationGalleryItemNode: ZoomableContentGalleryItemNode {
self.setupStatus(resource: fileReference.media.resource) self.setupStatus(resource: fileReference.media.resource)
self._title.set(.single("\(fileReference.media.fileName ?? "") - \(dataSizeString(fileReference.media.size ?? 0, forceDecimal: false, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))")) self._title.set(.single("\(fileReference.media.fileName ?? "") - \(dataSizeString(fileReference.media.size ?? 0, forceDecimal: false, formatting: DataSizeStringFormatting(presentationData: self.presentationData)))"))
let speedItem = UIBarButtonItem(image: UIImage(bundleImageName: "Media Gallery/SlowDown"), style: .plain, target: self, action: #selector(self.toggleSpeedButtonPressed)) let speedItem = UIBarButtonItem(image: UIImage(bundleImageName: "Media Gallery/SlowDown"), style: .plain, target: self, action: #selector(self.toggleSpeedButtonPressed))
let backgroundItem = UIBarButtonItem(image: backgroundButtonIcon, style: .plain, target: self, action: #selector(self.toggleBackgroundButtonPressed)) let backgroundItem = UIBarButtonItem(image: backgroundButtonIcon, style: .plain, target: self, action: #selector(self.toggleBackgroundButtonPressed))

View File

@ -1147,7 +1147,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.loadProgress.set(0.02) self.loadProgress.set(0.02)
self.loadWebpageDisposable.set(nil) self.loadWebpageDisposable.set(nil)
self.resolveUrlDisposable.set((self.context.sharedContext.resolveUrl(account: self.context.account, url: url.url, skipUrlAuth: true) self.resolveUrlDisposable.set((self.context.sharedContext.resolveUrl(context: self.context, peerId: nil, url: url.url, skipUrlAuth: true)
|> deliverOnMainQueue).start(next: { [weak self] result in |> deliverOnMainQueue).start(next: { [weak self] result in
if let strongSelf = self { if let strongSelf = self {
strongSelf.loadProgress.set(0.07) strongSelf.loadProgress.set(0.07)

View File

@ -420,7 +420,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
descriptionString = "\(stringForDuration(Int32(duration)))\(performer)" descriptionString = "\(stringForDuration(Int32(duration)))\(performer)"
} }
} else if let size = file.size { } else if let size = file.size {
descriptionString = dataSizeString(size, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) descriptionString = dataSizeString(size, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData))
} else { } else {
descriptionString = "" descriptionString = ""
} }
@ -512,9 +512,9 @@ public final class ListMessageFileItemNode: ListMessageNode {
var descriptionString: String = "" var descriptionString: String = ""
if let size = file.size { if let size = file.size {
if item.isGlobalSearchResult { if item.isGlobalSearchResult {
descriptionString = (dataSizeString(size, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)) descriptionString = dataSizeString(size, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData))
} else { } else {
descriptionString = "\(dataSizeString(size, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator))\(dateString)" descriptionString = "\(dataSizeString(size, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData)))\(dateString)"
} }
} else { } else {
if !item.isGlobalSearchResult { if !item.isGlobalSearchResult {
@ -990,7 +990,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
switch fetchStatus { switch fetchStatus {
case let .Fetching(_, progress): case let .Fetching(_, progress):
if let file = self.currentMedia as? TelegramMediaFile, let size = file.size { if let file = self.currentMedia as? TelegramMediaFile, let size = file.size {
downloadingString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator))" downloadingString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData))) / \(dataSizeString(size, forceDecimal: true, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData)))"
} }
descriptionOffset = 14.0 descriptionOffset = 14.0
case .Remote: case .Remote:
@ -1074,7 +1074,8 @@ public final class ListMessageFileItemNode: ListMessageNode {
alphaTransition.updateAlpha(node: self.descriptionProgressNode, alpha: 0.0) alphaTransition.updateAlpha(node: self.descriptionProgressNode, alpha: 0.0)
alphaTransition.updateAlpha(node: self.descriptionNode, alpha: 1.0) alphaTransition.updateAlpha(node: self.descriptionNode, alpha: 1.0)
} }
let descriptionFont = Font.regular(floor(item.presentationData.fontSize.baseDisplaySize * 13.0 / 17.0))
let descriptionFont = Font.with(size: floor(item.presentationData.fontSize.baseDisplaySize * 13.0 / 17.0), design: .regular, weight: .regular, traits: [.monospacedNumbers])
self.descriptionProgressNode.attributedText = NSAttributedString(string: downloadingString ?? "", font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) self.descriptionProgressNode.attributedText = NSAttributedString(string: downloadingString ?? "", font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor)
let descriptionSize = self.descriptionProgressNode.updateLayout(CGSize(width: size.width - 14.0, height: size.height)) let descriptionSize = self.descriptionProgressNode.updateLayout(CGSize(width: size.width - 14.0, height: size.height))
transition.updateFrame(node: self.descriptionProgressNode, frame: CGRect(origin: self.descriptionNode.frame.origin, size: descriptionSize)) transition.updateFrame(node: self.descriptionProgressNode, frame: CGRect(origin: self.descriptionNode.frame.origin, size: descriptionSize))

View File

@ -1,11 +1,12 @@
import Foundation import Foundation
import Display import Display
import SwiftSignalKit import SwiftSignalKit
import Postbox
import AccountContext import AccountContext
import OverlayStatusController import OverlayStatusController
import UrlWhitelist import UrlWhitelist
public func openUserGeneratedUrl(context: AccountContext, url: String, concealed: Bool, skipUrlAuth: Bool = false, present: @escaping (ViewController) -> Void, openResolved: @escaping (ResolvedUrl) -> Void) { public func openUserGeneratedUrl(context: AccountContext, peerId: PeerId?, url: String, concealed: Bool, skipUrlAuth: Bool = false, present: @escaping (ViewController) -> Void, openResolved: @escaping (ResolvedUrl) -> Void) {
var concealed = concealed var concealed = concealed
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -31,7 +32,7 @@ public func openUserGeneratedUrl(context: AccountContext, url: String, concealed
cancelImpl = { cancelImpl = {
disposable.dispose() disposable.dispose()
} }
disposable.set((context.sharedContext.resolveUrl(account: context.account, url: url, skipUrlAuth: skipUrlAuth) disposable.set((context.sharedContext.resolveUrl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth)
|> afterDisposed { |> afterDisposed {
Queue.mainQueue().async { Queue.mainQueue().async {
progressDisposable.dispose() progressDisposable.dispose()

View File

@ -71,7 +71,7 @@ private enum AutodownloadMediaCategoryEntry: ItemListNodeEntry {
case peerChannels(PresentationTheme, String, Bool) case peerChannels(PresentationTheme, String, Bool)
case sizeHeader(PresentationTheme, String) case sizeHeader(PresentationTheme, String)
case sizeItem(PresentationTheme, String, String, Int32) case sizeItem(PresentationTheme, PresentationStrings, String, String, Int32)
case sizePreload(PresentationTheme, String, Bool, Bool) case sizePreload(PresentationTheme, String, Bool, Bool)
case sizePreloadInfo(PresentationTheme, String) case sizePreloadInfo(PresentationTheme, String)
@ -145,8 +145,8 @@ private enum AutodownloadMediaCategoryEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .sizeItem(lhsTheme, lhsDecimalSeparator, lhsText, lhsValue): case let .sizeItem(lhsTheme, lhsStrings, lhsDecimalSeparator, lhsText, lhsValue):
if case let .sizeItem(rhsTheme, rhsDecimalSeparator, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsDecimalSeparator == rhsDecimalSeparator, lhsText == rhsText, lhsValue == rhsValue { if case let .sizeItem(rhsTheme, rhsStrings, rhsDecimalSeparator, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsDecimalSeparator == rhsDecimalSeparator, lhsText == rhsText, lhsValue == rhsValue {
return true return true
} else { } else {
return false return false
@ -173,35 +173,35 @@ private enum AutodownloadMediaCategoryEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! AutodownloadMediaCategoryControllerArguments let arguments = arguments as! AutodownloadMediaCategoryControllerArguments
switch self { switch self {
case let .peerHeader(theme, text): case let .peerHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .peerContacts(theme, text, value): case let .peerContacts(_, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
arguments.togglePeer(.contact) arguments.togglePeer(.contact)
}) })
case let .peerOtherPrivate(theme, text, value): case let .peerOtherPrivate(_, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
arguments.togglePeer(.otherPrivate) arguments.togglePeer(.otherPrivate)
}) })
case let .peerGroups(theme, text, value): case let .peerGroups(_, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
arguments.togglePeer(.group) arguments.togglePeer(.group)
}) })
case let .peerChannels(theme, text, value): case let .peerChannels(_, text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: true, enabled: true, sectionId: self.section, style: .blocks, updated: { value in
arguments.togglePeer(.channel) arguments.togglePeer(.channel)
}) })
case let .sizeHeader(theme, text): case let .sizeHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .sizeItem(theme, decimalSeparator, text, value): case let .sizeItem(theme, strings, decimalSeparator, text, value):
return AutodownloadSizeLimitItem(theme: theme, decimalSeparator: decimalSeparator, text: text, value: value, sectionId: self.section, updated: { value in return AutodownloadSizeLimitItem(theme: theme, strings: strings, decimalSeparator: decimalSeparator, text: text, value: value, sectionId: self.section, updated: { value in
arguments.adjustSize(value) arguments.adjustSize(value)
}) })
case let .sizePreload(theme, text, value, enabled): case let .sizePreload(_, text, value, enabled):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value && enabled, enableInteractiveChanges: true, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value && enabled, enableInteractiveChanges: true, enabled: enabled, sectionId: self.section, style: .blocks, updated: { value in
arguments.toggleVideoPreload() arguments.toggleVideoPreload()
}) })
case let .sizePreloadInfo(theme, text): case let .sizePreloadInfo(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
} }
} }
@ -277,7 +277,7 @@ private func autodownloadMediaCategoryControllerEntries(presentationData: Presen
sizeText = autodownloadDataSizeString(Int64(size), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) sizeText = autodownloadDataSizeString(Int64(size), decimalSeparator: presentationData.dateTimeFormat.decimalSeparator)
} }
let text = presentationData.strings.AutoDownloadSettings_UpTo(sizeText).0 let text = presentationData.strings.AutoDownloadSettings_UpTo(sizeText).0
entries.append(.sizeItem(presentationData.theme, presentationData.dateTimeFormat.decimalSeparator, text, size)) entries.append(.sizeItem(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat.decimalSeparator, text, size))
if #available(iOSApplicationExtension 10.3, *), category == .video { if #available(iOSApplicationExtension 10.3, *), category == .video {
entries.append(.sizePreload(presentationData.theme, presentationData.strings.AutoDownloadSettings_PreloadVideo, predownload, size > 2 * 1024 * 1024)) entries.append(.sizePreload(presentationData.theme, presentationData.strings.AutoDownloadSettings_PreloadVideo, predownload, size > 2 * 1024 * 1024))
entries.append(.sizePreloadInfo(presentationData.theme, presentationData.strings.AutoDownloadSettings_PreloadVideoInfo(sizeText).0)) entries.append(.sizePreloadInfo(presentationData.theme, presentationData.strings.AutoDownloadSettings_PreloadVideoInfo(sizeText).0))

View File

@ -51,14 +51,16 @@ private func sizeValue(for sliderValue: CGFloat) -> Int32 {
final class AutodownloadSizeLimitItem: ListViewItem, ItemListItem { final class AutodownloadSizeLimitItem: ListViewItem, ItemListItem {
let theme: PresentationTheme let theme: PresentationTheme
let strings: PresentationStrings
let decimalSeparator: String let decimalSeparator: String
let text: String let text: String
let value: Int32 let value: Int32
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
let updated: (Int32) -> Void let updated: (Int32) -> Void
init(theme: PresentationTheme, decimalSeparator: String, text: String, value: Int32, sectionId: ItemListSectionId, updated: @escaping (Int32) -> Void) { init(theme: PresentationTheme, strings: PresentationStrings, decimalSeparator: String, text: String, value: Int32, sectionId: ItemListSectionId, updated: @escaping (Int32) -> Void) {
self.theme = theme self.theme = theme
self.strings = strings
self.decimalSeparator = decimalSeparator self.decimalSeparator = decimalSeparator
self.text = text self.text = text
self.value = value self.value = value
@ -201,9 +203,11 @@ private final class AutodownloadSizeLimitItemNode: ListViewItemNode {
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.text, font: Font.regular(17.0), textColor: item.theme.list.itemPrimaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
let (minTextLayout, minTextApply) = makeMinTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: dataSizeString(512 * 1024, decimalSeparator: item.decimalSeparator), font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) let formatting = DataSizeStringFormatting(strings: item.strings, decimalSeparator: item.decimalSeparator)
let (maxTextLayout, maxTextApply) = makeMaxTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: dataSizeString(1536 * 1024 * 1024, decimalSeparator: item.decimalSeparator), font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets())) let (minTextLayout, minTextApply) = makeMinTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: dataSizeString(512 * 1024, formatting: formatting), font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
let (maxTextLayout, maxTextApply) = makeMaxTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: dataSizeString(1536 * 1024 * 1024, formatting: formatting), font: Font.regular(13.0), textColor: item.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width, height: CGFloat.greatestFiniteMagnitude), alignment: .center, lineSpacing: 0.0, cutout: nil, insets: UIEdgeInsets()))
contentSize = CGSize(width: params.width, height: 88.0) contentSize = CGSize(width: params.width, height: 88.0)
insets = itemListNeighborsGroupedInsets(neighbors) insets = itemListNeighborsGroupedInsets(neighbors)

View File

@ -24,7 +24,7 @@ private func stringForCacheSize(strings: PresentationStrings, size: Int32) -> St
if size > 100 { if size > 100 {
return strings.Cache_NoLimit return strings.Cache_NoLimit
} else { } else {
return dataSizeString(Int64(size) * 1024 * 1024 * 1024) return dataSizeString(Int64(size) * 1024 * 1024 * 1024, formatting: DataSizeStringFormatting(strings: strings, decimalSeparator: "."))
} }
} }

View File

@ -258,47 +258,47 @@ private enum NetworkUsageStatsEntry: ItemListNodeEntry {
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem { func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! NetworkUsageStatsControllerArguments let arguments = arguments as! NetworkUsageStatsControllerArguments
switch self { switch self {
case let .messagesHeader(theme, text): case let .messagesHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .messagesSent(theme, text, value): case let .messagesSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .messagesReceived(theme, text, value): case let .messagesReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .imageHeader(theme, text): case let .imageHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .imageSent(theme, text, value): case let .imageSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .imageReceived(theme, text, value): case let .imageReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .videoHeader(theme, text): case let .videoHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .videoSent(theme, text, value): case let .videoSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .videoReceived(theme, text, value): case let .videoReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .audioHeader(theme, text): case let .audioHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .audioSent(theme, text, value): case let .audioSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .audioReceived(theme, text, value): case let .audioReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .fileHeader(theme, text): case let .fileHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .fileSent(theme, text, value): case let .fileSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .fileReceived(theme, text, value): case let .fileReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .callHeader(theme, text): case let .callHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .callSent(theme, text, value): case let .callSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .callReceived(theme, text, value): case let .callReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil) return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .reset(theme, section, text): case let .reset(_, section, text):
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: { return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.resetStatistics(section) arguments.resetStatistics(section)
}) })
case let .resetTimestamp(theme, text): case let .resetTimestamp(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
} }
} }
@ -307,31 +307,32 @@ private enum NetworkUsageStatsEntry: ItemListNodeEntry {
private func networkUsageStatsControllerEntries(presentationData: PresentationData, section: NetworkUsageControllerSection, stats: NetworkUsageStats) -> [NetworkUsageStatsEntry] { private func networkUsageStatsControllerEntries(presentationData: PresentationData, section: NetworkUsageControllerSection, stats: NetworkUsageStats) -> [NetworkUsageStatsEntry] {
var entries: [NetworkUsageStatsEntry] = [] var entries: [NetworkUsageStatsEntry] = []
let formatting = DataSizeStringFormatting(presentationData: presentationData)
switch section { switch section {
case .cellular: case .cellular:
entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection)) entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection))
entries.append(.messagesSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.generic.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.messagesSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.generic.cellular.outgoing, formatting: formatting)))
entries.append(.messagesReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.generic.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.messagesReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.generic.cellular.incoming, formatting: formatting)))
entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection)) entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection))
entries.append(.imageSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.image.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.imageSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.image.cellular.outgoing, formatting: formatting)))
entries.append(.imageReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.image.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.imageReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.image.cellular.incoming, formatting: formatting)))
entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection)) entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection))
entries.append(.videoSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.video.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.videoSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.video.cellular.outgoing, formatting: formatting)))
entries.append(.videoReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.video.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.videoReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.video.cellular.incoming, formatting: formatting)))
entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection)) entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection))
entries.append(.audioSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.audio.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.audioSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.audio.cellular.outgoing, formatting: formatting)))
entries.append(.audioReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.audio.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.audioReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.audio.cellular.incoming, formatting: formatting)))
entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection)) entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection))
entries.append(.fileSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.file.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.fileSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.file.cellular.outgoing, formatting: formatting)))
entries.append(.fileReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.file.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.fileReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.file.cellular.incoming, formatting: formatting)))
entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection)) entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection))
entries.append(.callSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.call.cellular.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.callSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.call.cellular.outgoing, formatting: formatting)))
entries.append(.callReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.call.cellular.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.callReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.call.cellular.incoming, formatting: formatting)))
entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats)) entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats))
@ -344,28 +345,28 @@ private func networkUsageStatsControllerEntries(presentationData: PresentationDa
} }
case .wifi: case .wifi:
entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection)) entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection))
entries.append(.messagesSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.generic.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.messagesSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.generic.wifi.outgoing, formatting: formatting)))
entries.append(.messagesReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.generic.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.messagesReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.generic.wifi.incoming, formatting: formatting)))
entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection)) entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection))
entries.append(.imageSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.image.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.imageSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.image.wifi.outgoing, formatting: formatting)))
entries.append(.imageReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.image.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.imageReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.image.wifi.incoming, formatting: formatting)))
entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection)) entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection))
entries.append(.videoSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.video.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.videoSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.video.wifi.outgoing, formatting: formatting)))
entries.append(.videoReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.video.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.videoReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.video.wifi.incoming, formatting: formatting)))
entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection)) entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection))
entries.append(.audioSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.audio.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.audioSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.audio.wifi.outgoing, formatting: formatting)))
entries.append(.audioReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.audio.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.audioReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.audio.wifi.incoming, formatting: formatting)))
entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection)) entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection))
entries.append(.fileSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.file.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.fileSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.file.wifi.outgoing, formatting: formatting)))
entries.append(.fileReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.file.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.fileReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.file.wifi.incoming, formatting: formatting)))
entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection)) entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection))
entries.append(.callSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.call.wifi.outgoing, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.callSent(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesSent, dataSizeString(stats.call.wifi.outgoing, formatting: formatting)))
entries.append(.callReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.call.wifi.incoming, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))) entries.append(.callReceived(presentationData.theme, presentationData.strings.NetworkUsageSettings_BytesReceived, dataSizeString(stats.call.wifi.incoming, formatting: formatting)))
entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats)) entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats))
if stats.resetWifiTimestamp != 0 { if stats.resetWifiTimestamp != 0 {

View File

@ -71,7 +71,7 @@ private enum StorageUsageEntry: ItemListNodeEntry {
case maximumSizeInfo(PresentationTheme, String) case maximumSizeInfo(PresentationTheme, String)
case storageHeader(PresentationTheme, String) case storageHeader(PresentationTheme, String)
case storageUsage(PresentationTheme, PresentationDateTimeFormat, [StorageUsageCategory]) case storageUsage(PresentationTheme, PresentationStrings, PresentationDateTimeFormat, [StorageUsageCategory])
case collecting(PresentationTheme, String) case collecting(PresentationTheme, String)
case clearAll(PresentationTheme, String, Bool) case clearAll(PresentationTheme, String, Bool)
@ -164,8 +164,8 @@ private enum StorageUsageEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .storageUsage(lhsTheme, lhsDateTimeFormat, lhsCategories): case let .storageUsage(lhsTheme, lhsStrings, lhsDateTimeFormat, lhsCategories):
if case let .storageUsage(rhsTheme, rhsDateTimeFormat, rhsCategories) = rhs, lhsTheme === rhsTheme, lhsDateTimeFormat == rhsDateTimeFormat, lhsCategories == rhsCategories { if case let .storageUsage(rhsTheme, rhsStrings, rhsDateTimeFormat, rhsCategories) = rhs, lhsTheme === rhsTheme, lhsStrings == rhsStrings, lhsDateTimeFormat == rhsDateTimeFormat, lhsCategories == rhsCategories {
return true return true
} else { } else {
return false return false
@ -249,8 +249,8 @@ private enum StorageUsageEntry: ItemListNodeEntry {
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
case let .storageHeader(_, text): case let .storageHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .storageUsage(theme, dateTimeFormat, categories): case let .storageUsage(theme, strings, dateTimeFormat, categories):
return StorageUsageItem(theme: theme, dateTimeFormat: dateTimeFormat, categories: categories, sectionId: self.section) return StorageUsageItem(theme: theme, strings: strings, dateTimeFormat: dateTimeFormat, categories: categories, sectionId: self.section)
case let .collecting(theme, text): case let .collecting(theme, text):
return CalculatingCacheSizeItem(theme: theme, title: text, sectionId: self.section, style: .blocks) return CalculatingCacheSizeItem(theme: theme, title: text, sectionId: self.section, style: .blocks)
case let .clearAll(_, text, enabled): case let .clearAll(_, text, enabled):
@ -262,7 +262,7 @@ private enum StorageUsageEntry: ItemListNodeEntry {
case let .peersHeader(_, text): case let .peersHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .peer(_, _, strings, dateTimeFormat, nameDisplayOrder, peer, chatPeer, value, revealed): case let .peer(_, _, strings, dateTimeFormat, nameDisplayOrder, peer, chatPeer, value, revealed):
var options: [ItemListPeerItemRevealOption] = [ItemListPeerItemRevealOption(type: .destructive, title: strings.ClearCache_Clear, action: { let options: [ItemListPeerItemRevealOption] = [ItemListPeerItemRevealOption(type: .destructive, title: strings.ClearCache_Clear, action: {
arguments.clearPeerMedia(peer.id) arguments.clearPeerMedia(peer.id)
})] })]
return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: { return ItemListPeerItem(presentationData: presentationData, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameDisplayOrder, context: arguments.context, peer: peer, aliasHandling: .threatSelfAsSaved, nameColor: chatPeer == nil ? .primary : .secret, presence: nil, text: .none, label: .disclosure(value), editing: ItemListPeerItemEditing(editable: true, editing: false, revealed: revealed), revealOptions: ItemListPeerItemRevealOptions(options: options), switchValue: nil, enabled: true, selectable: true, sectionId: self.section, action: {
@ -340,7 +340,7 @@ private func storageUsageControllerEntries(presentationData: PresentationData, c
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageOtherApps, size: otherAppsSpace, fraction: CGFloat(otherAppsSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color2)) categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageOtherApps, size: otherAppsSpace, fraction: CGFloat(otherAppsSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color2))
categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageFree, size: freeSpace, fraction: CGFloat(freeSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color3)) categories.append(StorageUsageCategory(title: presentationData.strings.ClearCache_StorageFree, size: freeSpace, fraction: CGFloat(freeSpace) / totalSpaceValue, color: presentationData.theme.list.itemBarChart.color3))
entries.append(.storageUsage(presentationData.theme, presentationData.dateTimeFormat, categories)) entries.append(.storageUsage(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, categories))
entries.append(.clearAll(presentationData.theme, presentationData.strings.ClearCache_ClearCache, telegramCacheSize > 0)) entries.append(.clearAll(presentationData.theme, presentationData.strings.ClearCache_ClearCache, telegramCacheSize > 0))
@ -358,7 +358,7 @@ private func storageUsageControllerEntries(presentationData: PresentationData, c
chatPeer = mainPeer chatPeer = mainPeer
mainPeer = associatedPeer mainPeer = associatedPeer
} }
entries.append(.peer(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, mainPeer, chatPeer, dataSizeString(size, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), state.peerIdWithRevealedOptions == peer.id)) entries.append(.peer(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, presentationData.nameDisplayOrder, mainPeer, chatPeer, dataSizeString(size, formatting: DataSizeStringFormatting(presentationData: presentationData)), state.peerIdWithRevealedOptions == peer.id))
index += 1 index += 1
} }
} }
@ -490,7 +490,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
if filteredSize == 0 { if filteredSize == 0 {
title = presentationData.strings.Cache_ClearNone title = presentationData.strings.Cache_ClearNone
} else { } else {
title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0 title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0
} }
if let item = item as? ActionSheetButtonItem { if let item = item as? ActionSheetButtonItem {
@ -527,7 +527,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
let categorySize: Int64 = size let categorySize: Int64 = size
totalSize += categorySize totalSize += categorySize
let index = itemIndex let index = itemIndex
items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), value: true, action: { value in items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, formatting: DataSizeStringFormatting(presentationData: presentationData)), value: true, action: { value in
toggleCheck(categoryId, index) toggleCheck(categoryId, index)
})) }))
itemIndex += 1 itemIndex += 1
@ -537,7 +537,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
if otherSize.1 != 0 { if otherSize.1 != 0 {
totalSize += otherSize.1 totalSize += otherSize.1
let index = itemIndex let index = itemIndex
items.append(ActionSheetCheckboxItem(title: presentationData.strings.Localization_LanguageOther, label: dataSizeString(otherSize.1, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), value: true, action: { value in items.append(ActionSheetCheckboxItem(title: presentationData.strings.Localization_LanguageOther, label: dataSizeString(otherSize.1, formatting: DataSizeStringFormatting(presentationData: presentationData)), value: true, action: { value in
toggleCheck(nil, index) toggleCheck(nil, index)
})) }))
itemIndex += 1 itemIndex += 1
@ -545,7 +545,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
selectedSize = totalSize selectedSize = totalSize
if !items.isEmpty { if !items.isEmpty {
items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0, action: { items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0, action: {
if let statsPromise = statsPromise { if let statsPromise = statsPromise {
let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 }) let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 })
@ -637,7 +637,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
clearDisposable.set((signal clearDisposable.set((signal
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
statsPromise.set(.single(.result(resultStats))) statsPromise.set(.single(.result(resultStats)))
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil) presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil)
})) }))
} }
@ -692,7 +692,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
if filteredSize == 0 { if filteredSize == 0 {
title = presentationData.strings.Cache_ClearNone title = presentationData.strings.Cache_ClearNone
} else { } else {
title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0 title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0
} }
if let item = item as? ActionSheetButtonItem { if let item = item as? ActionSheetButtonItem {
@ -732,7 +732,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
totalSize += categorySize totalSize += categorySize
if categorySize > 1024 { if categorySize > 1024 {
let index = itemIndex let index = itemIndex
items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), value: true, action: { value in items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, formatting: DataSizeStringFormatting(presentationData: presentationData)), value: true, action: { value in
toggleCheck(categoryId, index) toggleCheck(categoryId, index)
})) }))
itemIndex += 1 itemIndex += 1
@ -742,7 +742,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
selectedSize = totalSize selectedSize = totalSize
if !items.isEmpty { if !items.isEmpty {
items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0, action: { items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0, action: {
if let statsPromise = statsPromise { if let statsPromise = statsPromise {
let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 }) let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 })
var clearMediaIds = Set<MediaId>() var clearMediaIds = Set<MediaId>()
@ -818,7 +818,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
clearDisposable.set((signal clearDisposable.set((signal
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
statsPromise.set(.single(.result(resultStats))) statsPromise.set(.single(.result(resultStats)))
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil) presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil)
})) }))
} }
@ -945,7 +945,7 @@ public func storageUsageController(context: AccountContext, cacheUsagePromise: P
clearDisposable.set((signal clearDisposable.set((signal
|> deliverOnMainQueue).start(completed: { |> deliverOnMainQueue).start(completed: {
statsPromise.set(.single(.result(resultStats))) statsPromise.set(.single(.result(resultStats)))
presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil) presentControllerImpl?(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(totalSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), .current, nil)
})) }))
} }
} }

View File

@ -19,12 +19,14 @@ struct StorageUsageCategory: Equatable {
final class StorageUsageItem: ListViewItem, ItemListItem { final class StorageUsageItem: ListViewItem, ItemListItem {
let theme: PresentationTheme let theme: PresentationTheme
let strings: PresentationStrings
let dateTimeFormat: PresentationDateTimeFormat let dateTimeFormat: PresentationDateTimeFormat
let categories: [StorageUsageCategory] let categories: [StorageUsageCategory]
let sectionId: ItemListSectionId let sectionId: ItemListSectionId
init(theme: PresentationTheme, dateTimeFormat: PresentationDateTimeFormat, categories: [StorageUsageCategory], sectionId: ItemListSectionId) { init(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, categories: [StorageUsageCategory], sectionId: ItemListSectionId) {
self.theme = theme self.theme = theme
self.strings = strings
self.dateTimeFormat = dateTimeFormat self.dateTimeFormat = dateTimeFormat
self.categories = categories self.categories = categories
self.sectionId = sectionId self.sectionId = sectionId
@ -187,7 +189,7 @@ private final class StorageUsageItemNode: ListViewItemNode {
let category = item.categories[i] let category = item.categories[i]
let attributedString = NSMutableAttributedString(string: category.title, font: Font.regular(14.0), textColor: item.theme.list.itemPrimaryTextColor, paragraphAlignment: .natural) let attributedString = NSMutableAttributedString(string: category.title, font: Font.regular(14.0), textColor: item.theme.list.itemPrimaryTextColor, paragraphAlignment: .natural)
attributedString.append(NSAttributedString(string: "\(dataSizeString(category.size, forceDecimal: true, decimalSeparator: item.dateTimeFormat.decimalSeparator))", font: Font.bold(14.0), textColor: item.theme.list.itemPrimaryTextColor)) attributedString.append(NSAttributedString(string: "\(dataSizeString(category.size, forceDecimal: true, formatting: DataSizeStringFormatting(strings: item.strings, decimalSeparator: item.dateTimeFormat.decimalSeparator)))", font: Font.bold(14.0), textColor: item.theme.list.itemPrimaryTextColor))
let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 60.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (textLayout, textApply) = makeTextLayout(TextNodeLayoutArguments(attributedString: attributedString, backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: params.width - params.leftInset - params.rightInset - 60.0, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))

View File

@ -238,7 +238,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
case .builtin: case .builtin:
displaySize = CGSize(width: 1308.0, height: 2688.0).fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor displaySize = CGSize(width: 1308.0, height: 2688.0).fitted(CGSize(width: 1280.0, height: 1280.0)).dividedByScreenScale().integralFloor
contentSize = displaySize contentSize = displaySize
signal = settingsBuiltinWallpaperImage(account: context.account) signal = settingsBuiltinWallpaperImage(account: self.context.account)
fetchSignal = .complete() fetchSignal = .complete()
statusSignal = .single(.Local) statusSignal = .single(.Local)
subtitleSignal = .single(nil) subtitleSignal = .single(nil)
@ -316,8 +316,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.colorPreview = self.arguments.colorPreview self.colorPreview = self.arguments.colorPreview
signal = patternWallpaperImage(account: context.account, accountManager: context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true) signal = patternWallpaperImage(account: self.context.account, accountManager: self.context.sharedContext.accountManager, representations: convertedRepresentations, mode: .screen, autoFetchFullSize: true)
colorSignal = chatServiceBackgroundColor(wallpaper: wallpaper, mediaBox: context.account.postbox.mediaBox) colorSignal = chatServiceBackgroundColor(wallpaper: wallpaper, mediaBox: self.context.account.postbox.mediaBox)
isBlurrable = false isBlurrable = false
} else { } else {
@ -341,7 +341,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
} }
if let fileSize = file.file.size { if let fileSize = file.file.size {
subtitleSignal = .single(dataSizeString(fileSize)) subtitleSignal = .single(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData)))
} else { } else {
subtitleSignal = .single(nil) subtitleSignal = .single(nil)
} }
@ -374,7 +374,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
} }
} }
if let fileSize = largestSize.resource.size { if let fileSize = largestSize.resource.size {
subtitleSignal = .single(dataSizeString(fileSize)) subtitleSignal = .single(dataSizeString(fileSize, formatting: DataSizeStringFormatting(presentationData: self.presentationData)))
} else { } else {
subtitleSignal = .single(nil) subtitleSignal = .single(nil)
} }

View File

@ -1920,7 +1920,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
for participant in membersValue.participants { for participant in membersValue.participants {
if participant.peer.id == self.joinAsPeerId { if participant.peer.id == self.joinAsPeerId {
if participant.raiseHandRating != nil { if participant.hasRaiseHand {
return return
} }
break break
@ -1936,7 +1936,7 @@ public final class PresentationGroupCallImpl: PresentationGroupCall {
} }
for participant in membersValue.participants { for participant in membersValue.participants {
if participant.peer.id == self.joinAsPeerId { if participant.peer.id == self.joinAsPeerId {
if participant.raiseHandRating == nil { if !participant.hasRaiseHand {
return return
} }
break break

View File

@ -140,7 +140,7 @@ private final class VoiceChatControllerTitleNode: ASDisplayNode {
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: UIColor(rgb: 0xffffff)) self.titleNode.attributedText = NSAttributedString(string: title, font: Font.medium(17.0), textColor: UIColor(rgb: 0xffffff))
self.infoNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(13.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.5)) self.infoNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(13.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.5))
let constrainedSize = CGSize(width: size.width - 120.0, height: size.height) let constrainedSize = CGSize(width: size.width - 140.0, height: size.height)
let titleSize = self.titleNode.measure(constrainedSize) let titleSize = self.titleNode.measure(constrainedSize)
let infoSize = self.infoNode.measure(constrainedSize) let infoSize = self.infoNode.measure(constrainedSize)
let titleInfoSpacing: CGFloat = 0.0 let titleInfoSpacing: CGFloat = 0.0

View File

@ -4,33 +4,49 @@ import Foundation
private final class LinkHelperClass: NSObject { private final class LinkHelperClass: NSObject {
} }
public func dataSizeString(_ size: Int, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { public func dataSizeString(_ size: Int, forceDecimal: Bool = false, formatting: DataSizeStringFormatting) -> String {
return dataSizeString(Int64(size), forceDecimal: forceDecimal, decimalSeparator: decimalSeparator) return dataSizeString(Int64(size), forceDecimal: forceDecimal, formatting: formatting)
} }
public func dataSizeString(_ size: Int64, forceDecimal: Bool = false, decimalSeparator: String = ".") -> String { public struct DataSizeStringFormatting {
let decimalSeparator: String
let byte: (String) -> (String, [(Int, NSRange)])
let kilobyte: (String) -> (String, [(Int, NSRange)])
let megabyte: (String) -> (String, [(Int, NSRange)])
let gigabyte: (String) -> (String, [(Int, NSRange)])
public init(decimalSeparator: String, byte: @escaping (String) -> (String, [(Int, NSRange)]), kilobyte: @escaping (String) -> (String, [(Int, NSRange)]), megabyte: @escaping (String) -> (String, [(Int, NSRange)]), gigabyte: @escaping (String) -> (String, [(Int, NSRange)])) {
self.decimalSeparator = decimalSeparator
self.byte = byte
self.kilobyte = kilobyte
self.megabyte = megabyte
self.gigabyte = gigabyte
}
}
public func dataSizeString(_ size: Int64, forceDecimal: Bool = false, formatting: DataSizeStringFormatting) -> String {
if size >= 1024 * 1024 * 1024 { if size >= 1024 * 1024 * 1024 {
let remainder = Int64((Double(size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102.4)).rounded(.down)) let remainder = Int64((Double(size % (1024 * 1024 * 1024)) / (1024 * 1024 * 102.4)).rounded(.down))
if remainder != 0 || forceDecimal { if remainder != 0 || forceDecimal {
return "\(size / (1024 * 1024 * 1024))\(decimalSeparator)\(remainder) GB" return formatting.gigabyte("\(size / (1024 * 1024 * 1024))\(formatting.decimalSeparator)\(remainder)").0
} else { } else {
return "\(size / (1024 * 1024 * 1024)) GB" return formatting.gigabyte("\(size / (1024 * 1024 * 1024))").0
} }
} else if size >= 1024 * 1024 { } else if size >= 1024 * 1024 {
let remainder = Int64((Double(size % (1024 * 1024)) / (1024.0 * 102.4)).rounded(.down)) let remainder = Int64((Double(size % (1024 * 1024)) / (1024.0 * 102.4)).rounded(.down))
if remainder != 0 || forceDecimal { if remainder != 0 || forceDecimal {
return "\(size / (1024 * 1024))\(decimalSeparator)\(remainder) MB" return formatting.megabyte( "\(size / (1024 * 1024))\(formatting.decimalSeparator)\(remainder)").0
} else { } else {
return "\(size / (1024 * 1024)) MB" return formatting.megabyte("\(size / (1024 * 1024))").0
} }
} else if size >= 1024 { } else if size >= 1024 {
let remainder = (size % (1024)) / (102) let remainder = (size % (1024)) / (102)
if remainder != 0 || forceDecimal { if remainder != 0 || forceDecimal {
return "\(size / 1024)\(decimalSeparator)\(remainder) KB" return formatting.kilobyte("\(size / 1024)\(formatting.decimalSeparator)\(remainder)").0
} else { } else {
return "\(size / 1024) KB" return formatting.kilobyte("\(size / 1024)").0
} }
} else { } else {
return "\(size) B" return formatting.byte("\(size)").0
} }
} }

View File

@ -0,0 +1,17 @@
import Foundation
import TelegramCore
import TelegramPresentationData
public extension DataSizeStringFormatting {
init(presentationData: PresentationData) {
self.init(decimalSeparator: presentationData.dateTimeFormat.decimalSeparator, byte: presentationData.strings.FileSize_B(_:), kilobyte: presentationData.strings.FileSize_KB(_:), megabyte: presentationData.strings.FileSize_MB(_:), gigabyte: presentationData.strings.FileSize_GB(_:))
}
init (chatPresentationData: ChatPresentationData) {
self.init(decimalSeparator: chatPresentationData.dateTimeFormat.decimalSeparator, byte: chatPresentationData.strings.FileSize_B(_:), kilobyte: chatPresentationData.strings.FileSize_KB(_:), megabyte: chatPresentationData.strings.FileSize_MB(_:), gigabyte: chatPresentationData.strings.FileSize_GB(_:))
}
init (strings: PresentationStrings, decimalSeparator: String) {
self.init(decimalSeparator: decimalSeparator, byte: strings.FileSize_B(_:), kilobyte: strings.FileSize_KB(_:), megabyte: strings.FileSize_MB(_:), gigabyte: strings.FileSize_GB(_:))
}
}

View File

@ -8080,7 +8080,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if filteredSize == 0 { if filteredSize == 0 {
title = presentationData.strings.Cache_ClearNone title = presentationData.strings.Cache_ClearNone
} else { } else {
title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0 title = presentationData.strings.Cache_Clear("\(dataSizeString(filteredSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0
} }
if let item = item as? ActionSheetButtonItem { if let item = item as? ActionSheetButtonItem {
@ -8133,7 +8133,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
totalSize += categorySize totalSize += categorySize
if categorySize > 1024 { if categorySize > 1024 {
let index = itemIndex let index = itemIndex
items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator), value: true, action: { value in items.append(ActionSheetCheckboxItem(title: stringForCategory(strings: presentationData.strings, category: categoryId), label: dataSizeString(categorySize, formatting: DataSizeStringFormatting(presentationData: presentationData)), value: true, action: { value in
toggleCheck(categoryId, index) toggleCheck(categoryId, index)
})) }))
itemIndex += 1 itemIndex += 1
@ -8145,7 +8145,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if items.isEmpty { if items.isEmpty {
strongSelf.presentClearCacheSuggestion() strongSelf.presentClearCacheSuggestion()
} else { } else {
items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))").0, action: { items.append(ActionSheetButtonItem(title: presentationData.strings.Cache_Clear("\(dataSizeString(totalSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))").0, action: {
let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 }) let clearCategories = sizeIndex.keys.filter({ sizeIndex[$0]!.0 })
var clearMediaIds = Set<MediaId>() var clearMediaIds = Set<MediaId>()
@ -8203,7 +8203,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
disposable.set((signal disposable.set((signal
|> deliverOnMainQueue).start(completed: { [weak self] in |> deliverOnMainQueue).start(completed: { [weak self] in
if let strongSelf = self, let _ = strongSelf.validLayout { if let strongSelf = self, let _ = strongSelf.validLayout {
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), in: .current) strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .succeed(text: presentationData.strings.ClearCache_Success("\(dataSizeString(selectedSize, formatting: DataSizeStringFormatting(presentationData: presentationData)))", stringForDeviceType()).0), elevatedLayout: false, action: { _ in return false }), in: .current)
} }
})) }))
@ -11273,7 +11273,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
openUserGeneratedUrl(context: self.context, url: url, concealed: concealed, skipUrlAuth: skipUrlAuth, present: { [weak self] c in openUserGeneratedUrl(context: self.context, peerId: self.peerView?.peerId, url: url, concealed: concealed, skipUrlAuth: skipUrlAuth, present: { [weak self] c in
self?.present(c, in: .window(.root)) self?.present(c, in: .window(.root))
}, openResolved: { [weak self] resolved in }, openResolved: { [weak self] resolved in
self?.openResolved(resolved) self?.openResolved(resolved)

View File

@ -222,7 +222,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
return { context, presentationData, message, associatedData, chatLocation, attributes, isPinned, forcedIsEdited, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, messageSelection, constrainedSize in return { context, presentationData, message, associatedData, chatLocation, attributes, isPinned, forcedIsEdited, file, automaticDownload, incoming, isRecentActions, forcedResourceStatus, dateAndStatusType, messageSelection, constrainedSize in
return (CGFloat.greatestFiniteMagnitude, { constrainedSize in return (CGFloat.greatestFiniteMagnitude, { constrainedSize in
let titleFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 16.0 / 17.0)) let titleFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 16.0 / 17.0))
let descriptionFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0)) let descriptionFont = Font.with(size: floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0), design: .regular, weight: .regular, traits: [.monospacedNumbers])
let durationFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 11.0 / 17.0)) let durationFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 11.0 / 17.0))
var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? var updateImageSignal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
@ -384,7 +384,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
if let performer = performer { if let performer = performer {
descriptionText = performer descriptionText = performer
} else if let size = file.size { } else if let size = file.size {
descriptionText = dataSizeString(size, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) descriptionText = dataSizeString(size, formatting: DataSizeStringFormatting(chatPresentationData: presentationData))
} else { } else {
descriptionText = "" descriptionText = ""
} }
@ -408,7 +408,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
} else if !isVoice { } else if !isVoice {
let descriptionText: String let descriptionText: String
if let size = file.size { if let size = file.size {
descriptionText = dataSizeString(size, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) descriptionText = dataSizeString(size, formatting: DataSizeStringFormatting(chatPresentationData: presentationData))
} else { } else {
descriptionText = "" descriptionText = ""
} }
@ -818,9 +818,9 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
switch fetchStatus { switch fetchStatus {
case let .Fetching(_, progress): case let .Fetching(_, progress):
if let size = file.size { if let size = file.size {
let compactString = dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator) let compactString = dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: DataSizeStringFormatting(chatPresentationData: presentationData))
let descriptionFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0)) let descriptionFont = Font.with(size: floor(presentationData.fontSize.baseDisplaySize * 13.0 / 17.0), design: .regular, weight: .regular, traits: [.monospacedNumbers])
downloadingStrings = ("\(compactString) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator))", compactString, descriptionFont) downloadingStrings = ("\(compactString) / \(dataSizeString(size, forceDecimal: true, formatting: DataSizeStringFormatting(chatPresentationData: presentationData)))", compactString, descriptionFont)
} }
default: default:
break break

View File

@ -1077,6 +1077,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
let gifTitle = game != nil ? strings.Message_Game.uppercased() : strings.Message_Animation.uppercased() let gifTitle = game != nil ? strings.Message_Game.uppercased() : strings.Message_Animation.uppercased()
let formatting = DataSizeStringFormatting(strings: strings, decimalSeparator: decimalSeparator)
switch fetchStatus { switch fetchStatus {
case let .Fetching(_, progress): case let .Fetching(_, progress):
let adjustedProgress = max(progress, 0.027) let adjustedProgress = max(progress, 0.027)
@ -1093,7 +1095,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
if let file = self.media as? TelegramMediaFile { if let file = self.media as? TelegramMediaFile {
if wideLayout { if wideLayout {
if let size = file.size { if let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))" let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if file.isAnimated { if file.isAnimated {
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(gifTitle)", size: nil, muted: false, active: false) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(gifTitle)", size: nil, muted: false, active: false)
} }
@ -1116,7 +1118,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
state = automaticPlayback ? .none : state state = automaticPlayback ? .none : state
} }
} else { } else {
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))", size: nil, muted: false, active: false) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))", size: nil, muted: false, active: false)
} }
} else if let _ = file.duration { } else if let _ = file.duration {
if file.isAnimated { if file.isAnimated {
@ -1130,7 +1132,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
} }
} else { } else {
if isMediaStreamable(message: message, media: file), let size = file.size { if isMediaStreamable(message: message, media: file), let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))" let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
if message.flags.contains(.Unsent), let duration = file.duration { if message.flags.contains(.Unsent), let duration = file.duration {
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition) let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
@ -1158,7 +1160,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition) let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition)
if automaticPlayback, let size = file.size { if automaticPlayback, let size = file.size {
let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, decimalSeparator: decimalSeparator)) / \(dataSizeString(size, forceDecimal: true, decimalSeparator: decimalSeparator))" let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))"
mediaDownloadState = .fetching(progress: progress) mediaDownloadState = .fetching(progress: progress)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active)
} else { } else {
@ -1206,14 +1208,14 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio
state = .download(messageTheme.mediaOverlayControlColors.foregroundColor) state = .download(messageTheme.mediaOverlayControlColors.foregroundColor)
if let file = self.media as? TelegramMediaFile { if let file = self.media as? TelegramMediaFile {
if file.isAnimated && (!automaticDownload || !automaticPlayback) { if file.isAnimated && (!automaticDownload || !automaticPlayback) {
let string = "\(gifTitle) " + dataSizeString(file.size ?? 0, decimalSeparator: decimalSeparator) let string = "\(gifTitle) " + dataSizeString(file.size ?? 0, formatting: formatting)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: string, size: nil, muted: false, active: false) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: string, size: nil, muted: false, active: false)
} else { } else {
let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : (file.duration ?? 0), position: playerPosition) let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : (file.duration ?? 0), position: playerPosition)
if wideLayout { if wideLayout {
if isMediaStreamable(message: message, media: file) { if isMediaStreamable(message: message, media: file) {
state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor) state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor)
badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(file.size ?? 0, decimalSeparator: decimalSeparator), muted: muted, active: true) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(file.size ?? 0, formatting: formatting), muted: muted, active: true)
mediaDownloadState = .remote mediaDownloadState = .remote
} else { } else {
state = automaticPlayback ? .none : state state = automaticPlayback ? .none : state

View File

@ -182,7 +182,7 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
let media = WallpaperPreviewMedia(content: .file(file, topColor, bottomColor, rotation, false, false)) let media = WallpaperPreviewMedia(content: .file(file, topColor, bottomColor, rotation, false, false))
mediaAndFlags = (media, [.preferMediaAspectFilled]) mediaAndFlags = (media, [.preferMediaAspectFilled])
if let fileSize = file.size { if let fileSize = file.size {
badge = dataSizeString(fileSize, decimalSeparator: item.presentationData.dateTimeFormat.decimalSeparator) badge = dataSizeString(fileSize, formatting: DataSizeStringFormatting(chatPresentationData: item.presentationData))
} }
} else { } else {
mediaAndFlags = (file, []) mediaAndFlags = (file, [])

View File

@ -880,7 +880,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
} }
private func openUrl(_ url: String) { private func openUrl(_ url: String) {
self.navigationActionDisposable.set((self.context.sharedContext.resolveUrl(account: self.context.account, url: url, skipUrlAuth: true) |> deliverOnMainQueue).start(next: { [weak self] result in self.navigationActionDisposable.set((self.context.sharedContext.resolveUrl(context: self.context, peerId: nil, url: url, skipUrlAuth: true) |> deliverOnMainQueue).start(next: { [weak self] result in
if let strongSelf = self { if let strongSelf = self {
switch result { switch result {
case let .externalUrl(url): case let .externalUrl(url):

View File

@ -250,7 +250,7 @@ func openChatInstantPage(context: AccountContext, message: Message, sourcePeerTy
func openChatWallpaper(context: AccountContext, message: Message, present: @escaping (ViewController, Any?) -> Void) { func openChatWallpaper(context: AccountContext, message: Message, present: @escaping (ViewController, Any?) -> Void) {
for media in message.media { for media in message.media {
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url, skipUrlAuth: true) let _ = (context.sharedContext.resolveUrl(context: context, peerId: nil, url: content.url, skipUrlAuth: true)
|> deliverOnMainQueue).start(next: { resolvedUrl in |> deliverOnMainQueue).start(next: { resolvedUrl in
if case let .wallpaper(parameter) = resolvedUrl { if case let .wallpaper(parameter) = resolvedUrl {
let source: WallpaperListSource let source: WallpaperListSource
@ -274,7 +274,7 @@ func openChatWallpaper(context: AccountContext, message: Message, present: @esca
func openChatTheme(context: AccountContext, message: Message, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) { func openChatTheme(context: AccountContext, message: Message, pushController: @escaping (ViewController) -> Void, present: @escaping (ViewController, Any?) -> Void) {
for media in message.media { for media in message.media {
if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
let _ = (context.sharedContext.resolveUrl(account: context.account, url: content.url, skipUrlAuth: true) let _ = (context.sharedContext.resolveUrl(context: context, peerId: nil, url: content.url, skipUrlAuth: true)
|> deliverOnMainQueue).start(next: { resolvedUrl in |> deliverOnMainQueue).start(next: { resolvedUrl in
var file: TelegramMediaFile? var file: TelegramMediaFile?
var settings: TelegramThemeSettings? var settings: TelegramThemeSettings?

View File

@ -229,7 +229,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} }
let handleInternalUrl: (String) -> Void = { url in let handleInternalUrl: (String) -> Void = { url in
let _ = (context.sharedContext.resolveUrl(account: context.account, url: url, skipUrlAuth: true) let _ = (context.sharedContext.resolveUrl(context: context, peerId: nil, url: url, skipUrlAuth: true)
|> deliverOnMainQueue).start(next: handleResolvedUrl) |> deliverOnMainQueue).start(next: handleResolvedUrl)
} }

View File

@ -3147,7 +3147,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
private func openUrl(url: String, concealed: Bool, external: Bool) { private func openUrl(url: String, concealed: Bool, external: Bool) {
openUserGeneratedUrl(context: self.context, url: url, concealed: concealed, present: { [weak self] c in openUserGeneratedUrl(context: self.context, peerId: self.peerId, url: url, concealed: concealed, present: { [weak self] c in
self?.controller?.present(c, in: .window(.root)) self?.controller?.present(c, in: .window(.root))
}, openResolved: { [weak self] tempResolved in }, openResolved: { [weak self] tempResolved in
guard let strongSelf = self else { guard let strongSelf = self else {
@ -3544,6 +3544,46 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
if let strongSelf = self, let peer = strongSelf.data?.peer as? TelegramUser, let phone = peer.phone { if let strongSelf = self, let peer = strongSelf.data?.peer as? TelegramUser, let phone = peer.phone {
let contact = TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil) let contact = TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil)
let shareController = ShareController(context: strongSelf.context, subject: .media(.standalone(media: contact))) let shareController = ShareController(context: strongSelf.context, subject: .media(.standalone(media: contact)))
shareController.completed = { [weak self] peerIds in
if let strongSelf = self {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
var peers: [Peer] = []
for peerId in peerIds {
if let peer = transaction.getPeer(peerId) {
peers.append(peer)
}
}
return peers
} |> deliverOnMainQueue).start(next: { [weak self] peers in
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String
var savedMessages = false
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
text = presentationData.strings.UserInfo_ContactForwardTooltip_SavedMessages_One
savedMessages = true
} else {
if peers.count == 1, let peer = peers.first {
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_ContactForwardTooltip_Chat_One(peerName).0
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_ContactForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).0
} else if let peer = peers.first {
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_ContactForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").0
} else {
text = ""
}
}
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .window(.root))
}
})
}
}
strongSelf.controller?.present(shareController, in: .window(.root)) strongSelf.controller?.present(shareController, in: .window(.root))
} }
}))) })))
@ -3866,6 +3906,46 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
private func openUsername(value: String) { private func openUsername(value: String) {
let shareController = ShareController(context: self.context, subject: .url("https://t.me/\(value)")) let shareController = ShareController(context: self.context, subject: .url("https://t.me/\(value)"))
shareController.completed = { [weak self] peerIds in
if let strongSelf = self {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
var peers: [Peer] = []
for peerId in peerIds {
if let peer = transaction.getPeer(peerId) {
peers.append(peer)
}
}
return peers
} |> deliverOnMainQueue).start(next: { [weak self] peers in
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String
var savedMessages = false
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
text = presentationData.strings.UserInfo_LinkForwardTooltip_SavedMessages_One
savedMessages = true
} else {
if peers.count == 1, let peer = peers.first {
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peerName).0
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).0
} else if let peer = peers.first {
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").0
} else {
text = ""
}
}
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .window(.root))
}
})
}
}
shareController.actionCompleted = { [weak self] in shareController.actionCompleted = { [weak self] in
if let strongSelf = self { if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
@ -4392,6 +4472,46 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
} }
if let peer = peer as? TelegramUser, let username = peer.username { if let peer = peer as? TelegramUser, let username = peer.username {
let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/\(username)")) let shareController = ShareController(context: strongSelf.context, subject: .url("https://t.me/\(username)"))
shareController.completed = { [weak self] peerIds in
if let strongSelf = self {
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in
var peers: [Peer] = []
for peerId in peerIds {
if let peer = transaction.getPeer(peerId) {
peers.append(peer)
}
}
return peers
} |> deliverOnMainQueue).start(next: { [weak self] peers in
if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
let text: String
var savedMessages = false
if peerIds.count == 1, let peerId = peerIds.first, peerId == strongSelf.context.account.peerId {
text = presentationData.strings.UserInfo_LinkForwardTooltip_SavedMessages_One
savedMessages = true
} else {
if peers.count == 1, let peer = peers.first {
let peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_Chat_One(peerName).0
} else if peers.count == 2, let firstPeer = peers.first, let secondPeer = peers.last {
let firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
let secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).0
} else if let peer = peers.first {
let peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
text = presentationData.strings.UserInfo_LinkForwardTooltip_ManyChats_One(peerName, "\(peers.count - 1)").0
} else {
text = ""
}
}
strongSelf.controller?.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .window(.root))
}
})
}
}
shareController.actionCompleted = { [weak self] in shareController.actionCompleted = { [weak self] in
if let strongSelf = self { if let strongSelf = self {
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
@ -6441,6 +6561,26 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
} }
} }
private func dismissAllTooltips() {
self.window?.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction()
}
})
self.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction()
}
return true
})
}
override public func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.dismissAllTooltips()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) super.containerLayoutUpdated(layout, transition: transition)

View File

@ -1144,8 +1144,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
} }
} }
public func resolveUrl(account: Account, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> { public func resolveUrl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> {
return resolveUrlImpl(account: account, url: url, skipUrlAuth: skipUrlAuth) return resolveUrlImpl(context: context, peerId: peerId, url: url, skipUrlAuth: skipUrlAuth)
} }
public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) { public func openResolvedUrl(_ resolvedUrl: ResolvedUrl, context: AccountContext, urlContext: OpenURLContext, navigationController: NavigationController?, openPeer: @escaping (PeerId, ChatControllerInteractionNavigateToPeer) -> Void, sendFile: ((FileMediaReference) -> Void)?, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?, requestMessageActionUrlAuth: ((MessageActionUrlSubject) -> Void)?, joinVoiceChat: ((PeerId, String?, CachedChannelData.ActiveCall) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, contentContext: Any?) {

View File

@ -51,7 +51,7 @@ func handleTextLinkActionImpl(context: AccountContext, peerId: PeerId?, navigate
} }
let openLinkImpl: (String) -> Void = { [weak controller] url in let openLinkImpl: (String) -> Void = { [weak controller] url in
navigateDisposable.set((context.sharedContext.resolveUrl(account: context.account, url: url, skipUrlAuth: true) |> deliverOnMainQueue).start(next: { result in navigateDisposable.set((context.sharedContext.resolveUrl(context: context, peerId: peerId, url: url, skipUrlAuth: true) |> deliverOnMainQueue).start(next: { result in
if let controller = controller { if let controller = controller {
switch result { switch result {
case let .externalUrl(url): case let .externalUrl(url):

View File

@ -14,6 +14,7 @@ swift_library(
"//submodules/MtProtoKit:MtProtoKit", "//submodules/MtProtoKit:MtProtoKit",
"//submodules/AccountContext:AccountContext", "//submodules/AccountContext:AccountContext",
"//submodules/TelegramUIPreferences:TelegramUIPreferences", "//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/TelegramNotices:TelegramNotices",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -7,6 +7,7 @@ import SyncCore
import MtProtoKit import MtProtoKit
import TelegramPresentationData import TelegramPresentationData
import TelegramUIPreferences import TelegramUIPreferences
import TelegramNotices
import AccountContext import AccountContext
private let baseTelegramMePaths = ["telegram.me", "t.me", "telegram.dog"] private let baseTelegramMePaths = ["telegram.me", "t.me", "telegram.dog"]
@ -525,13 +526,23 @@ private struct UrlHandlingConfiguration {
} }
} }
public func resolveUrlImpl(account: Account, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> { public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String, skipUrlAuth: Bool) -> Signal<ResolvedUrl, NoError> {
let schemes = ["http://", "https://", ""] let schemes = ["http://", "https://", ""]
return account.postbox.transaction { transaction -> Signal<ResolvedUrl, NoError> in return ApplicationSpecificNotice.getSecretChatLinkPreviews(accountManager: context.sharedContext.accountManager)
|> mapToSignal { linkPreviews -> Signal<ResolvedUrl, NoError> in
return context.account.postbox.transaction { transaction -> Signal<ResolvedUrl, NoError> in
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration) as? AppConfiguration ?? AppConfiguration.defaultValue
let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration) let urlHandlingConfiguration = UrlHandlingConfiguration.with(appConfiguration: appConfiguration)
var skipUrlAuth = skipUrlAuth
if let peerId = peerId, peerId.namespace == Namespaces.Peer.SecretChat {
if let linkPreviews = linkPreviews, linkPreviews {
} else {
skipUrlAuth = true
}
}
var url = url var url = url
if !url.contains("://") && !url.hasPrefix("tel:") && !url.hasPrefix("mailto:") && !url.hasPrefix("calshow:") { if !url.contains("://") && !url.hasPrefix("tel:") && !url.hasPrefix("mailto:") && !url.hasPrefix("calshow:") {
if !(url.hasPrefix("http") || url.hasPrefix("https")) { if !(url.hasPrefix("http") || url.hasPrefix("https")) {
@ -555,7 +566,7 @@ public func resolveUrlImpl(account: Account, url: String, skipUrlAuth: Bool) ->
let basePrefix = scheme + basePath + "/" let basePrefix = scheme + basePath + "/"
if url.lowercased().hasPrefix(basePrefix) { if url.lowercased().hasPrefix(basePrefix) {
if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) { if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) {
return resolveInternalUrl(account: account, url: internalUrl) return resolveInternalUrl(account: context.account, url: internalUrl)
|> map { resolved -> ResolvedUrl in |> map { resolved -> ResolvedUrl in
if let resolved = resolved { if let resolved = resolved {
return resolved return resolved
@ -573,12 +584,13 @@ public func resolveUrlImpl(account: Account, url: String, skipUrlAuth: Bool) ->
for scheme in schemes { for scheme in schemes {
let basePrefix = scheme + basePath let basePrefix = scheme + basePath
if url.lowercased().hasPrefix(basePrefix) { if url.lowercased().hasPrefix(basePrefix) {
return resolveInstantViewUrl(account: account, url: url) return resolveInstantViewUrl(account: context.account, url: url)
} }
} }
} }
return .single(.externalUrl(url)) return .single(.externalUrl(url))
} |> switchToLatest } |> switchToLatest
}
} }
public func resolveInstantViewUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> { public func resolveInstantViewUrl(account: Account, url: String) -> Signal<ResolvedUrl, NoError> {