diff --git a/Rosetta/Features/Chats/ChatDetail/ListView/RosettaMessageListController.swift b/Rosetta/Features/Chats/ChatDetail/ListView/RosettaMessageListController.swift index 262a56c..7a7ae4f 100644 --- a/Rosetta/Features/Chats/ChatDetail/ListView/RosettaMessageListController.swift +++ b/Rosetta/Features/Chats/ChatDetail/ListView/RosettaMessageListController.swift @@ -26,6 +26,32 @@ final class RosettaMessageListController: UIViewController { private let config: Config + // MARK: - Callbacks (mirrors NativeMessageListController API) + + var onScrollToBottomVisibilityChange: ((Bool) -> Void)? + var onPaginationTrigger: (() -> Void)? + var onBottomPaginationTrigger: (() -> Void)? + var onJumpToBottom: (() -> Void)? + var onTapBackground: (() -> Void)? + var onComposerHeightChange: ((CGFloat) -> Void)? + var onKeyboardDidHide: (() -> Void)? + var onComposerSend: (() -> Void)? + var onComposerAttach: (() -> Void)? + var onComposerTextChange: ((String) -> Void)? + var onComposerFocusChange: ((Bool) -> Void)? + var onComposerReplyCancel: (() -> Void)? + var onComposerForwardCancel: (() -> Void)? + var onComposerTyping: (() -> Void)? + + // MARK: - Public State + + var hasMoreMessages: Bool = true + var hasNewerMessages: Bool = false + + // MARK: - Composer + + private(set) var composerView: ComposerView? + // MARK: - Views private let listView = RosettaListView(frame: .zero) @@ -56,6 +82,58 @@ final class RosettaMessageListController: UIViewController { listView.autoresizingMask = [.flexibleWidth, .flexibleHeight] listView.stackFromBottom = true view.addSubview(listView) + + // Wire listView callbacks + listView.onTapBackground = { [weak self] in + self?.onTapBackground?() + } + listView.displayedItemRangeChanged = { [weak self] range in + guard let self, let range else { return } + // Pagination: load more when near top + if range.lowerBound <= 5, self.hasMoreMessages { + self.onPaginationTrigger?() + } + // Reverse pagination: load newer when near bottom + if range.upperBound >= self.messages.count - 5, self.hasNewerMessages { + self.onBottomPaginationTrigger?() + } + } + listView.onScroll = { [weak self] _, _ in + // TODO: scroll-to-bottom button visibility + } + } + + /// Setup composer view (called externally after init). + /// TODO: Full composer integration — currently NativeMessageListController handles this. + func setupComposer() { + // Composer setup is complex (voice recording, attachments, reply bar, etc.) + // Will be ported from NativeMessageListController in a later phase. + } + + // MARK: - Selection Mode (stub) + + func setSelectionMode(_ enabled: Bool, animated: Bool) { + // TODO: implement selection mode + } + + func updateSelectedIds(_ ids: Set) { + // TODO: implement selection + } + + // MARK: - Highlight (stub) + + func scrollToMessage(id: String, animated: Bool) { + listView.scrollToItem(id: id, animated: animated) + } + + func animateHighlight(messageId: String?) { + // TODO: implement highlight + } + + // MARK: - Empty State (stub) + + func updateEmptyState(isEmpty: Bool, info: Any?) { + // TODO: implement empty state } // MARK: - Public API