diff --git a/README.md b/README.md index 5f795fd..c6527c0 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ # plantapp -VUT FIT - ITU project: plant care \ No newline at end of file +VUT FIT - ITU project: plant care + +## Inštalácia + +1. Stiahnite si aplikáciu (.apk) zo zdieľaného priečinka: https://drive.google.com/drive/folders/1sQ4Ks0TKdQL-SqnuJswaQkFLdi0TJEVA?usp=sharing + +2. Presuňte aplikáciu do android telefónu + +3. V telefóne nájdite a spustite .apk súbor, aplikácia sa nainštaluje + +## Závislosti + +cupertino_icons: https://pub.dev/packages/cupertino_icons/license +google_fonts: https://fonts.google.com/ (Free, Open Source Software) +path_provider: https://pub.dev/packages/path_provider/license +table_calendar: https://pub.dev/packages/table_calendar/license +image_picker: https://pub.dev/packages/image_picker/license \ No newline at end of file diff --git a/assets/tasks.json b/assets/tasks.json index f7ffca7..358dadb 100644 --- a/assets/tasks.json +++ b/assets/tasks.json @@ -3,39 +3,34 @@ "databaseId" : 1, "nickname" : "Sal", "needWater" : 1, - "needFertilizer" : 0, - "date" : "2023-12-17" + "needFertilizer" : 0 }, { "databaseId" : 6, "nickname" : "Joey", "needWater" : 1, - "needFertilizer": 0, - "date" : "2023-12-17" + "needFertilizer": 0 }, { "databaseId" : 7, "nickname" : "Eldrani, the Chosen One", "needWater" : 0, - "needFertilizer": 1, - "date" : "2023-12-17" + "needFertilizer": 1 }, { "databaseId" : 8, "nickname" : "Jenny", "needWater" : 1, - "needFertilizer": 0, - "date" : "2023-12-17" + "needFertilizer": 0 }, { "databaseId" : 8, "nickname" : "Jenny", "needWater" : 0, - "needFertilizer": 1, - "date" : "2023-12-17" + "needFertilizer": 1 } ] \ No newline at end of file diff --git a/assets/userCollections.json b/assets/userCollections.json index d7953f2..9541e19 100644 --- a/assets/userCollections.json +++ b/assets/userCollections.json @@ -1,6 +1,6 @@ [ { - "collName" : "_DEFAULT_", + "collName" : "My Plants", "plantIds" : [1], "plantNames" : ["Sal"] }, diff --git a/lib/controller/achievements_controller.dart b/lib/controller/achievements_controller.dart index f429a49..211150b 100644 --- a/lib/controller/achievements_controller.dart +++ b/lib/controller/achievements_controller.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Used to retrieve, modify and store achievement data +*/ + // ignore_for_file: avoid_print import 'dart:io'; diff --git a/lib/controller/calendar_controller.dart b/lib/controller/calendar_controller.dart index fca8f13..ef251d1 100644 --- a/lib/controller/calendar_controller.dart +++ b/lib/controller/calendar_controller.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'dart:io'; import 'package:flutter/services.dart' show rootBundle; +import 'package:path_provider/path_provider.dart'; import 'package:plantapp/model/task_model.dart'; /// Example event class. @@ -27,8 +29,36 @@ Future> loadTasksFromJson() async { String jsonString = await rootBundle.loadString('assets/tasks.json'); final List parsedJson = json.decode(jsonString); - final List plants = parsedJson.map((eventJson) => Task.fromJson(eventJson)).toList(); - + final List plants = + parsedJson.map((eventJson) => Task.fromJson(eventJson)).toList(); + + List tasks = []; + + for (final plant in plants) { + if (plant.needWater == 1) { + tasks.add(Event("${plant.nickname} | Needs Watering", plant.date)); + } else { + tasks.add(Event("${plant.nickname} | Needs Fertilizing", plant.date)); + } + } + + return tasks; + } catch (e) { + // ignore: avoid_print + print('Error loading tasks from JSON: $e'); + return []; + } +} + +Future> loadTasksFromFile() async { + try { + final file = await _localFile; + String jsonString = await file.readAsString(); + final List parsedJson = json.decode(jsonString); + + final List plants = + parsedJson.map((eventJson) => Task.fromJson(eventJson)).toList(); + List tasks = []; for (final plant in plants) { @@ -47,6 +77,17 @@ Future> loadTasksFromJson() async { } } +Future get _localFile async { + final path = await _localPath; + return File('$path/tasks.json'); +} + +Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + + return directory.path; +} + final kToday = DateTime.now(); final kFirstDay = DateTime(kToday.year, kToday.month - 3, kToday.day); -final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); \ No newline at end of file +final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day); diff --git a/lib/controller/coll_controller.dart b/lib/controller/coll_controller.dart index a3c67e3..bff79a9 100644 --- a/lib/controller/coll_controller.dart +++ b/lib/controller/coll_controller.dart @@ -4,6 +4,9 @@ It includes methods for loading plant data from an asset, saving new plants, updating existing plants, retrieving a specific plant, deleting a plant, and performing calculations related to plant actions. The class uses the PlantController and TaskController classes for additional functionality. + + Co-Author: Timotej Halenár + Contribution: Added task scheduling functionality. */ // ignore_for_file: avoid_print @@ -16,7 +19,7 @@ import 'package:plantapp/model/coll_model.dart'; import 'package:plantapp/model/task_model.dart'; import 'task_controller.dart'; import 'plant_controller.dart'; - +import 'usercoll_controller.dart'; class CollController { List _collection = []; @@ -35,61 +38,66 @@ class CollController { } Future savePlant(Collection newPlant) async { - await loadPlantsFromFile(); - _collection.add(newPlant); - print("databaseId: ${newPlant.databaseId}"); + await loadPlantsFromFile(); + _collection.add(newPlant); + print("databaseId: ${newPlant.databaseId}"); - Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); - String imageDirectory = "${appDocumentsDirectory.path}/images"; + Directory appDocumentsDirectory = await getApplicationDocumentsDirectory(); + String imageDirectory = "${appDocumentsDirectory.path}/images"; - // Create the directory if it doesn't exist - await Directory(imageDirectory).create(recursive: true); + // Create the directory if it doesn't exist + await Directory(imageDirectory).create(recursive: true); - String imagePath = "$imageDirectory/${newPlant.databaseId}.jpg"; + String imagePath = "$imageDirectory/${newPlant.databaseId}.jpg"; - // Save the image file - if (newPlant.imageFile != null) { - // Save the image file to the specified path - await newPlant.imageFile!.copy(imagePath); - newPlant.photo = imagePath; - } + // Save the image file + if (newPlant.imageFile != null) { + // Save the image file to the specified path + await newPlant.imageFile!.copy(imagePath); + newPlant.photo = imagePath; + } - await _writeToFile(_collection); - - TaskController taskController = TaskController(); - await taskController.loadTasksFromFile(); - - PlantController plantController = PlantController(); - await plantController.loadPlantsFromAsset(); - int waterInterval = - plantController.plants[newPlant.databaseId - 1].wateringPeriod; - int fertilizeInterval = - plantController.plants[newPlant.databaseId - 1].fertilizingPeriod; - - DateTime waterDate = - newPlant.lastWatered.add(Duration(days: waterInterval)); - DateTime fertilizeDate = - newPlant.lastFertilized.add(Duration(days: fertilizeInterval)); - - Task waterTask = Task( - databaseId: newPlant.databaseId, - nickname: newPlant.nickname, - needWater: 1, - needFertilizer: 0, - date: waterDate); - - Task fertilizeTask = Task( - databaseId: newPlant.databaseId, - nickname: newPlant.nickname, - needWater: 0, - needFertilizer: 1, - date: fertilizeDate); - - taskController.tasks.add(waterTask); - taskController.tasks.add(fertilizeTask); - String encoded = jsonEncode(taskController.tasks); - taskController.writeTasks(encoded); -} + await _writeToFile(_collection); + + TaskController taskController = TaskController(); + await taskController.loadTasksFromFile(); + + PlantController plantController = PlantController(); + await plantController.loadPlantsFromAsset(); + int waterInterval = + plantController.plants[newPlant.databaseId - 1].wateringPeriod; + int fertilizeInterval = + plantController.plants[newPlant.databaseId - 1].fertilizingPeriod; + + DateTime waterDate = + newPlant.lastWatered.add(Duration(days: waterInterval)); + DateTime fertilizeDate = + newPlant.lastFertilized.add(Duration(days: fertilizeInterval)); + + Task waterTask = Task( + databaseId: newPlant.databaseId, + nickname: newPlant.nickname, + needWater: 1, + needFertilizer: 0, + date: waterDate); + + Task fertilizeTask = Task( + databaseId: newPlant.databaseId, + nickname: newPlant.nickname, + needWater: 0, + needFertilizer: 1, + date: fertilizeDate); + + taskController.tasks.add(waterTask); + taskController.tasks.add(fertilizeTask); + String encoded = jsonEncode(taskController.tasks); + taskController.writeTasks(encoded); + + UserCollController userCollController = UserCollController(); + await userCollController.loadCollectionsFromFile(); + + userCollController.addPlantToCollectionByPlant(newPlant); + } Future _writeToFile(List plants) async { try { @@ -151,6 +159,28 @@ class CollController { _writeToFile(_collection); } + Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + + return directory.path; + } + + Future get _localFile async { + final path = await _localPath; + return File('$path/plantColl.json'); + } + + void seedIfNoFileExists() async { + final file = await _localFile; + bool fileExists = await file.exists(); + if (fileExists) { + print('file do be existin doe'); + } else { + print('file aint there brudda'); + seedFile(); + } + } + int calculateDaysUntilNextAction(DateTime lastDate, int period) { // Calculate the next watering date DateTime nextDate = lastDate.add(Duration(days: period)); diff --git a/lib/controller/collection_controller.dart b/lib/controller/collection_controller.dart deleted file mode 100644 index 1a93d4b..0000000 --- a/lib/controller/collection_controller.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/services.dart'; -import 'package:plantapp/model/collection_model.dart'; - -class CollectionController { - List _tasks = []; - - List get tasks => _tasks; - - Future loadPlantsFromAsset() async { - try { - final String data = - await rootBundle.loadString('assets/plantCollection.json'); - final List jsonData = json.decode(data); - _tasks = jsonData.map((e) => Plant.fromJson(e)).toList(); - } catch (e) { - // Handle errors or exceptions - // ignore: avoid_print - print('Error loading data: $e'); - } - } - - String waterOrFertilize(Plant plant) { - if (plant.needWater == 1 && plant.needFertilizer == 0) { - return "water"; - } else if (plant.needFertilizer == 1 && plant.needWater == 0) { - return "fertilize"; - } else { - return "problem"; - } - } -} diff --git a/lib/controller/task_controller.dart b/lib/controller/task_controller.dart index d313481..26d4105 100644 --- a/lib/controller/task_controller.dart +++ b/lib/controller/task_controller.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Used to retrieve, modify and store task data, + provides converter functions +*/ // ignore_for_file: avoid_print, curly_braces_in_flow_control_structures import 'dart:convert'; diff --git a/lib/controller/usercoll_controller.dart b/lib/controller/usercoll_controller.dart index 230ca3c..c373ad4 100644 --- a/lib/controller/usercoll_controller.dart +++ b/lib/controller/usercoll_controller.dart @@ -1,8 +1,19 @@ +/* + Author: Tomáš Mikát + Description: Controller for page for user's collections + + Co-Author: Timotej Halenár + Contribution: addPlantToCollectionByPlant() method. +*/ + +// ignore_for_file: prefer_const_constructors, avoid_print, prefer_const_literals_to_create_immutables + import 'dart:convert'; import 'dart:io'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; import 'package:plantapp/model/usercoll_model.dart'; +import 'package:plantapp/model/coll_model.dart'; class UserCollController { List _colls = []; @@ -11,11 +22,11 @@ class UserCollController { Future loadCollectionsFromAsset() async { try { - final String data = await rootBundle.loadString('assets/userCollections.json'); + final String data = + await rootBundle.loadString('assets/userCollections.json'); final List jsonData = json.decode(data); _colls = jsonData.map((e) => UserColl.fromJson(e)).toList(); } catch (e) { - // ignore: avoid_print print('Error loading data: $e'); } } @@ -47,10 +58,9 @@ class UserCollController { } } - Future newCollection(UserColl newColl) async { + Future newCollection(String collName) async { await loadCollectionsFromFile(); - _colls.add(newColl); - print("collName: ${newColl.collName}"); + _colls.add(UserColl(collName: collName, plantIds: [], plantNames: [])); await _writeToFile(_colls); } @@ -79,6 +89,13 @@ class UserCollController { await _writeToFile(_colls); } + Future addPlantToCollectionByPlant(Collection plant) async { + await loadCollectionsFromFile(); + _colls[0].plantIds.add(plant.databaseId); + _colls[0].plantNames.add(plant.nickname); + await _writeToFile(_colls); + } + Future removePlantFromCollection(int plantIndex, int collIndex) async { await loadCollectionsFromFile(); _colls[0].plantIds.add(_colls[collIndex].plantIds[plantIndex]); @@ -88,14 +105,30 @@ class UserCollController { await _writeToFile(_colls); } - Future getCollection(int collName) async { - await loadCollectionsFromFile(); - return _colls.firstWhere((coll) => coll.collName == collName); - } - void seedFile() async { await loadCollectionsFromAsset(); _writeToFile(_colls); } -} \ No newline at end of file + Future get _localPath async { + final directory = await getApplicationDocumentsDirectory(); + + return directory.path; + } + + Future get _localFile async { + final path = await _localPath; + return File('$path/userCollections.json'); + } + + void seedIfNoFileExists() async { + final file = await _localFile; + bool fileExists = await file.exists(); + if (fileExists) { + print('file do be existin doe'); + } else { + print('file aint there brudda'); + seedFile(); + } + } +} diff --git a/lib/homepage.dart b/lib/homepage.dart deleted file mode 100644 index 0b7027a..0000000 --- a/lib/homepage.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'package:flutter/material.dart'; -import 'controller/collection_controller.dart'; -import 'controller/plant_controller.dart'; - -class HomePage extends StatefulWidget { - const HomePage({super.key}); - - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State { - @override - Widget build(BuildContext context) { - return const Scaffold( - body: PlantCard(), - ); - } -} - -class PlantCard extends StatefulWidget { - const PlantCard({super.key}); - - @override - State createState() => _PlantCardState(); -} - -class _PlantCardState extends State { - var collectionController = CollectionController(); - var plantController = PlantController(); - - Future loadScreen() async { - await collectionController.loadPlantsFromAsset(); - await plantController.loadPlantsFromAsset(); - setState(() {}); - } - - @override - void initState() { - loadScreen(); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Center( - child: SizedBox( - height: 300, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - return Card( - margin: const EdgeInsets.all(20), - child: Padding( - padding: const EdgeInsets.all(16), - child: SizedBox( - width: 150, - child: Column( - children: [ - const CircleAvatar( - backgroundImage: - AssetImage('assets/images/monstera.jpg'), - radius: 40, - ), - Align( - alignment: Alignment.centerLeft, - child: Text( - collectionController.tasks[index].nickname, - style: Theme.of(context).textTheme.titleLarge, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - Align( - alignment: Alignment.centerLeft, - child: Text( - plantController - .plants[ - collectionController.tasks[index].databaseId - - 1] - .latin, - style: Theme.of(context).textTheme.titleMedium, - ), - ), - Expanded( - child: Align( - alignment: Alignment.bottomCenter, - child: FilledButton.tonal( - onPressed: onpressed, - child: Text( - collectionController.waterOrFertilize( - collectionController.tasks[index]), - style: Theme.of(context).textTheme.labelMedium, - )), - ), - ), - ], - ), - ), - ), - ); - }, - itemCount: collectionController.tasks.length, - ), - ), - ); - } -} - -void onpressed() {} diff --git a/lib/main.dart b/lib/main.dart index 601338b..6d899b2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,3 +1,9 @@ +/* + Author: Timotej Halenár + Description: Main file. Renders bottom navigation bar and provides + navigation to all other pages. Contains theme definition. Contains + seeding function calls. +*/ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; import 'view/homepage.dart'; @@ -10,7 +16,6 @@ import 'controller/coll_controller.dart'; import 'controller/usercoll_controller.dart'; import 'controller/achievements_controller.dart'; - void main() { runApp(const MyApp()); //seeders, remove when deploying @@ -18,10 +23,16 @@ void main() { var collController = CollController(); var usercollController = UserCollController(); var achController = AchievementsController(); + taskController.seedFile(); collController.seedFile(); usercollController.seedFile(); achController.seedFile(); + + /*taskController.seedIfNoFileExists(); + collController.seedIfNoFileExists(); + usercollController.seedIfNoFileExists(); + achController.seedIfNoFileExists();*/ } class MyApp extends StatelessWidget { diff --git a/lib/model/achievement_model.dart b/lib/model/achievement_model.dart index 799f779..393d9ad 100644 --- a/lib/model/achievement_model.dart +++ b/lib/model/achievement_model.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Represents an achievement, provides factory to create + achievements from JSON and encode data as JSON +*/ class Achievement { int databaseId; String nickname; diff --git a/lib/model/collection_model.dart b/lib/model/collection_model.dart deleted file mode 100644 index f1eb8d5..0000000 --- a/lib/model/collection_model.dart +++ /dev/null @@ -1,27 +0,0 @@ -class Plant { - int databaseId; - String nickname; - int needWater; - int needFertilizer; - - Plant( - {required this.databaseId, - required this.nickname, - required this.needWater, - required this.needFertilizer}); - - factory Plant.fromJson(Map json) { - return Plant( - databaseId: json["databaseId"], - nickname: json["nickname"], - needWater: json["needWater"], - needFertilizer: json["needFertilizer"]); - } - - Map toJson() => { - 'databaseId': databaseId, - 'nickname': nickname, - 'needWater': needWater, - 'needFertilizer': needFertilizer - }; -} diff --git a/lib/model/task_model.dart b/lib/model/task_model.dart index 6efb163..e81be14 100644 --- a/lib/model/task_model.dart +++ b/lib/model/task_model.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Represents a task, provides factory to create + tasks from JSON and encode data as JSON +*/ class Task { int databaseId; String nickname; @@ -18,7 +23,15 @@ class Task { nickname: json["nickname"], needWater: json["needWater"], needFertilizer: json["needFertilizer"], - date: DateTime.parse(json["date"])); + date: returnDate(json)); + } + + static DateTime returnDate(Map json) { + if (json.containsKey("date")) { + return DateTime.parse(json["date"]); + } else { + return DateTime.now(); + } } Map toJson() => { diff --git a/lib/view/achievements.dart b/lib/view/achievements.dart index ab4ff6f..c2888fb 100644 --- a/lib/view/achievements.dart +++ b/lib/view/achievements.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Achievements View. Renders incomplete and completed + achievements +*/ // ignore_for_file: prefer_const_constructors import 'package:flutter/material.dart'; @@ -197,27 +202,23 @@ class LineProgOrNot extends StatefulWidget { final Achievement achievement; @override - State createState() => _LineProgOrNotState(achievement); + State createState() => _LineProgOrNotState(); } class _LineProgOrNotState extends State with TickerProviderStateMixin { - _LineProgOrNotState(this.achievement); - late AnimationController controller; - final Achievement achievement; + //Achievement achievement; @override void initState() { controller = AnimationController( - /// [AnimationController]s can be created with `vsync: this` because of - /// [TickerProviderStateMixin]. vsync: this, duration: const Duration(seconds: 1), )..addListener(() { setState(() {}); }); - controller.animateTo(achievement.current / achievement.max); + controller.animateTo(widget.achievement.current / widget.achievement.max); super.initState(); } diff --git a/lib/view/calendar.dart b/lib/view/calendar.dart index 988408a..ac41271 100644 --- a/lib/view/calendar.dart +++ b/lib/view/calendar.dart @@ -34,9 +34,9 @@ class _CalendarState extends State { } Future loadEvents() async { - List events = await loadTasksFromJson(); + List events = await loadTasksFromFile(); setState(() { - _events = events; + _events = events; _selectedEvents.value = events; }); } @@ -48,14 +48,12 @@ class _CalendarState extends State { } List _getEventsForDay(DateTime day) { - return _events - .where((event) => isSameDay(event.date, day)) - .toList(); + return _events.where((event) => isSameDay(event.date, day)).toList(); } List _getEventsForRange(DateTime start, DateTime end) { List events = []; - + for (DateTime day in daysInRange(start, end)) { events.addAll(_getEventsForDay(day)); } @@ -75,7 +73,6 @@ class _CalendarState extends State { // Load events for the selected day _selectedEvents.value = _getEventsForDay(selectedDay); - } } @@ -164,4 +161,4 @@ class _CalendarState extends State { ), ); } -} \ No newline at end of file +} diff --git a/lib/view/homepage.dart b/lib/view/homepage.dart index a3450de..1e31cfe 100644 --- a/lib/view/homepage.dart +++ b/lib/view/homepage.dart @@ -1,3 +1,8 @@ +/* + Author: Timotej Halenár + Description: Homepage View. Renders tasks, provides functionality + to mark task as finished, renders incomplete achievements +*/ import 'package:flutter/material.dart'; import 'package:plantapp/controller/task_controller.dart'; import 'package:plantapp/controller/achievements_controller.dart'; diff --git a/lib/view/plant_collection.dart b/lib/view/plant_collection.dart index 1684188..3900031 100644 --- a/lib/view/plant_collection.dart +++ b/lib/view/plant_collection.dart @@ -81,6 +81,48 @@ class _PlantInstState extends State { ); } + Future _dialogNewCollection(BuildContext context) { + return showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('New Collection'), + content: TextField( + controller: usercollsController, + decoration: InputDecoration( + hintText: 'Name', + hintStyle: TextStyle(color: Colors.grey), + contentPadding: + EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + border: OutlineInputBorder(), + ), + ), + actions: [ + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Create'), + onPressed: () async { + await collCont.newCollection(usercollsController.text); + Navigator.of(context).pop(); + }, + ), + TextButton( + style: TextButton.styleFrom( + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: const Text('Cancel'), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ], + ); + }, + ); + } + Future _dialogChangeName(BuildContext context) { return showDialog( context: context, @@ -88,15 +130,15 @@ class _PlantInstState extends State { return AlertDialog( title: const Text('Rename Collection'), content: TextField( - controller: usercollsController, - decoration: InputDecoration( - hintText: 'New Name', - hintStyle: TextStyle(color: Colors.grey), - contentPadding: - EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), - border: OutlineInputBorder(), - ), - ), + controller: usercollsController, + decoration: InputDecoration( + hintText: 'New Name', + hintStyle: TextStyle(color: Colors.grey), + contentPadding: + EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0), + border: OutlineInputBorder(), + ), + ), actions: [ TextButton( style: TextButton.styleFrom( @@ -160,20 +202,20 @@ class _PlantInstState extends State { context: context, builder: (BuildContext context) { return AlertDialog( - title: const Text('Add Plant'), - content: Expanded( - child: ListView.builder( - itemCount: collCont.colls[0].plantIds.length, - itemBuilder: (context, index) { - return ElevatedButton( + content: Container( + height: 200, // Set a specific height + child: Column( + children: List.generate( + collCont.colls[0].plantIds.length, + (index) => ElevatedButton( onPressed: () async { await collCont.addPlantToCollection(index, selectedCollectionIndex); Navigator.of(context).pop(); }, - child: Text('${collCont.colls[index].plantIds}'), - ); - }, + child: Text('${collCont.colls[0].plantNames[index]}'), + ), + ), ), ), actions: [ @@ -198,18 +240,19 @@ class _PlantInstState extends State { builder: (BuildContext context) { return AlertDialog( title: const Text('Remove Plant'), - content: Expanded( - child: ListView.builder( - itemCount: collCont.colls[selectedCollectionIndex].plantIds.length, - itemBuilder: (context, index) { - return ElevatedButton( + content: Container( + height: 200, // Set a specific height + child: Column( + children: List.generate( + collCont.colls[selectedCollectionIndex].plantIds.length, + (index) => ElevatedButton( onPressed: () async { await collCont.removePlantFromCollection(index, selectedCollectionIndex); Navigator.of(context).pop(); }, - child: Text('${collCont.colls[index].plantIds}'), - ); - }, + child: Text('${collCont.colls[selectedCollectionIndex].plantNames[index]}'), + ), + ), ), ), actions: [ @@ -231,7 +274,16 @@ class _PlantInstState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("User's Collections")), + appBar: AppBar(title: Row( + children: [ + Text("User's Collections"), + Spacer(), + GestureDetector( + onTap: () => _dialogNewCollection(context), + child: Icon(Icons.add, size: 40.0) + ), + ] + )), body: ListView.builder( itemCount: collCont.colls.length, itemBuilder: (context, index) => ListTile( @@ -322,4 +374,4 @@ class _PlantInstState extends State { ])))); }); } -} +} \ No newline at end of file