@@ -38,6 +38,41 @@ class _ChatRoomScreenState extends ConsumerState<ChatRoomScreen> {
3838 super .dispose ();
3939 }
4040
41+ @override
42+ void didChangeDependencies () {
43+ super .didChangeDependencies ();
44+ final isKeyboardVisible = MediaQuery .of (context).viewInsets.bottom > 0 ;
45+
46+ if (isKeyboardVisible && ! _wasKeyboardVisible) {
47+ Future .delayed (const Duration (milliseconds: 100 ), () {
48+ if (_scrollController.hasClients &&
49+ _scrollController.position.maxScrollExtent > 0 ) {
50+ try {
51+ _scrollController.animateTo (
52+ _scrollController.position.maxScrollExtent,
53+ duration: const Duration (milliseconds: 300 ),
54+ curve: Curves .easeOut,
55+ );
56+ } catch (e) {
57+ // Silently handle any scroll errors
58+ }
59+ }
60+ });
61+ }
62+
63+ _wasKeyboardVisible = isKeyboardVisible;
64+ }
65+
66+ /// Shared callback for dismissing keyboard and updating info type selection.
67+ void _handleInfoTypeChanged (String ? type) {
68+ if (type != null ) {
69+ FocusScope .of (context).unfocus ();
70+ }
71+ setState (() {
72+ _selectedInfoType = type;
73+ });
74+ }
75+
4176 @override
4277 Widget build (BuildContext context) {
4378 final chatDetailState = ref.watch (chatRoomsProvider (widget.orderId));
@@ -63,31 +98,6 @@ class _ChatRoomScreenState extends ConsumerState<ChatRoomScreen> {
6398 // Check if keyboard is visible
6499 final isKeyboardVisible = MediaQuery .of (context).viewInsets.bottom > 0 ;
65100
66- // If keyboard just became visible, scroll to bottom
67- if (isKeyboardVisible && ! _wasKeyboardVisible) {
68- // Use Future.delayed instead of microtask to ensure the list is built
69- Future .delayed (const Duration (milliseconds: 100 ), () {
70- // Verify controller is attached and list has content
71- if (_scrollController.hasClients &&
72- chatDetailState.messages.isNotEmpty &&
73- _scrollController.position.maxScrollExtent > 0 ) {
74- try {
75- _scrollController.animateTo (
76- _scrollController.position.maxScrollExtent,
77- duration: const Duration (milliseconds: 300 ),
78- curve: Curves .easeOut,
79- );
80- } catch (e) {
81- // Silently handle any scroll errors
82- // This prevents exceptions from breaking the UI
83- }
84- }
85- });
86- }
87-
88- // Update keyboard visibility tracking
89- _wasKeyboardVisible = isKeyboardVisible;
90-
91101 return Scaffold (
92102 backgroundColor: AppTheme .backgroundDark,
93103 appBar: AppBar (
@@ -118,15 +128,7 @@ class _ChatRoomScreenState extends ConsumerState<ChatRoomScreen> {
118128 // Info buttons
119129 InfoButtons (
120130 selectedInfoType: _selectedInfoType,
121- onInfoTypeChanged: (type) {
122- // Dismiss keyboard when selecting info tabs to prevent overlap
123- if (type != null ) {
124- FocusScope .of (context).unfocus ();
125- }
126- setState (() {
127- _selectedInfoType = type;
128- });
129- },
131+ onInfoTypeChanged: _handleInfoTypeChanged,
130132 ),
131133
132134 // Selected info content
@@ -156,23 +158,15 @@ class _ChatRoomScreenState extends ConsumerState<ChatRoomScreen> {
156158 color: AppTheme .backgroundDark,
157159 border: Border (
158160 top: BorderSide (
159- color: Colors .grey.withValues (alpha: 0.03 ),
160- width: 0.3 ,
161+ color: Colors .grey.withValues (alpha: 0.15 ),
162+ width: 0.5 ,
161163 ),
162164 ),
163165 ),
164166 child: MessageInput (
165167 orderId: widget.orderId,
166168 selectedInfoType: _selectedInfoType,
167- onInfoTypeChanged: (type) {
168- // Dismiss keyboard when selecting info tabs to prevent overlap
169- if (type != null ) {
170- FocusScope .of (context).unfocus ();
171- }
172- setState (() {
173- _selectedInfoType = type;
174- });
175- },
169+ onInfoTypeChanged: _handleInfoTypeChanged,
176170 ),
177171 ),
178172
0 commit comments