diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..f992054 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "boxchecker", + "request": "launch", + "type": "dart", + "program": "lib/box_checker.dart", + "flutterMode": "debug" + }, + { + "name": "boxchecker (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + } + ] +} \ No newline at end of file diff --git a/lib/add_form.dart b/lib/add_form.dart new file mode 100644 index 0000000..b8fd62b --- /dev/null +++ b/lib/add_form.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'data_util.dart' as data; + +class AddForm extends StatelessWidget { + AddForm({Key? key, required this.type}) : super(key: key); + final _formKey = GlobalKey(); + + final data.Page type; + int _templatChoice = -1; + + final FocusNode _TemplateFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text( + 'Add ' + + ((type == data.Page.lists) + ? 'Check List' + : (type == data.Page.templates) + ? 'Template' + : ''), + ), + ), + body: Container( + margin: const EdgeInsets.all(10), + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + onFieldSubmitted: (value) { + FocusScope.of(context).requestFocus(_TemplateFocusNode); + }, + decoration: const InputDecoration(labelText: 'Label')), + DropdownButtonFormField( + focusNode: _TemplateFocusNode, + value: _templatChoice, + onChanged: (value) { + setState() { + _templatChoice = value as int; + } + }, + decoration: + const InputDecoration(labelText: "Starting Template"), + items: const [ + // TODO get templates from database + DropdownMenuItem(child: Text("None"), value: -1), + DropdownMenuItem(child: Text("1"), value: 0), + ], + ) + ], + ), + ), + ), + floatingActionButton: FloatingActionButton( + child: Icon(Icons.save_alt), + onPressed: () { + // TODO implement adding list to database + Navigator.pop(context); // TODO replace route with checklist page + }, + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, + ); + } +} diff --git a/lib/box_checker.dart b/lib/box_checker.dart new file mode 100644 index 0000000..1efae4b --- /dev/null +++ b/lib/box_checker.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'add_form.dart'; +import 'data_util.dart' as data; + +void main() { + runApp(const BoxChecker()); +} + +class BoxChecker extends StatelessWidget { + const BoxChecker({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData(brightness: Brightness.dark), + themeMode: ThemeMode.dark, + home: const MainListPage(title: 'BoxChecker'), + ); + } +} + +class MainListPage extends StatefulWidget { + const MainListPage({Key? key, required this.title}) : super(key: key); + final String title; + + @override + State createState() => _MainListPageState(); +} + +class _MainListPageState extends State { + int _selectedPage = data.Page.lists.index; + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.title), + ), + floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked, + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + AddForm(type: data.Page.values[_selectedPage]))); + }, // TODO Implement add button + tooltip: 'Add List', + child: const Icon(Icons.add), + ), + body: ListView.builder(itemBuilder: (context, index) { + return ListTile(); // TODO Implement tile rendering + }), + bottomNavigationBar: BottomNavigationBar( + currentIndex: _selectedPage, + onTap: (index) { + setState(() { + _selectedPage = index; + }); + }, + items: const [ + BottomNavigationBarItem( + icon: Icon(Icons.checklist), + label: "Lists", + ), + BottomNavigationBarItem( + icon: Icon(Icons.folder_open), + label: "Templates", + ), + ])); + } +} diff --git a/lib/data_util.dart b/lib/data_util.dart new file mode 100644 index 0000000..919ebb3 --- /dev/null +++ b/lib/data_util.dart @@ -0,0 +1,44 @@ +enum Page { lists, templates } + +class List { + List(this.id, this.name, {this.isTemplate}); + + int id; + String name; + bool? isTemplate; + + Map toMap() { + var map = Map(); + map["id"] = this.id; + map["list_name"] = this.name; + if (isTemplate != null) map["is_template"] = this.isTemplate as int; + return map; + } + + static List fromMap(Map map) { + return List(map["id"], map["list_name"], isTemplate: map["is_template"]); + } +} + +class Check { + Check(this.id, this.text, this.value, {this.listID}); + + int id; + String text; + bool value; + int? listID; + + Map toMap() { + var map = Map(); + map["id"] = this.id; + map["check_text"] = this.text; + map["value"] = this.value as int; + if (listID != null) map["list_id"] = this.listID as int; + return map; + } + + static Check fromMap(Map map) { + return Check(map["id"], map["check_text"], map["value"], + listID: map["list_id"]); + } +} diff --git a/lib/db_helper.dart b/lib/db_helper.dart new file mode 100644 index 0000000..a6279d2 --- /dev/null +++ b/lib/db_helper.dart @@ -0,0 +1,54 @@ +import "package:sqflite/sqflite.dart"; +import "package:sqflite/sqlite_api.dart"; +import "package:path/path.dart"; + +class DBHelper { + DBHelper._(); + + static DBHelper dbHelper = DBHelper._(); + + late Database _database; + + Future get database async { + _database = await _createDatabase(); + + return _database; + } + + Future _createDatabase() async { + Database database = + await openDatabase(join(await getDatabasesPath(), 'mydb.db'), + onCreate: (Database db, int version) { + db.execute(""" + CREATE TABLE List( + id INTEGER PRIMARY KEY AUTOINCREMENT, + list_name TEXT + is_template int2 + ) + """); + db.execute(""" + CREATE TABLE Check( + id INTEGER PRIMARY KEY AUTOINCREMENT, + check_text TEXT, + value int2, + list_id INTEGER + ) + """); + }, version: 1); + return database; + } + + Future> getAllLists() async { + Database db = await database; + + return db.query("List", where: "is_template = ?", whereArgs: ['0']) + as Map; + } + + Future> getAllTemplates() async { + Database db = await database; + + return db.query("List", where: "is_template = ?", whereArgs: ['1']) + as Map; + } +} diff --git a/lib/main.dart b/lib/main.dart deleted file mode 100644 index 5619abf..0000000 --- a/lib/main.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; - -void main() { - runApp(const BoxChecker()); -} - -class BoxChecker extends StatelessWidget { - const BoxChecker({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData(brightness: Brightness.dark), - themeMode: ThemeMode.dark, - home: const MainListPage(title: 'BoxChecker'), - ); - } -} - -class MainListPage extends StatefulWidget { - const MainListPage({Key? key, required this.title}) : super(key: key); - final String title; - - @override - State createState() => _MainListPageState(); -} - -class _MainListPageState extends State { - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.title), - actions: [ - IconButton( - onPressed: () {}, // TODO implement dropdown meny for more options - icon: const Icon(Icons.more_vert_rounded), - tooltip: 'More Options', - ) - ], - ), - floatingActionButton: FloatingActionButton( - onPressed: () {}, // TODO Implement add button - tooltip: 'Add List', - child: const Icon(Icons.add), - ), - body: ListView.builder(itemBuilder: (context, index) { - return ListTile(); // TODO Implement tile rendering - }), - ); - } -} diff --git a/pubspec.lock b/pubspec.lock index 750761f..9284d08 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -114,6 +114,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0+4" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1+1" stack_trace: dependency: transitive description: @@ -135,6 +149,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.0" term_glyph: dependency: transitive description: @@ -165,3 +186,4 @@ packages: version: "2.1.0" sdks: dart: ">=2.12.0 <3.0.0" + flutter: ">=1.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 6970cdf..b705fc8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,7 @@ environment: dependencies: flutter: sdk: flutter + sqflite: ^2.0.0+4 # The following adds the Cupertino Icons font to your application. diff --git a/test/widget_test.dart b/test/widget_test.dart index 014b8d4..a407237 100644 --- a/test/widget_test.dart +++ b/test/widget_test.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:boxchecker/main.dart'; +import 'package:boxchecker/box_checker.dart'; void main() { testWidgets('Counter increments smoke test', (WidgetTester tester) async {