Merge commit '4c500ce3b2fb03264150c7f20d7d9927eb23d12f'

This commit is contained in:
Ali 2023-02-23 23:56:19 +04:00
commit bea0076bf7
24 changed files with 205 additions and 2154 deletions

View File

@ -8934,3 +8934,5 @@ Sorry for the inconvenience.";
"MediaPicker.VoiceOver.Camera" = "Camera";
"ChatList.ReadAll" = "Read All";
"ChatList.ClearSavedMessagesConfirmation" = "Are you sure you want to delete all your saved messages?";

View File

@ -168,13 +168,13 @@ public final class AuthorizationSequenceController: NavigationController, MFMail
guard let self else {
return
}
controller?.inProgress = true
let authorizationPushConfiguration = self.sharedContext.authorizationPushConfiguration
|> take(1)
|> timeout(2.0, queue: .mainQueue(), alternate: .single(nil))
let _ = (authorizationPushConfiguration
|> deliverOnMainQueue).start(next: { [weak self] authorizationPushConfiguration in
if let strongSelf = self {
controller?.inProgress = true
strongSelf.actionDisposable.set((sendAuthorizationCode(accountManager: strongSelf.sharedContext.accountManager, account: strongSelf.account, phoneNumber: number, apiId: strongSelf.apiId, apiHash: strongSelf.apiHash, pushNotificationConfiguration: authorizationPushConfiguration, firebaseSecretStream: strongSelf.sharedContext.firebaseSecretStream, syncContacts: syncContacts, forcedPasswordSetupNotice: { value in
guard let entry = CodableEntry(ApplicationSpecificCounterNotice(value: value)) else {
return nil

View File

@ -2177,6 +2177,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
reorderedFilterIdsValue = reorderedFilterIds
}
let completion = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.chatListDisplayNode.isReorderingFilters = false
strongSelf.isReorderingTabsValue.set(false)
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(true, transition: .animated(duration: 0.2, curve: .easeInOut))
strongSelf.searchContentNode?.setIsEnabled(true, animated: true)
if let layout = strongSelf.validLayout {
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
}
}
if let reorderedFilterIds = reorderedFilterIdsValue {
let _ = (self.context.engine.peers.updateChatListFiltersInteractively { stateFilters in
var updatedFilters: [ChatListFilter] = []
@ -2199,18 +2211,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
return
}
strongSelf.reloadFilters(firstUpdate: {
guard let strongSelf = self else {
return
}
strongSelf.chatListDisplayNode.isReorderingFilters = false
strongSelf.isReorderingTabsValue.set(false)
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(true, transition: .animated(duration: 0.2, curve: .easeInOut))
strongSelf.searchContentNode?.setIsEnabled(true, animated: true)
if let layout = strongSelf.validLayout {
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
}
completion()
})
})
} else {
completion()
}
}

View File

@ -32,7 +32,7 @@ func chatListSelectionOptions(context: AccountContext, peerIds: Set<PeerId>, fil
return context.engine.data.subscribe(TelegramEngine.EngineData.Item.Messages.TotalReadCounters())
|> map { readCounters -> ChatListSelectionOptions in
var hasUnread = false
if readCounters.count(for: .filtered, in: .chats, with: .all) != 0 {
if readCounters.count(for: .raw, in: .chats, with: .all) != 0 {
hasUnread = true
}
return ChatListSelectionOptions(read: .all(enabled: hasUnread), delete: false)

View File

@ -129,7 +129,7 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode {
}
case let .clearHistory(canClearCache):
if peer.id == context.account.peerId {
text = PresentationStrings.FormattedString(string: strings.ChatList_DeleteSavedMessagesConfirmation, ranges: [])
text = PresentationStrings.FormattedString(string: strings.ChatList_ClearSavedMessagesConfirmation, ranges: [])
} else if case .user = peer {
text = strings.ChatList_ClearChatConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder))
} else {

View File

@ -67,7 +67,6 @@ public final class ListViewBackingView: UIView {
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !self.isHidden, let target = self.target {
if target.bounds.contains(point) {
target.scroller.forceDecelerating = false
if target.decelerationAnimator != nil {
target.decelerationAnimator?.isPaused = true
target.decelerationAnimator = nil
@ -836,6 +835,7 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
}
self.scrolledToItem = nil
self.scroller.forceDecelerating = false
self.isDragging = true
self.beganInteractiveDragging(self.touchesPosition)

View File

@ -1514,7 +1514,7 @@ open class TextNode: ASDisplayNode {
if glyphCount == 2, let font = attributes["NSFont"] as? UIFont, font.fontName.contains("ColorEmoji"), let string = layout.attributedString {
let range = CTRunGetStringRange(run)
if range.location < string.length && (range.location + range.length) < string.length {
if range.location < string.length && (range.location + range.length) <= string.length {
let substring = string.attributedSubstring(from: NSMakeRange(range.location, range.length)).string
let heart = Unicode.Scalar(0x2764)!

View File

@ -2619,15 +2619,15 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
c.setItems(strongSelf.contextMenuMainItems(dismiss: dismiss) |> map { ContextController.Items(content: .list($0)) }, minHeight: nil)
})))
// items.append(.custom(SliderContextItem(minValue: 0.05, maxValue: 2.5, value: status.baseRate, valueChanged: { [weak self] newValue, finished in
// guard let strongSelf = self, let videoNode = strongSelf.videoNode else {
// return
// }
// videoNode.setBaseRate(newValue)
// if finished {
// dismiss()
// }
// }), true))
items.append(.custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: status.baseRate, valueChanged: { [weak self] newValue, finished in
guard let strongSelf = self else {
return
}
strongSelf.updatePlaybackRate(newValue)
if finished {
dismiss()
}
}), true))
items.append(.separator)

View File

@ -192,17 +192,17 @@ open class ManagedAnimationNode: ASDisplayNode {
displayLinkUpdate = { [weak self] in
if let strongSelf = self {
let timestamp = CACurrentMediaTime()
var delta: Double
if let previousTimestamp = strongSelf.previousTimestamp {
delta = min(timestamp - previousTimestamp, 1.0 / 60.0)
if let currentDelta = strongSelf.delta, currentDelta < delta {
delta = currentDelta
}
} else {
delta = 1.0 / 60.0
}
strongSelf.previousTimestamp = timestamp
// let timestamp = CACurrentMediaTime()
// var delta: Double
// if let previousTimestamp = strongSelf.previousTimestamp {
// delta = min(timestamp - previousTimestamp, 1.0 / 60.0)
// if let currentDelta = strongSelf.delta, currentDelta < delta {
// delta = currentDelta
// }
// } else {
let delta = 1.0 / 60.0
// }
// strongSelf.previousTimestamp = timestamp
strongSelf.delta = delta
strongSelf.updateAnimation()

View File

@ -1,435 +0,0 @@
import Foundation
import UIKit
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import ItemListUI
import PresentationDataUtils
import AccountContext
private enum NetworkUsageControllerSection {
case cellular
case wifi
}
private final class NetworkUsageStatsControllerArguments {
let resetStatistics: (NetworkUsageControllerSection) -> Void
init(resetStatistics: @escaping (NetworkUsageControllerSection) -> Void) {
self.resetStatistics = resetStatistics
}
}
private enum NetworkUsageStatsSection: Int32 {
case messages
case image
case video
case audio
case file
case call
case total
case reset
}
private enum NetworkUsageStatsEntry: ItemListNodeEntry {
case messagesHeader(PresentationTheme, String)
case messagesSent(PresentationTheme, String, String)
case messagesReceived(PresentationTheme, String, String)
case imageHeader(PresentationTheme, String)
case imageSent(PresentationTheme, String, String)
case imageReceived(PresentationTheme, String, String)
case videoHeader(PresentationTheme, String)
case videoSent(PresentationTheme, String, String)
case videoReceived(PresentationTheme, String, String)
case audioHeader(PresentationTheme, String)
case audioSent(PresentationTheme, String, String)
case audioReceived(PresentationTheme, String, String)
case fileHeader(PresentationTheme, String)
case fileSent(PresentationTheme, String, String)
case fileReceived(PresentationTheme, String, String)
case callHeader(PresentationTheme, String)
case callSent(PresentationTheme, String, String)
case callReceived(PresentationTheme, String, String)
case reset(PresentationTheme, NetworkUsageControllerSection, String)
case resetTimestamp(PresentationTheme, String)
var section: ItemListSectionId {
switch self {
case .messagesHeader, .messagesSent, .messagesReceived:
return NetworkUsageStatsSection.messages.rawValue
case .imageHeader, .imageSent, .imageReceived:
return NetworkUsageStatsSection.image.rawValue
case .videoHeader, .videoSent, .videoReceived:
return NetworkUsageStatsSection.video.rawValue
case .audioHeader, .audioSent, .audioReceived:
return NetworkUsageStatsSection.audio.rawValue
case .fileHeader, .fileSent, .fileReceived:
return NetworkUsageStatsSection.file.rawValue
case .callHeader, .callSent, .callReceived:
return NetworkUsageStatsSection.call.rawValue
case .reset, .resetTimestamp:
return NetworkUsageStatsSection.reset.rawValue
}
}
var stableId: Int32 {
switch self {
case .messagesHeader:
return 0
case .messagesSent:
return 1
case .messagesReceived:
return 2
case .imageHeader:
return 3
case .imageSent:
return 4
case .imageReceived:
return 5
case .videoHeader:
return 6
case .videoSent:
return 7
case .videoReceived:
return 8
case .audioHeader:
return 9
case .audioSent:
return 10
case .audioReceived:
return 11
case .fileHeader:
return 12
case .fileSent:
return 13
case .fileReceived:
return 14
case .callHeader:
return 15
case .callSent:
return 16
case .callReceived:
return 17
case .reset:
return 18
case .resetTimestamp:
return 19
}
}
static func ==(lhs: NetworkUsageStatsEntry, rhs: NetworkUsageStatsEntry) -> Bool {
switch lhs {
case let .messagesHeader(lhsTheme, lhsText):
if case let .messagesHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .messagesSent(lhsTheme, lhsText, lhsValue):
if case let .messagesSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .messagesReceived(lhsTheme, lhsText, lhsValue):
if case let .messagesReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .imageHeader(lhsTheme, lhsText):
if case let .imageHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .imageSent(lhsTheme, lhsText, lhsValue):
if case let .imageSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .imageReceived(lhsTheme, lhsText, lhsValue):
if case let .imageReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .videoHeader(lhsTheme, lhsText):
if case let .videoHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .videoSent(lhsTheme, lhsText, lhsValue):
if case let .videoSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .videoReceived(lhsTheme, lhsText, lhsValue):
if case let .videoReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .audioHeader(lhsTheme, lhsText):
if case let .audioHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .audioSent(lhsTheme, lhsText, lhsValue):
if case let .audioSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .audioReceived(lhsTheme, lhsText, lhsValue):
if case let .audioReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .fileHeader(lhsTheme, lhsText):
if case let .fileHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .fileSent(lhsTheme, lhsText, lhsValue):
if case let .fileSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .fileReceived(lhsTheme, lhsText, lhsValue):
if case let .fileReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callHeader(lhsTheme, lhsText):
if case let .callHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
case let .callSent(lhsTheme, lhsText, lhsValue):
if case let .callSent(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .callReceived(lhsTheme, lhsText, lhsValue):
if case let .callReceived(rhsTheme, rhsText, rhsValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue {
return true
} else {
return false
}
case let .reset(lhsTheme, lhsSection, lhsText):
if case let .reset(rhsTheme, rhsSection, rhsText) = rhs, lhsTheme === rhsTheme, lhsSection == rhsSection, lhsText == rhsText {
return true
} else {
return false
}
case let .resetTimestamp(lhsTheme, lhsText):
if case let .resetTimestamp(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
return true
} else {
return false
}
}
}
static func <(lhs: NetworkUsageStatsEntry, rhs: NetworkUsageStatsEntry) -> Bool {
return lhs.stableId < rhs.stableId
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! NetworkUsageStatsControllerArguments
switch self {
case let .messagesHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .messagesSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .messagesReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .imageHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .imageSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .imageReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .videoHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .videoSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .videoReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .audioHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .audioSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .audioReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .fileHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .fileSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .fileReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .callHeader(_, text):
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
case let .callSent(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .callReceived(_, text, value):
return ItemListDisclosureItem(presentationData: presentationData, title: text, label: value, sectionId: self.section, style: .blocks, disclosureStyle: .none , action: nil)
case let .reset(_, section, text):
return ItemListActionItem(presentationData: presentationData, title: text, kind: .generic, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.resetStatistics(section)
})
case let .resetTimestamp(_, text):
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
}
}
}
private func networkUsageStatsControllerEntries(presentationData: PresentationData, section: NetworkUsageControllerSection, stats: NetworkUsageStats) -> [NetworkUsageStatsEntry] {
var entries: [NetworkUsageStatsEntry] = []
let formatting = DataSizeStringFormatting(presentationData: presentationData)
switch section {
case .cellular:
entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection))
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, formatting: formatting)))
entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection))
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, formatting: formatting)))
entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection))
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, formatting: formatting)))
entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection))
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, formatting: formatting)))
entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection))
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, formatting: formatting)))
entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection))
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, formatting: formatting)))
entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats))
if stats.resetCellularTimestamp != 0 {
let formatter = DateFormatter()
formatter.dateFormat = "E, d MMM yyyy HH:mm"
let dateStringPlain = formatter.string(from: Date(timeIntervalSince1970: Double(stats.resetCellularTimestamp)))
entries.append(.resetTimestamp(presentationData.theme, presentationData.strings.NetworkUsageSettings_CellularUsageSince(dateStringPlain).string))
}
case .wifi:
entries.append(.messagesHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_GeneralDataSection))
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, formatting: formatting)))
entries.append(.imageHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaImageDataSection))
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, formatting: formatting)))
entries.append(.videoHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaVideoDataSection))
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, formatting: formatting)))
entries.append(.audioHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaAudioDataSection))
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, formatting: formatting)))
entries.append(.fileHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_MediaDocumentDataSection))
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, formatting: formatting)))
entries.append(.callHeader(presentationData.theme, presentationData.strings.NetworkUsageSettings_CallDataSection))
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, formatting: formatting)))
entries.append(.reset(presentationData.theme, section, presentationData.strings.NetworkUsageSettings_ResetStats))
if stats.resetWifiTimestamp != 0 {
let formatter = DateFormatter()
formatter.dateFormat = "E, d MMM yyyy HH:mm"
let dateStringPlain = formatter.string(from: Date(timeIntervalSince1970: Double(stats.resetWifiTimestamp)))
entries.append(.resetTimestamp(presentationData.theme, presentationData.strings.NetworkUsageSettings_WifiUsageSince(dateStringPlain).string))
}
}
return entries
}
func networkUsageStatsController(context: AccountContext) -> ViewController {
let section = ValuePromise<NetworkUsageControllerSection>(.cellular)
let stats = Promise<NetworkUsageStats>()
stats.set(accountNetworkUsageStats(account: context.account, reset: []))
var presentControllerImpl: ((ViewController) -> Void)?
let arguments = NetworkUsageStatsControllerArguments(resetStatistics: { [weak stats] section in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = ActionSheetController(presentationData: presentationData)
let dismissAction: () -> Void = { [weak controller] in
controller?.dismissAnimated()
}
controller.setItemGroups([
ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: presentationData.strings.NetworkUsageSettings_ResetStats, color: .destructive, action: {
dismissAction()
let reset: ResetNetworkUsageStats
switch section {
case .wifi:
reset = .wifi
case .cellular:
reset = .cellular
}
stats?.set(accountNetworkUsageStats(account: context.account, reset: reset))
}),
]),
ActionSheetItemGroup(items: [ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, action: { dismissAction() })])
])
presentControllerImpl?(controller)
})
let signal = combineLatest(context.sharedContext.presentationData, section.get(), stats.get()) |> deliverOnMainQueue
|> map { presentationData, section, stats -> (ItemListControllerState, (ItemListNodeState, Any)) in
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .sectionControl([presentationData.strings.NetworkUsageSettings_Cellular, presentationData.strings.NetworkUsageSettings_Wifi], 0), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: networkUsageStatsControllerEntries(presentationData: presentationData, section: section, stats: stats), style: .blocks, emptyStateItem: nil, animateChanges: false)
return (controllerState, (listState, arguments))
}
let controller = ItemListController(context: context, state: signal)
controller.titleControlValueChanged = { [weak section] index in
section?.set(index == 0 ? .cellular : .wifi)
}
presentControllerImpl = { [weak controller] c in
controller?.present(c, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
return controller
}

View File

@ -16,6 +16,7 @@ import UrlHandling
import AccountUtils
import PremiumUI
import PasswordSetupUI
import StorageUsageScreen
private struct DeleteAccountOptionsArguments {
let changePhoneNumber: () -> Void
@ -276,7 +277,9 @@ public func deleteAccountOptionsController(context: AccountContext, navigationCo
}, clearCache: {
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_cache_tap")
pushControllerImpl?(storageUsageController(context: context))
pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
}))
dismissImpl?()
}, clearSyncedContacts: {
addAppLogEvent(postbox: context.account.postbox, type: "deactivate.options_clear_contacts_tap")

View File

@ -15,6 +15,7 @@ import PresentationDataUtils
import UrlHandling
import AccountUtils
import PremiumUI
import StorageUsageScreen
private struct LogoutOptionsItemArguments {
let addAccount: () -> Void
@ -181,7 +182,9 @@ public func logoutOptionsController(context: AccountContext, navigationControlle
})
dismissImpl?()
}, clearCache: {
pushControllerImpl?(storageUsageController(context: context))
pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
}))
dismissImpl?()
}, changePhoneNumber: {
let introController = PrivacyIntroController(context: context, mode: .changePhoneNumber(phoneNumber), proceedAction: {

View File

@ -20,6 +20,7 @@ import InstantPageCache
import NotificationPeerExceptionController
import QrCodeUI
import PremiumUI
import StorageUsageScreen
enum SettingsSearchableItemIcon {
case profile
@ -681,16 +682,54 @@ private func dataSearchableItems(context: AccountContext) -> [SettingsSearchable
presentDataSettings(context, present, nil)
}),
SettingsSearchableItem(id: .data(1), title: strings.ChatSettings_Cache, alternate: synonyms(strings.SettingsSearch_Synonyms_Data_Storage_Title), icon: icon, breadcrumbs: [strings.Settings_ChatSettings], present: { context, _, present in
present(.push, storageUsageController(context: context))
let controller = StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
})
present(.push, controller)
}),
SettingsSearchableItem(id: .data(2), title: strings.Cache_KeepMedia, alternate: synonyms(strings.SettingsSearch_Synonyms_Data_Storage_KeepMedia), icon: icon, breadcrumbs: [strings.Settings_ChatSettings, strings.ChatSettings_Cache], present: { context, _, present in
present(.push, storageUsageController(context: context))
let controller = StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
})
present(.push, controller)
}),
SettingsSearchableItem(id: .data(3), title: strings.Cache_ClearCache, alternate: synonyms(strings.SettingsSearch_Synonyms_Data_Storage_ClearCache), icon: icon, breadcrumbs: [strings.Settings_ChatSettings, strings.ChatSettings_Cache], present: { context, _, present in
present(.push, storageUsageController(context: context))
let controller = StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
})
present(.push, controller)
}),
SettingsSearchableItem(id: .data(4), title: strings.NetworkUsageSettings_Title, alternate: synonyms(strings.SettingsSearch_Synonyms_Data_NetworkUsage), icon: icon, breadcrumbs: [strings.Settings_ChatSettings], present: { context, _, present in
present(.push, networkUsageStatsController(context: context))
let mediaAutoDownloadSettings = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings])
|> map { sharedData -> MediaAutoDownloadSettings in
var automaticMediaDownloadSettings: MediaAutoDownloadSettings
if let value = sharedData.entries[ApplicationSpecificSharedDataKeys.automaticMediaDownloadSettings]?.get(MediaAutoDownloadSettings.self) {
automaticMediaDownloadSettings = value
} else {
automaticMediaDownloadSettings = .defaultSettings
}
return automaticMediaDownloadSettings
}
let _ = (combineLatest(
accountNetworkUsageStats(account: context.account, reset: []),
mediaAutoDownloadSettings
)
|> take(1)
|> deliverOnMainQueue).start(next: { stats, mediaAutoDownloadSettings in
var stats = stats
if stats.resetWifiTimestamp == 0 {
var value = stat()
if stat(context.account.basePath, &value) == 0 {
stats.resetWifiTimestamp = Int32(value.st_ctimespec.tv_sec)
}
}
present(.push, DataUsageScreen(context: context, stats: stats, mediaAutoDownloadSettings: mediaAutoDownloadSettings, makeAutodownloadSettingsController: { isCellular in
return autodownloadMediaConnectionTypeController(context: context, connectionType: isCellular ? .cellular : .wifi)
}))
})
}),
SettingsSearchableItem(id: .data(5), title: strings.ChatSettings_AutoDownloadUsingCellular, alternate: synonyms(strings.SettingsSearch_Synonyms_Data_AutoDownloadUsingCellular), icon: icon, breadcrumbs: [strings.Settings_ChatSettings, strings.ChatSettings_AutoDownloadTitle], present: { context, _, present in
present(.push, autodownloadMediaConnectionTypeController(context: context, connectionType: .cellular))

View File

@ -527,14 +527,14 @@ public final class MediaNavigationAccessoryHeaderNode: ASDisplayNode, UIScrollVi
private func contextMenuSpeedItems(dismiss: @escaping () -> Void) -> Signal<[ContextMenuItem], NoError> {
var items: [ContextMenuItem] = []
// items.append(.custom(SliderContextItem(minValue: 0.05, maxValue: 2.5, value: self.playbackBaseRate?.doubleValue ?? 1.0, valueChanged: { [weak self] newValue, finished in
// self?.setRate?(AudioPlaybackRate(newValue), true)
// if finished {
// dismiss()
// }
// }), true))
items.append(.custom(SliderContextItem(minValue: 0.5, maxValue: 2.5, value: self.playbackBaseRate?.doubleValue ?? 1.0, valueChanged: { [weak self] newValue, finished in
self?.setRate?(AudioPlaybackRate(newValue), true)
if finished {
dismiss()
}
}), true))
// items.append(.separator)
items.append(.separator)
for (text, _, rate) in self.speedList(strings: self.strings) {
let isSelected = self.playbackBaseRate == rate

View File

@ -15,6 +15,7 @@ swift_library(
"//submodules/Display:Display",
"//submodules/ContextUI:ContextUI",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/AnimatedCountLabelNode:AnimatedCountLabelNode",
],
visibility = [
"//visibility:public",

View File

@ -4,6 +4,7 @@ import Display
import AsyncDisplayKit
import ContextUI
import TelegramPresentationData
import AnimatedCountLabelNode
public final class SliderContextItem: ContextMenuCustomItem {
private let minValue: CGFloat
@ -23,15 +24,15 @@ public final class SliderContextItem: ContextMenuCustomItem {
}
}
private let textFont = Font.regular(17.0)
private let textFont = Font.with(size: 17.0, design: .regular, traits: .monospacedNumbers)
private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode {
private var presentationData: PresentationData
private let backgroundTextNode: ImmediateTextNode
private let backgroundTextNode: ImmediateAnimatedCountLabelNode
private let foregroundNode: ASDisplayNode
private let foregroundTextNode: ImmediateTextNode
private let foregroundTextNode: ImmediateAnimatedCountLabelNode
let minValue: CGFloat
let maxValue: CGFloat
@ -51,24 +52,18 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode
self.maxValue = maxValue
self.value = value
self.valueChanged = valueChanged
self.backgroundTextNode = ImmediateTextNode()
self.backgroundTextNode.isAccessibilityElement = false
self.backgroundTextNode.isUserInteractionEnabled = false
self.backgroundTextNode.displaysAsynchronously = false
self.backgroundTextNode.textAlignment = .left
self.backgroundTextNode = ImmediateAnimatedCountLabelNode()
self.backgroundTextNode.alwaysOneDirection = true
self.foregroundNode = ASDisplayNode()
self.foregroundNode.clipsToBounds = true
self.foregroundNode.isAccessibilityElement = false
self.foregroundNode.backgroundColor = UIColor(rgb: 0xffffff)
self.foregroundNode.isUserInteractionEnabled = false
self.foregroundTextNode = ImmediateTextNode()
self.foregroundTextNode.isAccessibilityElement = false
self.foregroundTextNode.isUserInteractionEnabled = false
self.foregroundTextNode.displaysAsynchronously = false
self.foregroundTextNode.textAlignment = .left
self.foregroundTextNode = ImmediateAnimatedCountLabelNode()
self.foregroundTextNode.alwaysOneDirection = true
super.init()
@ -77,6 +72,27 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode
self.addSubnode(self.backgroundTextNode)
self.addSubnode(self.foregroundNode)
self.foregroundNode.addSubnode(self.foregroundTextNode)
let stringValue = "1.0x"
let backgroundTextColor = self.presentationData.theme.contextMenu.secondaryColor
let foregroundTextColor = UIColor.black
var backgroundSegments: [AnimatedCountLabelNode.Segment] = []
var foregroundSegments: [AnimatedCountLabelNode.Segment] = []
var textCount = 0
for char in stringValue {
if let intValue = Int(String(char)) {
backgroundSegments.append(.number(intValue, NSAttributedString(string: String(char), font: textFont, textColor: backgroundTextColor)))
foregroundSegments.append(.number(intValue, NSAttributedString(string: String(char), font: textFont, textColor: foregroundTextColor)))
} else {
backgroundSegments.append(.text(textCount, NSAttributedString(string: String(char), font: textFont, textColor: backgroundTextColor)))
foregroundSegments.append(.text(textCount, NSAttributedString(string: String(char), font: textFont, textColor: foregroundTextColor)))
textCount += 1
}
}
self.backgroundTextNode.segments = backgroundSegments
self.foregroundTextNode.segments = foregroundSegments
}
override func didLoad() {
@ -101,28 +117,43 @@ private final class SliderContextItemNode: ASDisplayNode, ContextMenuCustomNode
let value = (self.value - self.minValue) / range
transition.updateFrameAdditive(node: self.foregroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: value * width, height: self.frame.height)))
var stringValue = String(format: "%.1fx", self.value)
if stringValue.hasSuffix(".0x") {
stringValue = stringValue.replacingOccurrences(of: ".0x", with: "x")
}
self.backgroundTextNode.attributedText = NSAttributedString(string: stringValue, font: textFont, textColor: UIColor(rgb: 0xffffff))
self.foregroundTextNode.attributedText = NSAttributedString(string: stringValue, font: textFont, textColor: UIColor(rgb: 0x000000))
let stringValue = String(format: "%.1fx", self.value)
let _ = self.backgroundTextNode.updateLayout(CGSize(width: 70.0, height: .greatestFiniteMagnitude))
let _ = self.foregroundTextNode.updateLayout(CGSize(width: 70.0, height: .greatestFiniteMagnitude))
let backgroundTextColor = self.presentationData.theme.contextMenu.secondaryColor
let foregroundTextColor = UIColor.black
var backgroundSegments: [AnimatedCountLabelNode.Segment] = []
var foregroundSegments: [AnimatedCountLabelNode.Segment] = []
var textCount = 0
for char in stringValue {
if let intValue = Int(String(char)) {
backgroundSegments.append(.number(intValue, NSAttributedString(string: String(char), font: textFont, textColor: backgroundTextColor)))
foregroundSegments.append(.number(intValue, NSAttributedString(string: String(char), font: textFont, textColor: foregroundTextColor)))
} else {
backgroundSegments.append(.text(textCount, NSAttributedString(string: String(char), font: textFont, textColor: backgroundTextColor)))
foregroundSegments.append(.text(textCount, NSAttributedString(string: String(char), font: textFont, textColor: foregroundTextColor)))
textCount += 1
}
}
self.backgroundTextNode.segments = backgroundSegments
self.foregroundTextNode.segments = foregroundSegments
let _ = self.backgroundTextNode.updateLayout(size: CGSize(width: 70.0, height: .greatestFiniteMagnitude), animated: true)
let _ = self.foregroundTextNode.updateLayout(size: CGSize(width: 70.0, height: .greatestFiniteMagnitude), animated: true)
}
func updateLayout(constrainedWidth: CGFloat, constrainedHeight: CGFloat) -> (CGSize, (CGSize, ContainedViewLayoutTransition) -> Void) {
let valueWidth: CGFloat = 70.0
let height: CGFloat = 45.0
var textSize = self.backgroundTextNode.updateLayout(CGSize(width: valueWidth, height: .greatestFiniteMagnitude))
textSize.width = valueWidth
var backgroundTextSize = self.backgroundTextNode.updateLayout(size: CGSize(width: 70.0, height: .greatestFiniteMagnitude), animated: true)
backgroundTextSize.width = valueWidth
let _ = self.foregroundTextNode.updateLayout(size: CGSize(width: 70.0, height: .greatestFiniteMagnitude), animated: true)
return (CGSize(width: height * 3.0, height: height), { size, transition in
let leftInset: CGFloat = 17.0
let textFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((size.height - textSize.height) / 2.0)), size: textSize)
let textFrame = CGRect(origin: CGPoint(x: leftInset, y: floor((height - backgroundTextSize.height) / 2.0)), size: backgroundTextSize)
transition.updateFrameAdditive(node: self.backgroundTextNode, frame: textFrame)
transition.updateFrameAdditive(node: self.foregroundTextNode, frame: textFrame)

View File

@ -89,6 +89,7 @@ import ChatListHeaderComponent
import ChatControllerInteraction
import FeaturedStickersScreen
import ChatEntityKeyboardInputNode
import StorageUsageScreen
#if DEBUG
import os.signpost
@ -525,6 +526,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private var translationStateDisposable: Disposable?
private var nextChannelToReadDisposable: Disposable?
private var offerNextChannelToRead = false
private var inviteRequestsContext: PeerInvitationImportersContext?
private var inviteRequestsDisposable = MetaDisposable()
@ -5010,7 +5012,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return
}
strongSelf.chatDisplayNode.historyNode.offerNextChannelToRead = true
strongSelf.offerNextChannelToRead = true
strongSelf.chatDisplayNode.historyNode.nextChannelToRead = nextPeer.flatMap { nextPeer -> (peer: EnginePeer, unreadCount: Int, location: TelegramEngine.NextUnreadChannelLocation) in
return (peer: nextPeer.peer, unreadCount: nextPeer.unreadCount, location: nextPeer.location)
}
@ -5029,6 +5031,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.preloadNextChatPeerIdDisposable.set(nil)
}
}
strongSelf.updateNextChannelToReadVisibility()
})
}
}
@ -11459,6 +11463,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if (self.presentationInterfaceState.interfaceState.selectionState == nil) != (updatedChatPresentationInterfaceState.interfaceState.selectionState == nil) {
self.isSelectingMessagesUpdated?(updatedChatPresentationInterfaceState.interfaceState.selectionState != nil)
self.updateNextChannelToReadVisibility()
}
self.presentationInterfaceState = updatedChatPresentationInterfaceState
@ -11700,6 +11705,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self?.beginClearHistory(type: type)
}
let context = self.context
let _ = (self.context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: peerId),
TelegramEngine.EngineData.Item.Peer.CanDeleteHistory(id: peerId)
@ -11886,9 +11892,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
default:
text = strongSelf.presentationData.strings.ChatList_DeleteForCurrentUser
}
items.append(ActionSheetButtonItem(title: text, color: .destructive, action: { [weak actionSheet] in
items.append(ActionSheetButtonItem(title: text, color: .destructive, action: { [weak self, weak actionSheet] in
actionSheet?.dismissAnimated()
beginClear(.forLocalPeer)
if mainPeer.id == context.account.peerId, let strongSelf = self {
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationTitle, text: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationText, actions: [
TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {
}),
TextAlertAction(type: .destructiveAction, title: strongSelf.presentationData.strings.ChatList_DeleteSavedMessagesConfirmationAction, action: {
beginClear(.forLocalPeer)
})
], parseMarkdown: true), in: .window(.root))
} else {
beginClear(.forLocalPeer)
}
}))
}
}
@ -12156,7 +12172,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }) })
if let strongSelf = self {
let controller = storageUsageController(context: strongSelf.context, isModal: true)
let context = strongSelf.context
let controller = StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
})
strongSelf.present(controller, in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}))
@ -16970,7 +16989,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
actionSheet?.dismissAnimated()
if let strongSelf = self, !presented {
presented = true
strongSelf.push(storageUsageController(context: strongSelf.context, isModal: true))
let context = strongSelf.context
strongSelf.push(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
}))
}
}))
@ -18179,6 +18201,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return self.presentationData.strings.Chat_SendAllowedContentText(itemListString).string
}
private func updateNextChannelToReadVisibility() {
self.chatDisplayNode.historyNode.offerNextChannelToRead = self.offerNextChannelToRead && self.presentationInterfaceState.interfaceState.selectionState == nil
}
}
private final class ContextControllerContentSourceImpl: ContextControllerContentSource {

View File

@ -1426,6 +1426,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
isSelectionEnabled = false
} else if case .pinnedMessages = self.chatPresentationInterfaceState.subject {
isSelectionEnabled = false
} else if self.chatPresentationInterfaceState.inputTextPanelState.mediaRecordingState != nil {
isSelectionEnabled = false
}
self.historyNode.isSelectionGestureEnabled = isSelectionEnabled
@ -2459,8 +2461,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if textView.inputView !== updatedInputView {
textView.inputView = updatedInputView
if textView.isFirstResponder {
if self.chatPresentationInterfaceStateRequiresInputFocus(chatPresentationInterfaceState) {
if let validLayout = self.validLayout, let inputHeight = validLayout.0.inputHeight, inputHeight > 100.0 {
if self.chatPresentationInterfaceStateRequiresInputFocus(chatPresentationInterfaceState), let validLayout = self.validLayout {
if case .compact = validLayout.0.metrics.widthClass {
waitForKeyboardLayout = true
} else if let inputHeight = validLayout.0.inputHeight, inputHeight > 100.0 {
waitForKeyboardLayout = true
}
}

View File

@ -5,6 +5,7 @@ import AccountContext
import AlertUI
import PresentationDataUtils
import SettingsUI
import StorageUsageScreen
private func totalDiskSpace() -> Int64 {
do {
@ -31,7 +32,9 @@ func checkAvailableDiskSpace(context: AccountContext, threshold: Int64 = 100 * 1
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = textAlertController(context: context, title: nil, text: presentationData.strings.Cache_LowDiskSpaceText, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
push(storageUsageController(context: context, isModal: true))
push(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
}))
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
push(controller)

View File

@ -199,7 +199,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection
let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed))
self.rightNavigationButton = rightNavigationButton
self.navigationItem.rightBarButtonItem = self.rightNavigationButton
rightNavigationButton.isEnabled = count != 0 || self.params.alwaysEnabled
rightNavigationButton.isEnabled = true //count != 0 || self.params.alwaysEnabled
case .channelCreation:
self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "")
let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed))

View File

@ -907,7 +907,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
let _ = (settings
|> deliverOnMainQueue).start(next: { settings in
if settings.defaultWebBrowser == nil {
if isCompact {
if !"".isEmpty && isCompact {
let controller = BrowserScreen(context: context, subject: .webPage(url: parsedUrl.absoluteString))
navigationController?.pushViewController(controller)
} else {

View File

@ -4564,7 +4564,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
canSetupAutoremoveTimeout = true
}
} else if let user = chatPeer as? TelegramUser {
if user.id != strongSelf.context.account.peerId && user.botInfo == nil {
if user.id != strongSelf.context.account.peerId {
canSetupAutoremoveTimeout = true
}
} else if let channel = chatPeer as? TelegramChannel {

View File

@ -1239,8 +1239,9 @@ public final class SharedAccountContextImpl: SharedAccountContext {
guard let navigationController = self.mainWindow?.viewController as? NavigationController else {
return
}
let controller = storageUsageController(context: context, isModal: true)
let controller = StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category)
})
navigationController.pushViewController(controller)
}