refactor: improve MultiStreamBuilder and snapshot handling
This commit is contained in:
@@ -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));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user