Phase 3.1: Complete mitra_app Riverpod migration (all blocs, fix auth bug)
- Migrate AuthBloc → MitraAuthNotifier (fixes stuck-loading bug: now returns MitraAuthInitialData when currentUser is null) - Migrate StatusBloc → OnlineStatusNotifier (heartbeat timer + lifecycle) - Migrate ExtensionBloc → MitraExtensionNotifier (accept/reject + goodbye) - Migrate ChatRequestBloc → ChatRequestNotifier (WebSocket incoming requests) - Migrate MitraChatBloc → MitraChatNotifier (WebSocket chat + messages) - Update router to use Riverpod auth state for redirects - Remove all flutter_bloc usage from mitra_app screens and main.dart - MultiBlocProvider fully removed from mitra_app Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
97
mitra_app/lib/core/status/status_notifier.dart
Normal file
97
mitra_app/lib/core/status/status_notifier.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'dart:async';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import '../api/api_client_provider.dart';
|
||||
|
||||
part 'status_notifier.g.dart';
|
||||
|
||||
// States
|
||||
sealed class OnlineStatusData {
|
||||
const OnlineStatusData();
|
||||
}
|
||||
|
||||
class StatusInitialData extends OnlineStatusData {
|
||||
const StatusInitialData();
|
||||
}
|
||||
|
||||
class StatusLoadedData extends OnlineStatusData {
|
||||
final bool isOnline;
|
||||
const StatusLoadedData({required this.isOnline});
|
||||
}
|
||||
|
||||
class StatusLoadingData extends OnlineStatusData {
|
||||
const StatusLoadingData();
|
||||
}
|
||||
|
||||
class StatusErrorData extends OnlineStatusData {
|
||||
final String message;
|
||||
const StatusErrorData(this.message);
|
||||
}
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class OnlineStatus extends _$OnlineStatus {
|
||||
Timer? _heartbeatTimer;
|
||||
|
||||
@override
|
||||
OnlineStatusData build() => const StatusInitialData();
|
||||
|
||||
Future<void> load() async {
|
||||
try {
|
||||
final response = await ref.read(apiClientProvider).get('/api/mitra/status');
|
||||
final data = response['data'] as Map<String, dynamic>;
|
||||
state = StatusLoadedData(isOnline: data['is_online'] as bool);
|
||||
} catch (e) {
|
||||
state = const StatusLoadedData(isOnline: false);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleOnline() async {
|
||||
state = const StatusLoadingData();
|
||||
try {
|
||||
await ref.read(apiClientProvider).post('/api/mitra/status/online');
|
||||
_startHeartbeat();
|
||||
state = const StatusLoadedData(isOnline: true);
|
||||
} catch (e) {
|
||||
state = const StatusErrorData('Gagal mengubah status. Coba lagi.');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> toggleOffline() async {
|
||||
state = const StatusLoadingData();
|
||||
try {
|
||||
await ref.read(apiClientProvider).post('/api/mitra/status/offline');
|
||||
_stopHeartbeat();
|
||||
state = const StatusLoadedData(isOnline: false);
|
||||
} catch (e) {
|
||||
state = const StatusErrorData('Gagal mengubah status. Coba lagi.');
|
||||
}
|
||||
}
|
||||
|
||||
void onAppPaused() {
|
||||
_stopHeartbeat();
|
||||
}
|
||||
|
||||
void onAppResumed() {
|
||||
if (state is StatusLoadedData && (state as StatusLoadedData).isOnline) {
|
||||
_startHeartbeat();
|
||||
}
|
||||
load();
|
||||
}
|
||||
|
||||
void _startHeartbeat() {
|
||||
_stopHeartbeat();
|
||||
_heartbeatTimer = Timer.periodic(const Duration(seconds: 15), (_) {
|
||||
_heartbeatTick();
|
||||
});
|
||||
}
|
||||
|
||||
void _stopHeartbeat() {
|
||||
_heartbeatTimer?.cancel();
|
||||
_heartbeatTimer = null;
|
||||
}
|
||||
|
||||
Future<void> _heartbeatTick() async {
|
||||
try {
|
||||
await ref.read(apiClientProvider).post('/api/mitra/status/heartbeat');
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
||||
25
mitra_app/lib/core/status/status_notifier.g.dart
Normal file
25
mitra_app/lib/core/status/status_notifier.g.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'status_notifier.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$onlineStatusHash() => r'6b42328eaba0f7934b0e3eaa54eb6b764f1c4e53';
|
||||
|
||||
/// See also [OnlineStatus].
|
||||
@ProviderFor(OnlineStatus)
|
||||
final onlineStatusProvider =
|
||||
NotifierProvider<OnlineStatus, OnlineStatusData>.internal(
|
||||
OnlineStatus.new,
|
||||
name: r'onlineStatusProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$onlineStatusHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$OnlineStatus = Notifier<OnlineStatusData>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
Reference in New Issue
Block a user