feat: upgrade Riverpod 3, go_router 17, google_fonts 8, package_info_plus 9
Migrate StateNotifierProvider/StateNotifier → NotifierProvider/Notifier, StateProvider → NotifierProvider with simple notifier, FamilyAsyncNotifier removed in Riverpod 3 (replaced with constructor-arg pattern), and rename .valueOrNull → .value throughout all providers and screens. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -4,8 +4,19 @@ import '../data/models/conversation.dart';
|
||||
import '../data/models/message.dart';
|
||||
import 'api_client_provider.dart';
|
||||
|
||||
// Separate StateProvider so UI re-builds immediately when streaming starts/stops.
|
||||
final isStreamingProvider = StateProvider.family<bool, int>((ref, _) => false);
|
||||
// Separate NotifierProvider.family so UI re-builds immediately when streaming starts/stops.
|
||||
final isStreamingProvider =
|
||||
NotifierProvider.family<_IsStreamingNotifier, bool, int>(
|
||||
(convId) => _IsStreamingNotifier(convId),
|
||||
);
|
||||
|
||||
class _IsStreamingNotifier extends Notifier<bool> {
|
||||
// ignore: avoid_unused_constructor_parameters
|
||||
_IsStreamingNotifier(int convId);
|
||||
|
||||
@override
|
||||
bool build() => false;
|
||||
}
|
||||
|
||||
final conversationsProvider =
|
||||
AsyncNotifierProvider<ConversationsNotifier, List<Conversation>>(
|
||||
@@ -20,14 +31,14 @@ class ConversationsNotifier extends AsyncNotifier<List<Conversation>> {
|
||||
Future<Conversation> create(String title) async {
|
||||
final conv =
|
||||
await ref.read(chatRepositoryProvider).createConversation(title);
|
||||
state = AsyncData([conv, ...state.valueOrNull ?? []]);
|
||||
state = AsyncData([conv, ...state.value ?? []]);
|
||||
return conv;
|
||||
}
|
||||
|
||||
Future<void> delete(int id) async {
|
||||
await ref.read(chatRepositoryProvider).deleteConversation(id);
|
||||
state = AsyncData([
|
||||
for (final c in state.valueOrNull ?? [])
|
||||
for (final c in state.value ?? [])
|
||||
if (c.id != id) c,
|
||||
]);
|
||||
}
|
||||
@@ -35,7 +46,7 @@ class ConversationsNotifier extends AsyncNotifier<List<Conversation>> {
|
||||
// Called after a message is sent to patch the server-generated title
|
||||
// in-place without triggering a full reload or loading state.
|
||||
void patchConversation(Conversation updated) {
|
||||
final list = state.valueOrNull;
|
||||
final list = state.value;
|
||||
if (list == null) return;
|
||||
state = AsyncData([
|
||||
for (final c in list)
|
||||
@@ -44,21 +55,26 @@ class ConversationsNotifier extends AsyncNotifier<List<Conversation>> {
|
||||
}
|
||||
}
|
||||
|
||||
final messagesProvider = AsyncNotifierProvider.family<MessagesNotifier,
|
||||
List<Message>, int>(MessagesNotifier.new);
|
||||
final messagesProvider =
|
||||
AsyncNotifierProvider.family<MessagesNotifier, List<Message>, int>(
|
||||
(convId) => MessagesNotifier(convId),
|
||||
);
|
||||
|
||||
class MessagesNotifier extends AsyncNotifier<List<Message>> {
|
||||
final int _convId;
|
||||
MessagesNotifier(this._convId);
|
||||
|
||||
class MessagesNotifier extends FamilyAsyncNotifier<List<Message>, int> {
|
||||
@override
|
||||
Future<List<Message>> build(int arg) async {
|
||||
Future<List<Message>> build() async {
|
||||
final (_, messages) =
|
||||
await ref.watch(chatRepositoryProvider).getMessages(arg);
|
||||
await ref.watch(chatRepositoryProvider).getMessages(_convId);
|
||||
return messages;
|
||||
}
|
||||
|
||||
Future<void> sendMessage(String content) async {
|
||||
final convId = arg;
|
||||
final convId = _convId;
|
||||
final repo = ref.read(chatRepositoryProvider);
|
||||
final previousMessages = state.valueOrNull ?? [];
|
||||
final previousMessages = state.value ?? [];
|
||||
|
||||
// Optimistic UI: show the user message + assistant placeholder immediately.
|
||||
final userMsg = Message(
|
||||
@@ -132,7 +148,7 @@ class MessagesNotifier extends FamilyAsyncNotifier<List<Message>, int> {
|
||||
} catch (_) {
|
||||
// Polling failed entirely — clear the generating placeholder so the UI
|
||||
// doesn't spin forever.
|
||||
final msgs = state.valueOrNull;
|
||||
final msgs = state.value;
|
||||
if (msgs != null && msgs.isNotEmpty && msgs.last.status == 'generating') {
|
||||
state = AsyncData([
|
||||
...msgs.sublist(0, msgs.length - 1),
|
||||
|
||||
Reference in New Issue
Block a user