Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-11-23 23:35:56 +04:00
commit ca34b4e93a
31 changed files with 627 additions and 413 deletions

View File

@ -377,6 +377,7 @@ official_apple_pay_merchants = [
"merchant.privatbank.test.telergramios",
"merchant.privatbank.prod.telergram",
"merchant.paymaster.test.telegramios",
"merchant.paymaster.prod.telegramios",
"merchant.smartglocal.prod.telegramios",
"merchant.smartglocal.test.telegramios",
"merchant.yoomoney.test.telegramios",

View File

@ -49,7 +49,7 @@ func unreadMessages(account: Account) -> Signal<[INMessage], NoError> {
}
if !isMuted && hasUnread {
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
signals.append(account.postbox.aroundMessageHistoryViewForLocation(.peer(index.messageIndex.id.peerId), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: .combinedLocation)
|> take(1)
|> map { view -> [INMessage] in
var messages: [INMessage] = []

View File

@ -14,7 +14,7 @@ public func authorizationCurrentOptionText(_ type: SentAuthorizationCodeType, st
let body = MarkdownAttributeSet(font: Font.regular(16.0), textColor: primaryColor)
let bold = MarkdownAttributeSet(font: Font.semibold(16.0), textColor: primaryColor)
return parseMarkdownIntoAttributedString(strings.Login_CodeSentInternal, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in nil }), textAlignment: .center)
case .call, .flashCall:
case .call, .flashCall, .missedCall:
return NSAttributedString(string: strings.ChangePhoneNumberCode_Called, font: Font.regular(16.0), textColor: primaryColor, paragraphAlignment: .center)
}
}
@ -31,7 +31,7 @@ public func authorizationNextOptionText(currentType: SentAuthorizationCodeType,
let timeString = NSString(format: "%d:%.02d", Int(minutes), Int(seconds))
return (NSAttributedString(string: strings.Login_WillSendSms(timeString as String).string, font: Font.regular(16.0), textColor: primaryColor, paragraphAlignment: .center), false)
}
case .call, .flashCall:
case .call, .flashCall, .missedCall:
if timeout <= 0 {
return (NSAttributedString(string: strings.ChangePhoneNumberCode_Called, font: Font.regular(16.0), textColor: primaryColor, paragraphAlignment: .center), false)
} else {

View File

@ -28,6 +28,12 @@ private class SimpleLayer: CALayer {
}
}
private enum SelectionTransition {
case begin
case change
case end
}
private final class MediaPreviewView: SimpleLayer {
private let context: AccountContext
private let message: EngineMessage
@ -282,6 +288,7 @@ private final class ImageCache: Equatable {
private final class DayEnvironment: Equatable {
let imageCache: ImageCache
let directImageCache: DirectMediaImageCache
var selectionDelayCoordination: Int = 0
init(imageCache: ImageCache, directImageCache: DirectMediaImageCache) {
self.imageCache = imageCache
@ -417,6 +424,7 @@ private final class DayComponent: Component {
private var action: (() -> Void)?
private var currentMedia: DayMedia?
private var currentSelection: DaySelection?
private(set) var timestamp: Int32?
private(set) var index: MessageIndex?
@ -460,6 +468,11 @@ private final class DayComponent: Component {
self.timestamp = component.timestamp
self.index = component.media?.message.index
self.isHighlightingEnabled = component.isEnabled && component.media != nil && !component.isSelecting
let previousSelection = self.currentSelection ?? component.selection
let previousSelected = previousSelection != .none
let isSelected = component.selection != .none
self.currentSelection = component.selection
let diameter = min(availableSize.width, availableSize.height)
let contentFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - diameter) / 2.0), y: floor((availableSize.height - diameter) / 2.0)), size: CGSize(width: diameter, height: diameter))
@ -471,6 +484,7 @@ private final class DayComponent: Component {
self.highlightView.contents = nil
}
var animateTitle = false
var animateMediaIn = false
if self.currentMedia != component.media {
self.currentMedia = component.media
@ -545,35 +559,32 @@ private final class DayComponent: Component {
case .middle, .none:
if let selectionView = self.selectionView {
self.selectionView = nil
selectionView.removeFromSuperlayer()
if let _ = transition.userData(SelectionTransition.self), previousSelected != isSelected {
selectionView.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false, completion: { [weak selectionView] _ in
selectionView?.removeFromSuperlayer()
})
} else {
selectionView.removeFromSuperlayer()
}
}
}
let minimizedContentScale: CGFloat = (contentFrame.width - 8.0) / contentFrame.width
let contentScale: CGFloat
switch component.selection {
case .edge, .middle:
contentScale = (contentFrame.width - 8.0) / contentFrame.width
contentScale = minimizedContentScale
case .none:
contentScale = 1.0
}
let titleImage = dayEnvironment.imageCache.text(fontSize: titleFontSize, isSemibold: titleFontIsSemibold, color: titleColor, string: component.title)
if animateMediaIn {
let previousTitleView = SimpleLayer()
previousTitleView.contents = self.titleView.contents
previousTitleView.frame = self.titleView.frame
self.titleView.superlayer?.insertSublayer(previousTitleView, above: self.titleView)
previousTitleView.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousTitleView] _ in
previousTitleView?.removeFromSuperlayer()
})
self.titleView.animateAlpha(from: 0.0, to: 1.0, duration: 0.16)
animateTitle = true
}
self.titleView.contents = titleImage.cgImage
let titleSize = titleImage.size
self.highlightView.frame = CGRect(origin: CGPoint(x: contentFrame.midX - contentFrame.width * contentScale / 2.0, y: contentFrame.midY - contentFrame.width * contentScale / 2.0), size: CGSize(width: contentFrame.width * contentScale, height: contentFrame.height * contentScale))
self.titleView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) / 2.0), y: floor((availableSize.height - titleSize.height) / 2.0)), size: titleSize)
self.highlightView.bounds = CGRect(origin: CGPoint(), size: contentFrame.size)
self.highlightView.position = CGPoint(x: contentFrame.midX, y: contentFrame.midY)
if let mediaPreviewView = self.mediaPreviewView {
mediaPreviewView.bounds = CGRect(origin: CGPoint(), size: contentFrame.size)
@ -587,6 +598,69 @@ private final class DayComponent: Component {
self.highlightView.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
}
self.highlightView.transform = CATransform3DMakeScale(contentScale, contentScale, 1.0)
if let _ = transition.userData(SelectionTransition.self), previousSelected != isSelected {
if self.mediaPreviewView == nil {
animateTitle = true
}
if isSelected {
if component.selection == .edge {
let scaleIn = self.layer.makeAnimation(from: 1.0 as NSNumber, to: 0.75 as NSNumber, keyPath: "transform.scale", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.1)
let scaleOut = self.layer.springAnimation(from: 0.75 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
self.layer.animateGroup([scaleIn, scaleOut], key: "selection")
if let selectionView = self.selectionView {
if self.mediaPreviewView != nil {
let shapeLayer = CAShapeLayer()
let lineWidth: CGFloat = 2.0
shapeLayer.path = UIBezierPath(arcCenter: CGPoint(x: diameter / 2.0, y: diameter / 2.0), radius: diameter / 2.0 - lineWidth / 2.0, startAngle: -CGFloat.pi / 2.0, endAngle: 2 * CGFloat.pi - CGFloat.pi / 2.0, clockwise: true).cgPath
shapeLayer.frame = selectionView.frame
shapeLayer.strokeColor = component.theme.list.itemCheckColors.fillColor.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineWidth = lineWidth
shapeLayer.lineCap = .round
selectionView.isHidden = true
self.layer.insertSublayer(shapeLayer, above: selectionView)
shapeLayer.animate(from: 0.0 as NSNumber, to: 1.0 as NSNumber, keyPath: "strokeEnd", timingFunction: CAMediaTimingFunctionName.easeOut.rawValue, duration: 0.25, delay: 0.1, completion: { [weak selectionView, weak shapeLayer] _ in
shapeLayer?.removeFromSuperlayer()
selectionView?.isHidden = false
})
} else {
selectionView.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
}
}
} else {
if let mediaPreviewView = self.mediaPreviewView {
mediaPreviewView.animateScale(from: 1.0, to: contentScale, duration: 0.2)
}
self.highlightView.animateScale(from: 1.0, to: contentScale, duration: 0.2)
}
} else {
if let mediaPreviewView = self.mediaPreviewView {
mediaPreviewView.animateScale(from: minimizedContentScale, to: contentScale, duration: 0.2)
}
self.highlightView.animateScale(from: minimizedContentScale, to: contentScale, duration: 0.2)
}
}
if animateTitle {
let previousTitleView = SimpleLayer()
previousTitleView.contents = self.titleView.contents
previousTitleView.frame = self.titleView.frame
self.titleView.superlayer?.insertSublayer(previousTitleView, above: self.titleView)
previousTitleView.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak previousTitleView] _ in
previousTitleView?.removeFromSuperlayer()
})
self.titleView.animateAlpha(from: 0.0, to: 1.0, duration: 0.16)
}
self.titleView.contents = titleImage.cgImage
let titleSize = titleImage.size
self.highlightView.frame = CGRect(origin: CGPoint(x: contentFrame.midX - contentFrame.width * contentScale / 2.0, y: contentFrame.midY - contentFrame.width * contentScale / 2.0), size: CGSize(width: contentFrame.width * contentScale, height: contentFrame.height * contentScale))
self.titleView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - titleSize.width) / 2.0), y: floorToScreenPixels((availableSize.height - titleSize.height) / 2.0)), size: titleSize)
return availableSize
}
@ -601,219 +675,6 @@ private final class DayComponent: Component {
}
}
private final class ManualMonthComponent: Component {
typealias EnvironmentType = DayEnvironment
let context: AccountContext
let model: MonthModel
let foregroundColor: UIColor
let strings: PresentationStrings
let theme: PresentationTheme
let dayAction: (Int32) -> Void
let selectedDays: ClosedRange<Int32>?
init(
context: AccountContext,
model: MonthModel,
foregroundColor: UIColor,
strings: PresentationStrings,
theme: PresentationTheme,
dayAction: @escaping (Int32) -> Void,
selectedDays: ClosedRange<Int32>?
) {
self.context = context
self.model = model
self.foregroundColor = foregroundColor
self.strings = strings
self.theme = theme
self.dayAction = dayAction
self.selectedDays = selectedDays
}
static func ==(lhs: ManualMonthComponent, rhs: ManualMonthComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.model != rhs.model {
return false
}
if lhs.foregroundColor != rhs.foregroundColor {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.selectedDays != rhs.selectedDays {
return false
}
return true
}
final class View: UIView {
private let title: Text.View
private var weekdayTitles: [UIImageView] = []
private var days: [Int: DayComponent.View] = [:]
init() {
self.title = Text.View()
super.init(frame: CGRect())
self.addSubview(self.title)
}
required init?(coder aDecoder: NSCoder) {
preconditionFailure()
}
func update(component: ManualMonthComponent, availableSize: CGSize, environment: Environment<DayEnvironment>, transition: Transition) -> CGSize {
let sideInset: CGFloat = 14.0
let titleWeekdaysSpacing: CGFloat = 18.0
let weekdayDaySpacing: CGFloat = 14.0
let weekdaySize: CGFloat = 46.0
let weekdaySpacing: CGFloat = 6.0
let dayEnvironment = environment[DayEnvironment.self].value
let usableWeekdayWidth = floor((availableSize.width - sideInset * 2.0 - weekdaySpacing * 6.0) / 7.0)
let weekdayWidth = floor((availableSize.width - sideInset * 2.0) / 7.0)
let monthName = stringForMonth(strings: component.strings, month: Int32(component.model.index - 1), ofYear: Int32(component.model.year - 1900))
let titleSize = self.title.update(
component: Text(
text: monthName,
font: Font.semibold(17.0),
color: component.foregroundColor
),
availableSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 100.0)
)
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) / 2.0), y: 0.0), size: titleSize)
self.title.frame = titleFrame
for i in 0 ..< 7 {
let weekdayTitle: UIImageView
if self.weekdayTitles.count > i {
weekdayTitle = self.weekdayTitles[i]
} else {
weekdayTitle = UIImageView()
self.addSubview(weekdayTitle)
self.weekdayTitles.append(weekdayTitle)
}
let image = dayEnvironment.imageCache.text(fontSize: 10.0, isSemibold: false, color: component.foregroundColor, string: gridDayName(index: i, firstDayOfWeek: component.model.firstWeekday, strings: component.strings))
weekdayTitle.image = image
}
let baseWeekdayTitleY = titleFrame.maxY + titleWeekdaysSpacing
var maxWeekdayY = baseWeekdayTitleY
for i in 0 ..< self.weekdayTitles.count {
guard let image = self.weekdayTitles[i].image else {
continue
}
let weekdaySize = image.size
let weekdayFrame = CGRect(origin: CGPoint(x: sideInset + CGFloat(i) * weekdayWidth + floor((weekdayWidth - weekdaySize.width) / 2.0), y: baseWeekdayTitleY), size: weekdaySize)
maxWeekdayY = max(maxWeekdayY, weekdayFrame.maxY)
self.weekdayTitles[i].frame = weekdayFrame
}
var daySizes: [Int: CGSize] = [:]
for index in 0 ..< component.model.numberOfDays {
let dayOfMonth = index + 1
let isCurrent = component.model.currentYear == component.model.year && component.model.currentMonth == component.model.index && component.model.currentDayOfMonth == dayOfMonth
var isEnabled = true
if component.model.currentYear == component.model.year {
if component.model.currentMonth == component.model.index {
if dayOfMonth > component.model.currentDayOfMonth {
isEnabled = false
}
} else if component.model.index > component.model.currentMonth {
isEnabled = false
}
} else if component.model.year > component.model.currentYear {
isEnabled = false
}
let dayTimestamp = Int32(component.model.firstDay.timeIntervalSince1970) + 24 * 60 * 60 * Int32(index)
let dayAction = component.dayAction
let daySelection: DayComponent.DaySelection
if let selectedDays = component.selectedDays, selectedDays.contains(dayTimestamp) {
if selectedDays.lowerBound == dayTimestamp || selectedDays.upperBound == dayTimestamp {
daySelection = .edge
} else {
daySelection = .middle
}
} else {
daySelection = .none
}
let day: DayComponent.View
if let current = self.days[index] {
day = current
} else {
day = DayComponent.View()
self.addSubview(day)
self.days[index] = day
}
let daySize = day.update(
component: DayComponent(
title: "\(dayOfMonth)",
isCurrent: isCurrent,
isEnabled: isEnabled,
theme: component.theme,
context: component.context,
timestamp: dayTimestamp,
media: component.model.mediaByDay[index],
selection: daySelection,
isSelecting: component.selectedDays != nil,
action: {
dayAction(dayTimestamp)
}
),
availableSize: CGSize(width: usableWeekdayWidth, height: weekdaySize),
environment: environment,
transition: .immediate
)
daySizes[index] = daySize
}
let baseDayY = maxWeekdayY + weekdayDaySpacing
var maxDayY = baseDayY
for i in 0 ..< component.model.numberOfDays {
guard let dayView = self.days[i], let dayItemSize = daySizes[i] else {
continue
}
let gridIndex = gridDayOffset(firstDayOfWeek: component.model.firstWeekday, firstWeekdayOfMonth: component.model.firstDayWeekday) + i
let rowIndex = gridIndex % 7
let lineIndex = gridIndex / 7
let gridX = sideInset + CGFloat(rowIndex) * weekdayWidth
let gridY = baseDayY + CGFloat(lineIndex) * (weekdaySize + weekdaySpacing)
let dayFrame = CGRect(origin: CGPoint(x: gridX + floor((weekdayWidth - dayItemSize.width) / 2.0), y: gridY + floor((weekdaySize - dayItemSize.height) / 2.0)), size: dayItemSize)
maxDayY = max(maxDayY, gridY + weekdaySize)
dayView.frame = dayFrame
}
return CGSize(width: availableSize.width, height: maxDayY)
}
}
func makeView() -> View {
return View()
}
func update(view: View, availableSize: CGSize, environment: Environment<DayEnvironment>, transition: Transition) -> CGSize {
return view.update(component: self, availableSize: availableSize, environment: environment, transition: transition)
}
}
private final class MonthComponent: CombinedComponent {
typealias EnvironmentType = DayEnvironment
@ -954,7 +815,7 @@ private final class MonthComponent: CombinedComponent {
context.environment[DayEnvironment.self]
},
availableSize: CGSize(width: usableWeekdayWidth, height: weekdaySize),
transition: .immediate
transition: context.transition
)
}
@ -1016,7 +877,10 @@ private final class MonthComponent: CombinedComponent {
}
if let selectedDays = context.component.selectedDays {
for (lineIndex, selection) in selectionsByLine {
for (lineIndex, selection) in selectionsByLine.sorted(by: { $0.key < $1.key }) {
if selection.leftTimestamp == selection.rightTimestamp && selection.leftTimestamp == selectedDays.lowerBound && selection.rightTimestamp == selectedDays.upperBound {
continue
}
let dayEnvironment = context.environment[DayEnvironment.self].value
let dayItemSize = updatedDays[0].size
@ -1027,18 +891,8 @@ private final class MonthComponent: CombinedComponent {
let minY = baseDayY + CGFloat(lineIndex) * (weekdaySize + weekdaySpacing) + deltaHeight
let maxY = minY + dayItemSize.width
let leftRadius: CGFloat
if selectedDays.lowerBound == selection.leftTimestamp {
leftRadius = dayItemSize.width
} else {
leftRadius = 10.0
}
let rightRadius: CGFloat
if selectedDays.upperBound == selection.rightTimestamp {
rightRadius = dayItemSize.width
} else {
rightRadius = 10.0
}
let leftRadius: CGFloat = dayItemSize.width
let rightRadius: CGFloat = dayItemSize.width
let monthSelectionColor = context.component.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.1)
@ -1048,9 +902,28 @@ private final class MonthComponent: CombinedComponent {
availableSize: selectionRect.size,
transition: .immediate
)
let delayIndex = dayEnvironment.selectionDelayCoordination
context.add(selection
.position(CGPoint(x: selectionRect.midX, y: selectionRect.midY))
.appear(Transition.Appear { _, view, transition in
if case .none = transition.animation {
return
}
let delay = Double(delayIndex) * 0.1
view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.05, delay: delay)
view.layer.animateFrame(from: CGRect(origin: view.frame.origin, size: CGSize(width: leftRadius, height: view.frame.height)), to: view.frame, duration: 0.25, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
})
.disappear(Transition.Disappear { view, transition, completion in
if case .none = transition.animation {
completion()
return
}
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { _ in
completion()
})
})
)
dayEnvironment.selectionDelayCoordination += 1
}
}
@ -1376,26 +1249,31 @@ public final class CalendarMessageScreen: ViewController {
}
func toggleSelectionMode() {
var transition: Transition = .immediate
if self.selectionState == nil {
self.selectionState = SelectionState(dayRange: nil)
} else {
self.selectionState = nil
transition = Transition(animation: .curve(duration: 0.25, curve: .easeInOut))
transition = transition.withUserData(SelectionTransition.end)
}
self.contextGestureContainerNode.isGestureEnabled = self.selectionState == nil
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring))
}
self.updateSelectionState(transition: transition)
}
func selectDay(timestamp: Int32) {
self.selectionState = SelectionState(dayRange: timestamp ... timestamp)
if let selectionState = self.selectionState, selectionState.dayRange == timestamp ... timestamp {
self.selectionState = SelectionState(dayRange: nil)
} else {
self.selectionState = SelectionState(dayRange: timestamp ... timestamp)
}
self.contextGestureContainerNode.isGestureEnabled = self.selectionState == nil
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring))
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring), componentsTransition: .immediate)
}
}
@ -1404,7 +1282,7 @@ public final class CalendarMessageScreen: ViewController {
self.selectionToolbarActionSelected()
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition, componentsTransition: Transition) {
let isFirstLayout = self.validLayout == nil
self.validLayout = (layout, navigationHeight)
@ -1422,13 +1300,39 @@ public final class CalendarMessageScreen: ViewController {
let tabBarFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - tabBarHeight), size: CGSize(width: layout.size.width, height: tabBarHeight))
if let _ = self.selectionState {
if let selectionState = self.selectionState {
let selectionToolbarNode: ToolbarNode
if let currrent = self.selectionToolbarNode {
selectionToolbarNode = currrent
var selectedCount = 0
if let dayRange = selectionState.dayRange {
for i in 0 ..< self.months.count {
let firstDayTimestamp = Int32(self.months[i].firstDay.timeIntervalSince1970)
for day in 0 ..< self.months[i].numberOfDays {
let dayTimestamp = firstDayTimestamp + 24 * 60 * 60 * Int32(day)
if dayRange.contains(dayTimestamp) {
selectedCount += 1
}
}
}
}
let toolbarText: String
if selectedCount == 0 {
toolbarText = self.presentationData.strings.DialogList_ClearHistoryConfirmation
} else if selectedCount == 1 {
//TODO:localize
toolbarText = "Clear History For This Day"
} else {
//TODO:localize
toolbarText = "Clear History For These Days"
}
transition.updateFrame(node: selectionToolbarNode, frame: tabBarFrame)
selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: self.presentationData.strings.DialogList_ClearHistoryConfirmation, isEnabled: self.selectionState?.dayRange != nil, color: .custom(self.presentationData.theme.list.itemDestructiveColor))), transition: transition)
selectionToolbarNode.updateLayout(size: tabBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, bottomInset: bottomInset, toolbar: Toolbar(leftAction: nil, rightAction: nil, middleAction: ToolbarAction(title: toolbarText, isEnabled: self.selectionState?.dayRange != nil, color: .custom(self.presentationData.theme.list.itemDestructiveColor))), transition: transition)
} else {
selectionToolbarNode = ToolbarNode(
theme: TabBarControllerTheme(
@ -1505,7 +1409,7 @@ public final class CalendarMessageScreen: ViewController {
}
updateMonthViews()
updateMonthViews(transition: componentsTransition)
}
private func selectionToolbarActionSelected() {
@ -1630,15 +1534,9 @@ public final class CalendarMessageScreen: ViewController {
guard let strongSelf = self else {
return
}
let _ = strongSelf.calendarSource.removeMessagesInRange(minTimestamp: minTimestampValue, maxTimestamp: maxTimestampValue, type: type, completion: {
Queue.mainQueue().async {
guard let strongSelf = self else {
return
}
strongSelf.controller?.dismiss(completion: nil)
}
})
strongSelf.controller?.completedWithRemoveMessagesInRange?(minTimestampValue ... maxTimestampValue, type, selectedCount, strongSelf.calendarSource)
strongSelf.controller?.dismiss(completion: nil)
}
if let _ = info.canClearForMyself ?? info.canClearForEveryone {
@ -1685,8 +1583,6 @@ public final class CalendarMessageScreen: ViewController {
strongSelf.controller?.present(actionSheet, in: .window(.root))
})
self.controller?.toggleSelectPressed()
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
@ -1699,7 +1595,7 @@ public final class CalendarMessageScreen: ViewController {
indicator.transform = CGAffineTransform(scaleX: -1.0, y: 1.0)
}
self.updateMonthViews()
self.updateMonthViews(transition: .immediate)
}
}
@ -1751,15 +1647,17 @@ public final class CalendarMessageScreen: ViewController {
return true
}
func updateMonthViews() {
func updateMonthViews(transition: Transition) {
guard let (width, _, frames) = self.scrollLayout else {
return
}
self.dayEnvironment.selectionDelayCoordination = 0
let visibleRect = self.scrollView.bounds.insetBy(dx: 0.0, dy: -200.0)
var validMonths = Set<Int>()
for i in 0 ..< self.months.count {
for i in (0 ..< self.months.count).reversed() {
guard let monthFrame = frames[i] else {
continue
}
@ -1768,17 +1666,19 @@ public final class CalendarMessageScreen: ViewController {
}
validMonths.insert(i)
var monthTransition = transition
let monthView: ComponentHostView<DayEnvironment>
if let current = self.monthViews[i] {
monthView = current
} else {
monthTransition = .immediate
monthView = ComponentHostView()
monthView.layer.transform = CATransform3DMakeRotation(CGFloat.pi, 0.0, 0.0, 1.0)
self.monthViews[i] = monthView
self.scrollView.addSubview(monthView)
}
let _ = monthView.update(
transition: .immediate,
transition: monthTransition,
component: AnyComponent(MonthComponent(
context: self.context,
model: self.months[i],
@ -1790,22 +1690,29 @@ public final class CalendarMessageScreen: ViewController {
return
}
if var selectionState = strongSelf.selectionState {
var transition = Transition(animation: .curve(duration: 0.2, curve: .spring))
if let dayRange = selectionState.dayRange {
if dayRange.lowerBound == dayRange.upperBound {
if dayRange.lowerBound == timestamp || dayRange.upperBound == timestamp {
selectionState.dayRange = nil
transition = transition.withUserData(SelectionTransition.end)
} else if dayRange.lowerBound == dayRange.upperBound {
if timestamp < dayRange.lowerBound {
selectionState.dayRange = timestamp ... dayRange.upperBound
} else {
selectionState.dayRange = dayRange.lowerBound ... timestamp
}
transition = transition.withUserData(SelectionTransition.change)
} else {
selectionState.dayRange = timestamp ... timestamp
transition = transition.withUserData(SelectionTransition.change)
}
} else {
selectionState.dayRange = timestamp ... timestamp
transition = transition.withUserData(SelectionTransition.begin)
}
strongSelf.selectionState = selectionState
strongSelf.updateSelectionState()
strongSelf.updateSelectionState(transition: transition)
} else if let calendarState = strongSelf.calendarState {
outer: for month in strongSelf.months {
let firstDayTimestamp = Int32(month.firstDay.timeIntervalSince1970)
@ -1853,7 +1760,7 @@ public final class CalendarMessageScreen: ViewController {
}
}
private func updateSelectionState() {
private func updateSelectionState(transition: Transition) {
var title = self.presentationData.strings.MessageCalendar_Title
if let selectionState = self.selectionState, let dayRange = selectionState.dayRange {
var selectedCount = 0
@ -1876,7 +1783,7 @@ public final class CalendarMessageScreen: ViewController {
self.controller?.navigationItem.title = title
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring))
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.5, curve: .spring), componentsTransition: transition)
}
}
@ -1922,7 +1829,7 @@ public final class CalendarMessageScreen: ViewController {
self.months[monthIndex].mediaByDay = mediaByDay
}
self.updateMonthViews()
self.updateMonthViews(transition: .immediate)
}
}
@ -1940,6 +1847,8 @@ public final class CalendarMessageScreen: ViewController {
private let previewDay: (Int32, MessageIndex?, ASDisplayNode, CGRect, ContextGesture) -> Void
private var presentationData: PresentationData
public var completedWithRemoveMessagesInRange: ((ClosedRange<Int32>, InteractiveHistoryClearingType, Int, SparseMessageCalendar) -> Void)?
public init(
context: AccountContext,
@ -2034,6 +1943,6 @@ public final class CalendarMessageScreen: ViewController {
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.node.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
self.node.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition, componentsTransition: .immediate)
}
}

View File

@ -147,7 +147,7 @@ public extension CALayer {
self.add(animation, forKey: additive ? nil : keyPath)
}
func animateGroup(_ animations: [CAAnimation], key: String) {
func animateGroup(_ animations: [CAAnimation], key: String, completion: ((Bool) -> Void)? = nil) {
let animationGroup = CAAnimationGroup()
var timeOffset = 0.0
for animation in animations {
@ -156,6 +156,10 @@ public extension CALayer {
}
animationGroup.animations = animations
animationGroup.duration = timeOffset
if let completion = completion {
animationGroup.delegate = CALayerAnimationDelegate(animation: animationGroup, completion: completion)
}
self.add(animationGroup, forKey: key)
}
@ -194,6 +198,35 @@ public extension CALayer {
self.add(animation, forKey: keyPath)
}
func springAnimation(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, delay: Double = 0.0, initialVelocity: CGFloat = 0.0, damping: CGFloat = 88.0, removeOnCompletion: Bool = true, additive: Bool = false) -> CABasicAnimation {
let animation: CABasicAnimation
if #available(iOS 9.0, *) {
animation = makeSpringBounceAnimation(keyPath, initialVelocity, damping)
} else {
animation = makeSpringAnimation(keyPath)
}
animation.fromValue = from
animation.toValue = to
animation.isRemovedOnCompletion = removeOnCompletion
animation.fillMode = .forwards
let k = Float(UIView.animationDurationFactor())
var speed: Float = 1.0
if k != 0 && k != 1 {
speed = Float(1.0) / k
}
if !delay.isZero {
animation.beginTime = self.convertTime(CACurrentMediaTime(), from: nil) + delay * UIView.animationDurationFactor()
animation.fillMode = .both
}
animation.speed = speed * Float(animation.duration / duration)
animation.isAdditive = additive
return animation
}
func animateSpring(from: AnyObject, to: AnyObject, keyPath: String, duration: Double, delay: Double = 0.0, initialVelocity: CGFloat = 0.0, damping: CGFloat = 88.0, removeOnCompletion: Bool = true, additive: Bool = false, completion: ((Bool) -> Void)? = nil) {
let animation: CABasicAnimation

View File

@ -448,7 +448,7 @@ public class GalleryController: ViewController, StandalonePresentableController
} else {
namespaces = .not(Namespaces.Message.allScheduled)
}
return context.account.postbox.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(message!.index), count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [.combinedLocation])
return context.account.postbox.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(message!.index), ignoreMessagesInTimestampRange: nil, count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tags, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [.combinedLocation])
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
let mapped = GalleryMessageHistoryView.view(view)
return .single(mapped)
@ -1139,7 +1139,7 @@ public class GalleryController: ViewController, StandalonePresentableController
} else {
namespaces = .not(Namespaces.Message.allScheduled)
}
let signal = strongSelf.context.account.postbox.aroundMessageHistoryViewForLocation(strongSelf.context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(reloadAroundIndex), count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [.combinedLocation])
let signal = strongSelf.context.account.postbox.aroundMessageHistoryViewForLocation(strongSelf.context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), anchor: .index(reloadAroundIndex), ignoreMessagesInTimestampRange: nil, count: 50, clipHoles: false, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [.combinedLocation])
|> mapToSignal { (view, _, _) -> Signal<GalleryMessageHistoryView?, NoError> in
let mapped = GalleryMessageHistoryView.view(view)
return .single(mapped)

View File

@ -2904,7 +2904,7 @@ final class MessageHistoryTable: Table {
return (result, mediaRefs, count == 0 ? nil : lastIndex)
}
func fetch(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags?, threadId: Int64?, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, limit: Int) -> [IntermediateMessage] {
func fetch(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags?, threadId: Int64?, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, limit: Int) -> [IntermediateMessage] {
precondition(fromIndex.id.peerId == toIndex.id.peerId)
precondition(fromIndex.id.namespace == toIndex.id.namespace)
var result: [IntermediateMessage] = []
@ -2926,6 +2926,11 @@ final class MessageHistoryTable: Table {
localIncludeFrom = false
for index in sliceIndices {
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
continue
}
}
if let tag = tag {
if self.tagsTable.entryExists(tag: tag, index: index) {
indices.append(index)
@ -2961,6 +2966,72 @@ final class MessageHistoryTable: Table {
} else {
indices = self.tagsTable.earlierIndices(tag: tag, peerId: peerId, namespace: namespace, index: fromIndex, includeFrom: includeFrom, count: limit)
}
for index in indices {
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
continue
}
}
if fromIndex < toIndex {
if index < fromIndex || index > toIndex {
continue
}
} else {
if index < toIndex || index > fromIndex {
continue
}
}
if let message = self.getMessage(index) {
result.append(message)
} else {
assertionFailure()
}
}
} else if ignoreMessagesInTimestampRange != nil {
var indices: [MessageIndex] = []
var startIndex = fromIndex
var localIncludeFrom = includeFrom
while true {
let startKey: ValueBoxKey
if localIncludeFrom && startIndex != MessageIndex.upperBound(peerId: peerId, namespace: namespace) {
if startIndex < toIndex {
startKey = self.key(startIndex).predecessor
} else {
startKey = self.key(startIndex).successor
}
} else {
startKey = self.key(startIndex)
}
var sliceIndices: [MessageIndex] = []
self.valueBox.range(self.table, start: startKey, end: self.key(toIndex), values: { key, value in
sliceIndices.append(extractKey(key))
return true
}, limit: limit)
if sliceIndices.isEmpty {
break
}
startIndex = sliceIndices[sliceIndices.count - 1]
localIncludeFrom = false
for index in sliceIndices {
if let ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(index.timestamp) {
continue
}
}
indices.append(index)
if indices.count >= limit {
break
}
}
if indices.count >= limit {
break
}
}
assert(Set(indices).count == indices.count)
for index in indices {
if fromIndex < toIndex {
if index < fromIndex || index > toIndex {

View File

@ -311,6 +311,7 @@ public enum HistoryViewInputAnchor: Equatable {
final class MutableMessageHistoryView {
private(set) var peerIds: MessageHistoryViewInput
private let ignoreMessagesInTimestampRange: ClosedRange<Int32>?
let tag: MessageTags?
private let appendMessagesFromTheSameGroup: Bool
let namespaces: MessageIdNamespaces
@ -331,12 +332,29 @@ final class MutableMessageHistoryView {
fileprivate var isAddedToChatList: Bool
init(postbox: PostboxImpl, orderStatistics: MessageHistoryViewOrderStatistics, clipHoles: Bool, peerIds: MessageHistoryViewInput, anchor inputAnchor: HistoryViewInputAnchor, combinedReadStates: MessageHistoryViewReadState?, transientReadStates: MessageHistoryViewReadState?, tag: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) {
init(
postbox: PostboxImpl,
orderStatistics: MessageHistoryViewOrderStatistics,
clipHoles: Bool,
peerIds: MessageHistoryViewInput,
ignoreMessagesInTimestampRange: ClosedRange<Int32>?,
anchor inputAnchor: HistoryViewInputAnchor,
combinedReadStates: MessageHistoryViewReadState?,
transientReadStates: MessageHistoryViewReadState?,
tag: MessageTags?,
appendMessagesFromTheSameGroup: Bool,
namespaces: MessageIdNamespaces,
count: Int,
topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?],
additionalDatas: [AdditionalMessageHistoryViewDataEntry],
getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32
) {
self.anchor = inputAnchor
self.orderStatistics = orderStatistics
self.clipHoles = clipHoles
self.peerIds = peerIds
self.ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange
self.combinedReadStates = combinedReadStates
self.transientReadStates = transientReadStates
self.tag = tag
@ -355,12 +373,12 @@ final class MutableMessageHistoryView {
self.isAddedToChatList = postbox.chatListTable.getPeerChatListIndex(peerId: input.peerId) != nil
}
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds)
self.state = HistoryViewState(postbox: postbox, inputAnchor: inputAnchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: count + 1, locations: peerIds)
if case let .loading(loadingState) = self.state {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: self.orderStatistics, halfLimit: count + 1, locations: peerIds, postbox: postbox, holes: holes))
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: count + 1, locations: peerIds, postbox: postbox, holes: holes))
self.sampledState = self.state.sample(postbox: postbox, clipHoles: self.clipHoles)
case .loadHole:
break
@ -372,12 +390,12 @@ final class MutableMessageHistoryView {
}
private func reset(postbox: PostboxImpl) {
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds)
self.state = HistoryViewState(postbox: postbox, inputAnchor: self.anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: self.fillCount + 1, locations: self.peerIds)
if case let .loading(loadingState) = self.state {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
case .loadHole:
break
}
@ -386,7 +404,7 @@ final class MutableMessageHistoryView {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
case .loadHole:
break
}
@ -629,7 +647,7 @@ final class MutableMessageHistoryView {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
self.state = .loaded(HistoryViewLoadedState(anchor: anchor, tag: self.tag, appendMessagesFromTheSameGroup: self.appendMessagesFromTheSameGroup, namespaces: self.namespaces, statistics: self.orderStatistics, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, halfLimit: self.fillCount + 1, locations: self.peerIds, postbox: postbox, holes: holes))
case .loadHole:
break
}

View File

@ -25,10 +25,10 @@ public enum MessageHistoryInput: Equatable, Hashable {
}
private extension MessageHistoryInput {
func fetch(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, limit: Int) -> [IntermediateMessage] {
func fetch(postbox: PostboxImpl, peerId: PeerId, namespace: MessageId.Namespace, from fromIndex: MessageIndex, includeFrom: Bool, to toIndex: MessageIndex, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, limit: Int) -> [IntermediateMessage] {
switch self {
case let .automatic(automatic):
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: nil, from: fromIndex, includeFrom: includeFrom, to: toIndex, limit: limit)
var items = postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: automatic?.tag, threadId: nil, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
if let automatic = automatic, automatic.appendMessagesFromTheSameGroup {
enum Direction {
case lowToHigh
@ -70,7 +70,7 @@ private extension MessageHistoryInput {
}
return items
case let .external(input, tag):
return postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: tag, threadId: input.threadId, from: fromIndex, includeFrom: includeFrom, to: toIndex, limit: limit)
return postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: tag, threadId: input.threadId, from: fromIndex, includeFrom: includeFrom, to: toIndex, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, limit: limit)
}
}
@ -878,17 +878,19 @@ final class HistoryViewLoadedState {
let namespaces: MessageIdNamespaces
let input: MessageHistoryInput
let statistics: MessageHistoryViewOrderStatistics
let ignoreMessagesInTimestampRange: ClosedRange<Int32>?
let halfLimit: Int
let seedConfiguration: SeedConfiguration
var orderedEntriesBySpace: [PeerIdAndNamespace: OrderedHistoryViewEntries]
var holes: HistoryViewHoles
var spacesWithRemovals = Set<PeerIdAndNamespace>()
init(anchor: HistoryViewAnchor, tag: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewInput, postbox: PostboxImpl, holes: HistoryViewHoles) {
init(anchor: HistoryViewAnchor, tag: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, statistics: MessageHistoryViewOrderStatistics, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, halfLimit: Int, locations: MessageHistoryViewInput, postbox: PostboxImpl, holes: HistoryViewHoles) {
precondition(halfLimit >= 3)
self.anchor = anchor
self.namespaces = namespaces
self.statistics = statistics
self.ignoreMessagesInTimestampRange = ignoreMessagesInTimestampRange
self.halfLimit = halfLimit
self.seedConfiguration = postbox.seedConfiguration
self.orderedEntriesBySpace = [:]
@ -962,7 +964,7 @@ final class HistoryViewLoadedState {
} else {
nextLowerIndex = (anchorIndex, true)
}
lowerOrAtAnchorMessages.append(contentsOf: self.input.fetch(postbox: postbox, peerId: space.peerId, namespace: space.namespace, from: nextLowerIndex.index, includeFrom: nextLowerIndex.includeFrom, to: lowerBound, limit: self.halfLimit - lowerOrAtAnchorMessages.count).map(mapEntry))
lowerOrAtAnchorMessages.append(contentsOf: self.input.fetch(postbox: postbox, peerId: space.peerId, namespace: space.namespace, from: nextLowerIndex.index, includeFrom: nextLowerIndex.includeFrom, to: lowerBound, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, limit: self.halfLimit - lowerOrAtAnchorMessages.count).map(mapEntry))
}
if higherThanAnchorMessages.count < self.halfLimit {
let nextHigherIndex: MessageIndex
@ -971,7 +973,7 @@ final class HistoryViewLoadedState {
} else {
nextHigherIndex = anchorIndex
}
higherThanAnchorMessages.append(contentsOf: self.input.fetch(postbox: postbox, peerId: space.peerId, namespace: space.namespace, from: nextHigherIndex, includeFrom: false, to: upperBound, limit: self.halfLimit - higherThanAnchorMessages.count).map(mapEntry))
higherThanAnchorMessages.append(contentsOf: self.input.fetch(postbox: postbox, peerId: space.peerId, namespace: space.namespace, from: nextHigherIndex, includeFrom: false, to: upperBound, ignoreMessagesInTimestampRange: self.ignoreMessagesInTimestampRange, limit: self.halfLimit - higherThanAnchorMessages.count).map(mapEntry))
}
lowerOrAtAnchorMessages.reverse()
@ -1131,6 +1133,12 @@ final class HistoryViewLoadedState {
}
func add(entry: MutableMessageHistoryEntry) -> Bool {
if let ignoreMessagesInTimestampRange = self.ignoreMessagesInTimestampRange {
if ignoreMessagesInTimestampRange.contains(entry.index.timestamp) {
return false
}
}
let space = PeerIdAndNamespace(peerId: entry.index.id.peerId, namespace: entry.index.id.namespace)
if self.orderedEntriesBySpace[space] == nil {
@ -1447,14 +1455,14 @@ enum HistoryViewState {
case loaded(HistoryViewLoadedState)
case loading(HistoryViewLoadingState)
init(postbox: PostboxImpl, inputAnchor: HistoryViewInputAnchor, tag: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, statistics: MessageHistoryViewOrderStatistics, halfLimit: Int, locations: MessageHistoryViewInput) {
init(postbox: PostboxImpl, inputAnchor: HistoryViewInputAnchor, tag: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, statistics: MessageHistoryViewOrderStatistics, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, halfLimit: Int, locations: MessageHistoryViewInput) {
switch inputAnchor {
case let .index(index):
self = .loaded(HistoryViewLoadedState(anchor: .index(index), tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
self = .loaded(HistoryViewLoadedState(anchor: .index(index), tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
case .lowerBound:
self = .loaded(HistoryViewLoadedState(anchor: .lowerBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
self = .loaded(HistoryViewLoadedState(anchor: .lowerBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
case .upperBound:
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
case .unread:
let anchorPeerId: PeerId
switch locations {
@ -1463,7 +1471,7 @@ enum HistoryViewState {
case let .associated(peerId, _):
anchorPeerId = peerId
case .external:
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
self = .loaded(HistoryViewLoadedState(anchor: .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
return
}
if postbox.chatListIndexTable.get(peerId: anchorPeerId).includedIndex(peerId: anchorPeerId) != nil, let combinedState = postbox.readStateTable.getCombinedState(anchorPeerId) {
@ -1494,12 +1502,12 @@ enum HistoryViewState {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
case .loadHole:
self = .loading(loadingState)
}
} else {
self = .loaded(HistoryViewLoadedState(anchor: anchor ?? .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
self = .loaded(HistoryViewLoadedState(anchor: anchor ?? .upperBound, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: HistoryViewHoles(holesBySpace: fetchHoles(postbox: postbox, locations: locations, tag: tag, namespaces: namespaces))))
}
} else {
preconditionFailure()
@ -1516,7 +1524,7 @@ enum HistoryViewState {
let sampledState = loadingState.checkAndSample(postbox: postbox)
switch sampledState {
case let .ready(anchor, holes):
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
self = .loaded(HistoryViewLoadedState(anchor: anchor, tag: tag, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, statistics: statistics, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, halfLimit: halfLimit, locations: locations, postbox: postbox, holes: holes))
case .loadHole:
self = .loading(loadingState)
}

View File

@ -60,7 +60,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
}
}
self.anchor = anchor
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
let _ = self.updateFromView()
}
@ -132,7 +132,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
case let .peer(id):
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
}
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
return self.updateFromView()
} else if self.wrappedView.replay(postbox: postbox, transaction: transaction) {
var reloadView = false
@ -163,7 +163,7 @@ final class MutableMessageOfInterestHolesView: MutablePostboxView {
case let .peer(id):
peerIds = postbox.peerIdsForLocation(.peer(id), ignoreRelatedChats: false)
}
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
self.wrappedView = MutableMessageHistoryView(postbox: postbox, orderStatistics: [], clipHoles: true, peerIds: peerIds, ignoreMessagesInTimestampRange: nil, anchor: self.anchor, combinedReadStates: nil, transientReadStates: nil, tag: nil, appendMessagesFromTheSameGroup: false, namespaces: .all, count: self.count, topTaggedMessages: [:], additionalDatas: [], getMessageCountInRange: { _, _ in return 0})
}
return self.updateFromView()

View File

@ -1013,7 +1013,7 @@ public final class Transaction {
guard let postbox = self.postbox else {
return []
}
return postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: threadId, from: from, includeFrom: includeFrom, to: to, limit: limit).map(postbox.renderIntermediateMessage(_:))
return postbox.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: threadId, from: from, includeFrom: includeFrom, to: to, ignoreMessagesInTimestampRange: nil, limit: limit).map(postbox.renderIntermediateMessage(_:))
}
public func scanMessages(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags, _ f: (Message) -> Bool) {
@ -1030,7 +1030,7 @@ public final class Transaction {
self.postbox?.scanMessageAttributes(peerId: peerId, namespace: namespace, limit: limit, f)
}
public func getMessagesHistoryViewState(input: MessageHistoryViewInput, count: Int, clipHoles: Bool, anchor: HistoryViewInputAnchor, namespaces: MessageIdNamespaces) -> MessageHistoryView {
public func getMessagesHistoryViewState(input: MessageHistoryViewInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool, anchor: HistoryViewInputAnchor, namespaces: MessageIdNamespaces) -> MessageHistoryView {
precondition(!self.disposed)
guard let postbox = self.postbox else {
preconditionFailure()
@ -1044,7 +1044,7 @@ public final class Transaction {
view = next.0
}, error: { _ in }, completed: {})
let disposable = postbox.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: input, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: MessageHistoryViewOrderStatistics(), additionalData: [])
let disposable = postbox.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: input, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: MessageHistoryViewOrderStatistics(), additionalData: [])
disposable.dispose()
return view!
@ -1871,7 +1871,7 @@ final class PostboxImpl {
if let states = initialCombinedStates?.states {
for (namespace, state) in states {
if namespace != messageIndex.id.namespace && state.count != 0 {
if let item = self.messageHistoryTable.fetch(peerId: messageIndex.id.peerId, namespace: namespace, tag: nil, threadId: nil, from: MessageIndex(id: MessageId(peerId: messageIndex.id.peerId, namespace: namespace, id: 1), timestamp: messageIndex.timestamp), includeFrom: true, to: MessageIndex.lowerBound(peerId: messageIndex.id.peerId, namespace: namespace), limit: 1).first {
if let item = self.messageHistoryTable.fetch(peerId: messageIndex.id.peerId, namespace: namespace, tag: nil, threadId: nil, from: MessageIndex(id: MessageId(peerId: messageIndex.id.peerId, namespace: namespace, id: 1), timestamp: messageIndex.timestamp), includeFrom: true, to: MessageIndex.lowerBound(peerId: messageIndex.id.peerId, namespace: namespace), ignoreMessagesInTimestampRange: nil, limit: 1).first {
resultIds.append(contentsOf: self.messageHistoryTable.applyInteractiveMaxReadIndex(postbox: self, messageIndex: item.index, operationsByPeerId: &self.currentOperationsByPeerId, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations))
}
}
@ -2559,7 +2559,7 @@ final class PostboxImpl {
return peerIds
}
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageOfInterestHistoryViewForChatLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|> mapToSignal { chatLocationData in
let (chatLocation, isHoleFill) = chatLocationData
@ -2615,7 +2615,7 @@ final class PostboxImpl {
anchor = .upperBound
}
}
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
})
return signal
@ -2629,13 +2629,13 @@ final class PostboxImpl {
}
}
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, messageId: MessageId, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, messageId: MessageId, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|> mapToSignal { chatLocationData in
let (chatLocation, isHoleFill) = chatLocationData
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> = self.transactionSignal { subscriber, transaction in
let peerIds = self.peerIdsForLocation(chatLocation, ignoreRelatedChats: ignoreRelatedChats)
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, clipHoles: clipHoles, anchor: .message(messageId), fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, clipHoles: clipHoles, anchor: .message(messageId), fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
}
return signal
@ -2649,14 +2649,14 @@ final class PostboxImpl {
}
}
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, anchor: HistoryViewInputAnchor, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, anchor: HistoryViewInputAnchor, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
return self.resolvedChatLocationInput(chatLocation: chatLocation)
|> mapToSignal { chatLocationData -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in
let (chatLocation, isHoleFill) = chatLocationData
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> = self.transactionSignal { subscriber, transaction in
let peerIds = self.peerIdsForLocation(chatLocation, ignoreRelatedChats: ignoreRelatedChats)
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
return self.syncAroundMessageHistoryViewForPeerId(subscriber: subscriber, peerIds: peerIds, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, clipHoles: clipHoles, anchor: anchor, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, orderStatistics: orderStatistics, additionalData: additionalData)
}
return signal
@ -2671,7 +2671,21 @@ final class PostboxImpl {
}
}
fileprivate func syncAroundMessageHistoryViewForPeerId(subscriber: Subscriber<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>, peerIds: MessageHistoryViewInput, count: Int, clipHoles: Bool, anchor: HistoryViewInputAnchor, fixedCombinedReadStates: MessageHistoryViewReadState?, topTaggedMessageIdNamespaces: Set<MessageId.Namespace>, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, namespaces: MessageIdNamespaces, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Disposable {
fileprivate func syncAroundMessageHistoryViewForPeerId(
subscriber: Subscriber<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>,
peerIds: MessageHistoryViewInput,
ignoreMessagesInTimestampRange: ClosedRange<Int32>?,
count: Int,
clipHoles: Bool,
anchor: HistoryViewInputAnchor,
fixedCombinedReadStates: MessageHistoryViewReadState?,
topTaggedMessageIdNamespaces: Set<MessageId.Namespace>,
tagMask: MessageTags?,
appendMessagesFromTheSameGroup: Bool,
namespaces: MessageIdNamespaces,
orderStatistics: MessageHistoryViewOrderStatistics,
additionalData: [AdditionalMessageHistoryViewData]
) -> Disposable {
var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] = [:]
var mainPeerIdForTopTaggedMessages: PeerId?
switch peerIds {
@ -2767,7 +2781,7 @@ final class PostboxImpl {
readStates = transientReadStates
}
let mutableView = MutableMessageHistoryView(postbox: self, orderStatistics: orderStatistics, clipHoles: clipHoles, peerIds: peerIds, anchor: anchor, combinedReadStates: readStates, transientReadStates: transientReadStates, tag: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, count: count, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in
let mutableView = MutableMessageHistoryView(postbox: self, orderStatistics: orderStatistics, clipHoles: clipHoles, peerIds: peerIds, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, anchor: anchor, combinedReadStates: readStates, transientReadStates: transientReadStates, tag: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: namespaces, count: count, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in
if let tagMask = tagMask {
return Int32(self.messageHistoryTable.getMessageCountInRange(peerId: lowerBound.id.peerId, namespace: lowerBound.id.namespace, tag: tagMask, lowerBound: lowerBound, upperBound: upperBound))
} else {
@ -3410,7 +3424,7 @@ final class PostboxImpl {
var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace)
var remainingLimit = limit
while remainingLimit > 0 {
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: nil, from: index, includeFrom: false, to: lowerBound, limit: 10)
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: nil, from: index, includeFrom: false, to: lowerBound, ignoreMessagesInTimestampRange: nil, limit: 10)
remainingLimit -= 10
for message in messages {
if !f(self.renderIntermediateMessage(message)) {
@ -3429,7 +3443,7 @@ final class PostboxImpl {
var remainingLimit = limit
var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace)
while remainingLimit > 0 {
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: nil, from: index, includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: namespace), limit: 32)
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, threadId: nil, from: index, includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: namespace), ignoreMessagesInTimestampRange: nil, limit: 32)
for message in messages {
let attributes = MessageHistoryTable.renderMessageAttributes(message)
if !f(message.id, attributes) {
@ -3684,6 +3698,7 @@ public class Postbox {
public func aroundMessageOfInterestHistoryViewForChatLocation(
_ chatLocation: ChatLocationInput,
ignoreMessagesInTimestampRange: ClosedRange<Int32>?,
count: Int,
clipHoles: Bool = true,
topTaggedMessageIdNamespaces: Set<MessageId.Namespace>,
@ -3699,6 +3714,7 @@ public class Postbox {
self.impl.with { impl in
disposable.set(impl.aroundMessageOfInterestHistoryViewForChatLocation(
chatLocation,
ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange,
count: count,
clipHoles: clipHoles,
topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces,
@ -3716,6 +3732,7 @@ public class Postbox {
public func aroundIdMessageHistoryViewForLocation(
_ chatLocation: ChatLocationInput,
ignoreMessagesInTimestampRange: ClosedRange<Int32>?,
count: Int,
clipHoles: Bool = true,
ignoreRelatedChats: Bool = false,
@ -3733,6 +3750,7 @@ public class Postbox {
self.impl.with { impl in
disposable.set(impl.aroundIdMessageHistoryViewForLocation(
chatLocation,
ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange,
count: count,
clipHoles: clipHoles,
ignoreRelatedChats: ignoreRelatedChats,
@ -3753,6 +3771,7 @@ public class Postbox {
public func aroundMessageHistoryViewForLocation(
_ chatLocation: ChatLocationInput,
anchor: HistoryViewInputAnchor,
ignoreMessagesInTimestampRange: ClosedRange<Int32>?,
count: Int,
clipHoles: Bool = true,
ignoreRelatedChats: Bool = false,
@ -3770,6 +3789,7 @@ public class Postbox {
self.impl.with { impl in
disposable.set(impl.aroundMessageHistoryViewForLocation(
chatLocation,
ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange,
anchor: anchor,
count: count,
clipHoles: clipHoles,

View File

@ -342,7 +342,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-842824308] = { return Api.account.WallPapers.parse_wallPapers($0) }
dict[1012306921] = { return Api.InputTheme.parse_inputTheme($0) }
dict[-175567375] = { return Api.InputTheme.parse_inputThemeSlug($0) }
dict[-1199954735] = { return Api.MessageReactions.parse_messageReactions($0) }
dict[142306870] = { return Api.MessageReactions.parse_messageReactions($0) }
dict[-2032041631] = { return Api.Poll.parse_poll($0) }
dict[-1195615476] = { return Api.InputNotifyPeer.parse_inputNotifyPeer($0) }
dict[423314455] = { return Api.InputNotifyPeer.parse_inputNotifyUsers($0) }
@ -521,7 +521,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-2128640689] = { return Api.account.SentEmailCode.parse_sentEmailCode($0) }
dict[-1038136962] = { return Api.EncryptedFile.parse_encryptedFileEmpty($0) }
dict[1248893260] = { return Api.EncryptedFile.parse_encryptedFile($0) }
dict[-557924733] = { return Api.CodeSettings.parse_codeSettings($0) }
dict[-1973130814] = { return Api.CodeSettings.parse_codeSettings($0) }
dict[-1343921601] = { return Api.phone.JoinAsPeers.parse_joinAsPeers($0) }
dict[-391902247] = { return Api.SecureValueError.parse_secureValueErrorData($0) }
dict[12467706] = { return Api.SecureValueError.parse_secureValueErrorFrontSide($0) }
@ -661,6 +661,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[1923290508] = { return Api.auth.CodeType.parse_codeTypeSms($0) }
dict[1948046307] = { return Api.auth.CodeType.parse_codeTypeCall($0) }
dict[577556219] = { return Api.auth.CodeType.parse_codeTypeFlashCall($0) }
dict[-702884114] = { return Api.auth.CodeType.parse_codeTypeMissedCall($0) }
dict[1815593308] = { return Api.DocumentAttribute.parse_documentAttributeImageSize($0) }
dict[297109817] = { return Api.DocumentAttribute.parse_documentAttributeAnimated($0) }
dict[1662637586] = { return Api.DocumentAttribute.parse_documentAttributeSticker($0) }
@ -790,7 +791,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-290921362] = { return Api.upload.CdnFile.parse_cdnFileReuploadNeeded($0) }
dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) }
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
dict[-764945220] = { return Api.MessageUserReaction.parse_messageUserReaction($0) }
dict[-1826077446] = { return Api.MessageUserReaction.parse_messageUserReaction($0) }
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
dict[85477117] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
@ -931,6 +932,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1073693790] = { return Api.auth.SentCodeType.parse_sentCodeTypeSms($0) }
dict[1398007207] = { return Api.auth.SentCodeType.parse_sentCodeTypeCall($0) }
dict[-1425815847] = { return Api.auth.SentCodeType.parse_sentCodeTypeFlashCall($0) }
dict[-2113903484] = { return Api.auth.SentCodeType.parse_sentCodeTypeMissedCall($0) }
dict[1577484359] = { return Api.PageListOrderedItem.parse_pageListOrderedItemText($0) }
dict[-1730311882] = { return Api.PageListOrderedItem.parse_pageListOrderedItemBlocks($0) }
dict[-1417756512] = { return Api.EncryptedChat.parse_encryptedChatEmpty($0) }
@ -940,6 +942,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[505183301] = { return Api.EncryptedChat.parse_encryptedChatDiscarded($0) }
dict[-901375139] = { return Api.PeerLocated.parse_peerLocated($0) }
dict[-118740917] = { return Api.PeerLocated.parse_peerSelfLocated($0) }
dict[-1957096922] = { return Api.auth.LoggedOut.parse_loggedOut($0) }
dict[922273905] = { return Api.Document.parse_documentEmpty($0) }
dict[512177195] = { return Api.Document.parse_document($0) }
dict[-1707344487] = { return Api.messages.HighScores.parse_highScores($0) }
@ -1657,6 +1660,8 @@ public struct Api {
_1.serialize(buffer, boxed)
case let _1 as Api.PeerLocated:
_1.serialize(buffer, boxed)
case let _1 as Api.auth.LoggedOut:
_1.serialize(buffer, boxed)
case let _1 as Api.Document:
_1.serialize(buffer, boxed)
case let _1 as Api.messages.HighScores:

View File

@ -8902,13 +8902,13 @@ public extension Api {
}
public enum MessageReactions: TypeConstructorDescription {
case messageReactions(flags: Int32, results: [Api.ReactionCount])
case messageReactions(flags: Int32, results: [Api.ReactionCount], recentReactons: [Api.MessageUserReaction]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageReactions(let flags, let results):
case .messageReactions(let flags, let results, let recentReactons):
if boxed {
buffer.appendInt32(-1199954735)
buffer.appendInt32(142306870)
}
serializeInt32(flags, buffer: buffer, boxed: false)
buffer.appendInt32(481674261)
@ -8916,14 +8916,19 @@ public extension Api {
for item in results {
item.serialize(buffer, true)
}
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(recentReactons!.count))
for item in recentReactons! {
item.serialize(buffer, true)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .messageReactions(let flags, let results):
return ("messageReactions", [("flags", flags), ("results", results)])
case .messageReactions(let flags, let results, let recentReactons):
return ("messageReactions", [("flags", flags), ("results", results), ("recentReactons", recentReactons)])
}
}
@ -8934,10 +8939,15 @@ public extension Api {
if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.ReactionCount.self)
}
var _3: [Api.MessageUserReaction]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageUserReaction.self)
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.MessageReactions.messageReactions(flags: _1!, results: _2!)
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.MessageReactions.messageReactions(flags: _1!, results: _2!, recentReactons: _3)
}
else {
return nil
@ -13262,32 +13272,42 @@ public extension Api {
}
public enum CodeSettings: TypeConstructorDescription {
case codeSettings(flags: Int32)
case codeSettings(flags: Int32, logoutTokens: [Buffer]?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .codeSettings(let flags):
case .codeSettings(let flags, let logoutTokens):
if boxed {
buffer.appendInt32(-557924733)
buffer.appendInt32(-1973130814)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 6) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(logoutTokens!.count))
for item in logoutTokens! {
serializeBytes(item, buffer: buffer, boxed: false)
}}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .codeSettings(let flags):
return ("codeSettings", [("flags", flags)])
case .codeSettings(let flags, let logoutTokens):
return ("codeSettings", [("flags", flags), ("logoutTokens", logoutTokens)])
}
}
public static func parse_codeSettings(_ reader: BufferReader) -> CodeSettings? {
var _1: Int32?
_1 = reader.readInt32()
var _2: [Buffer]?
if Int(_1!) & Int(1 << 6) != 0 {if let _ = reader.readInt32() {
_2 = Api.parseVector(reader, elementSignature: -1255641564, elementType: Buffer.self)
} }
let _c1 = _1 != nil
if _c1 {
return Api.CodeSettings.codeSettings(flags: _1!)
let _c2 = (Int(_1!) & Int(1 << 6) == 0) || _2 != nil
if _c1 && _c2 {
return Api.CodeSettings.codeSettings(flags: _1!, logoutTokens: _2)
}
else {
return nil
@ -20162,15 +20182,15 @@ public extension Api {
}
public enum MessageUserReaction: TypeConstructorDescription {
case messageUserReaction(userId: Int32, reaction: String)
case messageUserReaction(userId: Int64, reaction: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .messageUserReaction(let userId, let reaction):
if boxed {
buffer.appendInt32(-764945220)
buffer.appendInt32(-1826077446)
}
serializeInt32(userId, buffer: buffer, boxed: false)
serializeInt64(userId, buffer: buffer, boxed: false)
serializeString(reaction, buffer: buffer, boxed: false)
break
}
@ -20184,8 +20204,8 @@ public extension Api {
}
public static func parse_messageUserReaction(_ reader: BufferReader) -> MessageUserReaction? {
var _1: Int32?
_1 = reader.readInt32()
var _1: Int64?
_1 = reader.readInt64()
var _2: String?
_2 = parseString(reader)
let _c1 = _1 != nil

View File

@ -1236,6 +1236,7 @@ public struct auth {
case codeTypeSms
case codeTypeCall
case codeTypeFlashCall
case codeTypeMissedCall
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -1256,6 +1257,12 @@ public struct auth {
buffer.appendInt32(577556219)
}
break
case .codeTypeMissedCall:
if boxed {
buffer.appendInt32(-702884114)
}
break
}
}
@ -1268,6 +1275,8 @@ public struct auth {
return ("codeTypeCall", [])
case .codeTypeFlashCall:
return ("codeTypeFlashCall", [])
case .codeTypeMissedCall:
return ("codeTypeMissedCall", [])
}
}
@ -1280,6 +1289,9 @@ public struct auth {
public static func parse_codeTypeFlashCall(_ reader: BufferReader) -> CodeType? {
return Api.auth.CodeType.codeTypeFlashCall
}
public static func parse_codeTypeMissedCall(_ reader: BufferReader) -> CodeType? {
return Api.auth.CodeType.codeTypeMissedCall
}
}
public enum SentCodeType: TypeConstructorDescription {
@ -1287,6 +1299,7 @@ public struct auth {
case sentCodeTypeSms(length: Int32)
case sentCodeTypeCall(length: Int32)
case sentCodeTypeFlashCall(pattern: String)
case sentCodeTypeMissedCall(prefix: String, length: Int32)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
@ -1314,6 +1327,13 @@ public struct auth {
}
serializeString(pattern, buffer: buffer, boxed: false)
break
case .sentCodeTypeMissedCall(let prefix, let length):
if boxed {
buffer.appendInt32(-2113903484)
}
serializeString(prefix, buffer: buffer, boxed: false)
serializeInt32(length, buffer: buffer, boxed: false)
break
}
}
@ -1327,6 +1347,8 @@ public struct auth {
return ("sentCodeTypeCall", [("length", length)])
case .sentCodeTypeFlashCall(let pattern):
return ("sentCodeTypeFlashCall", [("pattern", pattern)])
case .sentCodeTypeMissedCall(let prefix, let length):
return ("sentCodeTypeMissedCall", [("prefix", prefix), ("length", length)])
}
}
@ -1374,6 +1396,62 @@ public struct auth {
return nil
}
}
public static func parse_sentCodeTypeMissedCall(_ reader: BufferReader) -> SentCodeType? {
var _1: String?
_1 = parseString(reader)
var _2: Int32?
_2 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.auth.SentCodeType.sentCodeTypeMissedCall(prefix: _1!, length: _2!)
}
else {
return nil
}
}
}
public enum LoggedOut: TypeConstructorDescription {
case loggedOut(flags: Int32, futureAuthToken: Buffer?, futureAuthExpires: Int32?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .loggedOut(let flags, let futureAuthToken, let futureAuthExpires):
if boxed {
buffer.appendInt32(-1957096922)
}
serializeInt32(flags, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeBytes(futureAuthToken!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 0) != 0 {serializeInt32(futureAuthExpires!, buffer: buffer, boxed: false)}
break
}
}
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .loggedOut(let flags, let futureAuthToken, let futureAuthExpires):
return ("loggedOut", [("flags", flags), ("futureAuthToken", futureAuthToken), ("futureAuthExpires", futureAuthExpires)])
}
}
public static func parse_loggedOut(_ reader: BufferReader) -> LoggedOut? {
var _1: Int32?
_1 = reader.readInt32()
var _2: Buffer?
if Int(_1!) & Int(1 << 0) != 0 {_2 = parseBytes(reader) }
var _3: Int32?
if Int(_1!) & Int(1 << 0) != 0 {_3 = reader.readInt32() }
let _c1 = _1 != nil
let _c2 = (Int(_1!) & Int(1 << 0) == 0) || _2 != nil
let _c3 = (Int(_1!) & Int(1 << 0) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.auth.LoggedOut.loggedOut(flags: _1!, futureAuthToken: _2, futureAuthExpires: _3)
}
else {
return nil
}
}
}
}

View File

@ -5426,15 +5426,15 @@ public extension Api {
})
}
public static func logOut() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
public static func logOut() -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.auth.LoggedOut>) {
let buffer = Buffer()
buffer.appendInt32(1461180992)
buffer.appendInt32(1047706137)
return (FunctionDescription(name: "auth.logOut", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
return (FunctionDescription(name: "auth.logOut", parameters: []), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.auth.LoggedOut? in
let reader = BufferReader(buffer)
var result: Api.Bool?
var result: Api.auth.LoggedOut?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.Bool
result = Api.parse(reader, signature: signature) as? Api.auth.LoggedOut
}
return result
})

View File

@ -426,8 +426,8 @@ private func cleanupAccount(networkArguments: NetworkInitializationArguments, ac
account.shouldBeServiceTaskMaster.set(.single(.always))
return account.network.request(Api.functions.auth.logOut())
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.Bool?, NoError> in
return .single(.boolFalse)
|> `catch` { _ -> Signal<Api.auth.LoggedOut?, NoError> in
return .single(nil)
}
|> mapToSignal { _ -> Signal<Void, NoError> in
account.shouldBeServiceTaskMaster.set(.single(.never))

View File

@ -5,7 +5,7 @@ import TelegramApi
extension ReactionsMessageAttribute {
func withUpdatedResults(_ reactions: Api.MessageReactions) -> ReactionsMessageAttribute {
switch reactions {
case let .messageReactions(flags, results):
case let .messageReactions(flags, results, _):
let min = (flags & (1 << 0)) != 0
var reactions = results.map { result -> MessageReaction in
switch result {
@ -87,7 +87,7 @@ public func mergedMessageReactions(attributes: [MessageAttribute]) -> ReactionsM
extension ReactionsMessageAttribute {
convenience init(apiReactions: Api.MessageReactions) {
switch apiReactions {
case let .messageReactions(_, results):
case let .messageReactions(_, results, _):
self.init(reactions: results.map { result in
switch result {
case let .reactionCount(flags, reaction, count):

View File

@ -72,7 +72,9 @@ private func ~=<T: RegularExpressionMatchable>(pattern: Regex, matchable: T) ->
}
public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccountManagerTypes>, account: UnauthorizedAccount, phoneNumber: String, apiId: Int32, apiHash: String, syncContacts: Bool) -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> {
let sendCode = Api.functions.auth.sendCode(phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, settings: .codeSettings(flags: 0))
var flags: Int32 = 0
flags |= 1 << 5 //allowMissedCall
let sendCode = Api.functions.auth.sendCode(phoneNumber: phoneNumber, apiId: apiId, apiHash: apiHash, settings: .codeSettings(flags: flags, logoutTokens: nil))
let codeAndAccount = account.network.request(sendCode, automaticFloodWait: false)
|> map { result in
@ -111,7 +113,7 @@ public func sendAuthorizationCode(accountManager: AccountManager<TelegramAccount
|> timeout(20.0, queue: Queue.concurrentDefaultQueue(), alternate: .fail(.timeout))
return codeAndAccount
|> mapToSignal { (sentCode, account) -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> in
|> mapToSignal { sentCode, account -> Signal<UnauthorizedAccount, AuthorizationCodeRequestError> in
return account.postbox.transaction { transaction -> UnauthorizedAccount in
switch sentCode {
case let .sentCode(_, type, phoneCodeHash, nextType, timeout):

View File

@ -28,6 +28,8 @@ extension SentAuthorizationCodeType {
self = .call(length: length)
case let .sentCodeTypeFlashCall(pattern):
self = .flashCall(pattern: pattern)
case let .sentCodeTypeMissedCall(prefix, length):
self = .missedCall(numberPrefix: prefix, length: length)
}
}
}
@ -41,6 +43,8 @@ extension AuthorizationCodeNextType {
self = .call
case .codeTypeFlashCall:
self = .flashCall
case .codeTypeMissedCall:
self = .missedCall
}
}
}

View File

@ -1479,7 +1479,7 @@ public final class AccountViewTracker {
public func scheduledMessagesViewForLocation(_ chatLocation: ChatLocationInput, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: .upperBound, count: 200, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .just(Namespaces.Message.allScheduled), orderStatistics: [], additionalData: additionalData)
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: 200, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: nil, appendMessagesFromTheSameGroup: false, namespaces: .just(Namespaces.Message.allScheduled), orderStatistics: [], additionalData: additionalData)
return withState(signal, { [weak self] () -> Int32 in
if let strongSelf = self {
return OSAtomicIncrement32(&strongSelf.nextViewId)
@ -1507,25 +1507,25 @@ public final class AccountViewTracker {
}
}
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocationInput, count: Int, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageOfInterestHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, count: Int, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
let signal = account.postbox.aroundMessageOfInterestHistoryViewForChatLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: true)
} else {
return .never()
}
}
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, count: Int, ignoreRelatedChats: Bool, messageId: MessageId, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundIdMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, count: Int, ignoreRelatedChats: Bool, messageId: MessageId, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let signal = account.postbox.aroundIdMessageHistoryViewForLocation(chatLocation, count: count, ignoreRelatedChats: ignoreRelatedChats, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
let signal = account.postbox.aroundIdMessageHistoryViewForLocation(chatLocation, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, ignoreRelatedChats: ignoreRelatedChats, messageId: messageId, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: false)
} else {
return .never()
}
}
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
public func aroundMessageHistoryViewForLocation(_ chatLocation: ChatLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil, index: MessageHistoryAnchorIndex, anchorIndex: MessageHistoryAnchorIndex, count: Int, clipHoles: Bool = true, ignoreRelatedChats: Bool = false, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags? = nil, appendMessagesFromTheSameGroup: Bool = false, orderStatistics: MessageHistoryViewOrderStatistics = [], additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> {
if let account = self.account {
let inputAnchor: HistoryViewInputAnchor
switch index {
@ -1536,7 +1536,7 @@ public final class AccountViewTracker {
case let .message(index):
inputAnchor = .index(index)
}
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, count: count, clipHoles: clipHoles, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
let signal = account.postbox.aroundMessageHistoryViewForLocation(chatLocation, anchor: inputAnchor, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, clipHoles: clipHoles, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, topTaggedMessageIdNamespaces: [Namespaces.Message.Cloud], tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, namespaces: .not(Namespaces.Message.allScheduled), orderStatistics: orderStatistics, additionalData: wrappedHistoryViewAdditionalData(chatLocation: chatLocation, additionalData: additionalData))
return wrappedMessageHistorySignal(chatLocation: chatLocation, signal: signal, addHoleIfNeeded: false)
} else {
return .never()

View File

@ -5,6 +5,7 @@ private enum SentAuthorizationCodeTypeValue: Int32 {
case sms = 1
case call = 2
case flashCall = 3
case missedCall = 4
}
public enum SentAuthorizationCodeType: PostboxCoding, Equatable {
@ -12,6 +13,7 @@ public enum SentAuthorizationCodeType: PostboxCoding, Equatable {
case sms(length: Int32)
case call(length: Int32)
case flashCall(pattern: String)
case missedCall(numberPrefix: String, length: Int32)
public init(decoder: PostboxDecoder) {
switch decoder.decodeInt32ForKey("v", orElse: 0) {
@ -23,6 +25,8 @@ public enum SentAuthorizationCodeType: PostboxCoding, Equatable {
self = .call(length: decoder.decodeInt32ForKey("l", orElse: 0))
case SentAuthorizationCodeTypeValue.flashCall.rawValue:
self = .flashCall(pattern: decoder.decodeStringForKey("p", orElse: ""))
case SentAuthorizationCodeTypeValue.missedCall.rawValue:
self = .missedCall(numberPrefix: decoder.decodeStringForKey("n", orElse: ""), length: decoder.decodeInt32ForKey("l", orElse: 0))
default:
preconditionFailure()
}
@ -42,35 +46,10 @@ public enum SentAuthorizationCodeType: PostboxCoding, Equatable {
case let .flashCall(pattern):
encoder.encodeInt32(SentAuthorizationCodeTypeValue.flashCall.rawValue, forKey: "v")
encoder.encodeString(pattern, forKey: "p")
}
}
public static func ==(lhs: SentAuthorizationCodeType, rhs: SentAuthorizationCodeType) -> Bool {
switch lhs {
case let .otherSession(length):
if case .otherSession(length) = rhs {
return true
} else {
return false
}
case let .sms(length):
if case .sms(length) = rhs {
return true
} else {
return false
}
case let .call(length):
if case .call(length) = rhs {
return true
} else {
return false
}
case let .flashCall(pattern):
if case .flashCall(pattern) = rhs {
return true
} else {
return false
}
case let .missedCall(numberPrefix, length):
encoder.encodeInt32(SentAuthorizationCodeTypeValue.missedCall.rawValue, forKey: "v")
encoder.encodeString(numberPrefix, forKey: "n")
encoder.encodeInt32(length, forKey: "l")
}
}
}
@ -79,6 +58,7 @@ public enum AuthorizationCodeNextType: Int32 {
case sms = 0
case call = 1
case flashCall = 2
case missedCall = 3
}
private enum UnauthorizedAccountStateContentsValue: Int32 {

View File

@ -37,7 +37,7 @@ public enum RequestChangeAccountPhoneNumberVerificationError {
}
func _internal_requestChangeAccountPhoneNumberVerification(account: Account, phoneNumber: String) -> Signal<ChangeAccountPhoneNumberData, RequestChangeAccountPhoneNumberVerificationError> {
return account.network.request(Api.functions.account.sendChangePhoneCode(phoneNumber: phoneNumber, settings: .codeSettings(flags: 0)), automaticFloodWait: false)
return account.network.request(Api.functions.account.sendChangePhoneCode(phoneNumber: phoneNumber, settings: .codeSettings(flags: 0, logoutTokens: nil)), automaticFloodWait: false)
|> mapError { error -> RequestChangeAccountPhoneNumberVerificationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded

View File

@ -18,7 +18,7 @@ public enum RequestCancelAccountResetDataError {
}
func _internal_requestCancelAccountResetData(network: Network, hash: String) -> Signal<CancelAccountResetData, RequestCancelAccountResetDataError> {
return network.request(Api.functions.account.sendConfirmPhoneCode(hash: hash, settings: .codeSettings(flags: 0)), automaticFloodWait: false)
return network.request(Api.functions.account.sendConfirmPhoneCode(hash: hash, settings: .codeSettings(flags: 0, logoutTokens: nil)), automaticFloodWait: false)
|> mapError { error -> RequestCancelAccountResetDataError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .limitExceeded

View File

@ -812,6 +812,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
Namespaces.Message.Cloud: holes
]
)),
ignoreMessagesInTimestampRange: nil,
count: 40,
clipHoles: true,
anchor: inputAnchor,

View File

@ -188,7 +188,7 @@ public final class SparseMessageList {
#else*/
count = 200
//#endif
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId), anchor: .upperBound, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
self.topItemsDisposable.set((self.account.postbox.aroundMessageHistoryViewForLocation(.peer(peerId), anchor: .upperBound, ignoreMessagesInTimestampRange: nil, count: count, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: Set(), tagMask: self.messageTag, appendMessagesFromTheSameGroup: false, namespaces: .not(Set(Namespaces.Message.allScheduled)), orderStatistics: [])
|> deliverOn(self.queue)).start(next: { [weak self] view, updateType, _ in
guard let strongSelf = self else {
return

View File

@ -19,7 +19,7 @@ public struct SecureIdPreparePhoneVerificationPayload {
}
public func secureIdPreparePhoneVerification(network: Network, value: SecureIdPhoneValue) -> Signal<SecureIdPreparePhoneVerificationPayload, SecureIdPreparePhoneVerificationError> {
return network.request(Api.functions.account.sendVerifyPhoneCode(phoneNumber: value.phone, settings: .codeSettings(flags: 0)), automaticFloodWait: false)
return network.request(Api.functions.account.sendVerifyPhoneCode(phoneNumber: value.phone, settings: .codeSettings(flags: 0, logoutTokens: nil)), automaticFloodWait: false)
|> mapError { error -> SecureIdPreparePhoneVerificationError in
if error.errorDescription.hasPrefix("FLOOD_WAIT") {
return .flood

View File

@ -137,6 +137,8 @@ final class AuthorizationSequenceCodeEntryController: ViewController {
minimalCodeLength = Int(length)
case .flashCall:
break
case let .missedCall(_, length):
minimalCodeLength = Int(length)
}
if self.controllerNode.currentCode.count < minimalCodeLength {

View File

@ -4511,7 +4511,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
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, appendMessagesFromTheSameGroup: false, additionalData: [], orderStatistics: .combinedLocation)
return (chatHistoryViewForLocation(ChatHistoryLocationInput(content: location, id: 0), ignoreMessagesInTimestampRange: nil, context: context, chatLocation: .peer(peerId), chatLocationContextHolder: Atomic<ChatLocationContextHolder?>(value: nil), scheduled: false, fixedCombinedReadStates: nil, tagMask: MessageTags.pinned, appendMessagesFromTheSameGroup: false, additionalData: [], orderStatistics: .combinedLocation)
|> castError(Bool.self)
|> mapToSignal { update -> Signal<ChatHistoryViewUpdate, Bool> in
switch update {
@ -11815,6 +11815,47 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.presentInGlobalOverlay(contextController)
}
)
calendarScreen.completedWithRemoveMessagesInRange = { [weak self] range, type, dayCount, calendarSource in
guard let strongSelf = self else {
return
}
//TODO:localize
var statusText: String
statusText = "Messages for \(dayCount) \(dayCount == 1 ? "day" : "days") deleted"
switch type {
case .forEveryone:
statusText += " for both sides"
default:
break
}
statusText += "."
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range
strongSelf.present(UndoOverlayController(presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(text: statusText), elevatedLayout: false, action: { value in
guard let strongSelf = self else {
return false
}
if value == .commit {
let _ = calendarSource.removeMessagesInRange(minTimestamp: range.lowerBound, maxTimestamp: range.upperBound, type: type, completion: {
Queue.mainQueue().after(1.0, {
guard let strongSelf = self else {
return
}
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
})
})
return true
} else if value == .undo {
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
return true
}
return false
}), in: .current)
}
self.push(calendarScreen)
dismissCalendarScreen = { [weak calendarScreen] in

View File

@ -82,6 +82,7 @@ struct ChatHistoryView {
let lastHeaderId: Int64
let id: Int32
let locationInput: ChatHistoryLocationInput?
let ignoreMessagesInTimestampRange: ClosedRange<Int32>?
}
enum ChatHistoryViewTransitionReason {
@ -467,6 +468,15 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
return id
}
private let ignoreMessagesInTimestampRangePromise = ValuePromise<ClosedRange<Int32>?>(nil)
var ignoreMessagesInTimestampRange: ClosedRange<Int32>? = nil {
didSet {
if self.ignoreMessagesInTimestampRange != oldValue {
self.ignoreMessagesInTimestampRangePromise.set(self.ignoreMessagesInTimestampRange)
}
}
}
private let galleryHiddenMesageAndMediaDisposable = MetaDisposable()
private let messageProcessingManager = ChatMessageThrottledProcessingManager()
@ -763,7 +773,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
let currentViewVersion = Atomic<Int?>(value: nil)
let historyViewUpdate: Signal<(ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?), NoError>
let historyViewUpdate: Signal<(ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?, ClosedRange<Int32>?), NoError>
var isFirstTime = true
var updateAllOnEachVersion = false
if case let .custom(messages, at, _) = source {
@ -786,13 +796,24 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
scrollPosition = nil
}
return (ChatHistoryViewUpdate.HistoryView(view: MessageHistoryView(tagMask: nil, namespaces: .all, entries: messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: hasMore, holeLater: false, isLoading: false), type: .Generic(type: version > 0 ? ViewUpdateType.Generic : ViewUpdateType.Initial), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: nil, buttonKeyboardMessage: nil, cachedData: nil, cachedDataMessages: nil, readStateData: nil), id: 0), version, nil)
return (ChatHistoryViewUpdate.HistoryView(view: MessageHistoryView(tagMask: nil, namespaces: .all, entries: messages.reversed().map { MessageHistoryEntry(message: $0, isRead: false, location: nil, monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)) }, holeEarlier: hasMore, holeLater: false, isLoading: false), type: .Generic(type: version > 0 ? ViewUpdateType.Generic : ViewUpdateType.Initial), scrollPosition: scrollPosition, flashIndicators: false, originalScrollPosition: nil, initialData: ChatHistoryCombinedInitialData(initialData: nil, buttonKeyboardMessage: nil, cachedData: nil, cachedDataMessages: nil, readStateData: nil), id: 0), version, nil, nil)
}
} else {
historyViewUpdate = self.chatHistoryLocationPromise.get()
|> distinctUntilChanged
|> mapToSignal { location in
return chatHistoryViewForLocation(location, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: isScheduledMessages, fixedCombinedReadStates: fixedCombinedReadStates.with { $0 }, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, additionalData: additionalData, orderStatistics: [.combinedLocation])
historyViewUpdate = combineLatest(queue: .mainQueue(),
self.chatHistoryLocationPromise.get(),
self.ignoreMessagesInTimestampRangePromise.get()
)
|> distinctUntilChanged(isEqual: { lhs, rhs in
if lhs.0 != rhs.0 {
return false
}
if lhs.1 != rhs.1 {
return false
}
return true
})
|> mapToSignal { location, ignoreMessagesInTimestampRange in
return chatHistoryViewForLocation(location, ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: isScheduledMessages, fixedCombinedReadStates: fixedCombinedReadStates.with { $0 }, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, additionalData: additionalData, orderStatistics: [.combinedLocation])
|> beforeNext { viewUpdate in
switch viewUpdate {
case let .HistoryView(view, _, _, _, _, _, _):
@ -801,7 +822,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
break
}
}
|> map { view -> (ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?) in
|> map { view -> (ChatHistoryViewUpdate, Int, ChatHistoryLocationInput?, ClosedRange<Int32>?) in
let version = currentViewVersion.modify({ value in
if let value = value {
return value + 1
@ -809,7 +830,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
return 0
}
})!
return (view, version, location)
return (view, version, location, ignoreMessagesInTimestampRange)
}
}
}
@ -1117,7 +1138,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
adMessages: adMessages
)
let lastHeaderId = filteredEntries.last.flatMap { listMessageDateHeaderId(timestamp: $0.index.timestamp) } ?? 0
let processedView = ChatHistoryView(originalView: view, filteredEntries: filteredEntries, associatedData: associatedData, lastHeaderId: lastHeaderId, id: id, locationInput: update.2)
let processedView = ChatHistoryView(originalView: view, filteredEntries: filteredEntries, associatedData: associatedData, lastHeaderId: lastHeaderId, id: id, locationInput: update.2, ignoreMessagesInTimestampRange: update.3)
let previousValueAndVersion = previousView.swap((processedView, update.1, selectedMessages))
let previous = previousValueAndVersion?.0
let previousSelectedMessages = previousValueAndVersion?.2

View File

@ -18,7 +18,7 @@ func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, c
tagMask = .pinned
}
return (chatHistoryViewForLocation(location, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: isScheduled, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: false, additionalData: additionalData, orderStatistics: orderStatistics)
return (chatHistoryViewForLocation(location, ignoreMessagesInTimestampRange: nil, context: context, chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, scheduled: isScheduled, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: false, additionalData: additionalData, orderStatistics: orderStatistics)
|> castError(Bool.self)
|> mapToSignal { update -> Signal<ChatHistoryViewUpdate, Bool> in
switch update {
@ -36,7 +36,7 @@ func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, c
|> restartIfError
}
func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, scheduled: Bool, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, scheduled: Bool, fixedCombinedReadStates: MessageHistoryViewReadState?, tagMask: MessageTags?, appendMessagesFromTheSameGroup: Bool, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
let account = context.account
if scheduled {
var first = true
@ -83,9 +83,9 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
var fadeIn = false
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>
if let tagMask = tagMask {
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: .upperBound, anchorIndex: .upperBound, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: nil, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics)
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: .upperBound, anchorIndex: .upperBound, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: nil, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics)
} else {
signal = account.viewTracker.aroundMessageOfInterestHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), count: count, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
signal = account.viewTracker.aroundMessageOfInterestHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
}
return signal
|> map { view, updateType, initialData -> ChatHistoryViewUpdate in
@ -175,9 +175,9 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
let signal: Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError>
switch searchLocation {
case let .index(index):
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: .message(index), anchorIndex: .message(index), count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: nil, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
signal = account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: .message(index), anchorIndex: .message(index), count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: nil, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
case let .id(id):
signal = account.viewTracker.aroundIdMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), count: count, ignoreRelatedChats: ignoreRelatedChats, messageId: id, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
signal = account.viewTracker.aroundIdMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, count: count, ignoreRelatedChats: ignoreRelatedChats, messageId: id, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
}
return signal |> map { view, updateType, initialData -> ChatHistoryViewUpdate in
@ -225,7 +225,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
}
case let .Navigation(index, anchorIndex, count, _):
var first = true
return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: index, anchorIndex: anchorIndex, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in
return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: index, anchorIndex: anchorIndex, count: count, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData) |> map { view, updateType, initialData -> ChatHistoryViewUpdate in
let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation)
let genericType: ViewUpdateType
@ -241,7 +241,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, context: A
let directionHint: ListViewScrollToItemDirectionHint = sourceIndex > index ? .Down : .Up
let chatScrollPosition = ChatHistoryViewScrollPosition.index(index: index, position: scrollPosition, directionHint: directionHint, animated: animated, highlight: highlight)
var first = true
return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), index: index, anchorIndex: anchorIndex, count: 128, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
return account.viewTracker.aroundMessageHistoryViewForLocation(context.chatLocationInput(for: chatLocation, contextHolder: chatLocationContextHolder), ignoreMessagesInTimestampRange: ignoreMessagesInTimestampRange, index: index, anchorIndex: anchorIndex, count: 128, ignoreRelatedChats: ignoreRelatedChats, fixedCombinedReadStates: fixedCombinedReadStates, tagMask: tagMask, appendMessagesFromTheSameGroup: appendMessagesFromTheSameGroup, orderStatistics: orderStatistics, additionalData: additionalData)
|> map { view, updateType, initialData -> ChatHistoryViewUpdate in
let (cachedData, cachedDataMessages, readStateData) = extractAdditionalData(view: view, chatLocation: chatLocation)

View File

@ -486,7 +486,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
return .single(nil)
}
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: .index(message.index), count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: .index(message.index), ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
|> mapToSignal { view -> Signal<(Message, [Message])?, NoError> in
if let (message, aroundMessages, _) = navigatedMessageFromView(view.0, anchorIndex: message.index, position: .exact) {
return .single((message, aroundMessages))
@ -584,7 +584,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
}
let historySignal = inputIndex
|> mapToSignal { inputIndex -> Signal<(Message, [Message])?, NoError> in
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: .index(inputIndex), count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: .index(inputIndex), ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
|> mapToSignal { view -> Signal<(Message, [Message])?, NoError> in
let position: NavigatedMessageFromViewPosition
switch navigation {
@ -614,7 +614,7 @@ final class PeerMessagesMediaPlaylist: SharedMediaPlaylist {
} else {
viewIndex = .lowerBound
}
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: viewIndex, count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
return self.context.account.postbox.aroundMessageHistoryViewForLocation(self.context.chatLocationInput(for: chatLocation, contextHolder: self.chatLocationContextHolder ?? Atomic<ChatLocationContextHolder?>(value: nil)), anchor: viewIndex, ignoreMessagesInTimestampRange: nil, count: 10, fixedCombinedReadStates: nil, topTaggedMessageIdNamespaces: [], tagMask: tagMask, appendMessagesFromTheSameGroup: false, namespaces: namespaces, orderStatistics: [])
|> mapToSignal { view -> Signal<(Message, [Message])?, NoError> in
let position: NavigatedMessageFromViewPosition
switch navigation {