mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
UI improvements
This commit is contained in:
parent
38935ca811
commit
4b2902ac71
@ -8847,3 +8847,7 @@ Sorry for the inconvenience.";
|
||||
"Chat.PlaceholderTextNotAllowed" = "Text not allowed";
|
||||
|
||||
"CallList.DeleteAll" = "Delete All";
|
||||
|
||||
"DataUsage.TopSectionAll" = "All";
|
||||
"DataUsage.TopSectionMobile" = "Mobile";
|
||||
"DataUsage.TopSectionWifi" = "Wifi";
|
||||
|
@ -76,4 +76,6 @@
|
||||
|
||||
+ (NSData *)_manuallyEncryptedMessage:(NSData *)preparedData messageId:(int64_t)messageId authKey:(MTDatacenterAuthKey *)authKey;
|
||||
|
||||
- (void)simulateDisconnection;
|
||||
|
||||
@end
|
||||
|
@ -62,4 +62,6 @@
|
||||
|
||||
- (void)updateSchemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes;
|
||||
|
||||
- (void)simulateDisconnection;
|
||||
|
||||
@end
|
||||
|
@ -228,7 +228,7 @@ static int32_t fixedTimeDifferenceValue = 0;
|
||||
_isTestingEnvironment = isTestingEnvironment;
|
||||
_useTempAuthKeys = useTempAuthKeys;
|
||||
#if DEBUG
|
||||
_tempKeyExpiration = 10 * 60;
|
||||
_tempKeyExpiration = 30;
|
||||
#else
|
||||
_tempKeyExpiration = 24 * 60 * 60;
|
||||
#endif
|
||||
|
@ -247,6 +247,12 @@ typedef enum {
|
||||
}
|
||||
case MTDatacenterAuthStageReqDH:
|
||||
{
|
||||
#if DEBUG
|
||||
if (arc4random_uniform(100) < 50) {
|
||||
[mtProto simulateDisconnection];
|
||||
}
|
||||
#endif
|
||||
|
||||
MTBuffer *reqDhBuffer = [[MTBuffer alloc] init];
|
||||
[reqDhBuffer appendInt32:(int32_t)0xd712e4be];
|
||||
[reqDhBuffer appendBytes:_nonce.bytes length:_nonce.length];
|
||||
|
@ -657,6 +657,15 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)simulateDisconnection {
|
||||
[[MTProto managerQueue] dispatchOnQueue:^
|
||||
{
|
||||
if (_transport != nil) {
|
||||
[_transport simulateDisconnection];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (bool)canAskForTransactions
|
||||
{
|
||||
return (_mtState & (MTProtoStateAwaitingDatacenterScheme | MTProtoStateAwaitingDatacenterAuthorization | MTProtoStateAwaitingDatacenterAuthToken | MTProtoStateAwaitingTimeFixAndSalts | MTProtoStateStopped)) == 0;
|
||||
@ -770,7 +779,10 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
|
||||
return;
|
||||
}
|
||||
if (_useUnauthorizedMode) {
|
||||
#if DEBUG
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (hasConnectionProblems) {
|
||||
|
@ -804,4 +804,18 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)simulateDisconnection {
|
||||
MTTcpTransportContext *transportContext = _transportContext;
|
||||
[[MTTcpTransport tcpTransportQueue] dispatchOnQueue:^ {
|
||||
if (transportContext.connection.scheme != nil) {
|
||||
MTTransportScheme *scheme = transportContext.connection.scheme;
|
||||
__weak MTTcpTransport *weakSelf = self;
|
||||
dispatch_async([MTTcpTransport tcpTransportQueue].nativeQueue, ^{
|
||||
__strong MTTcpTransport *strongSelf = weakSelf;
|
||||
[strongSelf connectionWatchdogTimeout:scheme];
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -92,4 +92,7 @@
|
||||
- (void)updateSchemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes {
|
||||
}
|
||||
|
||||
- (void)simulateDisconnection {
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -1475,6 +1475,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)]
|
||||
}
|
||||
@ -1528,6 +1529,7 @@ public final class ReactionContextNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], isFinalResult))
|
||||
}
|
||||
|
@ -397,10 +397,14 @@ final class StickerPackEmojisItemNode: GridItemNode {
|
||||
if let current = strongSelf.visibleItemPlaceholderViews[itemId] {
|
||||
placeholderView = current
|
||||
} else {
|
||||
var placeholderContent: EmojiPagerContentComponent.View.ItemPlaceholderView.Content?
|
||||
if let immediateThumbnailData = item.file.immediateThumbnailData {
|
||||
placeholderContent = .thumbnail(immediateThumbnailData)
|
||||
}
|
||||
placeholderView = EmojiPagerContentComponent.View.ItemPlaceholderView(
|
||||
context: context,
|
||||
dimensions: item.file.dimensions?.cgSize ?? CGSize(width: 512.0, height: 512.0),
|
||||
immediateThumbnailData: item.file.immediateThumbnailData,
|
||||
content: placeholderContent,
|
||||
shimmerView: nil,//strongSelf.shimmerHostView,
|
||||
color: theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.08),
|
||||
size: itemNativeFitSize
|
||||
|
@ -233,11 +233,11 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
||||
|
||||
let imageSize = dimensitons.cgSize.aspectFitted(boundingSize)
|
||||
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))()
|
||||
var imageFrame = CGRect(origin: CGPoint(x: floor((size.width - imageSize.width) / 2.0), y: textSize.height + textSpacing - topOffset), size: imageSize)
|
||||
var imageFrame = CGRect(origin: CGPoint(x: floor((boundingSize.width - imageSize.width) / 2.0), y: textSize.height + textSpacing - topOffset), size: imageSize)
|
||||
var centerOffset: CGFloat = 0.0
|
||||
if self.item.file.isPremiumSticker {
|
||||
let originalImageFrame = imageFrame
|
||||
imageFrame.origin.x = size.width - imageFrame.width - 18.0
|
||||
imageFrame.origin.x = min(imageFrame.minX + imageFrame.width * 0.1, size.width - imageFrame.width - 18.0)
|
||||
centerOffset = imageFrame.minX - originalImageFrame.minX
|
||||
}
|
||||
self.imageNode.frame = imageFrame
|
||||
@ -254,9 +254,9 @@ public final class StickerPreviewPeekContentNode: ASDisplayNode, PeekControllerC
|
||||
self.textNode.frame = CGRect(origin: CGPoint(x: floor((imageFrame.size.width - textSize.width) / 2.0) - centerOffset, y: -textSize.height - textSpacing), size: textSize)
|
||||
|
||||
if self.item.file.isCustomEmoji {
|
||||
return CGSize(width: size.width, height: imageFrame.height)
|
||||
return CGSize(width: boundingSize.width, height: imageFrame.height)
|
||||
} else {
|
||||
return CGSize(width: size.width, height: imageFrame.height + textSize.height + textSpacing)
|
||||
return CGSize(width: boundingSize.width, height: imageFrame.height + textSize.height + textSpacing)
|
||||
}
|
||||
} else {
|
||||
return CGSize(width: size.width, height: 10.0)
|
||||
|
@ -476,6 +476,9 @@ func _internal_searchEmoji(account: Account, query: [String], scope: SearchStick
|
||||
if let currentCached = cached, currentTime > currentCached.timestamp + searchStickersConfiguration.cacheTimeout {
|
||||
cached = nil
|
||||
}
|
||||
#if DEBUG
|
||||
cached = nil
|
||||
#endif
|
||||
|
||||
return (result, cached, isPremium, searchStickersConfiguration)
|
||||
}
|
||||
|
@ -189,32 +189,6 @@ public extension TelegramEngine {
|
||||
|> map { items, isFinalResult -> (items: [TelegramMediaFile], isFinalResult: Bool) in
|
||||
return (items.map(\.file), isFinalResult)
|
||||
}
|
||||
|
||||
/*return self.account.network.request(Api.functions.messages.searchCustomEmoji(emoticon: emojiString.joined(separator: ""), hash: 0))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.EmojiList?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<[TelegramMediaFile], NoError> in
|
||||
guard let result = result else {
|
||||
return .single([])
|
||||
}
|
||||
switch result {
|
||||
case let .emojiList(_, documentIds):
|
||||
return self.resolveInlineStickers(fileIds: documentIds)
|
||||
|> map { result -> [TelegramMediaFile] in
|
||||
var files: [TelegramMediaFile] = []
|
||||
for id in documentIds {
|
||||
if let file = result[id] {
|
||||
files.append(file)
|
||||
}
|
||||
}
|
||||
return files
|
||||
}
|
||||
default:
|
||||
return .single([])
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -435,6 +435,7 @@ final class AvatarEditorScreenComponent: Component {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: emojiItems
|
||||
)
|
||||
)
|
||||
@ -454,6 +455,7 @@ final class AvatarEditorScreenComponent: Component {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: stickerItems
|
||||
)
|
||||
)
|
||||
@ -510,6 +512,7 @@ final class AvatarEditorScreenComponent: Component {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], isFinalResult))
|
||||
}
|
||||
|
@ -1087,6 +1087,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)]
|
||||
}
|
||||
@ -1140,6 +1141,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], isFinalResult))
|
||||
}
|
||||
@ -1155,12 +1157,31 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
return
|
||||
}
|
||||
if group.items.isEmpty && !result.isFinalResult {
|
||||
self.emojiSearchStateValue.isSearching = true
|
||||
//self.emojiSearchStateValue.isSearching = true
|
||||
self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: [
|
||||
EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
groupId: "search",
|
||||
title: nil,
|
||||
subtitle: nil,
|
||||
actionButtonTitle: nil,
|
||||
isFeatured: false,
|
||||
isPremiumLocked: false,
|
||||
isEmbedded: false,
|
||||
hasClear: false,
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: true,
|
||||
items: []
|
||||
)
|
||||
], id: AnyHashable(value), version: version, isPreset: true), isSearching: false)
|
||||
return
|
||||
}
|
||||
|
||||
//DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
|
||||
self.emojiSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false)
|
||||
version += 1
|
||||
//})
|
||||
}))
|
||||
}
|
||||
},
|
||||
@ -1416,6 +1437,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], files.isFinalResult))
|
||||
}
|
||||
@ -1430,7 +1452,25 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
return
|
||||
}
|
||||
if group.items.isEmpty && !result.isFinalResult {
|
||||
strongSelf.stickerSearchStateValue.isSearching = true
|
||||
//strongSelf.stickerSearchStateValue.isSearching = true
|
||||
strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: [
|
||||
EmojiPagerContentComponent.ItemGroup(
|
||||
supergroupId: "search",
|
||||
groupId: "search",
|
||||
title: nil,
|
||||
subtitle: nil,
|
||||
actionButtonTitle: nil,
|
||||
isFeatured: false,
|
||||
isPremiumLocked: false,
|
||||
isEmbedded: false,
|
||||
hasClear: false,
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: true,
|
||||
items: []
|
||||
)
|
||||
], id: AnyHashable(value), version: version, isPreset: true), isSearching: false)
|
||||
return
|
||||
}
|
||||
strongSelf.stickerSearchStateValue = EmojiSearchState(result: EmojiSearchResult(groups: result.items, id: AnyHashable(value), version: version, isPreset: true), isSearching: false)
|
||||
@ -1467,7 +1507,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
|
||||
if let emojiSearchResult = emojiSearchState.result {
|
||||
var emptySearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
||||
if !emojiSearchResult.groups.contains(where: { !$0.items.isEmpty }) {
|
||||
if !emojiSearchResult.groups.contains(where: { !$0.items.isEmpty || $0.fillWithLoadingPlaceholders }) {
|
||||
emptySearchResults = EmojiPagerContentComponent.EmptySearchResults(
|
||||
text: presentationData.strings.EmojiSearch_SearchEmojiEmptyResult,
|
||||
iconFile: nil
|
||||
@ -1485,7 +1525,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
||||
|
||||
if let stickerSearchResult = stickerSearchState.result {
|
||||
var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
||||
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty }) {
|
||||
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty || $0.fillWithLoadingPlaceholders }) {
|
||||
stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults(
|
||||
text: presentationData.strings.EmojiSearch_SearchStickersEmptyResult,
|
||||
iconFile: nil
|
||||
|
@ -568,6 +568,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)]
|
||||
}
|
||||
@ -621,6 +622,7 @@ public final class EmojiStatusSelectionController: ViewController {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], isFinalResult))
|
||||
}
|
||||
|
@ -2472,6 +2472,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
public let collapsedLineCount: Int?
|
||||
public let displayPremiumBadges: Bool
|
||||
public let headerItem: EntityKeyboardAnimationData?
|
||||
public let fillWithLoadingPlaceholders: Bool
|
||||
public let items: [Item]
|
||||
|
||||
public init(
|
||||
@ -2487,6 +2488,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
collapsedLineCount: Int?,
|
||||
displayPremiumBadges: Bool,
|
||||
headerItem: EntityKeyboardAnimationData?,
|
||||
fillWithLoadingPlaceholders: Bool,
|
||||
items: [Item]
|
||||
) {
|
||||
self.supergroupId = supergroupId
|
||||
@ -2501,6 +2503,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.collapsedLineCount = collapsedLineCount
|
||||
self.displayPremiumBadges = displayPremiumBadges
|
||||
self.headerItem = headerItem
|
||||
self.fillWithLoadingPlaceholders = fillWithLoadingPlaceholders
|
||||
self.items = items
|
||||
}
|
||||
|
||||
@ -2544,6 +2547,9 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if lhs.headerItem != rhs.headerItem {
|
||||
return false
|
||||
}
|
||||
if lhs.fillWithLoadingPlaceholders != rhs.fillWithLoadingPlaceholders {
|
||||
return false
|
||||
}
|
||||
if lhs.items != rhs.items {
|
||||
return false
|
||||
}
|
||||
@ -3035,6 +3041,11 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
|
||||
public final class ItemPlaceholderView: UIView {
|
||||
public enum Content {
|
||||
case thumbnail(Data)
|
||||
case template(UIImage)
|
||||
}
|
||||
|
||||
private let shimmerView: PortalSourceView?
|
||||
private var placeholderView: PortalView?
|
||||
private let placeholderMaskLayer: SimpleLayer
|
||||
@ -3043,7 +3054,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
dimensions: CGSize?,
|
||||
immediateThumbnailData: Data?,
|
||||
content: Content?,
|
||||
shimmerView: PortalSourceView?,
|
||||
color: UIColor,
|
||||
size: CGSize
|
||||
@ -3063,6 +3074,9 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
|
||||
let useDirectContent = self.placeholderView == nil
|
||||
if let content {
|
||||
switch content {
|
||||
case let .thumbnail(immediateThumbnailData):
|
||||
Queue.concurrentDefaultQueue().async { [weak self] in
|
||||
if let image = generateStickerPlaceholderImage(data: immediateThumbnailData, size: size, scale: min(2.0, UIScreenScale), imageSize: dimensions ?? CGSize(width: 512.0, height: 512.0), backgroundColor: nil, foregroundColor: useDirectContent ? color : .black) {
|
||||
Queue.mainQueue().async {
|
||||
@ -3078,6 +3092,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .template(templateImage):
|
||||
if useDirectContent {
|
||||
self.layer.contents = templateImage.cgImage
|
||||
self.tintColor = color
|
||||
} else {
|
||||
self.placeholderMaskLayer.contents = templateImage.cgImage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
@ -3590,6 +3613,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
private var visibleSearchHeader: EmojiSearchHeaderView?
|
||||
private var visibleEmptySearchResultsView: EmptySearchResultsView?
|
||||
private var visibleItemPlaceholderViews: [ItemLayer.Key: ItemPlaceholderView] = [:]
|
||||
private var visibleFillPlaceholdersViews: [Int: ItemPlaceholderView] = [:]
|
||||
private var visibleItemSelectionLayers: [ItemLayer.Key: ItemSelectionLayer] = [:]
|
||||
private var visibleItemLayers: [ItemLayer.Key: ItemLayer] = [:]
|
||||
private var visibleGroupHeaders: [AnyHashable: GroupHeaderLayer] = [:]
|
||||
@ -3600,6 +3624,16 @@ public final class EmojiPagerContentComponent: Component {
|
||||
private var ignoreScrolling: Bool = false
|
||||
private var keepTopPanelVisibleUntilScrollingInput: Bool = false
|
||||
|
||||
private struct FillPlaceholderParams: Equatable {
|
||||
var size: CGSize
|
||||
|
||||
init(size: CGSize) {
|
||||
self.size = size
|
||||
}
|
||||
}
|
||||
|
||||
private var fillPlaceholder: (params: FillPlaceholderParams, image: UIImage)?
|
||||
|
||||
private var component: EmojiPagerContentComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
private var pagerEnvironment: PagerComponentChildEnvironment?
|
||||
@ -5243,6 +5277,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
var validGroupBorderIds = Set<AnyHashable>()
|
||||
var validGroupPremiumButtonIds = Set<AnyHashable>()
|
||||
var validGroupExpandActionButtons = Set<AnyHashable>()
|
||||
var validFillPlaceholdersIndices = Set<Int>()
|
||||
|
||||
let effectiveVisibleBounds = CGRect(origin: self.scrollView.bounds.origin, size: self.effectiveVisibleSize)
|
||||
let topVisibleDetectionBounds = effectiveVisibleBounds.offsetBy(dx: 0.0, dy: pagerEnvironment.containerInsets.top)
|
||||
@ -5541,7 +5576,6 @@ public final class EmojiPagerContentComponent: Component {
|
||||
for index in groupItemRange.lowerBound ..< groupItemRange.upperBound {
|
||||
let item = itemGroup.items[index]
|
||||
|
||||
|
||||
if assignTopVisibleSubgroupId {
|
||||
if let subgroupId = item.subgroupId {
|
||||
topVisibleSubgroupId = AnyHashable(subgroupId)
|
||||
@ -5600,10 +5634,14 @@ public final class EmojiPagerContentComponent: Component {
|
||||
if let current = strongSelf.visibleItemPlaceholderViews[itemId] {
|
||||
placeholderView = current
|
||||
} else {
|
||||
var placeholderContent: ItemPlaceholderView.Content?
|
||||
if let immediateThumbnailData = animationData.immediateThumbnailData {
|
||||
placeholderContent = .thumbnail(immediateThumbnailData)
|
||||
}
|
||||
placeholderView = ItemPlaceholderView(
|
||||
context: component.context,
|
||||
dimensions: animationData.dimensions,
|
||||
immediateThumbnailData: animationData.immediateThumbnailData,
|
||||
content: placeholderContent,
|
||||
shimmerView: strongSelf.shimmerHostView,
|
||||
color: placeholderColor,
|
||||
size: itemNativeFitSize
|
||||
@ -5756,6 +5794,61 @@ public final class EmojiPagerContentComponent: Component {
|
||||
itemLayer.isVisibleForAnimations = keyboardChildEnvironment.isContentInFocus
|
||||
}
|
||||
}
|
||||
if itemGroup.fillWithLoadingPlaceholders {
|
||||
let placeholderSizeFactor: CGFloat = 0.9
|
||||
let placeholderColor = keyboardChildEnvironment.theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.1)
|
||||
let fillPlaceholderImage: UIImage?
|
||||
let fillPlaceholderParams = FillPlaceholderParams(size: CGSize(width: floor(itemLayout.nativeItemSize * placeholderSizeFactor), height: floor(itemLayout.nativeItemSize * placeholderSizeFactor)))
|
||||
if let current = self.fillPlaceholder, current.params == fillPlaceholderParams {
|
||||
fillPlaceholderImage = current.image
|
||||
} else {
|
||||
switch component.itemLayoutType {
|
||||
case .compact:
|
||||
fillPlaceholderImage = generateFilledCircleImage(diameter: fillPlaceholderParams.size.width, color: .black)
|
||||
case .detailed:
|
||||
fillPlaceholderImage = generateFilledRoundedRectImage(size: fillPlaceholderParams.size, cornerRadius: floor(fillPlaceholderParams.size.width * 0.2), color: .black)
|
||||
}
|
||||
if let fillPlaceholderImage {
|
||||
self.fillPlaceholder = (fillPlaceholderParams, fillPlaceholderImage)
|
||||
}
|
||||
}
|
||||
let fillPlaceholderContent: ItemPlaceholderView.Content? = fillPlaceholderImage.flatMap(ItemPlaceholderView.Content.template)
|
||||
|
||||
var placeholderIndex = groupItems.groupItems?.lowerBound ?? 0
|
||||
while true {
|
||||
var itemFrame = itemLayout.frame(groupIndex: groupItems.groupIndex, itemIndex: placeholderIndex)
|
||||
if itemFrame.minY >= effectiveVisibleBounds.maxY {
|
||||
break
|
||||
}
|
||||
let visibleItemSize = CGSize(width: floor(itemFrame.width * placeholderSizeFactor), height: floor(itemFrame.height * placeholderSizeFactor))
|
||||
itemFrame = CGRect(origin: CGPoint(x: floor(itemFrame.midX - visibleItemSize.width * 0.5), y: floor(itemFrame.midY - visibleItemSize.height * 0.5)), size: visibleItemSize)
|
||||
|
||||
validFillPlaceholdersIndices.insert(placeholderIndex)
|
||||
|
||||
let placeholderView: ItemPlaceholderView
|
||||
if let current = self.visibleFillPlaceholdersViews[placeholderIndex] {
|
||||
placeholderView = current
|
||||
} else {
|
||||
placeholderView = ItemPlaceholderView(
|
||||
context: component.context,
|
||||
dimensions: nil,
|
||||
content: fillPlaceholderContent,
|
||||
shimmerView: self.shimmerHostView,
|
||||
color: placeholderColor,
|
||||
size: itemFrame.size
|
||||
)
|
||||
self.visibleFillPlaceholdersViews[placeholderIndex] = placeholderView
|
||||
self.placeholdersContainerView.addSubview(placeholderView)
|
||||
}
|
||||
|
||||
placeholderView.frame = itemFrame
|
||||
placeholderView.update(size: itemFrame.size)
|
||||
|
||||
placeholderIndex += 1
|
||||
}
|
||||
|
||||
self.updateShimmerIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
var removedPlaceholerViews = false
|
||||
@ -5869,6 +5962,26 @@ public final class EmojiPagerContentComponent: Component {
|
||||
self.visibleItemSelectionLayers.removeValue(forKey: id)
|
||||
}
|
||||
|
||||
var removedFillPlaceholderIndices: [Int] = []
|
||||
for (index, placeholderView) in self.visibleFillPlaceholdersViews {
|
||||
if !validFillPlaceholdersIndices.contains(index) {
|
||||
if !transition.animation.isImmediate {
|
||||
placeholderView.alpha = 0.0
|
||||
placeholderView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak placeholderView] _ in
|
||||
placeholderView?.removeFromSuperview()
|
||||
})
|
||||
} else {
|
||||
placeholderView.removeFromSuperview()
|
||||
}
|
||||
|
||||
removedFillPlaceholderIndices.append(index)
|
||||
removedPlaceholerViews = true
|
||||
}
|
||||
}
|
||||
for index in removedFillPlaceholderIndices {
|
||||
self.visibleFillPlaceholdersViews.removeValue(forKey: index)
|
||||
}
|
||||
|
||||
var removedGroupHeaderIds: [AnyHashable] = []
|
||||
for (id, groupHeaderLayer) in self.visibleGroupHeaders {
|
||||
if !validGroupHeaderIds.contains(id) {
|
||||
@ -6679,7 +6792,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
|
||||
var animateContentCrossfade = false
|
||||
if let previousComponent, previousComponent.itemContentUniqueId != component.itemContentUniqueId, itemTransition.animation.isImmediate {
|
||||
if previousComponent.itemContentUniqueId?.id != component.itemContentUniqueId?.id {
|
||||
if !(previousComponent.contentItemGroups.contains(where: { $0.fillWithLoadingPlaceholders }) && component.contentItemGroups.contains(where: { $0.fillWithLoadingPlaceholders })) && previousComponent.itemContentUniqueId?.id != component.itemContentUniqueId?.id {
|
||||
animateContentCrossfade = true
|
||||
}
|
||||
}
|
||||
@ -6705,6 +6818,15 @@ public final class EmojiPagerContentComponent: Component {
|
||||
snapshotLayer.animateScale(from: 1.0, to: crossfadeMinScale, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
for (_, placeholderView) in self.visibleFillPlaceholdersViews {
|
||||
if let snapshotLayer = placeholderView.layer.snapshotContentTree() {
|
||||
placeholderView.layer.superlayer?.insertSublayer(snapshotLayer, above: placeholderView.layer)
|
||||
snapshotLayer.animateAlpha(from: CGFloat(snapshotLayer.opacity), to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak snapshotLayer] _ in
|
||||
snapshotLayer?.removeFromSuperlayer()
|
||||
})
|
||||
snapshotLayer.animateScale(from: 1.0, to: crossfadeMinScale, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
for (_, selectionLayer) in self.visibleItemSelectionLayers {
|
||||
if let snapshotLayer = selectionLayer.snapshotContentTree() {
|
||||
selectionLayer.superlayer?.insertSublayer(snapshotLayer, above: selectionLayer)
|
||||
@ -6758,6 +6880,10 @@ public final class EmojiPagerContentComponent: Component {
|
||||
placeholderView.layer.animateAlpha(from: 0.0, to: CGFloat(placeholderView.layer.opacity), duration: 0.2)
|
||||
placeholderView.layer.animateScale(from: crossfadeMinScale, to: 1.0, duration: 0.2)
|
||||
}
|
||||
for (_, placeholderView) in self.visibleFillPlaceholdersViews {
|
||||
placeholderView.layer.animateAlpha(from: 0.0, to: CGFloat(placeholderView.layer.opacity), duration: 0.2)
|
||||
placeholderView.layer.animateScale(from: crossfadeMinScale, to: 1.0, duration: 0.2)
|
||||
}
|
||||
for (_, selectionLayer) in self.visibleItemSelectionLayers {
|
||||
selectionLayer.animateAlpha(from: 0.0, to: CGFloat(selectionLayer.opacity), duration: 0.2)
|
||||
}
|
||||
@ -7718,6 +7844,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
collapsedLineCount: group.collapsedLineCount,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: headerItem,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: group.items
|
||||
)
|
||||
}
|
||||
@ -8244,6 +8371,7 @@ public final class EmojiPagerContentComponent: Component {
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: group.displayPremiumBadges,
|
||||
headerItem: group.headerItem,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: group.items
|
||||
)
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
collapsedLineCount: 3,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: groupItems
|
||||
))
|
||||
}
|
||||
@ -286,6 +287,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)]
|
||||
}
|
||||
@ -339,6 +341,7 @@ public final class EmojiSearchContent: ASDisplayNode, EntitySearchContainerNode
|
||||
collapsedLineCount: nil,
|
||||
displayPremiumBadges: false,
|
||||
headerItem: nil,
|
||||
fillWithLoadingPlaceholders: false,
|
||||
items: items
|
||||
)], isFinalResult))
|
||||
}
|
||||
|
@ -215,10 +215,14 @@ final class EntityKeyboardAnimationTopPanelComponent: Component {
|
||||
private func updateDisplayPlaceholder(displayPlaceholder: Bool, duration: Double) {
|
||||
if displayPlaceholder {
|
||||
if self.placeholderView == nil, let component = self.component {
|
||||
var placeholderContent: EmojiPagerContentComponent.View.ItemPlaceholderView.Content?
|
||||
if let immediateThumbnailData = component.item.immediateThumbnailData {
|
||||
placeholderContent = .thumbnail(immediateThumbnailData)
|
||||
}
|
||||
let placeholderView = EmojiPagerContentComponent.View.ItemPlaceholderView(
|
||||
context: component.context,
|
||||
dimensions: component.item.dimensions,
|
||||
immediateThumbnailData: component.item.immediateThumbnailData,
|
||||
content: placeholderContent,
|
||||
shimmerView: nil,
|
||||
color: component.theme.chat.inputPanel.primaryTextColor.withMultipliedAlpha(0.08),
|
||||
size: CGSize(width: 28.0, height: 28.0)
|
||||
|
@ -913,9 +913,9 @@ final class DataUsageScreenComponent: Component {
|
||||
component: AnyComponent(SegmentControlComponent(
|
||||
theme: environment.theme,
|
||||
items: [
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.all), title: "All"),
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.mobile), title: "Mobile"),
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.wifi), title: "WiFi")
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.all), title: environment.strings.DataUsage_TopSectionAll),
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.mobile), title: environment.strings.DataUsage_TopSectionMobile),
|
||||
SegmentControlComponent.Item(id: AnyHashable(SelectedStats.wifi), title: environment.strings.DataUsage_TopSectionWifi)
|
||||
],
|
||||
selectedId: "total",
|
||||
action: { [weak self] id in
|
||||
|
@ -2479,8 +2479,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
textView.inputView = updatedInputView
|
||||
if textView.isFirstResponder {
|
||||
if self.chatPresentationInterfaceStateRequiresInputFocus(chatPresentationInterfaceState) {
|
||||
if let validLayout = self.validLayout, validLayout.0.inputHeight != nil {
|
||||
waitForKeyboardLayout = true
|
||||
}
|
||||
}
|
||||
textView.reloadInputViews()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user