fix: resolve errors in MultiStreamBuilder and income display

This commit is contained in:
2025-05-04 16:04:30 +03:00
parent 305f263735
commit 7e3a759282
+37 -15
View File
@@ -3,6 +3,8 @@ import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart'; // Used indirectly by SpendingPieChart
import 'package:intl/intl.dart'; // For date formatting
import 'dart:async';
import 'package:async/async.dart'; // Import StreamZip
// Removed import 'dart:math'; // No longer needed for random data
import '../database/database.dart' as db; // Import database with prefix 'db'
@@ -226,10 +228,12 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
],
builder: (context, snapshots) {
// Handle loading states for all streams
// FIX: Call .any on the list `snapshots`
if (snapshots.any((s) => s.connectionState == ConnectionState.waiting && !s.hasData)) {
return const Center(child: CircularProgressIndicator());
}
// Handle error states for all streams
// FIX: Call .any on the list `snapshots`
if (snapshots.any((s) => s.hasError)) {
// Combine error messages or show a generic one
String errors = snapshots.where((s) => s.hasError).map((s) => s.error.toString()).join('\n');
@@ -495,9 +499,10 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
// Get the db.Transaction object from the stream
final dbTransaction = transactions[index];
// Get the corresponding category details (icon, color) - use defaults for income
final categoryDetails = dbTransaction.type == 'expense'
// FIX: Define icon/color directly for income, no CategoryDetails class
final ({IconData iconCode, Color colorCode}) categoryDetails = dbTransaction.type == 'expense'
? CategoryUtils.getCategoryDetails(dbTransaction.categoryName)
: CategoryDetails( // Default/Placeholder for Income type
: ( // Default/Placeholder for Income type
iconCode: Icons.attach_money, // Or a more specific income icon
colorCode: Colors.green,
);
@@ -580,6 +585,7 @@ class _ExpensesScreenState extends State<ExpensesScreen> with TickerProviderStat
// Helper widget to manage multiple streams for the main body
class MultiStreamBuilder extends StatelessWidget {
final List<Stream<dynamic>> streams;
// FIX: Use AsyncWidgetBuilder<List<AsyncSnapshot<dynamic>>> for clarity
final AsyncWidgetBuilder<List<AsyncSnapshot<dynamic>>> builder;
const MultiStreamBuilder({
@@ -595,19 +601,35 @@ class MultiStreamBuilder extends StatelessWidget {
stream: StreamZip(streams), // Use StreamZip to combine latest values
builder: (context, snapshot) {
// Create a list of AsyncSnapshot objects from the combined snapshot data
final List<AsyncSnapshot<dynamic>> snapshots = streams.map((stream) {
// Find the corresponding data in the combined snapshot
// This assumes StreamZip maintains order, which it does.
int index = streams.indexOf(stream);
dynamic data = snapshot.hasData ? snapshot.data![index] : null;
// Reconstruct individual AsyncSnapshot states
return AsyncSnapshot<dynamic>(
connectionState: snapshot.connectionState,
data: data,
error: snapshot.error, // Note: StreamZip might only report the first error
stackTrace: snapshot.stackTrace,
);
}).toList();
final List<AsyncSnapshot<dynamic>> snapshots = List.generate(
streams.length,
(index) {
// Reconstruct individual AsyncSnapshot states based on the combined snapshot
if (snapshot.connectionState == ConnectionState.waiting && !snapshot.hasData) {
// If waiting and no data yet, return waiting snapshot
return AsyncSnapshot<dynamic>.waiting();
}
if (snapshot.hasError) {
// If combined stream has error, propagate error
// Note: StreamZip might only report the first error
return AsyncSnapshot<dynamic>.withError(
snapshot.connectionState,
snapshot.error!,
snapshot.stackTrace ?? StackTrace.empty,
);
}
if (snapshot.hasData) {
// If data exists, extract the data for this specific stream index
return AsyncSnapshot<dynamic>.withData(
snapshot.connectionState,
snapshot.data![index], // Assumes StreamZip maintains order
);
}
// Default/fallback case (e.g., ConnectionState.none)
return AsyncSnapshot<dynamic>.nothing();
},
growable: false, // Fixed-size list
);
return builder(context, snapshots);
},