Phase 3.1 WIP: Riverpod migration (client_app Auth + ChatOpening)
- Add phase3.1 requirement and implementation plan docs - Add Riverpod dependencies to both client_app and mitra_app - Wrap both app roots with ProviderScope - Migrate client_app AuthBloc → AuthNotifier (@riverpod annotation) - Migrate client_app ChatOpeningBloc → chatPricingProvider (FutureProvider) - Update router to use Riverpod-based auth state for redirects - Update all auth screens (display name, register, OTP, force register) - Update home screen and pricing bottom sheet - Add android:usesCleartextTraffic for dev HTTP access on both apps - mitra_app prepared with ProviderScope + ApiClient provider (blocs next) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,19 +1,20 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../../core/auth/auth_bloc.dart';
|
||||
import '../../core/api/api_client.dart';
|
||||
import '../../core/auth/auth_notifier.dart';
|
||||
import '../../core/api/api_client_provider.dart';
|
||||
import '../../core/pairing/pairing_bloc.dart';
|
||||
import '../chat/widgets/pricing_bottom_sheet.dart';
|
||||
|
||||
class HomeScreen extends StatefulWidget {
|
||||
class HomeScreen extends ConsumerStatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
ConsumerState<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||
class _HomeScreenState extends ConsumerState<HomeScreen> with WidgetsBindingObserver {
|
||||
Map<String, dynamic>? _activeSession;
|
||||
bool _loadingSession = true;
|
||||
|
||||
@@ -40,13 +41,12 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
super.didChangeDependencies();
|
||||
// Re-check when navigating back to this screen
|
||||
_checkActiveSession();
|
||||
}
|
||||
|
||||
Future<void> _checkActiveSession() async {
|
||||
try {
|
||||
final apiClient = context.read<ApiClient>();
|
||||
final apiClient = ref.read(apiClientProvider);
|
||||
final response = await apiClient.get('/api/client/chat/session/active');
|
||||
final data = response['data'];
|
||||
if (mounted) {
|
||||
@@ -62,6 +62,15 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final authState = ref.watch(authProvider);
|
||||
final authData = authState.valueOrNull;
|
||||
|
||||
final displayName = switch (authData) {
|
||||
AuthAuthenticatedData d => d.profile['display_name'] as String? ?? '',
|
||||
AuthAnonymousData d => d.displayName,
|
||||
_ => '',
|
||||
};
|
||||
|
||||
return BlocListener<PairingBloc, PairingState>(
|
||||
listener: (context, state) {
|
||||
if (state is PairingSearching) {
|
||||
@@ -74,63 +83,53 @@ class _HomeScreenState extends State<HomeScreen> with WidgetsBindingObserver {
|
||||
);
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, state) {
|
||||
final displayName = state is AuthAuthenticated
|
||||
? state.profile['display_name'] as String
|
||||
: state is AuthAnonymous
|
||||
? state.displayName
|
||||
: '';
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Halo Bestie'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.history),
|
||||
onPressed: () => context.push('/chat/history'),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.logout),
|
||||
onPressed: () => context.read<AuthBloc>().add(LogoutRequested()),
|
||||
),
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Halo Bestie'),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.history),
|
||||
onPressed: () => context.push('/chat/history'),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.logout),
|
||||
onPressed: () => ref.read(authProvider.notifier).logout(),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Halo, $displayName!', style: const TextStyle(fontSize: 24)),
|
||||
const SizedBox(height: 32),
|
||||
if (_loadingSession)
|
||||
const CircularProgressIndicator()
|
||||
else if (_activeSession != null)
|
||||
_ActiveSessionCard(
|
||||
session: _activeSession!,
|
||||
onTap: () {
|
||||
final sessionId = _activeSession!['id'] as String;
|
||||
final mitraName = _activeSession!['mitra_display_name'] as String? ?? 'Bestie';
|
||||
context.push('/chat/session/$sessionId', extra: mitraName);
|
||||
},
|
||||
)
|
||||
else ...[
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 16),
|
||||
),
|
||||
onPressed: () => PricingBottomSheet.show(context),
|
||||
child: const Text('Mulai Curhat', style: TextStyle(fontSize: 18)),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
body: Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text('Halo, $displayName!', style: const TextStyle(fontSize: 24)),
|
||||
const SizedBox(height: 32),
|
||||
if (_loadingSession)
|
||||
const CircularProgressIndicator()
|
||||
else if (_activeSession != null)
|
||||
_ActiveSessionCard(
|
||||
session: _activeSession!,
|
||||
onTap: () {
|
||||
final sessionId = _activeSession!['id'] as String;
|
||||
final mitraName = _activeSession!['mitra_display_name'] as String? ?? 'Bestie';
|
||||
context.push('/chat/session/$sessionId', extra: mitraName);
|
||||
},
|
||||
)
|
||||
else ...[
|
||||
const SizedBox(height: 16),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 48, vertical: 16),
|
||||
),
|
||||
onPressed: () => PricingBottomSheet.show(context),
|
||||
child: const Text('Mulai Curhat', style: TextStyle(fontSize: 18)),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user