230 lines
7.5 KiB
Dart
230 lines
7.5 KiB
Dart
|
import 'dart:async';
|
||
|
import 'dart:convert';
|
||
|
|
||
|
import 'package:flutter/material.dart';
|
||
|
import 'package:provider/provider.dart';
|
||
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||
|
|
||
|
import 'profile_screen.dart';
|
||
|
import 'shared_preferences_provider.dart';
|
||
|
|
||
|
class StatusPage extends StatefulWidget {
|
||
|
const StatusPage({super.key});
|
||
|
|
||
|
@override
|
||
|
StatusPageState createState() => StatusPageState();
|
||
|
}
|
||
|
|
||
|
class StatusPageState extends State<StatusPage> {
|
||
|
final WebSocketChannel channel = WebSocketChannel.connect(
|
||
|
Uri.parse('wss://api.pogdark.com:8889/ws'),
|
||
|
);
|
||
|
|
||
|
// Convert the stream to a broadcast stream
|
||
|
late final Stream<dynamic> broadcastStream;
|
||
|
late StreamController<dynamic> controller;
|
||
|
|
||
|
List<Map<String, dynamic>> messages =
|
||
|
[]; // To hold user messages with names and timestamps
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
super.initState();
|
||
|
controller = StreamController<dynamic>.broadcast();
|
||
|
controller.addStream(channel.stream);
|
||
|
broadcastStream = channel.stream.asBroadcastStream();
|
||
|
}
|
||
|
|
||
|
List<Map<String, dynamic>> _getMessagesByStatus(String status) {
|
||
|
return messages.where((message) => message['Status'] == status).toList();
|
||
|
}
|
||
|
|
||
|
void _navigateToEditProfile() {
|
||
|
Navigator.push(
|
||
|
context,
|
||
|
MaterialPageRoute(
|
||
|
builder: (context) => const ProfileScreen(isEditing: true)),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void _sendStatus(String id, String name, String? image, String status) {
|
||
|
final message = jsonEncode({
|
||
|
'Id': id,
|
||
|
'Name': name,
|
||
|
'Image': image,
|
||
|
'Status': status,
|
||
|
'Timestamp': DateTime.now().toIso8601String(),
|
||
|
});
|
||
|
channel.sink.add(message);
|
||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||
|
SnackBar(content: Text('Status "$status" sent!')),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
Widget _buildMessageItem(Map<String, dynamic> message) {
|
||
|
return Padding(
|
||
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||
|
child: Align(
|
||
|
alignment: Alignment.centerLeft,
|
||
|
child: Container(
|
||
|
padding: const EdgeInsets.all(10),
|
||
|
decoration: BoxDecoration(
|
||
|
color: Colors.blue.shade50,
|
||
|
borderRadius: BorderRadius.circular(12),
|
||
|
),
|
||
|
child: Column(
|
||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||
|
children: [
|
||
|
Row(
|
||
|
children: [
|
||
|
CircleAvatar(
|
||
|
radius: 20,
|
||
|
backgroundImage: message['Image'] != null
|
||
|
? Image.memory(base64Decode(message['Image'])).image
|
||
|
: const AssetImage('assets/default_logo.png'),
|
||
|
),
|
||
|
const SizedBox(width: 8),
|
||
|
Text(
|
||
|
"${message['Name']}",
|
||
|
style: const TextStyle(
|
||
|
fontSize: 16, fontWeight: FontWeight.bold),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
const SizedBox(height: 4),
|
||
|
Text(
|
||
|
"Received at: ${message['Timestamp']}",
|
||
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
final prefsProvider = Provider.of<SharedPreferencesProvider>(context);
|
||
|
final userName = prefsProvider.getUserName();
|
||
|
final userLogo = prefsProvider.getUserLogo();
|
||
|
final userId = prefsProvider.getUserId();
|
||
|
|
||
|
return Scaffold(
|
||
|
appBar: AppBar(
|
||
|
title: const Text('Pogdark'),
|
||
|
backgroundColor: Colors.blueAccent,
|
||
|
actions: [
|
||
|
IconButton(
|
||
|
icon: const Icon(Icons.edit),
|
||
|
onPressed: _navigateToEditProfile,
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
body: StreamBuilder(
|
||
|
stream: controller.stream,
|
||
|
builder: (context, snapshot) {
|
||
|
if (snapshot.hasData) {
|
||
|
final newMessage =
|
||
|
jsonDecode(snapshot.data as String) as Map<String, dynamic>;
|
||
|
|
||
|
// Update messages only if new or modified
|
||
|
final incomingId = newMessage['Id'];
|
||
|
messages.removeWhere((msg) => msg['Id'] == incomingId);
|
||
|
if (newMessage['Status'] != 'expired' ||
|
||
|
newMessage['Status'] != "is leaving") {
|
||
|
messages.add(newMessage);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Separate messages by status
|
||
|
final onTheWayMessages = _getMessagesByStatus('is on the way');
|
||
|
final arrivedMessages = _getMessagesByStatus('has arrived');
|
||
|
|
||
|
return Padding(
|
||
|
padding: const EdgeInsets.all(8.0),
|
||
|
child: Column(
|
||
|
children: [
|
||
|
Expanded(
|
||
|
child: Row(
|
||
|
children: [
|
||
|
// Column for "On the way" messages
|
||
|
Expanded(
|
||
|
child: Column(
|
||
|
children: [
|
||
|
const Text(
|
||
|
'On the Way',
|
||
|
style: TextStyle(
|
||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||
|
),
|
||
|
Expanded(
|
||
|
child: ListView.builder(
|
||
|
itemCount: onTheWayMessages.length,
|
||
|
itemBuilder: (context, index) {
|
||
|
return _buildMessageItem(
|
||
|
onTheWayMessages[index]);
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
// Column for "Arrived" messages
|
||
|
Expanded(
|
||
|
child: Column(
|
||
|
children: [
|
||
|
const Text(
|
||
|
'Arrived',
|
||
|
style: TextStyle(
|
||
|
fontSize: 18, fontWeight: FontWeight.bold),
|
||
|
),
|
||
|
Expanded(
|
||
|
child: ListView.builder(
|
||
|
itemCount: arrivedMessages.length,
|
||
|
itemBuilder: (context, index) {
|
||
|
return _buildMessageItem(
|
||
|
arrivedMessages[index]);
|
||
|
},
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
),
|
||
|
Row(
|
||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||
|
children: [
|
||
|
ElevatedButton(
|
||
|
onPressed: () => _sendStatus(
|
||
|
userId, userName, userLogo, 'is on the way'),
|
||
|
child: const Text('On the Way'),
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: () => _sendStatus(
|
||
|
userId, userName, userLogo, 'has arrived'),
|
||
|
child: const Text('Arrived'),
|
||
|
),
|
||
|
ElevatedButton(
|
||
|
onPressed: () =>
|
||
|
_sendStatus(userId, userName, userLogo, 'is leaving'),
|
||
|
child: const Text('Leaving'),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
},
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
channel.sink.close();
|
||
|
super.dispose();
|
||
|
}
|
||
|
}
|