Restructuration majeure du projet: migration de flutt vers app, ajout de l'API et mise à jour du site web

This commit is contained in:
d6soft
2025-05-16 09:19:03 +02:00
parent b5aafc424b
commit 5c2620de30
391 changed files with 19780 additions and 7233 deletions

View File

@@ -0,0 +1,262 @@
import 'package:flutter/material.dart';
import 'package:geosector_app/core/theme/app_theme.dart';
import 'package:geosector_app/chat/widgets/conversations_list.dart';
import 'package:geosector_app/chat/widgets/chat_screen.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/chat/models/conversation_model.dart';
class UserCommunicationPage extends StatefulWidget {
const UserCommunicationPage({super.key});
@override
State<UserCommunicationPage> createState() => _UserCommunicationPageState();
}
class _UserCommunicationPageState extends State<UserCommunicationPage> {
String? _selectedConversationId;
late Box<ConversationModel> _conversationsBox;
bool _hasConversations = false;
@override
void initState() {
super.initState();
_checkConversations();
}
Future<void> _checkConversations() async {
try {
_conversationsBox = Hive.box<ConversationModel>(AppKeys.chatConversationsBoxName);
setState(() {
_hasConversations = _conversationsBox.values.isNotEmpty;
});
} catch (e) {
debugPrint('Erreur lors de la vérification des conversations: $e');
}
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Scaffold(
backgroundColor: Colors.transparent,
body: Container(
margin: const EdgeInsets.all(16.0),
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: BorderRadius.circular(24),
boxShadow: [
BoxShadow(
color: theme.shadowColor.withOpacity(0.1),
blurRadius: 20,
spreadRadius: 1,
offset: const Offset(0, 4),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: Column(
children: [
// En-tête du chat
Container(
height: 70,
padding: const EdgeInsets.symmetric(horizontal: 20),
decoration: BoxDecoration(
color: theme.colorScheme.primary.withOpacity(0.05),
border: Border(
bottom: BorderSide(
color: theme.dividerColor.withOpacity(0.1),
width: 1,
),
),
),
child: Row(
children: [
Icon(
Icons.chat_bubble_outline,
color: theme.colorScheme.primary,
size: 26,
),
const SizedBox(width: 12),
Text(
'Messages d\'équipe',
style: theme.textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.w600,
color: theme.colorScheme.primary,
),
),
const Spacer(),
if (_hasConversations) ...[
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
decoration: BoxDecoration(
color: AppTheme.secondaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(20),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 8,
height: 8,
decoration: const BoxDecoration(
color: Colors.green,
shape: BoxShape.circle,
),
),
const SizedBox(width: 8),
Text(
'5 en ligne',
style: theme.textTheme.bodySmall?.copyWith(
color: AppTheme.secondaryColor,
fontWeight: FontWeight.w500,
),
),
],
),
),
const SizedBox(width: 16),
IconButton(
icon: const Icon(Icons.add_circle_outline),
iconSize: 28,
color: theme.colorScheme.primary,
onPressed: () {
// TODO: Créer une nouvelle conversation
},
),
],
],
),
),
// Contenu principal
Expanded(
child: _hasConversations
? Row(
children: [
// Liste des conversations (gauche)
Container(
width: 320,
decoration: BoxDecoration(
color: theme.colorScheme.surface,
border: Border(
right: BorderSide(
color: theme.dividerColor.withOpacity(0.1),
width: 1,
),
),
),
child: ConversationsList(
onConversationSelected: (conversation) {
setState(() {
// TODO: obtenir l'ID de la conversation à partir de l'objet conversation
_selectedConversationId = 'test-conversation-id';
});
},
),
),
// Zone de conversation (droite)
Expanded(
child: Container(
color: theme.colorScheme.surface,
child: _selectedConversationId != null
? ChatScreen(conversationId: _selectedConversationId!)
: _buildEmptyState(theme),
),
),
],
)
: _buildNoConversationsMessage(theme),
),
],
),
),
),
);
}
Widget _buildEmptyState(ThemeData theme) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.chat_bubble_outline,
size: 80,
color: theme.colorScheme.primary.withOpacity(0.3),
),
const SizedBox(height: 24),
Text(
'Sélectionnez une conversation',
style: theme.textTheme.titleLarge?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.5),
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 8),
Text(
'Choisissez une conversation dans la liste\npour commencer à discuter',
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.3),
),
),
],
),
);
}
Widget _buildNoConversationsMessage(ThemeData theme) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.forum_outlined,
size: 100,
color: theme.colorScheme.primary.withOpacity(0.3),
),
const SizedBox(height: 24),
Text(
'Aucune conversation',
style: theme.textTheme.headlineSmall?.copyWith(
color: theme.colorScheme.primary,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
Text(
'Vous n\'avez pas encore de conversations.\nCommencez une discussion avec votre équipe !',
textAlign: TextAlign.center,
style: theme.textTheme.bodyLarge?.copyWith(
color: theme.colorScheme.onSurface.withOpacity(0.6),
),
),
const SizedBox(height: 32),
ElevatedButton.icon(
onPressed: () {
// TODO: Créer une nouvelle conversation
},
icon: const Icon(Icons.add),
label: const Text('Démarrer une conversation'),
style: ElevatedButton.styleFrom(
backgroundColor: theme.colorScheme.primary,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 16,
),
textStyle: const TextStyle(fontSize: 16),
),
),
],
),
);
}
}