mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Complex pinned messages scrolling handling
This commit is contained in:
parent
656554c2b0
commit
51d8298e80
@ -51,6 +51,7 @@ private enum DebugControllerSection: Int32 {
|
||||
private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
case sendLogs(PresentationTheme)
|
||||
case sendOneLog(PresentationTheme)
|
||||
case sendShareLogs
|
||||
case sendNotificationLogs(PresentationTheme)
|
||||
case sendCriticalLogs(PresentationTheme)
|
||||
case accounts(PresentationTheme)
|
||||
@ -84,7 +85,7 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
|
||||
var section: ItemListSectionId {
|
||||
switch self {
|
||||
case .sendLogs, .sendOneLog, .sendNotificationLogs, .sendCriticalLogs:
|
||||
case .sendLogs, .sendOneLog, .sendShareLogs, .sendNotificationLogs, .sendCriticalLogs:
|
||||
return DebugControllerSection.logs.rawValue
|
||||
case .accounts:
|
||||
return DebugControllerSection.logs.rawValue
|
||||
@ -109,58 +110,60 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
return 0
|
||||
case .sendOneLog:
|
||||
return 1
|
||||
case .sendNotificationLogs:
|
||||
case .sendShareLogs:
|
||||
return 2
|
||||
case .sendCriticalLogs:
|
||||
case .sendNotificationLogs:
|
||||
return 3
|
||||
case .accounts:
|
||||
case .sendCriticalLogs:
|
||||
return 4
|
||||
case .logToFile:
|
||||
case .accounts:
|
||||
return 5
|
||||
case .logToConsole:
|
||||
case .logToFile:
|
||||
return 6
|
||||
case .redactSensitiveData:
|
||||
case .logToConsole:
|
||||
return 7
|
||||
case .enableRaiseToSpeak:
|
||||
case .redactSensitiveData:
|
||||
return 8
|
||||
case .keepChatNavigationStack:
|
||||
case .enableRaiseToSpeak:
|
||||
return 9
|
||||
case .skipReadHistory:
|
||||
case .keepChatNavigationStack:
|
||||
return 10
|
||||
case .crashOnSlowQueries:
|
||||
case .skipReadHistory:
|
||||
return 11
|
||||
case .clearTips:
|
||||
case .crashOnSlowQueries:
|
||||
return 12
|
||||
case .reimport:
|
||||
case .clearTips:
|
||||
return 13
|
||||
case .resetData:
|
||||
case .reimport:
|
||||
return 14
|
||||
case .resetDatabase:
|
||||
case .resetData:
|
||||
return 15
|
||||
case .resetDatabaseAndCache:
|
||||
case .resetDatabase:
|
||||
return 16
|
||||
case .resetHoles:
|
||||
case .resetDatabaseAndCache:
|
||||
return 17
|
||||
case .reindexUnread:
|
||||
case .resetHoles:
|
||||
return 18
|
||||
case .resetBiometricsData:
|
||||
case .reindexUnread:
|
||||
return 19
|
||||
case .optimizeDatabase:
|
||||
case .resetBiometricsData:
|
||||
return 20
|
||||
case .photoPreview:
|
||||
case .optimizeDatabase:
|
||||
return 21
|
||||
case .knockoutWallpaper:
|
||||
case .photoPreview:
|
||||
return 22
|
||||
case .alternativeFolderTabs:
|
||||
case .knockoutWallpaper:
|
||||
return 23
|
||||
case .playerEmbedding:
|
||||
case .alternativeFolderTabs:
|
||||
return 24
|
||||
case .playlistPlayback:
|
||||
case .playerEmbedding:
|
||||
return 25
|
||||
case .voiceConference:
|
||||
case .playlistPlayback:
|
||||
return 26
|
||||
case .voiceConference:
|
||||
return 27
|
||||
case let .preferredVideoCodec(index, _, _, _):
|
||||
return 27 + index
|
||||
return 28 + index
|
||||
case .disableVideoAspectScaling:
|
||||
return 100
|
||||
case .enableVoipTcp:
|
||||
@ -327,9 +330,77 @@ private enum DebugControllerEntry: ItemListNodeEntry {
|
||||
arguments.presentController(actionSheet, nil)
|
||||
})
|
||||
})
|
||||
case let .sendShareLogs:
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: "Send Share Logs (Up to 40 MB)", label: "", sectionId: self.section, style: .blocks, action: {
|
||||
let _ = (Logger.shared.collectLogs(prefix: "/share-logs")
|
||||
|> deliverOnMainQueue).start(next: { logs in
|
||||
let presentationData = arguments.sharedContext.currentPresentationData.with { $0 }
|
||||
let actionSheet = ActionSheetController(presentationData: presentationData)
|
||||
|
||||
var items: [ActionSheetButtonItem] = []
|
||||
|
||||
if let context = arguments.context {
|
||||
items.append(ActionSheetButtonItem(title: "Via Telegram", color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled]))
|
||||
controller.peerSelected = { [weak controller] peerId in
|
||||
if let strongController = controller {
|
||||
strongController.dismiss()
|
||||
|
||||
let lineFeed = "\n".data(using: .utf8)!
|
||||
var logData: Data = Data()
|
||||
for (name, path) in logs {
|
||||
if !logData.isEmpty {
|
||||
logData.append(lineFeed)
|
||||
logData.append(lineFeed)
|
||||
}
|
||||
|
||||
logData.append("------ File: \(name) ------\n".data(using: .utf8)!)
|
||||
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
|
||||
logData.append(data)
|
||||
}
|
||||
}
|
||||
|
||||
let id = arc4random64()
|
||||
let fileResource = LocalFileMediaResource(fileId: id, size: logData.count, isSecretRelated: false)
|
||||
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: logData)
|
||||
|
||||
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: logData.count, attributes: [.FileName(fileName: "Log-iOS-Full.txt")])
|
||||
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
|
||||
|
||||
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
|
||||
}
|
||||
}
|
||||
arguments.pushController(controller)
|
||||
}))
|
||||
}
|
||||
items.append(ActionSheetButtonItem(title: "Via Email", color: .accent, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
|
||||
let composeController = MFMailComposeViewController()
|
||||
composeController.mailComposeDelegate = arguments.mailComposeDelegate
|
||||
composeController.setSubject("Telegram Logs")
|
||||
for (name, path) in logs {
|
||||
if let data = try? Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe) {
|
||||
composeController.addAttachmentData(data, mimeType: "application/text", fileName: name)
|
||||
}
|
||||
}
|
||||
arguments.getRootController()?.present(composeController, animated: true, completion: nil)
|
||||
}))
|
||||
|
||||
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
|
||||
ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in
|
||||
actionSheet?.dismissAnimated()
|
||||
})
|
||||
])])
|
||||
arguments.presentController(actionSheet, nil)
|
||||
})
|
||||
})
|
||||
case let .sendNotificationLogs(theme):
|
||||
return ItemListDisclosureItem(presentationData: presentationData, title: "Send Notification Logs", label: "", sectionId: self.section, style: .blocks, action: {
|
||||
let _ = (Logger(basePath: arguments.sharedContext.basePath + "/notificationServiceLogs").collectLogs()
|
||||
let _ = (Logger(rootPath: arguments.sharedContext.basePath, basePath: arguments.sharedContext.basePath + "/notificationServiceLogs").collectLogs()
|
||||
|> deliverOnMainQueue).start(next: { logs in
|
||||
guard let context = arguments.context else {
|
||||
return
|
||||
@ -708,6 +779,7 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS
|
||||
|
||||
entries.append(.sendLogs(presentationData.theme))
|
||||
entries.append(.sendOneLog(presentationData.theme))
|
||||
entries.append(.sendShareLogs)
|
||||
entries.append(.sendNotificationLogs(presentationData.theme))
|
||||
entries.append(.sendCriticalLogs(presentationData.theme))
|
||||
entries.append(.accounts(presentationData.theme))
|
||||
|
@ -77,6 +77,7 @@ public final class Logger {
|
||||
private let maxShortLength: Int = 1 * 1024 * 1024
|
||||
private let maxFiles: Int = 20
|
||||
|
||||
private let rootPath: String
|
||||
private let basePath: String
|
||||
private var file: (ManagedFile, Int)?
|
||||
private var shortFile: (ManagedFile, Int)?
|
||||
@ -114,22 +115,30 @@ public final class Logger {
|
||||
return sharedLogger
|
||||
} else {
|
||||
assertionFailure()
|
||||
let tempLogger = Logger(basePath: "")
|
||||
let tempLogger = Logger(rootPath: "", basePath: "")
|
||||
tempLogger.logToFile = false
|
||||
tempLogger.logToConsole = false
|
||||
return tempLogger
|
||||
}
|
||||
}
|
||||
|
||||
public init(basePath: String) {
|
||||
public init(rootPath: String, basePath: String) {
|
||||
self.rootPath = rootPath
|
||||
self.basePath = basePath
|
||||
}
|
||||
|
||||
public func collectLogs() -> Signal<[(String, String)], NoError> {
|
||||
public func collectLogs(prefix: String? = nil) -> Signal<[(String, String)], NoError> {
|
||||
return Signal { subscriber in
|
||||
self.queue.async {
|
||||
let logsPath: String
|
||||
if let prefix = prefix {
|
||||
logsPath = self.rootPath + prefix
|
||||
} else {
|
||||
logsPath = self.basePath
|
||||
}
|
||||
|
||||
var result: [(Date, String, String)] = []
|
||||
if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: self.basePath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) {
|
||||
if let files = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: logsPath), includingPropertiesForKeys: [URLResourceKey.creationDateKey], options: []) {
|
||||
for url in files {
|
||||
if url.lastPathComponent.hasPrefix("log-") {
|
||||
if let creationDate = (try? url.resourceValues(forKeys: Set([.creationDateKey])))?.creationDate {
|
||||
|
@ -444,7 +444,7 @@ final class SharedApplicationContext {
|
||||
|
||||
let logsPath = rootPath + "/logs"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
Logger.setSharedLogger(Logger(basePath: logsPath))
|
||||
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: logsPath))
|
||||
|
||||
if let contents = try? FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: rootPath + "/accounts-metadata"), includingPropertiesForKeys: nil, options: [.skipsSubdirectoryDescendants]) {
|
||||
for url in contents {
|
||||
|
@ -155,6 +155,18 @@ private func calculateSlowmodeActiveUntilTimestamp(account: Account, untilTimest
|
||||
}
|
||||
}
|
||||
|
||||
private struct ScrolledToMessageId: Equatable {
|
||||
struct AllowedReplacementDirections: OptionSet {
|
||||
var rawValue: Int32
|
||||
|
||||
static let up = AllowedReplacementDirections(rawValue: 1 << 0)
|
||||
static let down = AllowedReplacementDirections(rawValue: 1 << 1)
|
||||
}
|
||||
|
||||
var id: MessageId
|
||||
var allowedReplacementDirection: AllowedReplacementDirections
|
||||
}
|
||||
|
||||
public final class ChatControllerImpl: TelegramBaseController, ChatController, GalleryHiddenMediaTarget, UIDropInteractionDelegate {
|
||||
private var validLayout: ContainerViewLayout?
|
||||
|
||||
@ -358,7 +370,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
|
||||
public var purposefulAction: (() -> Void)?
|
||||
|
||||
private let scrolledToMessageId = ValuePromise<MessageId?>(nil, ignoreRepeated: true)
|
||||
private let scrolledToMessageId = ValuePromise<ScrolledToMessageId?>(nil, ignoreRepeated: true)
|
||||
private var scrolledToMessageIdValue: ScrolledToMessageId? = nil {
|
||||
didSet {
|
||||
self.scrolledToMessageId.set(self.scrolledToMessageIdValue)
|
||||
}
|
||||
}
|
||||
|
||||
public init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?> = Atomic<ChatLocationContextHolder?>(value: nil), subject: ChatControllerSubject? = nil, botStart: ChatControllerInitialBotStart? = nil, mode: ChatControllerPresentationMode = .standard(previewing: false), peekData: ChatPeekTimeout? = nil, peerNearbyData: ChatPeerNearbyData? = nil) {
|
||||
let _ = ChatControllerCount.modify { value in
|
||||
@ -3247,23 +3264,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let topPinnedMessage: Signal<ChatPinnedMessage?, NoError>
|
||||
switch self.chatLocation {
|
||||
case let .peer(peerId):
|
||||
let replyHistory: Signal<ChatHistoryViewUpdate, NoError> = (chatHistoryViewForLocation(ChatHistoryLocationInput(content: .Initial(count: 100), id: 0), context: self.context, chatLocation: .peer(peerId), chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), scheduled: false, fixedCombinedReadStates: nil, tagMask: MessageTags.pinned, additionalData: [])
|
||||
|> castError(Bool.self)
|
||||
|> mapToSignal { update -> Signal<ChatHistoryViewUpdate, Bool> in
|
||||
switch update {
|
||||
case let .Loading(_, type):
|
||||
if case .Generic(.FillHole) = type {
|
||||
return .fail(true)
|
||||
}
|
||||
case let .HistoryView(_, type, _, _, _, _, _):
|
||||
if case .Generic(.FillHole) = type {
|
||||
return .fail(true)
|
||||
}
|
||||
}
|
||||
return .single(update)
|
||||
})
|
||||
|> restartIfError
|
||||
|
||||
struct ReferenceMessage {
|
||||
var id: MessageId
|
||||
var isScrolled: Bool
|
||||
@ -3279,55 +3279,181 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
self.chatDisplayNode.historyNode.topVisibleMessageRange.get()
|
||||
)
|
||||
|> map { scrolledToMessageId, topVisibleMessageRange -> ReferenceMessage? in
|
||||
let topVisibleMessage = topVisibleMessageRange?.upperBound
|
||||
|
||||
if let scrolledToMessageId = scrolledToMessageId {
|
||||
return ReferenceMessage(id: scrolledToMessageId, isScrolled: true)
|
||||
} else if let topVisibleMessageRange = topVisibleMessageRange {
|
||||
return ReferenceMessage(id: topVisibleMessageRange.upperBound, isScrolled: false)
|
||||
if let topVisibleMessage = topVisibleMessage {
|
||||
if scrolledToMessageId.allowedReplacementDirection.contains(.up) && topVisibleMessage < scrolledToMessageId.id {
|
||||
return ReferenceMessage(id: topVisibleMessage, isScrolled: false)
|
||||
}
|
||||
}
|
||||
return ReferenceMessage(id: scrolledToMessageId.id, isScrolled: true)
|
||||
} else if let topVisibleMessage = topVisibleMessage {
|
||||
return ReferenceMessage(id: topVisibleMessage, isScrolled: false)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
topPinnedMessage = combineLatest(
|
||||
replyHistory,
|
||||
referenceMessage
|
||||
)
|
||||
|> map { update, referenceMessage -> ChatPinnedMessage? in
|
||||
var message: ChatPinnedMessage?
|
||||
let context = self.context
|
||||
|
||||
func replyHistorySignal(anchorMessageId: MessageId?, count: Int) -> Signal<ChatHistoryViewUpdate, NoError> {
|
||||
let location: ChatHistoryLocation
|
||||
if let anchorMessageId = anchorMessageId {
|
||||
location = .InitialSearch(location: .id(anchorMessageId), count: count, highlight: false)
|
||||
} else {
|
||||
location = .Initial(count: count)
|
||||
}
|
||||
|
||||
return (chatHistoryViewForLocation(ChatHistoryLocationInput(content: location, id: 0), context: context, chatLocation: .peer(peerId), chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), scheduled: false, fixedCombinedReadStates: nil, tagMask: MessageTags.pinned, additionalData: [])
|
||||
|> castError(Bool.self)
|
||||
|> mapToSignal { update -> Signal<ChatHistoryViewUpdate, Bool> in
|
||||
switch update {
|
||||
case let .Loading(_, type):
|
||||
if case .Generic(.FillHole) = type {
|
||||
return .fail(true)
|
||||
}
|
||||
case let .HistoryView(_, type, _, _, _, _, _):
|
||||
if case .Generic(.FillHole) = type {
|
||||
return .fail(true)
|
||||
}
|
||||
}
|
||||
return .single(update)
|
||||
})
|
||||
|> restartIfError
|
||||
}
|
||||
|
||||
let topMessage = replyHistorySignal(anchorMessageId: nil, count: 3)
|
||||
|> map { update -> Message? in
|
||||
switch update {
|
||||
case .Loading:
|
||||
break
|
||||
case let .HistoryView(view, _, _, _, _, _, _):
|
||||
let topMessageId: MessageId
|
||||
if view.entries.isEmpty {
|
||||
return nil
|
||||
return nil
|
||||
case let .HistoryView(viewValue, _, _, _, _, _, _):
|
||||
return viewValue.entries.last?.message
|
||||
}
|
||||
}
|
||||
|
||||
let loadCount = 100
|
||||
|
||||
let adjustedReplyHistory: Signal<[Message], NoError>
|
||||
if latest {
|
||||
adjustedReplyHistory = replyHistorySignal(anchorMessageId: nil, count: loadCount)
|
||||
|> map { view -> [Message] in
|
||||
switch view {
|
||||
case .Loading:
|
||||
return []
|
||||
case let .HistoryView(viewValue, _, _, _, _, _, _):
|
||||
return viewValue.entries.map(\.message)
|
||||
}
|
||||
topMessageId = view.entries[view.entries.count - 1].message.id
|
||||
for i in 0 ..< view.entries.count {
|
||||
let entry = view.entries[i]
|
||||
var matches = false
|
||||
if message == nil {
|
||||
matches = true
|
||||
} else if let referenceMessage = referenceMessage {
|
||||
if referenceMessage.isScrolled {
|
||||
if entry.message.id < referenceMessage.id {
|
||||
matches = true
|
||||
}
|
||||
} else {
|
||||
adjustedReplyHistory = (Signal<[Message], NoError> { subscriber in
|
||||
var referenceMessageValue: ReferenceMessage?
|
||||
var view: ChatHistoryViewUpdate?
|
||||
|
||||
let updateState: () -> Void = {
|
||||
guard let view = view else {
|
||||
return
|
||||
}
|
||||
guard case let .HistoryView(viewValue, _, _, _, _, _, _) = view else {
|
||||
subscriber.putNext([])
|
||||
subscriber.putCompletion()
|
||||
return
|
||||
}
|
||||
|
||||
if let referenceId = referenceMessageValue?.id {
|
||||
if viewValue.entries.count < loadCount {
|
||||
subscriber.putNext(viewValue.entries.map(\.message))
|
||||
} else if referenceId < viewValue.entries[1].message.id {
|
||||
if viewValue.earlierId != nil {
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putNext(viewValue.entries.map(\.message))
|
||||
}
|
||||
} else if referenceId > viewValue.entries[viewValue.entries.count - 2].message.id {
|
||||
if viewValue.laterId != nil {
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putNext(viewValue.entries.map(\.message))
|
||||
}
|
||||
} else {
|
||||
if entry.message.id <= referenceMessage.id {
|
||||
matches = true
|
||||
}
|
||||
subscriber.putNext(viewValue.entries.map(\.message))
|
||||
}
|
||||
} else {
|
||||
matches = true
|
||||
}
|
||||
if matches {
|
||||
message = ChatPinnedMessage(message: entry.message, topMessageId: topMessageId)
|
||||
if viewValue.holeLater || viewValue.laterId != nil {
|
||||
subscriber.putCompletion()
|
||||
} else {
|
||||
subscriber.putNext(viewValue.entries.map(\.message))
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
var initializedView = false
|
||||
let viewDisposable = MetaDisposable()
|
||||
|
||||
let referenceDisposable = (referenceMessage
|
||||
|> deliverOnMainQueue).start(next: { referenceMessage in
|
||||
referenceMessageValue = referenceMessage
|
||||
if !initializedView {
|
||||
initializedView = true
|
||||
//print("reload at \(String(describing: referenceMessage?.id)) disposable \(unsafeBitCast(viewDisposable, to: UInt64.self))")
|
||||
viewDisposable.set((replyHistorySignal(anchorMessageId: referenceMessage?.id, count: loadCount)
|
||||
|> deliverOnMainQueue).start(next: { next in
|
||||
view = next
|
||||
updateState()
|
||||
}))
|
||||
}
|
||||
updateState()
|
||||
})
|
||||
|
||||
return ActionDisposable {
|
||||
//print("dispose \(unsafeBitCast(viewDisposable, to: UInt64.self))")
|
||||
referenceDisposable.dispose()
|
||||
viewDisposable.dispose()
|
||||
}
|
||||
}
|
||||
|> runOn(.mainQueue()))
|
||||
|> restart
|
||||
}
|
||||
|
||||
topPinnedMessage = combineLatest(queue: .mainQueue(),
|
||||
adjustedReplyHistory,
|
||||
topMessage,
|
||||
referenceMessage
|
||||
)
|
||||
|> map { messages, topMessage, referenceMessage -> ChatPinnedMessage? in
|
||||
var message: ChatPinnedMessage?
|
||||
|
||||
let topMessageId: MessageId
|
||||
if messages.isEmpty {
|
||||
return nil
|
||||
}
|
||||
topMessageId = topMessage?.id ?? messages[messages.count - 1].id
|
||||
//print("reference: \(String(describing: referenceMessage?.id.id)) entries: \(view.entries.map(\.index.id.id))")
|
||||
for i in 0 ..< messages.count {
|
||||
let entry = messages[i]
|
||||
var matches = false
|
||||
if message == nil {
|
||||
matches = true
|
||||
} else if let referenceMessage = referenceMessage {
|
||||
if referenceMessage.isScrolled {
|
||||
if entry.id < referenceMessage.id {
|
||||
matches = true
|
||||
}
|
||||
} else {
|
||||
if entry.id <= referenceMessage.id {
|
||||
matches = true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
matches = true
|
||||
}
|
||||
if matches {
|
||||
message = ChatPinnedMessage(message: entry, topMessageId: topMessageId)
|
||||
}
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
@ -3355,12 +3481,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.beganDragging = { [weak self] in
|
||||
self.chatDisplayNode.historyNode.didScrollWithOffset = { [weak self] offset, _, _ in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.scrolledToMessageId.set(nil)
|
||||
if offset > 0.0 {
|
||||
if var scrolledToMessageIdValue = strongSelf.scrolledToMessageIdValue {
|
||||
scrolledToMessageIdValue.allowedReplacementDirection.insert(.up)
|
||||
strongSelf.scrolledToMessageIdValue = scrolledToMessageIdValue
|
||||
}
|
||||
} else if offset < 0.0 {
|
||||
strongSelf.scrolledToMessageIdValue = nil
|
||||
}
|
||||
}
|
||||
|
||||
self.chatDisplayNode.peerView = self.peerView
|
||||
@ -3690,7 +3823,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
let highlightedState = ChatInterfaceHighlightedState(messageStableId: message.stableId)
|
||||
controllerInteraction.highlightedState = highlightedState
|
||||
strongSelf.updateItemNodesHighlightedStates(animated: false)
|
||||
strongSelf.scrolledToMessageId.set(index.id)
|
||||
strongSelf.scrolledToMessageIdValue = ScrolledToMessageId(id: index.id, allowedReplacementDirection: [])
|
||||
|
||||
strongSelf.messageContextDisposable.set((Signal<Void, NoError>.complete() |> delay(0.7, queue: Queue.mainQueue())).start(completed: {
|
||||
if let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction {
|
||||
@ -3709,7 +3842,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.scrolledToMessageId.set(nil)
|
||||
strongSelf.scrolledToMessageIdValue = nil
|
||||
}
|
||||
|
||||
self.chatDisplayNode.historyNode.maxVisibleMessageIndexUpdated = { [weak self] index in
|
||||
|
@ -25,10 +25,10 @@ private var sharedAccountContext: SharedAccountContext?
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
private func setupSharedLogger(_ path: String) {
|
||||
private func setupSharedLogger(rootPath: String, path: String) {
|
||||
if !installedSharedLogger {
|
||||
installedSharedLogger = true
|
||||
Logger.setSharedLogger(Logger(basePath: path))
|
||||
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: path))
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +107,7 @@ public final class NotificationViewControllerImpl {
|
||||
let logsPath = rootPath + "/notificationcontent-logs"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
setupSharedLogger(logsPath)
|
||||
setupSharedLogger(rootPath: rootPath, path: logsPath)
|
||||
|
||||
accountsPath = rootPath
|
||||
|
||||
|
@ -35,10 +35,10 @@ private var globalInternalContext: InternalContext?
|
||||
|
||||
private var installedSharedLogger = false
|
||||
|
||||
private func setupSharedLogger(_ path: String) {
|
||||
private func setupSharedLogger(rootPath: String, path: String) {
|
||||
if !installedSharedLogger {
|
||||
installedSharedLogger = true
|
||||
Logger.setSharedLogger(Logger(basePath: path))
|
||||
Logger.setSharedLogger(Logger(rootPath: rootPath, basePath: path))
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,7 +138,7 @@ public class ShareRootControllerImpl {
|
||||
let logsPath = rootPath + "/share-logs"
|
||||
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
setupSharedLogger(logsPath)
|
||||
setupSharedLogger(rootPath: rootPath, path: logsPath)
|
||||
|
||||
let applicationBindings = TelegramApplicationBindings(isMainApp: false, containerPath: self.initializationData.appGroupPath, appSpecificScheme: "tg", openUrl: { _ in
|
||||
}, openUniversalUrl: { _, completion in
|
||||
|
Loading…
x
Reference in New Issue
Block a user