update
@@ -1,4 +1,5 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
android:label="nexuschat"
|
android:label="nexuschat"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 544 B After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 442 B After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 721 B After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 24 KiB |
@@ -428,7 +428,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
@@ -485,7 +485,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||||
CLANG_ANALYZER_NONNULL = YES;
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
CLANG_CXX_LIBRARY = "libc++";
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 641 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 20 KiB |
@@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_giphy_picker/giphy_ui.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
@@ -19,7 +20,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
final FocusNode _focusNode = FocusNode();
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
|
||||||
List<Map<String, String>> messages = [];
|
List<Map<String, dynamic>> messages = [];
|
||||||
String? expediteur;
|
String? expediteur;
|
||||||
late String destinataire;
|
late String destinataire;
|
||||||
int idConversation = 0;
|
int idConversation = 0;
|
||||||
@@ -133,6 +134,45 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> _chiffrerMessage(String message) async {
|
||||||
|
final uri =
|
||||||
|
Uri.parse('https://nexuschat.derickexm.be/messages/crypt_message/')
|
||||||
|
.replace(queryParameters: {'message': message});
|
||||||
|
final response = await http.post(uri);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
print("Chiffrement → encrypted_message: ${data['encrypted_message']}");
|
||||||
|
print("Chiffrement → key: ${data['key']}");
|
||||||
|
return {
|
||||||
|
'encrypted_message': data['encrypted_message'] ?? message,
|
||||||
|
'key': data['key'] ?? ''
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
print("Erreur chiffrement: ${response.body}");
|
||||||
|
return {'encrypted_message': message, 'key': ''};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _dechiffrerMessage(String encryptedMessage, String key) async {
|
||||||
|
final uri =
|
||||||
|
Uri.parse('https://nexuschat.derickexm.be/messages/uncrypt_message/');
|
||||||
|
final response = await http.post(
|
||||||
|
uri,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: jsonEncode({
|
||||||
|
'encrypted_message': encryptedMessage,
|
||||||
|
'key': key,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
return data['decrypted_message'] ?? encryptedMessage;
|
||||||
|
} else {
|
||||||
|
print("Erreur déchiffrement: ${response.body}");
|
||||||
|
return encryptedMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _fetchMessages() async {
|
Future<void> _fetchMessages() async {
|
||||||
if (idConversation <= 0) return;
|
if (idConversation <= 0) return;
|
||||||
try {
|
try {
|
||||||
@@ -144,15 +184,24 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
final jsonResponse = jsonDecode(response.body);
|
final jsonResponse = jsonDecode(response.body);
|
||||||
if (jsonResponse.containsKey('messages')) {
|
if (jsonResponse.containsKey('messages')) {
|
||||||
final List<dynamic> messagesList = jsonResponse['messages'];
|
final List<dynamic> messagesList = jsonResponse['messages'];
|
||||||
setState(() {
|
final decryptedMessages =
|
||||||
messages = messagesList.map((msg) {
|
await Future.wait(messagesList.map((msg) async {
|
||||||
bool isMe = msg['expediteur'].toString() == expediteur;
|
final isMe = msg['expediteur'].toString() == expediteur;
|
||||||
|
|
||||||
|
final encrypted = msg['messages'].toString();
|
||||||
|
final cle = msg['key']?.toString() ?? '';
|
||||||
|
final texte = await _dechiffrerMessage(encrypted, cle);
|
||||||
return {
|
return {
|
||||||
'sender': msg['expediteur'].toString(),
|
'sender': msg['expediteur'].toString(),
|
||||||
'text': msg['messages'].toString(),
|
'text': texte,
|
||||||
|
'encrypted': msg['messages'].toString(),
|
||||||
'timestamp': msg['sent_at'].toString(),
|
'timestamp': msg['sent_at'].toString(),
|
||||||
|
'key': msg['key']?.toString() ?? '',
|
||||||
|
'type': msg['type'] ?? 'text'
|
||||||
};
|
};
|
||||||
}).toList();
|
}));
|
||||||
|
setState(() {
|
||||||
|
messages = decryptedMessages;
|
||||||
_isInitialLoading = false;
|
_isInitialLoading = false;
|
||||||
});
|
});
|
||||||
_scrollToBottom();
|
_scrollToBottom();
|
||||||
@@ -163,6 +212,31 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _supprimerMessage(Map<String, dynamic> message) async {
|
||||||
|
try {
|
||||||
|
final uri = Uri.parse(
|
||||||
|
'https://nexuschat.derickexm.be/messages/messages/delete_message/');
|
||||||
|
final response = await http.post(
|
||||||
|
uri,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: jsonEncode({
|
||||||
|
'expediteur': expediteur,
|
||||||
|
'id_conversation': idConversation,
|
||||||
|
'message': message['encrypted'],
|
||||||
|
'key': message['key'],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print("✅ Message supprimé");
|
||||||
|
_fetchMessages(); // refresh
|
||||||
|
} else {
|
||||||
|
print("❌ Erreur suppression: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("❌ Erreur _supprimerMessage: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _loadExpediteur() async {
|
Future<void> _loadExpediteur() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
String? expediteurEmail =
|
String? expediteurEmail =
|
||||||
@@ -178,6 +252,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
expediteur = jsonResponse['username'];
|
expediteur = jsonResponse['username'];
|
||||||
});
|
});
|
||||||
|
print("📦 Chargement expediteur : $expediteur");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -194,21 +269,41 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendMessage(String message) async {
|
Future<void> sendMessage(String message) async {
|
||||||
|
print("🧪 Appel à sendMessage()...");
|
||||||
|
print("🔍 expediteur: $expediteur");
|
||||||
if (expediteur == null || message.trim().isEmpty) return;
|
if (expediteur == null || message.trim().isEmpty) return;
|
||||||
|
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
|
|
||||||
|
final cryptoData = await _chiffrerMessage(message.trim());
|
||||||
|
print("Résultat chiffrement : $cryptoData");
|
||||||
|
final encryptedMessage = cryptoData['encrypted_message'] ?? '';
|
||||||
|
final key = cryptoData['key'] ?? '';
|
||||||
|
// Ajout du texte en clair
|
||||||
|
final plainText = _controller.text.trim();
|
||||||
|
if (key == null || key.isEmpty) {
|
||||||
|
print('❌ Clé de chiffrement manquante. Message non envoyé.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
messages.add({
|
messages = List<Map<String, dynamic>>.from(messages)
|
||||||
'sender': expediteur!,
|
..add({
|
||||||
'text': message.trim(),
|
'sender': expediteur ?? '',
|
||||||
|
'text': plainText,
|
||||||
|
'encrypted': encryptedMessage,
|
||||||
'timestamp': now.toIso8601String(),
|
'timestamp': now.toIso8601String(),
|
||||||
|
'key': key,
|
||||||
|
'type': 'text'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
_controller.clear();
|
_controller.clear();
|
||||||
_updateButtonState();
|
_updateButtonState();
|
||||||
_scrollToBottom();
|
_scrollToBottom();
|
||||||
|
|
||||||
|
print("✉️ Envoi du message chiffré : $encryptedMessage");
|
||||||
|
print("🔑 Clé : $key");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('https://nexuschat.derickexm.be/messages/send_message/'),
|
Uri.parse('https://nexuschat.derickexm.be/messages/send_message/'),
|
||||||
@@ -216,9 +311,12 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
'expediteur': expediteur,
|
'expediteur': expediteur,
|
||||||
'destinataire': destinataire,
|
'destinataire': destinataire,
|
||||||
'message': message.trim(),
|
'message': encryptedMessage,
|
||||||
'sent_at': now.toIso8601String(),
|
// Correction : horodatage en heure locale (Belgique)
|
||||||
|
'timestamp': DateTime.now().toIso8601String(),
|
||||||
'id_conversation': idConversation,
|
'id_conversation': idConversation,
|
||||||
|
// Correction : forcer 'key' non vide
|
||||||
|
'key': key.isNotEmpty ? key : 'test'
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
@@ -239,6 +337,66 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _sendGif(String gifUrl) async {
|
||||||
|
if (expediteur == null || gifUrl.isEmpty) return;
|
||||||
|
print('📤 Préparation à l’envoi du GIF :');
|
||||||
|
print(' ↪️ URL : $gifUrl');
|
||||||
|
|
||||||
|
final nowUtcIso = DateTime.now().toIso8601String();
|
||||||
|
// Désactivation du chiffrement pour les GIFs
|
||||||
|
final encryptedMessage = gifUrl;
|
||||||
|
final key = 'test';
|
||||||
|
print(' 🔐 Encrypted : $encryptedMessage');
|
||||||
|
print(' 🔑 Key : $key');
|
||||||
|
print(' 💬 ID conversation : $idConversation');
|
||||||
|
setState(() {
|
||||||
|
messages = List<Map<String, dynamic>>.from(messages)
|
||||||
|
..add({
|
||||||
|
'sender': expediteur ?? '',
|
||||||
|
'text': gifUrl,
|
||||||
|
'encrypted': encryptedMessage,
|
||||||
|
'timestamp': nowUtcIso,
|
||||||
|
'key': key,
|
||||||
|
'type': 'gif'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
_scrollToBottom();
|
||||||
|
|
||||||
|
final body = jsonEncode({
|
||||||
|
'expediteur': expediteur,
|
||||||
|
'destinataire': destinataire,
|
||||||
|
'message': encryptedMessage,
|
||||||
|
'timestamp': nowUtcIso,
|
||||||
|
'id_conversation': idConversation,
|
||||||
|
'key': key,
|
||||||
|
'type': 'gif'
|
||||||
|
});
|
||||||
|
print("📦 Corps envoyé à l’API :");
|
||||||
|
print(" expediteur : ${expediteur}");
|
||||||
|
print(" destinataire : ${destinataire}");
|
||||||
|
print(" message : $encryptedMessage");
|
||||||
|
print(" key : $key");
|
||||||
|
print(" timestamp : $nowUtcIso");
|
||||||
|
print(" id_conversation: $idConversation");
|
||||||
|
print(" type : gif");
|
||||||
|
print("🔒 Longueur message : ${encryptedMessage.length}");
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('https://nexuschat.derickexm.be/messages/send_message/'),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: body,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
print('Erreur envoi GIF : ${response.body}');
|
||||||
|
} else {
|
||||||
|
print('✅ GIF envoyé avec succès.');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('Erreur réseau envoi GIF : $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _scrollToBottom() {
|
void _scrollToBottom() {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (_scrollController.hasClients) {
|
if (_scrollController.hasClients) {
|
||||||
@@ -255,8 +413,20 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
print('Sélectionner une photo');
|
print('Sélectionner une photo');
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectGif() {
|
Future<void> _selectGif() async {
|
||||||
print('Sélectionner un GIF');
|
GiphyLocale? fr;
|
||||||
|
fr ??= GiphyLocale.fromContext(context);
|
||||||
|
|
||||||
|
final config = GiphyUIConfig(
|
||||||
|
apiKey: 'qG62ngUKbr66l2jVPcDGulJW1RbZy5xI',
|
||||||
|
);
|
||||||
|
final result =
|
||||||
|
await showGiphyPicker(context, config, locale: GiphyLocale.fr);
|
||||||
|
|
||||||
|
if (result != null) {
|
||||||
|
print("GIF sélectionné : ${result.url}");
|
||||||
|
_sendGif(result.url);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -308,20 +478,65 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
color: Colors.grey[700],
|
color: Colors.grey[700],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Flexible(
|
||||||
|
child: GestureDetector(
|
||||||
|
onLongPress: isMe
|
||||||
|
? () {
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(
|
||||||
|
"Supprimer le message ?"),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
child: Text("Annuler"),
|
||||||
|
onPressed: () =>
|
||||||
|
Navigator.of(context)
|
||||||
|
.pop(),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
child: Text("Supprimer"),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context)
|
||||||
|
.pop();
|
||||||
|
_supprimerMessage(
|
||||||
|
message);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
child: Container(
|
||||||
margin: const EdgeInsets.only(top: 2),
|
margin: const EdgeInsets.only(top: 2),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isMe ? Colors.orange : Colors.grey[300],
|
color: isMe
|
||||||
|
? Colors.orange
|
||||||
|
: Colors.grey[300],
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: message['type'] == 'gif'
|
||||||
|
? Image.network(message['text'] ?? '')
|
||||||
|
: Text(
|
||||||
message['text'] ?? '',
|
message['text'] ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isMe ? Colors.white : Colors.black,
|
color: isMe
|
||||||
|
? Colors.white
|
||||||
|
: Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
if (formattedTime.isNotEmpty)
|
if (formattedTime.isNotEmpty)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 2),
|
padding: const EdgeInsets.only(top: 2),
|
||||||
@@ -339,7 +554,10 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Row(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -371,6 +589,19 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange.shade100, // plus doux
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(Icons.gif_box,
|
||||||
|
color: Colors.deepOrange, size: 28),
|
||||||
|
onPressed: _selectGif,
|
||||||
|
tooltip: 'GIF',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 5),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange,
|
color: Colors.orange,
|
||||||
@@ -379,13 +610,26 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: Icon(Icons.send, color: Colors.black),
|
icon: Icon(Icons.send, color: Colors.black),
|
||||||
onPressed: _isButtonEnabled
|
onPressed: _isButtonEnabled
|
||||||
? () => sendMessage(_controller.text)
|
? () {
|
||||||
|
sendMessage(_controller.text);
|
||||||
|
_controller.clear();
|
||||||
|
_updateButtonState();
|
||||||
|
}
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 4, top: 2),
|
||||||
|
child: Text(
|
||||||
|
"🔒 Messages chiffrés de bout en bout",
|
||||||
|
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ class Contacts extends StatefulWidget {
|
|||||||
class _ContactsState extends State<Contacts>
|
class _ContactsState extends State<Contacts>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
List<dynamic> _contacts = [];
|
List<dynamic> _contacts = [];
|
||||||
|
List<dynamic> _filteredContacts = [];
|
||||||
List<dynamic> _demandes = [];
|
List<dynamic> _demandes = [];
|
||||||
List<dynamic> _users = [];
|
List<dynamic> _users = [];
|
||||||
List<dynamic> _filteredUsers = [];
|
List<dynamic> _filteredUsers = [];
|
||||||
TextEditingController _searchController = TextEditingController();
|
TextEditingController _searchController = TextEditingController();
|
||||||
|
TextEditingController _contactSearchController = TextEditingController();
|
||||||
|
|
||||||
String? _userEmail;
|
String? _userEmail;
|
||||||
String? currentUser;
|
String? currentUser;
|
||||||
@@ -28,6 +30,7 @@ class _ContactsState extends State<Contacts>
|
|||||||
super.initState();
|
super.initState();
|
||||||
_tabController = TabController(length: 3, vsync: this);
|
_tabController = TabController(length: 3, vsync: this);
|
||||||
_initUser();
|
_initUser();
|
||||||
|
_contactSearchController.addListener(_filterContacts);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _initUser() async {
|
Future<void> _initUser() async {
|
||||||
@@ -66,7 +69,10 @@ class _ContactsState extends State<Contacts>
|
|||||||
);
|
);
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
setState(() => _contacts = data);
|
setState(() {
|
||||||
|
_contacts = data;
|
||||||
|
_filteredContacts = data;
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
print("Erreur chargement contacts: ${response.statusCode}");
|
print("Erreur chargement contacts: ${response.statusCode}");
|
||||||
}
|
}
|
||||||
@@ -119,6 +125,15 @@ class _ContactsState extends State<Contacts>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _filterContacts() {
|
||||||
|
final query = _contactSearchController.text.toLowerCase();
|
||||||
|
setState(() {
|
||||||
|
_filteredContacts = _contacts
|
||||||
|
.where((contact) => contact['contacts'].toLowerCase().contains(query))
|
||||||
|
.toList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _envoyerDemandeContact(String destinataire) async {
|
Future<void> _envoyerDemandeContact(String destinataire) async {
|
||||||
if (destinataire == currentUser) {
|
if (destinataire == currentUser) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -202,6 +217,47 @@ class _ContactsState extends State<Contacts>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _supprimerContact(String destinataire) async {
|
||||||
|
final confirm = await showDialog<bool>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
title: Text("Confirmer la suppression"),
|
||||||
|
content: Text(
|
||||||
|
"Voulez-vous vraiment supprimer $destinataire de vos contacts ?"),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
|
child: Text("Annuler"),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
child: Text("Supprimer"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (confirm != true) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
Uri.parse('https://nexuschat.derickexm.be/contacts/supprimer_contact'),
|
||||||
|
headers: {"Content-Type": "application/json"},
|
||||||
|
body: jsonEncode({"owner": currentUser, "contact": destinataire}),
|
||||||
|
);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
await _loadContacts();
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text("Contact $destinataire supprimé")),
|
||||||
|
);
|
||||||
|
print("Status: ${response.statusCode}");
|
||||||
|
print("Body: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Erreur : $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> _getEtatRelation(String target) async {
|
Future<String> _getEtatRelation(String target) async {
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
Uri.parse(
|
Uri.parse(
|
||||||
@@ -234,28 +290,54 @@ class _ContactsState extends State<Contacts>
|
|||||||
children: [
|
children: [
|
||||||
_contacts.isEmpty
|
_contacts.isEmpty
|
||||||
? Center(child: Text("Aucun contact"))
|
? Center(child: Text("Aucun contact"))
|
||||||
: ListView.builder(
|
: Column(
|
||||||
itemCount: _contacts.length,
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: TextField(
|
||||||
|
controller: _contactSearchController,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Rechercher dans mes contacts...",
|
||||||
|
prefixIcon: Icon(Icons.search),
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView.builder(
|
||||||
|
itemCount: _filteredContacts.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final user = _contacts[index]['contacts'];
|
final user = _filteredContacts[index]['contacts'];
|
||||||
return Card(
|
return Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Text(user),
|
title: Text(user),
|
||||||
leading: Icon(Icons.person),
|
leading: Icon(Icons.person),
|
||||||
trailing: ElevatedButton(
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ElevatedButton(
|
||||||
onPressed: () => Navigator.push(
|
onPressed: () => Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => ChatScreen(
|
||||||
ChatScreen(usernameExpediteur: user),
|
usernameExpediteur: user),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text("Chat"),
|
child: Text("Chat"),
|
||||||
),
|
),
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.delete),
|
||||||
|
onPressed: () => _supprimerContact(user),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
_demandes.isEmpty
|
_demandes.isEmpty
|
||||||
? Center(child: Text("Aucune demande"))
|
? Center(child: Text("Aucune demande"))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
|
|||||||
@@ -42,6 +42,11 @@ class Inscription extends StatelessWidget {
|
|||||||
Future<void> _API_inscription(BuildContext context) async {
|
Future<void> _API_inscription(BuildContext context) async {
|
||||||
const String apiUrl = "https://nexuschat.derickexm.be/users/create_user";
|
const String apiUrl = "https://nexuschat.derickexm.be/users/create_user";
|
||||||
|
|
||||||
|
if (username.text.isEmpty || email.text.isEmpty || passwd.text.isEmpty) {
|
||||||
|
_showSnackBar(context, "Veuillez remplir tous les champs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse(apiUrl),
|
Uri.parse(apiUrl),
|
||||||
|
|||||||
@@ -271,6 +271,12 @@ class Listechatstate extends State<Listechat> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
|
// trailing: IconButton(
|
||||||
|
// icon: Icon(Icons.delete),
|
||||||
|
// color: Colors.red,
|
||||||
|
// onPressed: () =>
|
||||||
|
// _supprimerConversation(destinataire),
|
||||||
|
// ),
|
||||||
//
|
//
|
||||||
// subtitle: Column(
|
// subtitle: Column(
|
||||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ class Login extends StatelessWidget {
|
|||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
print("Connexion réussie");
|
print("Connexion réussie");
|
||||||
|
|
||||||
// Stocker l'email de l'utilisateur
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setString('user_email', email);
|
await prefs.setString('user_email', email);
|
||||||
|
|
||||||
@@ -99,8 +98,7 @@ class Login extends StatelessWidget {
|
|||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
width:
|
width: 400,
|
||||||
400, // Définition d'une largeur fixe pour un meilleur affichage
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: Colors.black, width: 2),
|
border: Border.all(color: Colors.black, width: 2),
|
||||||
@@ -159,6 +157,13 @@ class Login extends StatelessWidget {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
FocusManager.instance.primaryFocus?.unfocus();
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
|
||||||
|
if (email.text.isEmpty || passwd.text.isEmpty) {
|
||||||
|
_showErrorDialog(
|
||||||
|
context, "Veuillez remplir tous les champs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
print("Email saisi : ${email.text}");
|
print("Email saisi : ${email.text}");
|
||||||
print("Mot de passe : ${passwd.text}");
|
print("Mot de passe : ${passwd.text}");
|
||||||
checkCredentials(email.text, passwd.text);
|
checkCredentials(email.text, passwd.text);
|
||||||
|
|||||||
@@ -93,28 +93,6 @@ class _MenuState extends State<Menu> {
|
|||||||
padding: const EdgeInsets.fromLTRB(15, 10, 10, 10),
|
padding: const EdgeInsets.fromLTRB(15, 10, 10, 10),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (showEmailWarning)
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(10),
|
|
||||||
margin: const EdgeInsets.only(bottom: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.amber[200],
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: const [
|
|
||||||
Icon(Icons.warning_amber_rounded, color: Colors.black),
|
|
||||||
SizedBox(width: 10),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
" Les emails de vérification sont momentanément indisponibles. Veuillez nous en excuser !",
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: FontWeight.w600, color: Colors.red),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: _widgetOptions.elementAt(_selectedIndex),
|
child: _widgetOptions.elementAt(_selectedIndex),
|
||||||
|
|||||||
@@ -17,6 +17,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.6.1"
|
version: "3.6.1"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -41,6 +49,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
checked_yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: checked_yaml
|
||||||
|
sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.3"
|
||||||
|
cli_util:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cli_util
|
||||||
|
sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.5"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -110,14 +134,27 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_lints:
|
flutter_giphy_picker:
|
||||||
dependency: "direct dev"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_lints
|
name: flutter_giphy_picker
|
||||||
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
sha256: "249841f086ab5b7200a2316eb2a0a773a813f696d822a856e7803f17df759e35"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "1.0.11"
|
||||||
|
flutter_launcher_icons:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_launcher_icons
|
||||||
|
sha256: ce0e501cfc258907842238e4ca605e74b7fd1cdf04b3b43e86c43f3e40a1592c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.0"
|
||||||
|
flutter_localizations:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -126,6 +163,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.26"
|
version: "2.0.26"
|
||||||
|
flutter_staggered_grid_view:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_staggered_grid_view
|
||||||
|
sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.0"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -136,14 +181,22 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
focus_detector_v2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: focus_detector_v2
|
||||||
|
sha256: d4abc4c755ba894238ab92f42f6eee7ade78aa285199e112f45926c7053f90c6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0+1"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
|
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.13.6"
|
version: "1.4.0"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -168,6 +221,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.19.0"
|
version: "0.19.0"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.9.0"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -192,14 +253,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1"
|
version: "3.0.1"
|
||||||
lints:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: lints
|
|
||||||
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "5.1.1"
|
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -469,6 +522,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.4"
|
version: "2.1.4"
|
||||||
|
visibility_detector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: visibility_detector
|
||||||
|
sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.0+2"
|
||||||
vm_service:
|
vm_service:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -509,6 +570,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.5.0"
|
version: "6.5.0"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.6.0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.27.0"
|
flutter: ">=3.27.0"
|
||||||
|
|||||||
@@ -31,10 +31,13 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
http: ^0.13.6
|
|
||||||
|
flutter_giphy_picker: ^1.0.5
|
||||||
|
http: ^1.4.0
|
||||||
adaptive_theme: ^3.6.0
|
adaptive_theme: ^3.6.0
|
||||||
url_launcher: ^6.3.0
|
url_launcher: ^6.3.0
|
||||||
intl: ^0.19.0
|
intl: ^0.19.0
|
||||||
@@ -47,13 +50,10 @@ dependencies:
|
|||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_launcher_icons: ^0.11.0
|
||||||
|
|
||||||
# The "flutter_lints" package below contains a set of recommended lints to
|
|
||||||
# encourage good coding practices. The lint set provided by the package is
|
flutter_lints: ^1.0.0
|
||||||
# activated in the `analysis_options.yaml` file located at the root of your
|
|
||||||
# package. See that file for information about deactivating specific lint
|
|
||||||
# rules and activating additional ones.
|
|
||||||
flutter_lints: ^5.0.0
|
|
||||||
|
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
@@ -97,3 +97,8 @@ flutter:
|
|||||||
#
|
#
|
||||||
# For details regarding fonts from package dependencies,
|
# For details regarding fonts from package dependencies,
|
||||||
# see https://flutter.dev/to/font-from-package
|
# see https://flutter.dev/to/font-from-package
|
||||||
|
|
||||||
|
flutter_icons:
|
||||||
|
android: true
|
||||||
|
ios: true
|
||||||
|
image_path: "assets/logo.png"
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
|
||||||
<meta name="description" content="A new Flutter project.">
|
<meta name="description" content="Un chat qui respecte votre intimité.">
|
||||||
|
|
||||||
<!-- iOS meta tags & icons -->
|
<!-- iOS meta tags & icons -->
|
||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="assets/assets/logo.png" />
|
<link rel="icon" type="image/png" href="assets/assets/logo.png" />
|
||||||
|
|
||||||
<title>nexuschat</title>
|
<title>Nexuschat</title>
|
||||||
<link rel="manifest" href="manifest.json">
|
<link rel="manifest" href="manifest.json">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|||||||