refactor: improve MultiStreamBuilder and snapshot handling

This commit is contained in:
2025-05-04 16:43:21 +03:00
parent f411106154
commit 66ae257773
+19 -57
View File
@@ -227,31 +227,13 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
_totalExpensesStream, // Stream<double> for total expenses
],
builder: (context, snapshots) {
// Handle loading states for all streams
if (snapshots.any((s) => s.connectionState == ConnectionState.waiting && !s.hasData)) {
if (snapshots.length < 3) {
return const Center(child: CircularProgressIndicator());
}
// Handle error states for all streams
final errorSnapshots = snapshots.where((s) => s.hasError).toList();
if (errorSnapshots.isNotEmpty) {
return Center(
child: Text(
'Error loading data:\n${errorSnapshots.map((s) => s.error).join('\n')}',
textAlign: TextAlign.center,
),
);
}
// Safely extract data with proper type checking
try {
final combinedData = snapshots.data; // First access the List<dynamic> data
if (combinedData == null || combinedData.length < 3) {
return const Center(child: Text('Missing data streams'));
}
final expenseCategories = (combinedData[0] as List<Category>?) ?? [];
final totalIncome = (combinedData[1] as double?) ?? 0.0;
final totalExpenses = (combinedData[2] as double?) ?? 0.0;
final expenseCategories = snapshots[0].data as List<Category>? ?? [];
final totalIncome = snapshots[1].data as double? ?? 0.0;
final totalExpenses = snapshots[2].data as double? ?? 0.0;
// Main column layout
return Column(
@@ -590,16 +572,11 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
}
}
extension on AsyncSnapshot<List<AsyncSnapshot>> {
where(Function(dynamic s) param0) {}
any(bool Function(AsyncSnapshot s) param0) {}
}
// Helper widget to manage multiple streams for the main body
class MultiStreamBuilder extends StatelessWidget {
final List<Stream<dynamic>> streams;
final AsyncWidgetBuilder<List<AsyncSnapshot<dynamic>>> builder;
final Widget Function(BuildContext, List<AsyncSnapshot<dynamic>>) builder;
const MultiStreamBuilder({
Key? key,
@@ -609,42 +586,27 @@ class MultiStreamBuilder extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<List<dynamic>>(
stream: StreamZip(streams),
builder: (context, snapshot) {
// Handle loading state
if (snapshot.connectionState == ConnectionState.waiting) {
return StreamBuilder<List<AsyncSnapshot<dynamic>>>(
stream: _combineStreams(),
builder: (context, combinedSnapshot) {
if (combinedSnapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
// Handle errors
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
if (combinedSnapshot.hasError) {
return Center(child: Text('Error: ${combinedSnapshot.error}'));
}
// Ensure we have data
if (!snapshot.hasData) {
return const Center(child: Text('No data available'));
}
final data = snapshot.data!;
if (data.length != streams.length) {
return const Center(child: Text('Unexpected data format'));
}
// Create snapshots list
final snapshots = streams.asMap().entries.map((entry) {
final index = entry.key;
return AsyncSnapshot.withData(
ConnectionState.done,
data[index],
);
}).toList();
return builder(context, snapshots);
return builder(context, combinedSnapshot.data ?? []);
},
);
}
Stream<List<AsyncSnapshot<dynamic>>> _combineStreams() {
return StreamZip(streams.map((stream) {
return stream.map((data) => AsyncSnapshot.withData(ConnectionState.done, data));
}));
}
}