mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-04-20 22:13:48 +00:00
- Implemented ChatScrollController to manage scroll behavior and visibility of jump-to-bottom button. - Added functionality to automatically scroll to the bottom when the keyboard opens. - Created JumpToBottomButton widget that appears when the user scrolls up, allowing quick navigation back to the bottom of the chat.
68 lines
1.8 KiB
Dart
68 lines
1.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
class ChatScrollController extends ScrollController {
|
|
final ValueNotifier<bool> showJumpToBottom = ValueNotifier(false);
|
|
VoidCallback? onScrollNearTop;
|
|
|
|
static const _bottomThreshold = 100.0;
|
|
static const _topThreshold = 50.0;
|
|
|
|
ChatScrollController() {
|
|
addListener(_handleScroll);
|
|
}
|
|
|
|
void _handleScroll() {
|
|
if (!hasClients) return;
|
|
final pos = position;
|
|
|
|
// With reverse: true, position 0 is bottom, maxScrollExtent is top
|
|
// Show jump button when scrolled away from bottom (position > threshold)
|
|
final isAtBottom = pos.pixels <= _bottomThreshold;
|
|
if (showJumpToBottom.value == isAtBottom) {
|
|
showJumpToBottom.value = !isAtBottom;
|
|
}
|
|
|
|
// Pagination trigger when scrolled near top (maxScrollExtent)
|
|
if (pos.pixels >= pos.maxScrollExtent - _topThreshold) {
|
|
onScrollNearTop?.call();
|
|
}
|
|
}
|
|
|
|
void jumpToBottom() {
|
|
if (hasClients && position.maxScrollExtent > 0) {
|
|
animateTo(
|
|
0, // With reverse: true, position 0 is bottom
|
|
duration: const Duration(milliseconds: 300),
|
|
curve: Curves.easeOut,
|
|
);
|
|
}
|
|
}
|
|
|
|
void handleKeyboardOpen() {
|
|
// Simple: just scroll to bottom when keyboard opens
|
|
if (hasClients) {
|
|
animateTo(
|
|
0, // With reverse: true, position 0 is bottom
|
|
duration: const Duration(milliseconds: 200),
|
|
curve: Curves.easeOut,
|
|
);
|
|
}
|
|
}
|
|
|
|
void scrollToBottomIfAtBottom() {
|
|
// Only scroll if jump button is NOT showing (i.e., already at bottom)
|
|
if (!showJumpToBottom.value && hasClients && position.maxScrollExtent > 0) {
|
|
animateTo(
|
|
0, // With reverse: true, position 0 is bottom
|
|
duration: const Duration(milliseconds: 200),
|
|
curve: Curves.easeOut,
|
|
);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
showJumpToBottom.dispose();
|
|
super.dispose();
|
|
}
|
|
}
|