Add basic CRUD with sqlite
This commit is contained in:
		
							parent
							
								
									03eaa16842
								
							
						
					
					
						commit
						82ef2bf87c
					
				|  | @ -1,13 +1,13 @@ | |||
| import 'package:flutter/material.dart'; | ||||
| import 'package:fmassive/home_page.dart'; | ||||
| import 'package:fmassive/gym_set.dart'; | ||||
| 
 | ||||
| class EditGymSetPage extends StatefulWidget { | ||||
|   final GymSet gymSet; | ||||
| 
 | ||||
|   EditGymSetPage({required this.gymSet}); | ||||
|   const EditGymSetPage({required this.gymSet, super.key}); | ||||
| 
 | ||||
|   @override | ||||
|   _EditGymSetPageState createState() => _EditGymSetPageState(); | ||||
|   createState() => _EditGymSetPageState(); | ||||
| } | ||||
| 
 | ||||
| class _EditGymSetPageState extends State<EditGymSetPage> { | ||||
|  | @ -16,17 +16,18 @@ class _EditGymSetPageState extends State<EditGymSetPage> { | |||
|   final TextEditingController _weightController = TextEditingController(); | ||||
| 
 | ||||
|   late GymSet _editedGymSet; | ||||
|   late GymSetDatabaseHelper _db; | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
|     // Initialize the edited GymSet object with the values from the input GymSet object | ||||
|     _db = GymSetDatabaseHelper.instance; | ||||
|     _editedGymSet = GymSet( | ||||
|         id: widget.gymSet.id, | ||||
|         name: widget.gymSet.name, | ||||
|         reps: widget.gymSet.reps, | ||||
|         weight: widget.gymSet.weight, | ||||
|         created: DateTime.now()); | ||||
|     // Set the text controller values | ||||
|     _nameController.text = _editedGymSet.name; | ||||
|     _repsController.text = _editedGymSet.reps.toString(); | ||||
|     _weightController.text = _editedGymSet.weight.toString(); | ||||
|  | @ -35,9 +36,15 @@ class _EditGymSetPageState extends State<EditGymSetPage> { | |||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: Text('Edit Gym Set'), | ||||
|       ), | ||||
|       appBar: AppBar(title: const Text('Edit Gym Set'), actions: [ | ||||
|         IconButton( | ||||
|             onPressed: () async { | ||||
|               await _db.delete(_editedGymSet); | ||||
|               if (!mounted) return; | ||||
|               Navigator.pop(context, _editedGymSet); | ||||
|             }, | ||||
|             icon: const Icon(Icons.delete)) | ||||
|       ]), | ||||
|       body: Padding( | ||||
|         padding: const EdgeInsets.all(16.0), | ||||
|         child: Column( | ||||
|  | @ -76,7 +83,13 @@ class _EditGymSetPageState extends State<EditGymSetPage> { | |||
|         ), | ||||
|       ), | ||||
|       floatingActionButton: FloatingActionButton( | ||||
|         onPressed: () { | ||||
|         onPressed: () async { | ||||
|           print('edited gym set id: ${_editedGymSet.id}'); | ||||
|           if (_editedGymSet.id != null) | ||||
|             await _db.update(_editedGymSet); | ||||
|           else | ||||
|             await _db.insert(_editedGymSet); | ||||
|           if (!mounted) return; | ||||
|           Navigator.pop(context, _editedGymSet); | ||||
|         }, | ||||
|         child: const Icon(Icons.check), | ||||
|  |  | |||
							
								
								
									
										103
									
								
								lib/gym_set.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								lib/gym_set.dart
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,103 @@ | |||
| import 'package:path/path.dart'; | ||||
| import 'package:sqflite/sqflite.dart'; | ||||
| 
 | ||||
| class GymSet { | ||||
|   int? id; // added id for SQLite | ||||
|   String name; | ||||
|   int reps; | ||||
|   int weight; | ||||
|   DateTime created; | ||||
| 
 | ||||
|   GymSet( | ||||
|       {this.id, | ||||
|       required this.name, | ||||
|       required this.reps, | ||||
|       required this.weight, | ||||
|       required this.created}); | ||||
| } | ||||
| 
 | ||||
| class GymSetDatabaseHelper { | ||||
|   static final _databaseName = "gym_set_database.db"; | ||||
|   static final _databaseVersion = 1; | ||||
| 
 | ||||
|   static final table = 'gym_sets'; | ||||
| 
 | ||||
|   static final columnId = '_id'; | ||||
|   static final columnName = 'name'; | ||||
|   static final columnReps = 'reps'; | ||||
|   static final columnWeight = 'weight'; | ||||
|   static final columnCreated = 'created'; | ||||
| 
 | ||||
|   GymSetDatabaseHelper._privateConstructor(); | ||||
|   static final GymSetDatabaseHelper instance = | ||||
|       GymSetDatabaseHelper._privateConstructor(); | ||||
| 
 | ||||
|   static Database? _database; | ||||
|   Future<Database> get database async { | ||||
|     if (_database != null) return _database!; | ||||
|     _database = await _initDatabase(); | ||||
|     return _database!; | ||||
|   } | ||||
| 
 | ||||
|   _initDatabase() async { | ||||
|     String path = join(await getDatabasesPath(), _databaseName); | ||||
|     return await openDatabase(path, | ||||
|         version: _databaseVersion, onCreate: _onCreate); | ||||
|   } | ||||
| 
 | ||||
|   Future _onCreate(Database db, int version) async { | ||||
|     await db.execute(''' | ||||
|           CREATE TABLE $table ( | ||||
|             $columnId INTEGER PRIMARY KEY, | ||||
|             $columnName TEXT NOT NULL, | ||||
|             $columnReps INTEGER NOT NULL, | ||||
|             $columnWeight INTEGER NOT NULL, | ||||
|             $columnCreated TEXT NOT NULL | ||||
|           ) | ||||
|           '''); | ||||
|   } | ||||
| 
 | ||||
|   Future<int> insert(GymSet gymSet) async { | ||||
|     Database db = await instance.database; | ||||
|     return await db.insert(table, { | ||||
|       columnName: gymSet.name, | ||||
|       columnReps: gymSet.reps, | ||||
|       columnWeight: gymSet.weight, | ||||
|       columnCreated: gymSet.created.toIso8601String() | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   Future<List<GymSet>> getAll() async { | ||||
|     Database db = await instance.database; | ||||
|     List<Map<String, dynamic>> result = await db.query(table); | ||||
|     return result | ||||
|         .map((gymSetMap) => GymSet( | ||||
|               id: gymSetMap[columnId], | ||||
|               name: gymSetMap[columnName], | ||||
|               reps: gymSetMap[columnReps], | ||||
|               weight: gymSetMap[columnWeight], | ||||
|               created: DateTime.parse(gymSetMap[columnCreated]), | ||||
|             )) | ||||
|         .toList(); | ||||
|   } | ||||
| 
 | ||||
|   Future<int> update(GymSet gymSet) async { | ||||
|     Database db = await instance.database; | ||||
|     return await db.update( | ||||
|         table, | ||||
|         { | ||||
|           columnName: gymSet.name, | ||||
|           columnReps: gymSet.reps, | ||||
|           columnWeight: gymSet.weight, | ||||
|           columnCreated: gymSet.created.toIso8601String() | ||||
|         }, | ||||
|         where: '$columnId = ?', | ||||
|         whereArgs: [gymSet.id]); | ||||
|   } | ||||
| 
 | ||||
|   Future<int> delete(GymSet gymSet) async { | ||||
|     Database db = await instance.database; | ||||
|     return await db | ||||
|         .delete(table, where: '$columnId = ?', whereArgs: [gymSet.id]); | ||||
|   } | ||||
| } | ||||
|  | @ -1,10 +1,11 @@ | |||
| import 'package:flutter/material.dart'; | ||||
| import 'package:fmassive/edit_set.dart'; | ||||
| import 'package:fmassive/gym_set.dart'; | ||||
| 
 | ||||
| class HomePage extends StatelessWidget { | ||||
|   HomePage({super.key}); | ||||
| 
 | ||||
|   final List<Map<String, dynamic>> _pageData = [ | ||||
|   final List<Map<String, dynamic>> routes = [ | ||||
|     {'title': 'Home', 'icon': Icons.home}, | ||||
|     {'title': 'Plans', 'icon': Icons.calendar_today}, | ||||
|     {'title': 'Best', 'icon': Icons.star}, | ||||
|  | @ -17,19 +18,19 @@ class HomePage extends StatelessWidget { | |||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|       appBar: AppBar( | ||||
|         title: Text(_pageData[0]['title']), | ||||
|         title: Text(routes[0]['title']), | ||||
|       ), | ||||
|       drawer: Drawer( | ||||
|         child: ListView.builder( | ||||
|           itemCount: _pageData.length, | ||||
|           itemCount: routes.length, | ||||
|           itemBuilder: (context, index) { | ||||
|             return ListTile( | ||||
|               leading: Icon(_pageData[index]['icon']), | ||||
|               title: Text(_pageData[index]['title']), | ||||
|               leading: Icon(routes[index]['icon']), | ||||
|               title: Text(routes[index]['title']), | ||||
|               onTap: () { | ||||
|                 Navigator.pop(context); | ||||
|                 Navigator.pushNamed( | ||||
|                     context, '/${_pageData[index]['title'].toLowerCase()}'); | ||||
|                     context, '/${routes[index]['title'].toLowerCase()}'); | ||||
|               }, | ||||
|             ); | ||||
|           }, | ||||
|  | @ -42,130 +43,105 @@ class HomePage extends StatelessWidget { | |||
|   } | ||||
| } | ||||
| 
 | ||||
| class GymSet { | ||||
|   String name; | ||||
|   int reps; | ||||
|   int weight; | ||||
|   DateTime created; | ||||
| 
 | ||||
|   GymSet( | ||||
|       {required this.name, | ||||
|       required this.reps, | ||||
|       required this.weight, | ||||
|       required this.created}); | ||||
| } | ||||
| 
 | ||||
| class GymSetPage extends StatefulWidget { | ||||
|   const GymSetPage({Key? key}) : super(key: key); | ||||
| 
 | ||||
|   @override | ||||
|   _GymSetPageState createState() => _GymSetPageState(); | ||||
|   createState() => GymSetPageState(); | ||||
| } | ||||
| 
 | ||||
| class _GymSetPageState extends State<GymSetPage> { | ||||
|   final List<GymSet> _gymSets = [ | ||||
|     GymSet( | ||||
|         name: "Bench press", | ||||
|         reps: 10, | ||||
|         weight: 50, | ||||
|         created: DateTime(2022, 1, 1)), | ||||
|     GymSet( | ||||
|         name: "Bench press", | ||||
|         reps: 8, | ||||
|         weight: 60, | ||||
|         created: DateTime(2022, 1, 2)), | ||||
|     GymSet( | ||||
|         name: "Bench press", | ||||
|         reps: 6, | ||||
|         weight: 70, | ||||
|         created: DateTime(2022, 1, 3)), | ||||
|     GymSet( | ||||
|         name: "Shoulder press", | ||||
|         reps: 12, | ||||
|         weight: 40, | ||||
|         created: DateTime(2022, 1, 4)), | ||||
|     GymSet( | ||||
|         name: "Shoulder press", | ||||
|         reps: 15, | ||||
|         weight: 35, | ||||
|         created: DateTime(2022, 1, 5)), | ||||
|   ]; | ||||
| class GymSetPageState extends State<GymSetPage> { | ||||
|   late GymSetDatabaseHelper db; | ||||
|   List<GymSet> sets = []; | ||||
| 
 | ||||
|   List<GymSet> _searchResults = []; | ||||
|   List<GymSet> searchResults = []; | ||||
| 
 | ||||
|   final TextEditingController _searchController = TextEditingController(); | ||||
|   final TextEditingController searchController = TextEditingController(); | ||||
| 
 | ||||
|   void _searchGymSets(String searchQuery) { | ||||
|   void search(String searchQuery) { | ||||
|     List<GymSet> results = []; | ||||
| 
 | ||||
|     if (searchQuery.isEmpty) { | ||||
|       results = _gymSets; | ||||
|       results = sets; | ||||
|     } else { | ||||
|       for (int i = 0; i < _gymSets.length; i++) { | ||||
|         if (_gymSets[i].reps.toString().contains(searchQuery) || | ||||
|             _gymSets[i].weight.toString().contains(searchQuery) || | ||||
|             _gymSets[i].created.toString().contains(searchQuery) || | ||||
|             _gymSets[i].name.contains(searchQuery)) { | ||||
|           results.add(_gymSets[i]); | ||||
|       for (int i = 0; i < sets.length; i++) { | ||||
|         if (sets[i].reps.toString().contains(searchQuery) || | ||||
|             sets[i].weight.toString().contains(searchQuery) || | ||||
|             sets[i].created.toString().contains(searchQuery) || | ||||
|             sets[i].name.contains(searchQuery)) { | ||||
|           results.add(sets[i]); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     setState(() { | ||||
|       _searchResults = results; | ||||
|       searchResults = results; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   void reset() async { | ||||
|     print('Resetting...'); | ||||
|     final data = await db.getAll(); | ||||
|     setState(() { | ||||
|       sets = data; | ||||
|       searchResults = data; | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   void initState() { | ||||
|     super.initState(); | ||||
| 
 | ||||
|     // Initialize the search results to all the gym sets | ||||
|     _searchResults = _gymSets; | ||||
|     db = GymSetDatabaseHelper.instance; | ||||
|     reset(); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return Scaffold( | ||||
|         appBar: AppBar( | ||||
|           automaticallyImplyLeading: false, | ||||
|           title: TextField( | ||||
|             controller: _searchController, | ||||
|             controller: searchController, | ||||
|             decoration: const InputDecoration( | ||||
|               hintText: 'Search Gym Sets', | ||||
|               border: InputBorder.none, | ||||
|             ), | ||||
|             onChanged: (searchQuery) { | ||||
|               _searchGymSets(searchQuery); | ||||
|               search(searchQuery); | ||||
|             }, | ||||
|           ), | ||||
|         ), | ||||
|         body: ListView.builder( | ||||
|           itemCount: _searchResults.length, | ||||
|           itemCount: searchResults.length, | ||||
|           itemBuilder: (context, index) { | ||||
|             return ListTile( | ||||
|                 title: Text( | ||||
|                     '${_searchResults[index].name}: ${_searchResults[index].reps}x${_searchResults[index].weight}kg'), | ||||
|                 onTap: () { | ||||
|                   Navigator.push( | ||||
|                     '${searchResults[index].name}: ${searchResults[index].reps}x${searchResults[index].weight}kg'), | ||||
|                 onTap: () async { | ||||
|                   await Navigator.push( | ||||
|                     context, | ||||
|                     MaterialPageRoute( | ||||
|                       builder: (context) => | ||||
|                           EditGymSetPage(gymSet: _searchResults[index]), | ||||
|                           EditGymSetPage(gymSet: searchResults[index]), | ||||
|                     ), | ||||
|                   ); | ||||
|                   reset(); | ||||
|                 }); | ||||
|           }, | ||||
|         ), | ||||
|         floatingActionButton: FloatingActionButton( | ||||
|             onPressed: () { | ||||
|               Navigator.push( | ||||
|             onPressed: () async { | ||||
|               await Navigator.push( | ||||
|                 context, | ||||
|                 MaterialPageRoute( | ||||
|                   builder: (context) => | ||||
|                       EditGymSetPage(gymSet: _searchResults[0]), | ||||
|                   builder: (context) => EditGymSetPage( | ||||
|                       gymSet: GymSet( | ||||
|                           name: '', | ||||
|                           reps: 0, | ||||
|                           weight: 0, | ||||
|                           created: DateTime.now())), | ||||
|                 ), | ||||
|               ); | ||||
|               reset(); | ||||
|             }, | ||||
|             child: const Icon(Icons.add))); | ||||
|   } | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import 'package:flutter/material.dart'; | ||||
| import 'package:fmassive/best_page.dart'; | ||||
| import 'package:fmassive/edit_set.dart'; | ||||
| import 'package:fmassive/gym_set.dart'; | ||||
| import 'package:fmassive/home_page.dart'; | ||||
| import 'package:fmassive/plans_page.dart'; | ||||
| import 'package:fmassive/settings_page.dart'; | ||||
|  |  | |||
|  | @ -5,6 +5,8 @@ | |||
| import FlutterMacOS | ||||
| import Foundation | ||||
| 
 | ||||
| import sqflite | ||||
| 
 | ||||
| func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { | ||||
|   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) | ||||
| } | ||||
|  |  | |||
							
								
								
									
										27
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								pubspec.lock
									
									
									
									
									
								
							|  | @ -116,7 +116,7 @@ packages: | |||
|     source: hosted | ||||
|     version: "1.8.0" | ||||
|   path: | ||||
|     dependency: transitive | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: path | ||||
|       sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b | ||||
|  | @ -136,6 +136,22 @@ packages: | |||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.9.1" | ||||
|   sqflite: | ||||
|     dependency: "direct main" | ||||
|     description: | ||||
|       name: sqflite | ||||
|       sha256: "500d6fec583d2c021f2d25a056d96654f910662c64f836cd2063167b8f1fa758" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.2.6" | ||||
|   sqflite_common: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: sqflite_common | ||||
|       sha256: "963dad8c4aa2f814ce7d2d5b1da2f36f31bd1a439d8f27e3dc189bb9d26bc684" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "2.4.3" | ||||
|   stack_trace: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|  | @ -160,6 +176,14 @@ packages: | |||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "1.2.0" | ||||
|   synchronized: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|       name: synchronized | ||||
|       sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" | ||||
|       url: "https://pub.dev" | ||||
|     source: hosted | ||||
|     version: "3.0.1" | ||||
|   term_glyph: | ||||
|     dependency: transitive | ||||
|     description: | ||||
|  | @ -186,3 +210,4 @@ packages: | |||
|     version: "2.1.4" | ||||
| sdks: | ||||
|   dart: ">=2.19.5 <3.0.0" | ||||
|   flutter: ">=3.3.0" | ||||
|  |  | |||
|  | @ -34,6 +34,8 @@ dependencies: | |||
|   # The following adds the Cupertino Icons font to your application. | ||||
|   # Use with the CupertinoIcons class for iOS style icons. | ||||
|   cupertino_icons: ^1.0.2 | ||||
|   path: ^1.8.2 | ||||
|   sqflite: ^2.2.6 | ||||
| 
 | ||||
| dev_dependencies: | ||||
|   flutter_test: | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user