import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Named Pipe Stream Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: StreamListenerPage(),
);
}
}
class StreamListenerPage extends StatefulWidget {
@override
_StreamListenerPageState createState() => _StreamListenerPageState();
}
class _StreamListenerPageState extends State<StreamListenerPage> {
StreamSubscription<String>? _streamSubscription;
String _currentState = 'unknown';
List<String> _events = [];
bool _isListening = false;
@override
void initState() {
super.initState();
_startListening();
}
@override
void dispose() {
_streamSubscription?.cancel();
super.dispose();
}
void _startListening() {
setState(() {
_isListening = true;
});
_streamSubscription = _createPipeStream().listen(
(data) {
setState(() {
_events.add('${DateTime.now()}: $data');
// Simple state detection based on message content
if (data.toLowerCase().contains('signed in') ||
data.toLowerCase().contains('authenticated') ||
data.toLowerCase().contains('logged in')) {
_currentState = 'signed_in';
} else if (data.toLowerCase().contains('signed out') ||
data.toLowerCase().contains('logged out') ||
data.toLowerCase().contains('unauthenticated')) {
_currentState = 'signed_out';
}
});
},
onError: (error) {
setState(() {
_events.add('Error: $error');
_isListening = false;
});
},
onDone: () {
setState(() {
_isListening = false;
});
},
);
}
Stream<String> _createPipeStream() {
final controller = StreamController<String>();
// Path to your named pipe
const pipePath = '/tmp/auth_stream';
Timer.periodic(Duration(milliseconds: 500), (timer) async {
try {
final file = File(pipePath);
if (await file.exists()) {
// Try to read from the pipe (non-blocking)
try {
final process = await Process.start('timeout', [
'0.1',
'cat',
pipePath,
]);
process.stdout.transform(const SystemEncoding().decoder).listen((
data,
) {
final lines = data.trim().split('\n');
for (final line in lines) {
if (line.isNotEmpty) {
controller.add(line);
}
}
});
await process.exitCode;
} catch (e) {
// Pipe might be empty or blocked, continue listening
}
}
} catch (e) {
controller.addError('Failed to read from pipe: $e');
timer.cancel();
}
});
return controller.stream;
}
void _stopListening() {
_streamSubscription?.cancel();
setState(() {
_isListening = false;
});
}
void _clearEvents() {
setState(() {
_events.clear();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _buildCurrentScreen(),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: _isListening ? _stopListening : _startListening,
child: Icon(_isListening ? Icons.stop : Icons.play_arrow),
backgroundColor: _isListening ? Colors.red : Colors.green,
heroTag: "listen_btn",
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: _clearEvents,
child: Icon(Icons.clear),
backgroundColor: Colors.orange,
heroTag: "clear_btn",
),
],
),
);
}
Widget _buildCurrentScreen() {
switch (_currentState) {
case 'signed_in':
return _buildSignedInScreen();
case 'signed_out':
return _buildSignedOutScreen();
default:
return _buildUnknownScreen();
}
}
Widget _buildSignedInScreen() {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.green.shade300, Colors.green.shade600],
),
),
child: Column(
children: [
Expanded(
flex: 2,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.check_circle, size: 120, color: Colors.white),
SizedBox(height: 20),
Text(
'Welcome!',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 10),
Text(
'User is signed in',
style: TextStyle(fontSize: 18, color: Colors.white70),
),
],
),
),
),
_buildEventsList(),
],
),
);
}
Widget _buildSignedOutScreen() {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.red.shade300, Colors.red.shade600],
),
),
child: Column(
children: [
Expanded(
flex: 2,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.cancel, size: 120, color: Colors.white),
SizedBox(height: 20),
Text(
'Please Sign In',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 10),
Text(
'User is currently signed out',
style: TextStyle(fontSize: 18, color: Colors.white70),
),
],
),
),
),
_buildEventsList(),
],
),
);
}
Widget _buildUnknownScreen() {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Colors.grey.shade400, Colors.grey.shade700],
),
),
child: Column(
children: [
Expanded(
flex: 2,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.help_outline, size: 120, color: Colors.white),
SizedBox(height: 20),
Text(
'Listening...',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
SizedBox(height: 10),
Text(
_isListening
? 'Waiting for auth events from /tmp/auth_stream'
: 'Not listening to pipe',
style: TextStyle(fontSize: 16, color: Colors.white70),
textAlign: TextAlign.center,
),
],
),
),
),
_buildEventsList(),
],
),
);
}
Widget _buildEventsList() {
return Expanded(
flex: 1,
child: Container(
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
children: [
Container(
padding: EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.event_note, color: Colors.white70),
SizedBox(width: 8),
Text(
'Stream Events (${_events.length})',
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Spacer(),
Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: _isListening ? Colors.green : Colors.red,
borderRadius: BorderRadius.circular(12),
),
child: Text(
_isListening ? 'LIVE' : 'STOPPED',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
Expanded(
child: _events.isEmpty
? Center(
child: Text(
'No events received yet',
style: TextStyle(color: Colors.white54),
),
)
: ListView.builder(
reverse: true,
itemCount: _events.length,
itemBuilder: (context, index) {
final event = _events[_events.length - 1 - index];
return Container(
margin: EdgeInsets.symmetric(
horizontal: 16,
vertical: 2,
),
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white10,
borderRadius: BorderRadius.circular(8),
),
child: Text(
event,
style: TextStyle(
color: Colors.white,
fontFamily: 'monospace',
fontSize: 12,
),
),
);
},
),
),
],
),
),
);
}
}