mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-07-31 15:37:01 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
ca34b4e93a
@ -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",
|
||||
|
@ -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] = []
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
})
|
||||
|
@ -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))
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -812,6 +812,7 @@ func _internal_fetchChannelReplyThreadMessage(account: Account, messageId: Messa
|
||||
Namespaces.Message.Cloud: holes
|
||||
]
|
||||
)),
|
||||
ignoreMessagesInTimestampRange: nil,
|
||||
count: 40,
|
||||
clipHoles: true,
|
||||
anchor: inputAnchor,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user