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

This commit is contained in:
Ilya Laktyushin 2021-09-13 05:16:19 +03:00
commit 96da891b92
4 changed files with 98 additions and 23 deletions

View File

@ -243,7 +243,7 @@ def generate(header_path: str, implementation_path: str, data_path: str, entries
formatted_accessors += ''' formatted_accessors += '''
static _FormattedString * _Nonnull getFormatted{num_arguments}(_PresentationStrings * _Nonnull strings, static _FormattedString * _Nonnull getFormatted{num_arguments}(_PresentationStrings * _Nonnull strings,
uint32_t keyId{arguments_string}) {{ uint32_t keyId{arguments_string}) {{
NSString *formatString = getSingle(strings, strings->_idToKey[@(keyId)]); NSString *formatString = getSingle(strings, strings->_idToKey[@(keyId)], nil);
NSArray<_FormattedStringRange *> *argumentRanges = extractArgumentRanges(formatString); NSArray<_FormattedStringRange *> *argumentRanges = extractArgumentRanges(formatString);
return formatWithArgumentRanges(formatString, argumentRanges, @[{arguments_array}]); return formatWithArgumentRanges(formatString, argumentRanges, @[{arguments_array}]);
}} }}
@ -421,8 +421,8 @@ static _FormattedString * _Nonnull formatWithArgumentRanges(
return [[_FormattedString alloc] initWithString:result ranges:resultingRanges]; return [[_FormattedString alloc] initWithString:result ranges:resultingRanges];
} }
static NSString * _Nonnull getPluralizationSuffix(_PresentationStrings * _Nonnull strings, int32_t value) { static NSString * _Nonnull getPluralizationSuffix(uint32_t lc, int32_t value) {
NumberPluralizationForm pluralizationForm = numberPluralizationForm(strings.lc, value); NumberPluralizationForm pluralizationForm = numberPluralizationForm(lc, value);
switch (pluralizationForm) { switch (pluralizationForm) {
case NumberPluralizationFormZero: { case NumberPluralizationFormZero: {
return @"_0"; return @"_0";
@ -445,11 +445,15 @@ static NSString * _Nonnull getPluralizationSuffix(_PresentationStrings * _Nonnul
} }
} }
static NSString * _Nonnull getSingle(_PresentationStrings * _Nonnull strings, NSString * _Nonnull key) { static NSString * _Nonnull getSingle(_PresentationStrings * _Nullable strings, NSString * _Nonnull key,
NSString *result = strings.primaryComponent.dict[key]; bool * _Nullable isFound) {
NSString *result = nil;
if (strings) {
result = strings.primaryComponent.dict[key];
if (!result) { if (!result) {
result = strings.secondaryComponent.dict[key]; result = strings.secondaryComponent.dict[key];
} }
}
if (!result) { if (!result) {
static NSDictionary<NSString *, NSString *> *fallbackDict = nil; static NSDictionary<NSString *, NSString *> *fallbackDict = nil;
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
@ -472,18 +476,31 @@ static NSString * _Nonnull getSingle(_PresentationStrings * _Nonnull strings, NS
} }
if (!result) { if (!result) {
result = key; result = key;
if (isFound) {
*isFound = false;
}
} else {
if (isFound) {
*isFound = true;
}
} }
return result; return result;
} }
static NSString * _Nonnull getSingleIndirect(_PresentationStrings * _Nonnull strings, uint32_t keyId) { static NSString * _Nonnull getSingleIndirect(_PresentationStrings * _Nonnull strings, uint32_t keyId) {
return getSingle(strings, strings->_idToKey[@(keyId)]); return getSingle(strings, strings->_idToKey[@(keyId)], nil);
} }
static NSString * _Nonnull getPluralized(_PresentationStrings * _Nonnull strings, NSString * _Nonnull key, static NSString * _Nonnull getPluralized(_PresentationStrings * _Nonnull strings, NSString * _Nonnull key,
int32_t value) { int32_t value) {
NSString *parsedKey = [[NSString alloc] initWithFormat:@"%@%@", key, getPluralizationSuffix(strings, value)]; NSString *parsedKey = [[NSString alloc] initWithFormat:@"%@%@", key, getPluralizationSuffix(strings.lc, value)];
NSString *formatString = getSingle(strings, parsedKey); bool isFound = false;
NSString *formatString = getSingle(strings, parsedKey, &isFound);
if (!isFound) {
// fall back to English
parsedKey = [[NSString alloc] initWithFormat:@"%@%@", key, getPluralizationSuffix(0x656e, value)];
formatString = getSingle(nil, parsedKey, nil);
}
NSString *stringValue = formatNumberWithGroupingSeparator(strings.groupingSeparator, value); NSString *stringValue = formatNumberWithGroupingSeparator(strings.groupingSeparator, value);
NSArray<_FormattedStringRange *> *argumentRanges = extractArgumentRanges(formatString); NSArray<_FormattedStringRange *> *argumentRanges = extractArgumentRanges(formatString);
return formatWithArgumentRanges(formatString, argumentRanges, @[stringValue]).string; return formatWithArgumentRanges(formatString, argumentRanges, @[stringValue]).string;

View File

@ -555,8 +555,10 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
var nextChannelToReadDisplayName: Bool = false var nextChannelToReadDisplayName: Bool = false
private var currentOverscrollExpandProgress: CGFloat = 0.0 private var currentOverscrollExpandProgress: CGFloat = 0.0
private var freezeOverscrollControl: Bool = false private var freezeOverscrollControl: Bool = false
private var freezeOverscrollControlProgress: Bool = false
private var feedback: HapticFeedback? private var feedback: HapticFeedback?
var openNextChannelToRead: ((EnginePeer, TelegramEngine.NextUnreadChannelLocation) -> Void)? var openNextChannelToRead: ((EnginePeer, TelegramEngine.NextUnreadChannelLocation) -> Void)?
private var contentInsetAnimator: DisplayLinkAnimator?
private let adMessagesContext: AdMessagesHistoryContext? private let adMessagesContext: AdMessagesHistoryContext?
@ -1294,9 +1296,32 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if let nextChannelToRead = strongSelf.nextChannelToRead, strongSelf.currentOverscrollExpandProgress >= 0.99 { if strongSelf.offerNextChannelToRead, strongSelf.currentOverscrollExpandProgress >= 0.99 {
if let nextChannelToRead = strongSelf.nextChannelToRead {
strongSelf.freezeOverscrollControl = true strongSelf.freezeOverscrollControl = true
strongSelf.openNextChannelToRead?(nextChannelToRead.peer, nextChannelToRead.location) strongSelf.openNextChannelToRead?(nextChannelToRead.peer, nextChannelToRead.location)
} else {
strongSelf.freezeOverscrollControlProgress = true
strongSelf.scroller.contentInset = UIEdgeInsets(top: 94.0 + 12.0, left: 0.0, bottom: 0.0, right: 0.0)
Queue.mainQueue().after(0.3, {
let animator = DisplayLinkAnimator(duration: 0.2, from: 1.0, to: 0.0, update: { rawT in
guard let strongSelf = self else {
return
}
let t = listViewAnimationCurveEaseInOut(rawT)
let value = (94.0 + 12.0) * t
strongSelf.scroller.contentInset = UIEdgeInsets(top: value, left: 0.0, bottom: 0.0, right: 0.0)
}, completion: {
guard let strongSelf = self else {
return
}
strongSelf.contentInsetAnimator = nil
strongSelf.scroller.contentInset = UIEdgeInsets()
strongSelf.freezeOverscrollControlProgress = false
})
strongSelf.contentInsetAnimator = animator
})
}
} }
} }
@ -1396,7 +1421,12 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
chatControllerNode.setChatInputPanelOverscrollNode(overscrollNode: nil) chatControllerNode.setChatInputPanelOverscrollNode(overscrollNode: nil)
} }
let overscrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.insets.top), size: CGSize(width: self.bounds.width, height: 94.0)) var overscrollFrame = CGRect(origin: CGPoint(x: 0.0, y: self.insets.top), size: CGSize(width: self.bounds.width, height: 94.0))
if self.freezeOverscrollControlProgress {
overscrollFrame.origin.y -= max(0.0, 94.0 - expandDistance)
}
overscrollView.frame = self.view.convert(overscrollFrame, to: self.view.superview!)
let _ = overscrollView.update( let _ = overscrollView.update(
transition: .immediate, transition: .immediate,
@ -1407,7 +1437,8 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
unreadCount: self.nextChannelToRead?.unreadCount ?? 0, unreadCount: self.nextChannelToRead?.unreadCount ?? 0,
location: self.nextChannelToRead?.location ?? .same, location: self.nextChannelToRead?.location ?? .same,
context: self.context, context: self.context,
expandDistance: expandDistance, expandDistance: self.freezeOverscrollControl ? 94.0 : expandDistance,
freezeProgress: false,
absoluteRect: CGRect(origin: CGPoint(x: overscrollFrame.minX, y: self.bounds.height - overscrollFrame.minY), size: overscrollFrame.size), absoluteRect: CGRect(origin: CGPoint(x: overscrollFrame.minX, y: self.bounds.height - overscrollFrame.minY), size: overscrollFrame.size),
absoluteSize: self.bounds.size, absoluteSize: self.bounds.size,
wallpaperNode: chatControllerNode.backgroundNode wallpaperNode: chatControllerNode.backgroundNode
@ -1415,7 +1446,6 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
environment: {}, environment: {},
containerSize: CGSize(width: self.bounds.width, height: 200.0) containerSize: CGSize(width: self.bounds.width, height: 200.0)
) )
overscrollView.frame = self.view.convert(overscrollFrame, to: self.view.superview!)
} else if let overscrollView = self.overscrollView { } else if let overscrollView = self.overscrollView {
self.overscrollView = nil self.overscrollView = nil
overscrollView.removeFromSuperview() overscrollView.removeFromSuperview()

View File

@ -1738,6 +1738,7 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
private let backgroundNode: ASDisplayNode private let backgroundNode: ASDisplayNode
private let highlightedBackgroundNode: ASDisplayNode private let highlightedBackgroundNode: ASDisplayNode
private let placeholderCalculationTextNode: ImmediateTextNode
private let textNode: ImmediateTextNode private let textNode: ImmediateTextNode
private let shimmerNode: ShimmerEffectNode private let shimmerNode: ShimmerEffectNode
private let iconNode: ASImageNode private let iconNode: ASImageNode
@ -1772,11 +1773,15 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor self.highlightedBackgroundNode.backgroundColor = presentationData.theme.contextMenu.itemHighlightedBackgroundColor
self.highlightedBackgroundNode.alpha = 0.0 self.highlightedBackgroundNode.alpha = 0.0
self.placeholderCalculationTextNode = ImmediateTextNode()
self.placeholderCalculationTextNode.attributedText = NSAttributedString(string: presentationData.strings.Conversation_ContextMenuSeen(11), font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
self.placeholderCalculationTextNode.maximumNumberOfLines = 1
self.textNode = ImmediateTextNode() self.textNode = ImmediateTextNode()
self.textNode.isAccessibilityElement = false self.textNode.isAccessibilityElement = false
self.textNode.isUserInteractionEnabled = false self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = false self.textNode.displaysAsynchronously = false
self.textNode.attributedText = NSAttributedString(string: " ", font: textFont, textColor: presentationData.theme.contextMenu.destructiveColor) self.textNode.attributedText = NSAttributedString(string: " ", font: textFont, textColor: presentationData.theme.contextMenu.primaryColor)
self.textNode.maximumNumberOfLines = 1 self.textNode.maximumNumberOfLines = 1
self.textNode.alpha = 0.0 self.textNode.alpha = 0.0
@ -1918,6 +1923,8 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
let textSize = self.textNode.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0, height: .greatestFiniteMagnitude)) let textSize = self.textNode.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0, height: .greatestFiniteMagnitude))
let placeholderTextSize = self.placeholderCalculationTextNode.updateLayout(CGSize(width: calculatedWidth - sideInset - rightTextInset - iconSize.width - 4.0, height: .greatestFiniteMagnitude))
let combinedTextHeight = textSize.height let combinedTextHeight = textSize.height
return (CGSize(width: calculatedWidth, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in return (CGSize(width: calculatedWidth, height: verticalInset * 2.0 + combinedTextHeight), { size, transition in
self.validLayout = (calculatedWidth: calculatedWidth, size: size) self.validLayout = (calculatedWidth: calculatedWidth, size: size)
@ -1928,7 +1935,7 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
let shimmerHeight: CGFloat = 8.0 let shimmerHeight: CGFloat = 8.0
self.shimmerNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: floor((size.height - shimmerHeight) / 2.0)), size: CGSize(width: min(100.0, size.width - 40.0), height: shimmerHeight)) self.shimmerNode.frame = CGRect(origin: CGPoint(x: textFrame.minX, y: floor((size.height - shimmerHeight) / 2.0)), size: CGSize(width: placeholderTextSize.width, height: shimmerHeight))
self.shimmerNode.cornerRadius = shimmerHeight / 2.0 self.shimmerNode.cornerRadius = shimmerHeight / 2.0
let shimmeringForegroundColor = self.presentationData.theme.contextMenu.itemSeparatorColor.blitOver(self.presentationData.theme.list.plainBackgroundColor, alpha: 0.9) let shimmeringForegroundColor = self.presentationData.theme.contextMenu.itemSeparatorColor.blitOver(self.presentationData.theme.list.plainBackgroundColor, alpha: 0.9)
let shimmeringColor = self.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.2) let shimmeringColor = self.presentationData.theme.list.itemBlocksBackgroundColor.withAlphaComponent(0.2)

View File

@ -669,6 +669,7 @@ final class OverscrollContentsComponent: Component {
let unreadCount: Int let unreadCount: Int
let location: TelegramEngine.NextUnreadChannelLocation let location: TelegramEngine.NextUnreadChannelLocation
let expandOffset: CGFloat let expandOffset: CGFloat
let freezeProgress: Bool
let absoluteRect: CGRect let absoluteRect: CGRect
let absoluteSize: CGSize let absoluteSize: CGSize
let wallpaperNode: WallpaperBackgroundNode? let wallpaperNode: WallpaperBackgroundNode?
@ -681,6 +682,7 @@ final class OverscrollContentsComponent: Component {
unreadCount: Int, unreadCount: Int,
location: TelegramEngine.NextUnreadChannelLocation, location: TelegramEngine.NextUnreadChannelLocation,
expandOffset: CGFloat, expandOffset: CGFloat,
freezeProgress: Bool,
absoluteRect: CGRect, absoluteRect: CGRect,
absoluteSize: CGSize, absoluteSize: CGSize,
wallpaperNode: WallpaperBackgroundNode? wallpaperNode: WallpaperBackgroundNode?
@ -692,6 +694,7 @@ final class OverscrollContentsComponent: Component {
self.unreadCount = unreadCount self.unreadCount = unreadCount
self.location = location self.location = location
self.expandOffset = expandOffset self.expandOffset = expandOffset
self.freezeProgress = freezeProgress
self.absoluteRect = absoluteRect self.absoluteRect = absoluteRect
self.absoluteSize = absoluteSize self.absoluteSize = absoluteSize
self.wallpaperNode = wallpaperNode self.wallpaperNode = wallpaperNode
@ -719,6 +722,9 @@ final class OverscrollContentsComponent: Component {
if lhs.expandOffset != rhs.expandOffset { if lhs.expandOffset != rhs.expandOffset {
return false return false
} }
if lhs.freezeProgress != rhs.freezeProgress {
return false
}
if lhs.absoluteRect != rhs.absoluteRect { if lhs.absoluteRect != rhs.absoluteRect {
return false return false
} }
@ -811,7 +817,14 @@ final class OverscrollContentsComponent: Component {
let minBackgroundHeight: CGFloat = backgroundWidth + 5.0 let minBackgroundHeight: CGFloat = backgroundWidth + 5.0
let avatarInset: CGFloat = 6.0 let avatarInset: CGFloat = 6.0
let isFullyExpanded = component.expandOffset >= fullHeight let apparentExpandOffset: CGFloat
if component.freezeProgress {
apparentExpandOffset = fullHeight
} else {
apparentExpandOffset = component.expandOffset
}
let isFullyExpanded = apparentExpandOffset >= fullHeight
let isFolderMask: Bool let isFolderMask: Bool
switch component.location { switch component.location {
@ -821,20 +834,21 @@ final class OverscrollContentsComponent: Component {
isFolderMask = false isFolderMask = false
} }
let expandProgress: CGFloat = max(0.1, min(1.0, component.expandOffset / fullHeight)) let expandProgress: CGFloat = max(0.1, min(1.0, apparentExpandOffset / fullHeight))
let trueExpandProgress: CGFloat = max(0.1, min(1.0, component.expandOffset / fullHeight))
func interpolate(from: CGFloat, to: CGFloat, value: CGFloat) -> CGFloat { func interpolate(from: CGFloat, to: CGFloat, value: CGFloat) -> CGFloat {
return (1.0 - value) * from + value * to return (1.0 - value) * from + value * to
} }
let backgroundHeight: CGFloat = interpolate(from: minBackgroundHeight, to: fullHeight, value: expandProgress) let backgroundHeight: CGFloat = interpolate(from: minBackgroundHeight, to: fullHeight, value: trueExpandProgress)
let backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - backgroundWidth) / 2.0), y: fullHeight - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight)) let backgroundFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - backgroundWidth) / 2.0), y: fullHeight - backgroundHeight), size: CGSize(width: backgroundWidth, height: backgroundHeight))
let alphaProgress: CGFloat = max(0.0, min(1.0, component.expandOffset / 10.0)) let alphaProgress: CGFloat = max(0.0, min(1.0, apparentExpandOffset / 10.0))
let maxAvatarScale: CGFloat = 1.0 let maxAvatarScale: CGFloat = 1.0
var avatarExpandProgress: CGFloat = max(0.01, min(maxAvatarScale, component.expandOffset / fullHeight)) var avatarExpandProgress: CGFloat = max(0.01, min(maxAvatarScale, apparentExpandOffset / fullHeight))
avatarExpandProgress *= expandProgress avatarExpandProgress *= expandProgress
let avatarOffsetProgress = interpolate(from: 0.1, to: 1.0, value: avatarExpandProgress) let avatarOffsetProgress = interpolate(from: 0.1, to: 1.0, value: avatarExpandProgress)
@ -978,6 +992,7 @@ final class ChatOverscrollControl: CombinedComponent {
let location: TelegramEngine.NextUnreadChannelLocation let location: TelegramEngine.NextUnreadChannelLocation
let context: AccountContext let context: AccountContext
let expandDistance: CGFloat let expandDistance: CGFloat
let freezeProgress: Bool
let absoluteRect: CGRect let absoluteRect: CGRect
let absoluteSize: CGSize let absoluteSize: CGSize
let wallpaperNode: WallpaperBackgroundNode? let wallpaperNode: WallpaperBackgroundNode?
@ -990,6 +1005,7 @@ final class ChatOverscrollControl: CombinedComponent {
location: TelegramEngine.NextUnreadChannelLocation, location: TelegramEngine.NextUnreadChannelLocation,
context: AccountContext, context: AccountContext,
expandDistance: CGFloat, expandDistance: CGFloat,
freezeProgress: Bool,
absoluteRect: CGRect, absoluteRect: CGRect,
absoluteSize: CGSize, absoluteSize: CGSize,
wallpaperNode: WallpaperBackgroundNode? wallpaperNode: WallpaperBackgroundNode?
@ -1001,6 +1017,7 @@ final class ChatOverscrollControl: CombinedComponent {
self.location = location self.location = location
self.context = context self.context = context
self.expandDistance = expandDistance self.expandDistance = expandDistance
self.freezeProgress = freezeProgress
self.absoluteRect = absoluteRect self.absoluteRect = absoluteRect
self.absoluteSize = absoluteSize self.absoluteSize = absoluteSize
self.wallpaperNode = wallpaperNode self.wallpaperNode = wallpaperNode
@ -1028,6 +1045,9 @@ final class ChatOverscrollControl: CombinedComponent {
if lhs.expandDistance != rhs.expandDistance { if lhs.expandDistance != rhs.expandDistance {
return false return false
} }
if lhs.freezeProgress != rhs.freezeProgress {
return false
}
if lhs.absoluteRect != rhs.absoluteRect { if lhs.absoluteRect != rhs.absoluteRect {
return false return false
} }
@ -1053,6 +1073,7 @@ final class ChatOverscrollControl: CombinedComponent {
unreadCount: context.component.unreadCount, unreadCount: context.component.unreadCount,
location: context.component.location, location: context.component.location,
expandOffset: context.component.expandDistance, expandOffset: context.component.expandDistance,
freezeProgress: context.component.freezeProgress,
absoluteRect: context.component.absoluteRect, absoluteRect: context.component.absoluteRect,
absoluteSize: context.component.absoluteSize, absoluteSize: context.component.absoluteSize,
wallpaperNode: context.component.wallpaperNode wallpaperNode: context.component.wallpaperNode