update
This commit is contained in:
@@ -1,7 +1,6 @@
|
|||||||
// ✅ chat.dart (corrigé sans ChatApp)
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.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';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@@ -17,6 +16,9 @@ class ChatScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _ChatScreenState extends State<ChatScreen> {
|
class _ChatScreenState extends State<ChatScreen> {
|
||||||
final TextEditingController _controller = TextEditingController();
|
final TextEditingController _controller = TextEditingController();
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
|
||||||
List<Map<String, String>> messages = [];
|
List<Map<String, String>> messages = [];
|
||||||
String? expediteur;
|
String? expediteur;
|
||||||
late String destinataire;
|
late String destinataire;
|
||||||
@@ -45,6 +47,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
_pollingTimer.cancel();
|
_pollingTimer.cancel();
|
||||||
_controller.removeListener(_updateButtonState);
|
_controller.removeListener(_updateButtonState);
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
_focusNode.dispose();
|
||||||
|
_scrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,12 +148,14 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
messages = messagesList.map((msg) {
|
messages = messagesList.map((msg) {
|
||||||
bool isMe = msg['expediteur'].toString() == expediteur;
|
bool isMe = msg['expediteur'].toString() == expediteur;
|
||||||
return {
|
return {
|
||||||
'sender': isMe ? 'me' : 'bot',
|
'sender': msg['expediteur'].toString(),
|
||||||
'text': msg['messages'].toString(),
|
'text': msg['messages'].toString(),
|
||||||
|
'timestamp': msg['sent_at'].toString(),
|
||||||
};
|
};
|
||||||
}).toList();
|
}).toList();
|
||||||
_isInitialLoading = false;
|
_isInitialLoading = false;
|
||||||
});
|
});
|
||||||
|
_scrollToBottom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -183,16 +189,26 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
|
|
||||||
void _updateButtonState() {
|
void _updateButtonState() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isButtonEnabled = _controller.text.isNotEmpty;
|
_isButtonEnabled = _controller.text.trim().isNotEmpty;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> sendMessage(String message) async {
|
Future<void> sendMessage(String message) async {
|
||||||
|
if (expediteur == null || message.trim().isEmpty) return;
|
||||||
|
|
||||||
|
final now = DateTime.now();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
messages.add({'sender': 'me', 'text': message});
|
messages.add({
|
||||||
|
'sender': expediteur!,
|
||||||
|
'text': message.trim(),
|
||||||
|
'timestamp': now.toIso8601String(),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
_controller.clear();
|
_controller.clear();
|
||||||
_updateButtonState();
|
_updateButtonState();
|
||||||
|
_scrollToBottom();
|
||||||
|
|
||||||
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/'),
|
||||||
@@ -200,8 +216,8 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
'expediteur': expediteur,
|
'expediteur': expediteur,
|
||||||
'destinataire': destinataire,
|
'destinataire': destinataire,
|
||||||
'message': message,
|
'message': message.trim(),
|
||||||
'timestamp': DateTime.now().toIso8601String(),
|
'sent_at': now.toIso8601String(),
|
||||||
'id_conversation': idConversation,
|
'id_conversation': idConversation,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@@ -209,8 +225,13 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
final jsonResponse = jsonDecode(response.body);
|
final jsonResponse = jsonDecode(response.body);
|
||||||
if (jsonResponse.containsKey('reply')) {
|
if (jsonResponse.containsKey('reply')) {
|
||||||
setState(() {
|
setState(() {
|
||||||
messages.add({'sender': 'bot', 'text': jsonResponse['reply']});
|
messages.add({
|
||||||
|
'sender': destinataire,
|
||||||
|
'text': jsonResponse['reply'],
|
||||||
|
'timestamp': DateTime.now().toIso8601String(),
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
_scrollToBottom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -218,6 +239,26 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _scrollToBottom() {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
if (_scrollController.hasClients) {
|
||||||
|
_scrollController.animateTo(
|
||||||
|
_scrollController.position.maxScrollExtent,
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
curve: Curves.easeOut,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectPhoto() {
|
||||||
|
print('Sélectionner une photo');
|
||||||
|
}
|
||||||
|
|
||||||
|
void _selectGif() {
|
||||||
|
print('Sélectionner un GIF');
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -236,28 +277,62 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
itemCount: messages.length,
|
itemCount: messages.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final message = messages[index];
|
final message = messages[index];
|
||||||
final isMe = message['sender'] == 'me';
|
final isMe = message['sender'] == expediteur;
|
||||||
return Align(
|
|
||||||
|
// Formatage de l'heure
|
||||||
|
final time =
|
||||||
|
DateTime.tryParse(message['timestamp'] ?? '');
|
||||||
|
final formattedTime = time != null
|
||||||
|
? "${time.hour.toString().padLeft(2, '0')}:${time.minute.toString().padLeft(2, '0')}"
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return Container(
|
||||||
alignment:
|
alignment:
|
||||||
isMe ? Alignment.centerRight : Alignment.centerLeft,
|
isMe ? Alignment.centerRight : Alignment.centerLeft,
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.symmetric(
|
margin: const EdgeInsets.symmetric(
|
||||||
vertical: 5, horizontal: 10),
|
vertical: 4, horizontal: 8),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: isMe
|
||||||
|
? CrossAxisAlignment.end
|
||||||
|
: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
message['sender'] ?? '',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.grey[700],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
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: Text(
|
||||||
message['text']!,
|
message['text'] ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: isMe ? Colors.white : Colors.black,
|
color: isMe ? Colors.white : Colors.black,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (formattedTime.isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 2),
|
||||||
|
child: Text(
|
||||||
|
formattedTime,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10, color: Colors.grey[600]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -269,19 +344,46 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
decoration: const InputDecoration(
|
focusNode: _focusNode,
|
||||||
hintText: 'Écrire un message...',
|
style: TextStyle(fontSize: 16),
|
||||||
|
cursorColor: Colors.orange,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'Entrez votre message...',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
|
minLines: 1,
|
||||||
|
maxLines: 5,
|
||||||
|
keyboardType: TextInputType.multiline,
|
||||||
|
textInputAction: TextInputAction.newline,
|
||||||
|
onChanged: (text) => _updateButtonState(),
|
||||||
|
onEditingComplete: () {},
|
||||||
|
inputFormatters: [
|
||||||
|
_EnterKeyFormatter(
|
||||||
|
onEnter: () {
|
||||||
|
if (_controller.text.trim().isNotEmpty) {
|
||||||
|
sendMessage(_controller.text);
|
||||||
|
_controller
|
||||||
|
.clear(); // 👈 Ajout explicite du clear ici
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
SizedBox(width: 8),
|
||||||
icon: const Icon(Icons.send),
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.orange,
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
),
|
||||||
|
child: IconButton(
|
||||||
|
icon: Icon(Icons.send, color: Colors.black),
|
||||||
onPressed: _isButtonEnabled
|
onPressed: _isButtonEnabled
|
||||||
? () => sendMessage(_controller.text)
|
? () => sendMessage(_controller.text)
|
||||||
: null,
|
: null,
|
||||||
color: _isButtonEnabled ? Colors.orange : Colors.grey,
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -290,3 +392,25 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ Formatter : Enter = envoi / Shift+Enter = saut de ligne
|
||||||
|
class _EnterKeyFormatter extends TextInputFormatter {
|
||||||
|
final VoidCallback onEnter;
|
||||||
|
|
||||||
|
_EnterKeyFormatter({required this.onEnter});
|
||||||
|
|
||||||
|
@override
|
||||||
|
TextEditingValue formatEditUpdate(
|
||||||
|
TextEditingValue oldValue, TextEditingValue newValue) {
|
||||||
|
if (newValue.text.length > oldValue.text.length &&
|
||||||
|
newValue.text.endsWith('\n') &&
|
||||||
|
!RawKeyboard.instance.keysPressed
|
||||||
|
.contains(LogicalKeyboardKey.shiftLeft) &&
|
||||||
|
!RawKeyboard.instance.keysPressed
|
||||||
|
.contains(LogicalKeyboardKey.shiftRight)) {
|
||||||
|
onEnter();
|
||||||
|
return const TextEditingValue(text: ''); // vide le champ après envoi
|
||||||
|
}
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:nexuschat/listechat.dart';
|
|
||||||
import 'package:nexuschat/login.dart';
|
import 'package:nexuschat/login.dart';
|
||||||
|
|
||||||
class Inscription extends StatelessWidget {
|
class Inscription extends StatelessWidget {
|
||||||
@@ -13,33 +12,33 @@ class Inscription extends StatelessWidget {
|
|||||||
final TextEditingController username = TextEditingController();
|
final TextEditingController username = TextEditingController();
|
||||||
|
|
||||||
Future<void> sendVerificationEmail(BuildContext context, String email) async {
|
Future<void> sendVerificationEmail(BuildContext context, String email) async {
|
||||||
final url = Uri.parse('https://nexuschat.derickexm.be/email/send_email/');
|
final url = Uri.parse(
|
||||||
|
'https://nexuschat.derickexm.be/email/send_email?email=$email');
|
||||||
try {
|
try {
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
url,
|
url,
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Accept': 'application/json'},
|
||||||
body: jsonEncode({
|
|
||||||
"email": email,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context, "Email de vérification envoyé avec succès!");
|
||||||
SnackBar(content: Text("Email de vérification envoyé avec succès!")),
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context,
|
||||||
SnackBar(
|
"Impossible d'envoyer l'email de vérification. (${response.statusCode})");
|
||||||
content: Text("Impossible d'envoyer l'email de vérification.")),
|
print("Réponse serveur : ${response.body}");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context, "Erreur de connexion à l'API.");
|
||||||
SnackBar(content: Text("Erreur de connexion à l'API: $e")),
|
print("Erreur d'envoi email : $e");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showSnackBar(BuildContext context, String message) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(content: Text(message)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
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";
|
||||||
|
|
||||||
@@ -56,29 +55,20 @@ class Inscription extends StatelessWidget {
|
|||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
print("Inscription réussie !");
|
print("Inscription réussie !");
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context, "Inscription réussie !");
|
||||||
const SnackBar(content: Text("Inscription réussie !")),
|
sendVerificationEmail(context, email.text);
|
||||||
);
|
|
||||||
|
|
||||||
// Appel de la fonction pour envoyer l'email de confirmation
|
|
||||||
await sendVerificationEmail(context, email.text);
|
|
||||||
|
|
||||||
// Redirection vers la page de login
|
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => Login()),
|
MaterialPageRoute(builder: (context) => Login()),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
print("Erreur : ${response.body}");
|
print("Erreur : ${response.body}");
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context, "Erreur lors de l'inscription");
|
||||||
const SnackBar(content: Text("Erreur lors de l'inscription")),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur réseau : $e");
|
print("Erreur réseau : $e");
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
_showSnackBar(context, "Problème de connexion au serveur");
|
||||||
const SnackBar(content: Text("Problème de connexion au serveur")),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +96,6 @@ class Inscription extends StatelessWidget {
|
|||||||
const Text("S'inscrire sur NexusChat",
|
const Text("S'inscrire sur NexusChat",
|
||||||
style: TextStyle(fontSize: 24)),
|
style: TextStyle(fontSize: 24)),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Champ Nom d'utilisateur
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 400,
|
width: 400,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -121,8 +109,6 @@ class Inscription extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Champ Email
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 400,
|
width: 400,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -136,8 +122,6 @@ class Inscription extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Champ Mot de passe
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 400,
|
width: 400,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -151,15 +135,11 @@ class Inscription extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
|
|
||||||
// Bouton S'inscrire
|
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () => _API_inscription(context),
|
onPressed: () => _API_inscription(context),
|
||||||
child: const Text("S'inscrire"),
|
child: const Text("S'inscrire"),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// Bouton Déjà inscrit ?
|
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(context,
|
Navigator.push(context,
|
||||||
|
|||||||
@@ -99,17 +99,15 @@ class Listechatstate extends State<Listechat> {
|
|||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
if (data is Map<String, dynamic> && data.containsKey("conversations")) {
|
if (data is Map<String, dynamic>) {
|
||||||
|
if (data.containsKey("conversations")) {
|
||||||
return List<Map<String, dynamic>>.from(data["conversations"]);
|
return List<Map<String, dynamic>>.from(data["conversations"]);
|
||||||
} else {
|
} else if (data.containsKey("exists") && data["exists"] == false) {
|
||||||
setState(() {
|
|
||||||
errorMessage = "Format de réponse inattendu";
|
|
||||||
});
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
errorMessage = "Erreur serveur: ${response.statusCode}";
|
errorMessage = "Format de réponse inattendu";
|
||||||
});
|
});
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@@ -120,6 +118,9 @@ class Listechatstate extends State<Listechat> {
|
|||||||
});
|
});
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ Ce return évite l'erreur "body might complete normally"
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _refreshConversations() async {
|
Future<void> _refreshConversations() async {
|
||||||
@@ -146,6 +147,7 @@ class Listechatstate extends State<Listechat> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
title: const Text("Mes Conversations"),
|
title: const Text("Mes Conversations"),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -200,9 +202,21 @@ class Listechatstate extends State<Listechat> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text("Aucune conversation trouvée"),
|
const Icon(Icons.chat_bubble_outline,
|
||||||
|
size: 80, color: Colors.grey),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ElevatedButton(
|
const Text(
|
||||||
|
"Aucune conversation pour l’instant",
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18, fontWeight: FontWeight.w500),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
const Text(
|
||||||
|
"Commencez une discussion avec vos contacts.",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
ElevatedButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
@@ -211,7 +225,8 @@ class Listechatstate extends State<Listechat> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Text("Démarrer une conversation"),
|
icon: const Icon(Icons.add_comment),
|
||||||
|
label: const Text("Démarrer une conversation"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -234,13 +249,6 @@ class Listechatstate extends State<Listechat> {
|
|||||||
? "conversation_${expediteur}_$rawId"
|
? "conversation_${expediteur}_$rawId"
|
||||||
: "conversation_${expediteur}_${destinataire}_$index";
|
: "conversation_${expediteur}_${destinataire}_$index";
|
||||||
|
|
||||||
final lastMessage =
|
|
||||||
conv["last_message"] ?? "Aucun message";
|
|
||||||
final timestamp = conv["created_at"] ?? "Inconnu";
|
|
||||||
final formattedDate = formatTimestamp(timestamp);
|
|
||||||
final truncatedMessage =
|
|
||||||
truncateMessage(lastMessage, 40);
|
|
||||||
|
|
||||||
return Hero(
|
return Hero(
|
||||||
tag: uniqueTag,
|
tag: uniqueTag,
|
||||||
child: Card(
|
child: Card(
|
||||||
@@ -263,19 +271,20 @@ class Listechatstate extends State<Listechat> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
subtitle: Column(
|
//
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
// subtitle: Column(
|
||||||
children: [
|
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text(truncatedMessage),
|
// children: [
|
||||||
Text(
|
// Text(truncatedMessage),
|
||||||
formattedDate,
|
// Text(
|
||||||
style: TextStyle(
|
// formattedDate,
|
||||||
fontSize: 12,
|
// style: TextStyle(
|
||||||
color: Colors.grey[600],
|
// fontSize: 12,
|
||||||
),
|
// color: Colors.grey[600],
|
||||||
),
|
// ),
|
||||||
],
|
// ),
|
||||||
),
|
// ],
|
||||||
|
// ),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -36,6 +36,27 @@ class Login extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> sendAttemptLogin(String email) async {
|
||||||
|
final url = Uri.parse(
|
||||||
|
'https://nexuschat.derickexm.be/email/send_login_attempt_email/?email=$email');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
url,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
print(
|
||||||
|
"Erreur lors de l'envoi de l'alerte de tentative de connexion : ${response.body}");
|
||||||
|
} else {
|
||||||
|
print("Alerte de tentative de connexion envoyée à $email");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Erreur de connexion lors de l'envoi de l'alerte : $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> checkCredentials(String email, String password) async {
|
Future<void> checkCredentials(String email, String password) async {
|
||||||
final url =
|
final url =
|
||||||
Uri.parse('https://nexuschat.derickexm.be/users/check_credentials');
|
Uri.parse('https://nexuschat.derickexm.be/users/check_credentials');
|
||||||
@@ -63,6 +84,7 @@ class Login extends StatelessWidget {
|
|||||||
|
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context, MaterialPageRoute(builder: (context) => Menu()));
|
context, MaterialPageRoute(builder: (context) => Menu()));
|
||||||
|
await sendAttemptLogin(email);
|
||||||
} else {
|
} else {
|
||||||
_showErrorDialog(
|
_showErrorDialog(
|
||||||
context, "Nom d'utilisateur ou mot de passe incorrect");
|
context, "Nom d'utilisateur ou mot de passe incorrect");
|
||||||
|
|||||||
@@ -14,12 +14,14 @@ class _MenuState extends State<Menu> {
|
|||||||
int _selectedIndex = 0;
|
int _selectedIndex = 0;
|
||||||
String? _userDisplayName;
|
String? _userDisplayName;
|
||||||
String? _profilePictureURL;
|
String? _profilePictureURL;
|
||||||
|
bool showEmailWarning = true;
|
||||||
|
|
||||||
static late List<Widget> _widgetOptions;
|
static late List<Widget> _widgetOptions;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_widgetOptions = <Widget>[
|
_widgetOptions = <Widget>[
|
||||||
Listechat(),
|
Listechat(),
|
||||||
Setting(),
|
Setting(),
|
||||||
@@ -91,6 +93,28 @@ 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),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:nexuschat/login.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
late SharedPreferences prefs;
|
late SharedPreferences prefs;
|
||||||
@@ -109,6 +110,7 @@ class _ProfilState extends State<Profil> {
|
|||||||
final data = jsonDecode(response.body);
|
final data = jsonDecode(response.body);
|
||||||
setState(() {
|
setState(() {
|
||||||
_username = data['username'];
|
_username = data['username'];
|
||||||
|
prefs.setString('username', _username!);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
_showSnackBar("Impossible de récupérer le nom d'utilisateur.");
|
_showSnackBar("Impossible de récupérer le nom d'utilisateur.");
|
||||||
@@ -124,6 +126,167 @@ class _ProfilState extends State<Profil> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _ChangePassword() async {
|
||||||
|
final email = prefs.getString("user_email");
|
||||||
|
|
||||||
|
if (email == null) {
|
||||||
|
_showSnackBar("Email utilisateur introuvable.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final oldPasswordController = TextEditingController();
|
||||||
|
final newPasswordController = TextEditingController();
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Changer le mot de passe'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
TextField(
|
||||||
|
controller: oldPasswordController,
|
||||||
|
obscureText: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Ancien mot de passe',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
controller: newPasswordController,
|
||||||
|
obscureText: true,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
labelText: 'Nouveau mot de passe',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text('Annuler'),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final oldPassword = oldPasswordController.text.trim();
|
||||||
|
final newPassword = newPasswordController.text.trim();
|
||||||
|
|
||||||
|
if (oldPassword.isEmpty || newPassword.isEmpty) {
|
||||||
|
_showSnackBar("Les deux champs sont requis.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final url = Uri.parse(
|
||||||
|
'https://nexuschat.derickexm.be/users/change_password');
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
url,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: jsonEncode({
|
||||||
|
"email": email,
|
||||||
|
"old_password": oldPassword,
|
||||||
|
"new_password": newPassword,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
_showSnackBar("Mot de passe mis à jour !");
|
||||||
|
Navigator.of(context).pop(); // Fermer le popup
|
||||||
|
} else {
|
||||||
|
final responseData = jsonDecode(response.body);
|
||||||
|
_showSnackBar(responseData["error"] ?? "Erreur inconnue.");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_showSnackBar("Erreur lors de la connexion à l'API.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text('Confirmer'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _deleteAccount() async {
|
||||||
|
final username = prefs.getString('username');
|
||||||
|
final email = prefs.getString('user_email');
|
||||||
|
final passwordController = TextEditingController();
|
||||||
|
|
||||||
|
if (username == null || email == null) {
|
||||||
|
_showSnackBar("Impossible de récupérer les infos du compte.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: const Text('Confirmation'),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const Text(
|
||||||
|
"Pour supprimer votre compte, entrez votre mot de passe :"),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
TextField(
|
||||||
|
controller: passwordController,
|
||||||
|
obscureText: true,
|
||||||
|
decoration: const InputDecoration(labelText: "Mot de passe"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
child: const Text("Annuler"),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final password = passwordController.text.trim();
|
||||||
|
if (password.isEmpty) {
|
||||||
|
_showSnackBar("Le mot de passe est requis.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final url = Uri.parse(
|
||||||
|
'https://nexuschat.derickexm.be/users/delete_user');
|
||||||
|
try {
|
||||||
|
final response = await http.post(
|
||||||
|
url,
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
body: jsonEncode({
|
||||||
|
"username": username,
|
||||||
|
"email": email,
|
||||||
|
"password": password,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
_showSnackBar("Compte supprimé avec succès.");
|
||||||
|
await prefs.clear();
|
||||||
|
|
||||||
|
Navigator.pushReplacement(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(builder: (context) => const Login()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
_showSnackBar("Échec de la suppression du compte.");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_showSnackBar("Erreur de connexion à l'API.");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: const Text("Supprimer"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> sendVerificationEmail(BuildContext context, String email) async {
|
Future<void> sendVerificationEmail(BuildContext context, String email) async {
|
||||||
final url = Uri.parse(
|
final url = Uri.parse(
|
||||||
'https://nexuschat.derickexm.be/email/send_email?email=$_userEmail');
|
'https://nexuschat.derickexm.be/email/send_email?email=$_userEmail');
|
||||||
@@ -227,6 +390,7 @@ class _ProfilState extends State<Profil> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
|
if (!_isEmailVerified)
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_userEmail != null) {
|
if (_userEmail != null) {
|
||||||
@@ -290,6 +454,24 @@ class _ProfilState extends State<Profil> {
|
|||||||
},
|
},
|
||||||
child: const Text('Changer nom d\'utilisateur'),
|
child: const Text('Changer nom d\'utilisateur'),
|
||||||
),
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||||
|
onPressed: _ChangePassword,
|
||||||
|
child: const Text("Changer le mot de passe",
|
||||||
|
style: TextStyle(color: Colors.white)),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
height: 10,
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||||
|
onPressed: _deleteAccount,
|
||||||
|
child: const Text("Supprimer le compte",
|
||||||
|
style: TextStyle(color: Colors.white)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
29
nexuschat/macos/Podfile.lock
Normal file
29
nexuschat/macos/Podfile.lock
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
PODS:
|
||||||
|
- FlutterMacOS (1.0.0)
|
||||||
|
- shared_preferences_foundation (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
- FlutterMacOS
|
||||||
|
- url_launcher_macos (0.0.1):
|
||||||
|
- FlutterMacOS
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||||
|
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
|
- url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
FlutterMacOS:
|
||||||
|
:path: Flutter/ephemeral
|
||||||
|
shared_preferences_foundation:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||||
|
url_launcher_macos:
|
||||||
|
:path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||||
|
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
|
||||||
|
url_launcher_macos: 0fba8ddabfc33ce0a9afe7c5fef5aab3d8d2d673
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: 236401fc2c932af29a9fcf0e97baeeb2d750d367
|
||||||
|
|
||||||
|
COCOAPODS: 1.16.2
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
|
||||||
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
|
||||||
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
|
||||||
|
B8BA568225B7722CCF96E8D8 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 715EBAFB738B4F4A7653918C /* Pods_RunnerTests.framework */; };
|
||||||
|
C2185F62C3CD9FF30DDE5155 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C83475F4656F24A643903FD /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -60,11 +62,13 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
070AC6A69E7291C1C4854DFA /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
0C83475F4656F24A643903FD /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
|
||||||
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
|
||||||
33CC10ED2044A3C60003C045 /* nexuschat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "nexuschat.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
33CC10ED2044A3C60003C045 /* nexuschat.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = nexuschat.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
|
||||||
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
@@ -76,8 +80,14 @@
|
|||||||
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
|
||||||
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
|
||||||
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
|
||||||
|
715EBAFB738B4F4A7653918C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9DC09B5245FF3C3E541B7D09 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
B92B3CB62787A38FD35339CD /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
CF42FF394810944FE028C7BC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
DE1B5073B319B2490AAEB036 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
E34584EA242300AA26F1BA1B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -85,6 +95,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
B8BA568225B7722CCF96E8D8 /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -92,6 +103,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
C2185F62C3CD9FF30DDE5155 /* Pods_Runner.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -125,6 +137,7 @@
|
|||||||
331C80D6294CF71000263BE5 /* RunnerTests */,
|
331C80D6294CF71000263BE5 /* RunnerTests */,
|
||||||
33CC10EE2044A3C60003C045 /* Products */,
|
33CC10EE2044A3C60003C045 /* Products */,
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
D73912EC22F37F3D000D13A0 /* Frameworks */,
|
||||||
|
9866A980C9448EA5D225CC03 /* Pods */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -172,9 +185,25 @@
|
|||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
9866A980C9448EA5D225CC03 /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
070AC6A69E7291C1C4854DFA /* Pods-Runner.debug.xcconfig */,
|
||||||
|
CF42FF394810944FE028C7BC /* Pods-Runner.release.xcconfig */,
|
||||||
|
E34584EA242300AA26F1BA1B /* Pods-Runner.profile.xcconfig */,
|
||||||
|
9DC09B5245FF3C3E541B7D09 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
B92B3CB62787A38FD35339CD /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
DE1B5073B319B2490AAEB036 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
D73912EC22F37F3D000D13A0 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
0C83475F4656F24A643903FD /* Pods_Runner.framework */,
|
||||||
|
715EBAFB738B4F4A7653918C /* Pods_RunnerTests.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -186,6 +215,7 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
239B5D276F88E359251E43FD /* [CP] Check Pods Manifest.lock */,
|
||||||
331C80D1294CF70F00263BE5 /* Sources */,
|
331C80D1294CF70F00263BE5 /* Sources */,
|
||||||
331C80D2294CF70F00263BE5 /* Frameworks */,
|
331C80D2294CF70F00263BE5 /* Frameworks */,
|
||||||
331C80D3294CF70F00263BE5 /* Resources */,
|
331C80D3294CF70F00263BE5 /* Resources */,
|
||||||
@@ -204,11 +234,13 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
0735B088592D17EFE1C39F67 /* [CP] Check Pods Manifest.lock */,
|
||||||
33CC10E92044A3C60003C045 /* Sources */,
|
33CC10E92044A3C60003C045 /* Sources */,
|
||||||
33CC10EA2044A3C60003C045 /* Frameworks */,
|
33CC10EA2044A3C60003C045 /* Frameworks */,
|
||||||
33CC10EB2044A3C60003C045 /* Resources */,
|
33CC10EB2044A3C60003C045 /* Resources */,
|
||||||
33CC110E2044A8840003C045 /* Bundle Framework */,
|
33CC110E2044A8840003C045 /* Bundle Framework */,
|
||||||
3399D490228B24CF009A79C7 /* ShellScript */,
|
3399D490228B24CF009A79C7 /* ShellScript */,
|
||||||
|
976689EE1C53CE19E6E6C9A5 /* [CP] Embed Pods Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -291,6 +323,50 @@
|
|||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
0735B088592D17EFE1C39F67 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
|
239B5D276F88E359251E43FD /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -329,6 +405,23 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
|
||||||
};
|
};
|
||||||
|
976689EE1C53CE19E6E6C9A5 /* [CP] Embed Pods Frameworks */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
|
);
|
||||||
|
name = "[CP] Embed Pods Frameworks";
|
||||||
|
outputFileListPaths = (
|
||||||
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -380,6 +473,7 @@
|
|||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
331C80DB294CF71000263BE5 /* Debug */ = {
|
331C80DB294CF71000263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9DC09B5245FF3C3E541B7D09 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -394,6 +488,7 @@
|
|||||||
};
|
};
|
||||||
331C80DC294CF71000263BE5 /* Release */ = {
|
331C80DC294CF71000263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = B92B3CB62787A38FD35339CD /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
@@ -408,6 +503,7 @@
|
|||||||
};
|
};
|
||||||
331C80DD294CF71000263BE5 /* Profile */ = {
|
331C80DD294CF71000263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = DE1B5073B319B2490AAEB036 /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
|||||||
@@ -4,4 +4,7 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -25,10 +25,10 @@
|
|||||||
<meta name="mobile-web-app-capable" content="yes">
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||||
<meta name="apple-mobile-web-app-title" content="nexuschat">
|
<meta name="apple-mobile-web-app-title" content="nexuschat">
|
||||||
<link rel="apple-touch-icon" href="assets/logo.png">
|
<link rel="apple-touch-icon" href="assets/assets/logo.png">
|
||||||
|
|
||||||
<!-- Favicon -->
|
<!-- Favicon -->
|
||||||
<link rel="icon" type="image/png" href="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">
|
||||||
|
|||||||
Reference in New Issue
Block a user