refactor: conditionalize profile fields, update chat navigation transitions, and fix provider state management during widget lifecycle
This commit is contained in:
@@ -75,7 +75,8 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
MessagingNotifier(this._repository, this._ref)
|
MessagingNotifier(this._repository, this._ref)
|
||||||
: super(const MessagingState()) {
|
: super(const MessagingState()) {
|
||||||
_initSocketListeners();
|
_initSocketListeners();
|
||||||
loadUnreadCount();
|
// Defer to avoid modifying provider during widget tree build
|
||||||
|
Future.microtask(() => loadUnreadCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
String? get _currentUserId => _ref.read(authProvider).user?.id;
|
String? get _currentUserId => _ref.read(authProvider).user?.id;
|
||||||
@@ -529,6 +530,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
Future<void> markAsRead(String conversationId) async {
|
Future<void> markAsRead(String conversationId) async {
|
||||||
try {
|
try {
|
||||||
await _repository.markAsRead(conversationId);
|
await _repository.markAsRead(conversationId);
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
final updatedConversations = state.conversations.map((c) {
|
final updatedConversations = state.conversations.map((c) {
|
||||||
if (c.id == conversationId) {
|
if (c.id == conversationId) {
|
||||||
@@ -550,6 +552,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setActiveConversation(String? conversationId) {
|
void setActiveConversation(String? conversationId) {
|
||||||
|
if (!mounted) return;
|
||||||
if (conversationId == null) {
|
if (conversationId == null) {
|
||||||
state = state.copyWith(clearActiveConversation: true);
|
state = state.copyWith(clearActiveConversation: true);
|
||||||
} else {
|
} else {
|
||||||
@@ -560,7 +563,7 @@ class MessagingNotifier extends StateNotifier<MessagingState> {
|
|||||||
Future<void> loadUnreadCount() async {
|
Future<void> loadUnreadCount() async {
|
||||||
try {
|
try {
|
||||||
final count = await _repository.getUnreadCount();
|
final count = await _repository.getUnreadCount();
|
||||||
state = state.copyWith(unreadCount: count);
|
if (mounted) state = state.copyWith(unreadCount: count);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,16 +90,12 @@ class _ChatScreenState extends ConsumerState<ChatScreen>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
@override
|
|
||||||
void deactivate() {
|
|
||||||
// Clear active conversation while ref is still valid (before dispose)
|
|
||||||
ref.read(messagingProvider.notifier).setActiveConversation(null);
|
|
||||||
super.deactivate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
// Defer provider modification to avoid "modify during build" error
|
||||||
|
final notifier = ref.read(messagingProvider.notifier);
|
||||||
|
Future.microtask(() => notifier.setActiveConversation(null));
|
||||||
|
|
||||||
WidgetsBinding.instance.removeObserver(this);
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
_connectionSub?.cancel();
|
_connectionSub?.cancel();
|
||||||
// Stop typing and leave room before disposing
|
// Stop typing and leave room before disposing
|
||||||
|
|||||||
@@ -262,12 +262,14 @@ class _ProfileSettingsTabState extends ConsumerState<ProfileSettingsTab> {
|
|||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
|
||||||
ProfileFormField(label: 'Full Name', controller: _fullNameController),
|
ProfileFormField(label: 'Full Name', controller: _fullNameController),
|
||||||
|
if (isAgent) ...[
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
ProfileFormField(
|
ProfileFormField(
|
||||||
label: isAgent ? 'Career / Agent Type' : 'Professional Title',
|
label: 'Career / Agent Type',
|
||||||
controller: _titleController,
|
controller: _titleController,
|
||||||
enabled: false,
|
enabled: false,
|
||||||
),
|
),
|
||||||
|
],
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
ProfileFormField(
|
ProfileFormField(
|
||||||
label: 'Email Address',
|
label: 'Email Address',
|
||||||
|
|||||||
@@ -160,7 +160,9 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
return CustomTransitionPage(
|
return CustomTransitionPage(
|
||||||
key: state.pageKey,
|
key: state.pageKey,
|
||||||
child: ChatScreen(conversationId: id),
|
child: ChatScreen(conversationId: id),
|
||||||
transitionsBuilder: _fadeTransition,
|
transitionDuration: const Duration(milliseconds: 250),
|
||||||
|
reverseTransitionDuration: const Duration(milliseconds: 200),
|
||||||
|
transitionsBuilder: _slideTransition,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -272,6 +274,22 @@ class _HomeRouteWrapper extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Slide from right transition for push-style navigation.
|
||||||
|
Widget _slideTransition(
|
||||||
|
BuildContext context,
|
||||||
|
Animation<double> animation,
|
||||||
|
Animation<double> secondaryAnimation,
|
||||||
|
Widget child,
|
||||||
|
) {
|
||||||
|
return SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(1, 0),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(CurvedAnimation(parent: animation, curve: Curves.easeOut)),
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// Smooth fade transition for tab-to-tab navigation.
|
/// Smooth fade transition for tab-to-tab navigation.
|
||||||
Widget _fadeTransition(
|
Widget _fadeTransition(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
|||||||
Reference in New Issue
Block a user