mirror of
https://github.com/Shchoholiev/shopping-assistant-mobile-client.git
synced 2025-04-03 16:19:51 +00:00
add logic for stream
This commit is contained in:
parent
7b3963fad7
commit
06ae71960b
@ -17,6 +17,8 @@ const String startPersonalWishlistMutations = r'''
|
||||
}
|
||||
''';
|
||||
|
||||
SearchEventType type = SearchEventType.message;
|
||||
|
||||
class SearchService {
|
||||
final AuthenticationService _authenticationService = AuthenticationService();
|
||||
final ApiClient client = ApiClient();
|
||||
@ -29,35 +31,52 @@ class SearchService {
|
||||
await _authenticationService.initialize();
|
||||
}
|
||||
|
||||
bool checkerForProduct() {
|
||||
return type == SearchEventType.product;
|
||||
}
|
||||
|
||||
String? wishlistId;
|
||||
|
||||
Future<void> startPersonalWishlist(String message) async {
|
||||
await _authenticationService.initialize();
|
||||
|
||||
final options = MutationOptions(
|
||||
document: gql(startPersonalWishlistMutations),
|
||||
variables: <String, dynamic>{
|
||||
'dto': {'firstMessageText': message, 'type': 'Product'},
|
||||
},
|
||||
);
|
||||
// Перевіряємо, чи вже створений wishlist
|
||||
if (wishlistId == null) {
|
||||
final options = MutationOptions(
|
||||
document: gql(startPersonalWishlistMutations),
|
||||
variables: <String, dynamic>{
|
||||
'dto': {'firstMessageText': message, 'type': 'Product'},
|
||||
},
|
||||
);
|
||||
|
||||
final result = await client.mutate(options);
|
||||
final result = await client.mutate(options);
|
||||
|
||||
if (result != null && result.containsKey('startPersonalWishlist')) {
|
||||
final wishlistId = result['startPersonalWishlist']['id'];
|
||||
if (result != null && result.containsKey('startPersonalWishlist')) {
|
||||
wishlistId = result['startPersonalWishlist']['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if (wishlistId != null) {
|
||||
final sseStream = client.getServerSentEventStream(
|
||||
'api/productssearch/search/$wishlistId',
|
||||
{'text': message},
|
||||
);
|
||||
|
||||
StringBuffer fullMessage = StringBuffer(); // Використовуємо StringBuffer для зберігання повідомлення
|
||||
|
||||
await for (final chunk in sseStream) {
|
||||
fullMessage.write(chunk.data); // Додаємо чанк до повідомлення
|
||||
print("Original chunk.data: ${chunk.event}");
|
||||
final cleanedMessage = chunk.data.replaceAll(RegExp(r'(^"|"$)'), '');
|
||||
if(chunk.event == SearchEventType.message)
|
||||
{
|
||||
type = SearchEventType.message;
|
||||
}
|
||||
if(chunk.event == SearchEventType.product)
|
||||
{
|
||||
type = SearchEventType.product;
|
||||
}
|
||||
|
||||
final event = ServerSentEvent(type, cleanedMessage);
|
||||
_sseController.add(event);
|
||||
}
|
||||
|
||||
final cleanedMessage = fullMessage.toString().replaceAll('"', '');
|
||||
|
||||
final event = ServerSentEvent(SearchEventType.message, cleanedMessage.toString().trim());
|
||||
_sseController.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,15 +6,17 @@ import 'package:shopping_assistant_mobile_client/network/search_service.dart';
|
||||
class Message {
|
||||
final String text;
|
||||
final bool isUser;
|
||||
bool isProduct;
|
||||
|
||||
Message({required this.text, this.isUser = false});
|
||||
Message({required this.text, this.isUser = false, this.isProduct = false});
|
||||
}
|
||||
|
||||
class MessageBubble extends StatelessWidget {
|
||||
final String message;
|
||||
final bool isOutgoing;
|
||||
final bool isProduct;
|
||||
|
||||
MessageBubble({required this.message, this.isOutgoing = true});
|
||||
MessageBubble({required this.message, this.isOutgoing = true, this.isProduct = false});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -23,13 +25,34 @@ class MessageBubble extends StatelessWidget {
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 300.0, // Максимальна ширина контейнера
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: isOutgoing ? Colors.blue : Colors.white38,
|
||||
color: isOutgoing ? Colors.blue : Colors.grey[200],
|
||||
borderRadius: BorderRadius.circular(10.0),
|
||||
),
|
||||
child: Text(
|
||||
message,
|
||||
style: TextStyle(color: isOutgoing ? Colors.white : Colors.black),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
message,
|
||||
style: TextStyle(color: isOutgoing ? Colors.white : Colors.black),
|
||||
),
|
||||
if (isProduct) // Виводимо кнопку тільки для повідомлень типу Product
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
// Обробка натискання на кнопку "View Product"
|
||||
print('View Product button pressed');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
primary: Colors.indigo,
|
||||
onPrimary: Colors.white,
|
||||
minimumSize: Size(300, 50)
|
||||
),
|
||||
child: Text('View Product'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -46,31 +69,55 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
List<Message> messages = [];
|
||||
final TextEditingController _messageController = TextEditingController();
|
||||
bool buttonsVisible = true;
|
||||
bool isSendButtonEnabled = false;
|
||||
bool showButtonsContainer = true;
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
|
||||
String wishlistId = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_searchService.sseStream.listen((event) {
|
||||
_handleSSEMessage(Message(text: '${event.event}: ${event.data}'));
|
||||
_handleSSEMessage(Message(text: '${event.data}'));
|
||||
});
|
||||
}
|
||||
|
||||
void _handleSSEMessage(Message message) {
|
||||
setState(() {
|
||||
messages.add(message);
|
||||
final lastMessage = messages.isNotEmpty ? messages.last : null;
|
||||
message.isProduct = _searchService.checkerForProduct();
|
||||
print("Product status: ${message.isProduct}");
|
||||
if (lastMessage != null && !lastMessage.isUser && !message.isUser) {
|
||||
final updatedMessage = Message(
|
||||
text: "${lastMessage.text}${message.text}",
|
||||
isProduct: message.isProduct);
|
||||
messages.removeLast();
|
||||
messages.add(updatedMessage);
|
||||
} else {
|
||||
messages.add(message);
|
||||
}
|
||||
});
|
||||
_scrollToBottom();
|
||||
}
|
||||
|
||||
|
||||
Future<void> _startPersonalWishlist(String message) async {
|
||||
setState(() {
|
||||
buttonsVisible = false;
|
||||
showButtonsContainer = false;
|
||||
});
|
||||
await _searchService.initializeAuthenticationService();
|
||||
await _searchService.startPersonalWishlist(message);
|
||||
_scrollToBottom();
|
||||
}
|
||||
|
||||
Future<void> _sendMessageToAPI(String message) async {
|
||||
setState(() {
|
||||
buttonsVisible = false;
|
||||
showButtonsContainer = false;
|
||||
});
|
||||
await _searchService.startPersonalWishlist(message);
|
||||
_scrollToBottom();
|
||||
|
||||
setState(() {
|
||||
messages.add(Message(text: message, isUser: true));
|
||||
@ -90,11 +137,16 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
}
|
||||
|
||||
_messageController.clear();
|
||||
_scrollToBottom();
|
||||
}
|
||||
|
||||
void _scrollToBottom() {
|
||||
_scrollController.animateTo(
|
||||
_scrollController.position.maxScrollExtent,
|
||||
duration: Duration(milliseconds: 300),
|
||||
curve: Curves.easeOut,
|
||||
);}
|
||||
);
|
||||
}
|
||||
|
||||
void _showGiftNotAvailable() {
|
||||
showDialog(
|
||||
@ -149,7 +201,8 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
print('Product button pressed');
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 16),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 30, vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
@ -162,7 +215,8 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
ElevatedButton(
|
||||
onPressed: _showGiftNotAvailable,
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 16),
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 30, vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
@ -177,6 +231,56 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16.0), // Відступ вниз
|
||||
Visibility(
|
||||
visible: showButtonsContainer,
|
||||
child: Container(
|
||||
margin: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
margin: EdgeInsets.all(8),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
_messageController.text = 'Christmas gift🎁';
|
||||
_sendMessage();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
primary: Colors.white,
|
||||
onPrimary: Colors.blue,
|
||||
side: BorderSide(color: Colors.blue, width: 2.0),
|
||||
),
|
||||
child: Text('Christmas gift🎁', style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: EdgeInsets.all(8),
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
_messageController.text = 'Birthday gift🎉';
|
||||
_sendMessage();
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: 30, vertical: 16),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
primary: Colors.white,
|
||||
onPrimary: Colors.blue,
|
||||
side: BorderSide(color: Colors.blue, width: 2.0),
|
||||
),
|
||||
child: Text('Birthday gift🎉', style: TextStyle(color: Colors.grey)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
@ -187,6 +291,7 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
return MessageBubble(
|
||||
message: message.text,
|
||||
isOutgoing: message.isUser,
|
||||
isProduct: message.isProduct,
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -198,6 +303,12 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
Expanded(
|
||||
child: TextField(
|
||||
controller: _messageController,
|
||||
onChanged: (text) {
|
||||
// Коли текст змінюється, оновлюємо стан кнопки
|
||||
setState(() {
|
||||
isSendButtonEnabled = text.isNotEmpty;
|
||||
});
|
||||
},
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Enter your message...',
|
||||
),
|
||||
@ -205,7 +316,7 @@ class ChatScreenState extends State<ChatScreen> {
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.send),
|
||||
onPressed: _sendMessage,
|
||||
onPressed: isSendButtonEnabled ? _sendMessage : null,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user