Files
mobile-ios/Rosetta/Features/Chats/ChatDetail/ListView/RosettaListItem.swift
senseiGai dedef48a55 WIP: каркас кастомного RosettaListView (Telegram-parity ListView)
- RosettaListView: core UIScrollView с ручным node management, visibility culling (500pt), CADisplayLink анимации
- RosettaListNode: базовый класс ячейки с animation state (height/alpha/spring)
- RosettaListItem: протокол с async layout closure (Telegram asyncLayout pattern)
- RosettaTransactionQueue: FIFO сериализатор обновлений
- ChatMessageListItem: bridge ChatMessage → RosettaListItem (WIP, не подключен)

Следующий шаг: NativeMessageCell → NativeMessageView (UIView) рефакторинг

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 11:57:12 +05:00

140 lines
3.9 KiB
Swift

import UIKit
// MARK: - Layout Params
/// Parameters for layout calculation (screen width, insets).
/// Telegram equivalent: `ListViewItemLayoutParams`.
struct RosettaListLayoutParams: Sendable {
let width: CGFloat
let leftInset: CGFloat
let rightInset: CGFloat
}
// MARK: - Node Layout
/// Calculated layout result content size + insets.
/// Telegram equivalent: `ListViewItemNodeLayout`.
struct RosettaListNodeLayout {
let contentSize: CGSize
let insets: UIEdgeInsets
var size: CGSize {
CGSize(
width: contentSize.width + insets.left + insets.right,
height: contentSize.height + insets.top + insets.bottom
)
}
}
// MARK: - Update Animation
/// Animation type for node updates.
/// Telegram equivalent: `ListViewItemUpdateAnimation`.
enum RosettaListUpdateAnimation {
case none
case system(duration: Double, transition: ControlledTransitionConfig)
}
struct ControlledTransitionConfig {
let duration: Double
let curve: AnimationCurve
enum AnimationCurve {
case spring(damping: CGFloat)
case easeInOut
}
static let `default` = ControlledTransitionConfig(
duration: 0.4,
curve: .spring(damping: 0.78)
)
}
// MARK: - Direction Hint
/// Hint for insertion/deletion animation direction.
/// Telegram equivalent: `ListViewItemOperationDirectionHint`.
enum RosettaListDirectionHint {
case up
case down
}
// MARK: - Scroll Position
/// Target scroll position for programmatic scrolling.
/// Telegram equivalent: `ListViewScrollPosition`.
enum RosettaListScrollPosition {
case top(CGFloat)
case center
case bottom(CGFloat)
case visible
}
// MARK: - List Item Protocol
/// Data model protocol for list items.
/// Telegram equivalent: `ListViewItem` (ListViewItem.swift:72-106).
///
/// Two-phase async layout pattern:
/// 1. `nodeConfiguredForParams` creates node + calculates layout on background
/// 2. Completion delivers ready-to-display node + layout to main thread
protocol RosettaListItem: AnyObject {
/// Unique identifier for diffing.
var id: String { get }
/// Estimated height before layout calculation. Used for scroll position
/// estimation when exact layout isn't ready yet.
/// Telegram: `approximateHeight` property.
var approximateHeight: CGFloat { get }
/// Reuse identifier for node pool recycling.
var reuseIdentifier: String { get }
/// Create a new node and calculate its layout.
/// `async` closure schedules work on background queue.
/// Telegram: `nodeConfiguredForParams` (ListViewItem.swift:72-75).
func nodeConfiguredForParams(
async: @escaping (@escaping () -> Void) -> Void,
params: RosettaListLayoutParams,
previousItem: RosettaListItem?,
nextItem: RosettaListItem?,
completion: @escaping (RosettaListNode, RosettaListNodeLayout) -> Void
)
/// Update an existing (recycled) node with new data.
/// Telegram: `updateNode` (ListViewItem.swift:78-88).
func updateNode(
async: @escaping (@escaping () -> Void) -> Void,
node: RosettaListNode,
params: RosettaListLayoutParams,
previousItem: RosettaListItem?,
nextItem: RosettaListItem?,
animation: RosettaListUpdateAnimation,
completion: @escaping (RosettaListNodeLayout) -> Void
)
}
// MARK: - Insert/Delete/Update Operations
/// Batch operations for list updates.
/// Telegram equivalent: `ListViewInsertItem`, `ListViewDeleteItem`, `ListViewUpdateItem`.
struct RosettaListInsertItem {
let index: Int
let previousIndex: Int?
let item: RosettaListItem
let directionHint: RosettaListDirectionHint?
}
struct RosettaListDeleteItem {
let index: Int
let directionHint: RosettaListDirectionHint?
}
struct RosettaListUpdateItem {
let index: Int
let previousIndex: Int
let item: RosettaListItem
let directionHint: RosettaListDirectionHint?
}