Merge commit '7621e2f8dec938cf48181c8b10afc9b01f444e68' into beta

This commit is contained in:
Ilya Laktyushin
2025-12-06 02:17:48 +04:00
commit 8344b97e03
28070 changed files with 7995182 additions and 0 deletions
@@ -0,0 +1,28 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "CollectionTabItemComponent",
module_name = "CollectionTabItemComponent",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Display",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/AccountContext",
"//submodules/ComponentFlow",
"//submodules/TextFormat",
"//submodules/Components/MultilineTextComponent",
"//submodules/Components/BundleIconComponent",
"//submodules/TelegramUI/Components/TabSelectorComponent",
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
],
visibility = [
"//visibility:public",
],
)
@@ -0,0 +1,168 @@
import Foundation
import UIKit
import Display
import ComponentFlow
import TelegramCore
import TelegramPresentationData
import MultilineTextComponent
import BundleIconComponent
import TabSelectorComponent
import EmojiTextAttachmentView
import TextFormat
import AccountContext
public final class CollectionTabItemComponent: Component {
public typealias EnvironmentType = TabSelectorComponent.ItemEnvironment
public enum Icon: Equatable {
case collection(TelegramMediaFile)
case add
}
public let context: AccountContext
public let icon: Icon?
public let title: String
public let theme: PresentationTheme
public init(
context: AccountContext,
icon: Icon?,
title: String,
theme: PresentationTheme
) {
self.context = context
self.icon = icon
self.title = title
self.theme = theme
}
public static func ==(lhs: CollectionTabItemComponent, rhs: CollectionTabItemComponent) -> Bool {
if lhs.icon != rhs.icon {
return false
}
if lhs.title != rhs.title {
return false
}
if lhs.theme !== rhs.theme {
return false
}
return true
}
public final class View: UIView {
private let title = ComponentView<Empty>()
private let icon = ComponentView<Empty>()
private var iconLayer: InlineStickerItemLayer?
private var component: CollectionTabItemComponent?
func update(component: CollectionTabItemComponent, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
self.component = component
let environment = environment[EnvironmentType.self].value
let iconSpacing: CGFloat = 3.0
let normalColor = component.theme.list.itemSecondaryTextColor
let selectedColor = component.theme.list.freeTextColor
let effectiveColor = normalColor.mixedWith(selectedColor, alpha: environment.selectionFraction)
let titleSize = self.title.update(
transition: .immediate,
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: component.title, font: Font.medium(14.0), textColor: effectiveColor))
)),
environment: {},
containerSize: CGSize(width: availableSize.width, height: 100.0)
)
var iconOffset: CGFloat = 0.0
var iconSize = CGSize()
if let icon = component.icon {
switch icon {
case let .collection(file):
iconSize = CGSize(width: 16.0, height: 16.0)
let iconLayer: InlineStickerItemLayer
if let current = self.iconLayer {
iconLayer = current
} else {
iconLayer = InlineStickerItemLayer(
context: component.context,
userLocation: .other,
attemptSynchronousLoad: true,
emoji: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: file.fileId.id, file: file),
file: file,
cache: component.context.animationCache,
renderer: component.context.animationRenderer,
placeholderColor: component.theme.list.mediaPlaceholderColor,
pointSize: iconSize,
loopCount: 1
)
self.layer.addSublayer(iconLayer)
self.iconLayer = iconLayer
}
let iconFrame = CGRect(origin: CGPoint(x: iconOffset, y: floorToScreenPixels((titleSize.height - iconSize.height) * 0.5)), size: iconSize)
iconLayer.frame = iconFrame
case .add:
iconSize = self.icon.update(
transition: .immediate,
component: AnyComponent(BundleIconComponent(
name: "Chat/Input/Media/PanelBadgeAdd",
tintColor: component.theme.list.itemSecondaryTextColor
)),
environment: {},
containerSize: CGSize(width: 100.0, height: 100.0)
)
let iconFrame = CGRect(origin: CGPoint(x: iconOffset, y: floorToScreenPixels((titleSize.height - iconSize.height) * 0.5)), size: iconSize)
if let iconView = self.icon.view {
if iconView.superview == nil {
iconView.isUserInteractionEnabled = false
self.addSubview(iconView)
}
iconView.frame = iconFrame
}
}
iconOffset += iconSize.width + iconSpacing
} else {
if let iconLayer = self.iconLayer {
self.iconLayer = nil
iconLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { _ in
iconLayer.removeFromSuperlayer()
})
iconLayer.animateScale(from: 1.0, to: 0.01, duration: 0.2, removeOnCompletion: false)
}
if let iconView = self.icon.view {
iconView.removeFromSuperview()
}
}
let titleFrame = CGRect(origin: CGPoint(x: iconOffset, y: 0.0), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
titleView.frame = titleFrame
}
let size: CGSize
if let _ = component.icon {
size = CGSize(width: iconSize.width + iconSpacing + titleSize.width, height: titleSize.height)
} else {
size = titleSize
}
return size
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: State, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}