import 'package:flutter/cupertino.dart';
import '../../classes/event_class.dart';
import '../../constants.dart';
import '../../db/database.dart';
class PlantTypesList extends StatelessWidget {
const PlantTypesList({super.key});
AppDatabase get database => AppDatabase.instance;
@override
Widget build(BuildContext context) {
// To continously listen to database content, it's necessary to use [StreamBuilder]
// Stream is the function that watches [PlantTypes] table
return StreamBuilder(
stream: database.watchPlantTypes(),
builder: ((context, snapshot) {
// Snapshot data (a list of [PlantType]) are marked as 'plantTypes'
final plantTypes = snapshot.data;
if (plantTypes != null && plantTypes.isNotEmpty) {
// The ListView builder uses a plantType, which is a single row from the snapshot,
// and the 'index' paramether is needed to adress the proper query
return ListView.builder(
itemCount: plantTypes.length,
itemBuilder: (context, index) {
final plantType = plantTypes[index];
// Single record is passed to the [PlantTypeTile] widget as 'plantType'
return PlantTypeTile(plantType: plantType);
},
);
// Null-safety check
} else {
return noRecordsDisplay;
}
}),
);
}
}
// =======================================================================
// [PlantTypeTile] is the building block of PlantTypeList. PlantTypes are
// fetched from the database and forwarded to the widget as 'plantType'
class PlantTypeTile extends StatelessWidget {
final PlantType plantType;
const PlantTypeTile({
super.key,
required this.plantType
});
@override
Widget build(BuildContext context) {
// Events declaration - [EventType] is needed to determine which map should
// be used in order to get the proper [Frequency] attributes (label, days)
Event wateringEvent = Event(
plantType: plantType,
eventType: EventType.watering
);
Event fertilizingEvent = Event(
plantType: plantType,
eventType: EventType.fertilizing
);
// Due to the need of converting db records to displayed values, there's a need of
// using [FutureBuilder] - its results are stored as snapshot
return FutureBuilder<List<EventInfo>>(
// Functions that have to be done before build method is evoked
future: Future.wait([
getEventInfo(wateringEvent, 'Watering'),
getEventInfo(fertilizingEvent, 'Fertilizing'),
]),
// Build method
builder: (context, snapshot) {
// Async snapshot handler
if (snapshot.connectionState == ConnectionState.waiting) {
return const CupertinoActivityIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
// Build method if the snapshot is correct
} else if (snapshot.hasData) {
EventInfo wateringInfo = snapshot.data![0];
EventInfo fertilizingInfo = snapshot.data![1];
return CupertinoListTile.notched(
title: Text(plantType.name),
subtitle: FrequenciesInfoDisplay([
wateringInfo.description,
fertilizingInfo.description
])
);
// Null-safety check
} else {
return noRecordsDisplay;
}
},
);
}
}
// =======================================================================
// Widget used to display descriptions (excluded to keep the code clean); it has
// a positional parameter, that's a list of <Strings>
class FrequenciesInfoDisplay extends StatelessWidget {
final List<String> descriptions;
const FrequenciesInfoDisplay(this.descriptions, {super.key});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: descriptions
// Each child (labeled as 'description') is wrapped inside [Padding]
// to ensure the right amount of space
.map((description) => Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text(description),
))
.toList(),
);
}
}