From f1fb93ec2100acc68deac139371bb262ed4ef7fd Mon Sep 17 00:00:00 2001 From: simformsolutions Date: Tue, 1 Dec 2020 18:49:48 +0530 Subject: [PATCH] local storage, offline database, sharedpreference, secure storage, note App demo --- ios/Podfile.lock | 24 ++ lib/dashboardscreen.dart | 59 ++++- lib/main.dart | 86 ++++--- .../mobxapicall/MobxAPICall.g.dart | 4 +- lib/storage/database/DBHelper.dart | 77 ++++++ lib/storage/database/addNoteScreen.dart | 208 +++++++++++++++++ lib/storage/database/noteApp.dart | 219 ++++++++++++++++++ lib/storage/database/notemobx.dart | 71 ++++++ lib/storage/database/notemobx.g.dart | 84 +++++++ lib/storage/database/notemodel.dart | 18 ++ lib/storage/database/sqflitescreen.dart | 165 +++++++++++++ lib/storage/localstorage.dart | 161 +++++++++++++ lib/storage/securestorage.dart | 20 ++ pubspec.lock | 88 ++++++- pubspec.yaml | 5 + 15 files changed, 1247 insertions(+), 42 deletions(-) create mode 100644 lib/storage/database/DBHelper.dart create mode 100644 lib/storage/database/addNoteScreen.dart create mode 100644 lib/storage/database/noteApp.dart create mode 100644 lib/storage/database/notemobx.dart create mode 100644 lib/storage/database/notemobx.g.dart create mode 100644 lib/storage/database/notemodel.dart create mode 100644 lib/storage/database/sqflitescreen.dart create mode 100644 lib/storage/localstorage.dart create mode 100644 lib/storage/securestorage.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 95b4b41..4de15b8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -72,8 +72,13 @@ PODS: - Flutter - flutter_phone_direct_caller (0.0.1): - Flutter + - flutter_secure_storage (3.3.1): + - Flutter - fluttertoast (0.0.2): - Flutter + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) - google_sign_in (0.0.1): - Flutter - GoogleSignIn (~> 5.0) @@ -129,8 +134,13 @@ PODS: - Flutter - PromisesObjC (1.2.11) - Reachability (3.2) + - shared_preferences (0.0.1): + - Flutter - sign_in_with_apple (0.0.1): - Flutter + - sqflite (0.0.2): + - Flutter + - FMDB (>= 2.7.5) DEPENDENCIES: - camera (from `.symlinks/plugins/camera/ios`) @@ -141,13 +151,16 @@ DEPENDENCIES: - Flutter (from `Flutter`) - flutter_facebook_login (from `.symlinks/plugins/flutter_facebook_login/ios`) - flutter_phone_direct_caller (from `.symlinks/plugins/flutter_phone_direct_caller/ios`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - google_sign_in (from `.symlinks/plugins/google_sign_in/ios`) - GoogleSignIn - image_picker (from `.symlinks/plugins/image_picker/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - permission_handler (from `.symlinks/plugins/permission_handler/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) SPEC REPOS: trunk: @@ -160,6 +173,7 @@ SPEC REPOS: - FirebaseCore - FirebaseCoreDiagnostics - FirebaseInstallations + - FMDB - GoogleAppMeasurement - GoogleDataTransport - GoogleSignIn @@ -185,6 +199,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_facebook_login/ios" flutter_phone_direct_caller: :path: ".symlinks/plugins/flutter_phone_direct_caller/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" fluttertoast: :path: ".symlinks/plugins/fluttertoast/ios" google_sign_in: @@ -195,8 +211,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider/ios" permission_handler: :path: ".symlinks/plugins/permission_handler/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" sign_in_with_apple: :path: ".symlinks/plugins/sign_in_with_apple/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" SPEC CHECKSUMS: AppAuth: 31bcec809a638d7bd2f86ea8a52bd45f6e81e7c7 @@ -215,7 +235,9 @@ SPEC CHECKSUMS: Flutter: 0e3d915762c693b495b44d77113d4970485de6ec flutter_facebook_login: cfb5659f686b1c575ef205c6b6fd20db9679d3c4 flutter_phone_direct_caller: bd2ffd297f371a8a6c7bfbba0196964ffe3c4358 + flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec fluttertoast: b644586ef3b16f67fae9a1f8754cef6b2d6b634b + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a google_sign_in: 6bd214b9c154f881422f5fe27b66aaa7bbd580cc GoogleAppMeasurement: 966e88df9d19c15715137bb2ddaf52373f111436 GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833 @@ -229,7 +251,9 @@ SPEC CHECKSUMS: permission_handler: eac8e15b4a1a3fba55b761d19f3f4e6b005d15b6 PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d sign_in_with_apple: 34f3f5456a45fd7ac5fb42905e2ad31dae061b4a + sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 PODFILE CHECKSUM: 4dc7e1f03dbbb17642b97a859dc52e155761199a diff --git a/lib/dashboardscreen.dart b/lib/dashboardscreen.dart index 560794f..b5db9d0 100644 --- a/lib/dashboardscreen.dart +++ b/lib/dashboardscreen.dart @@ -23,6 +23,10 @@ import 'package:flutter_app/pulltorefreshdemo.dart'; import 'package:flutter_app/sidedrawer.dart'; import 'package:flutter_app/statemanagement/blocwetherapplication/WeatherAppScreen.dart'; import 'package:flutter_app/statemanagement/mobxapicall/MobxAPICallScreen.dart'; +import 'package:flutter_app/storage/database/noteApp.dart'; +import 'package:flutter_app/storage/database/sqflitescreen.dart'; +import 'package:flutter_app/storage/localstorage.dart'; +import 'package:flutter_app/storage/securestorage.dart'; import 'package:flutter_facebook_login/flutter_facebook_login.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:google_sign_in/google_sign_in.dart'; @@ -66,6 +70,19 @@ class _DashboardScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ + CustomRow( + childrens: [ + CustomRaisedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => MyHomePage(title: 'Flutter Demo Home Page')), + ); + }, + buttonLable: "Dashboard" + ) + ], + ), CustomRow( childrens: [ CustomRaisedButton( @@ -324,6 +341,41 @@ class _DashboardScreenState extends State { ), ], + ), + CustomRow( + childrens: [ + CustomRaisedButton( + onPressed: (){ + Navigator.push( + context, + MaterialPageRoute(builder: (context) => LocalStorageDemo()), + ); + }, + buttonLable: "Local Storage" + ), + CustomRaisedButton( + onPressed: (){ + Navigator.push( + context, + MaterialPageRoute(builder: (context) => SqfLiteScreen()), + ); + }, + buttonLable: "Flutter Database" + ), + ], + ), + CustomRow( + childrens: [ + CustomRaisedButton( + onPressed: (){ + Navigator.push( + context, + MaterialPageRoute(builder: (context) => NoteAppDemo()), + ); + }, + buttonLable: "Note APP" + ), + ], ) ], ), @@ -350,10 +402,13 @@ class _DashboardScreenState extends State { accessToken: googleAuth.accessToken, idToken: googleAuth.idToken, ); + UserCredential userCredential = await FirebaseAuth.instance.signInWithCredential(credential); + SecureStorageDemo secureStorageDemo = SecureStorageDemo(); + secureStorageDemo.writeSecureData("isLogin", true); // Once signed in, return the UserCredential Fluttertoast.showToast( - msg: (await FirebaseAuth.instance.signInWithCredential(credential)).user.email.toString(), + msg: userCredential.user.displayName.toString(), toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.BOTTOM, timeInSecForIos: 1, @@ -364,7 +419,7 @@ class _DashboardScreenState extends State { context, MaterialPageRoute(builder: (context) => MyHomePage(title: 'Flutter Demo Home Page')), ); - return await FirebaseAuth.instance.signInWithCredential(credential); + return userCredential; } Future signUpWithFacebook() async{ diff --git a/lib/main.dart b/lib/main.dart index 80c447f..b0f19c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,40 +5,42 @@ import 'package:flutter/material.dart'; import 'package:flutter_app/dashboardscreen.dart'; import 'package:flutter_app/model/enum/ConnectivityStatus.dart'; import 'package:flutter_app/model/mobxstore/countermobx.dart'; -import 'package:flutter_app/model/service/ConnectivityService.dart'; +import 'package:flutter_app/storage/database/notemobx.dart'; +import 'package:flutter_app/storage/securestorage.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:provider/provider.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +Widget customHomeWidget; +NoteMobxStore noteCommonObject = NoteMobxStore(); Future main() async { WidgetsFlutterBinding.ensureInitialized(); await Firebase.initializeApp(); + await noteCommonObject.updateCurrentTheme(); + SecureStorageDemo secureStorageDemo = SecureStorageDemo(); + await secureStorageDemo.readSecureData("isLogin").then((value) { + print(value.toString()); + customHomeWidget = (value == true ? MyHomePage(title: 'Flutter Demo Home Page') : DashboardScreen()); + return value; + }); runApp(MyApp()); } -class MyApp extends StatelessWidget { +class MyApp extends StatelessObserverWidget { // This widget is th e root of your application. @override Widget build(BuildContext context) { - return StreamProvider( - builder: (context) => ConnectivityService().connectionStatusController, - child: MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - // This is the theme of your application. - // - // Try running your application with "flutter run". You'll see the - // application has a blue toolbar. Then, without quitting the app, try - // changing the primarySwatch below to Colors.green and then invoke - // "hot reload" (press "r" in the console where you ran "flutter run", - // or simply save your changes to "hot reload" in a Flutter IDE). - // Notice that the counter didn't reset back to zero; the application - // is not restarted. - primarySwatch: Colors.blue, - ), - // home: MyHomePage(title: 'Flutter Demo Home Page'), - home: DashboardScreen(), - ), + + return Observer( + builder: (context){ + return MaterialApp( + title: 'Flutter Demo', + theme:noteCommonObject.themeData, + home: customHomeWidget, + ); + } ); } } @@ -66,6 +68,7 @@ class _MyHomePageState extends State { String textToDisplay; String textInputed; + int _counter; void changeText() { setState(() { @@ -73,17 +76,24 @@ class _MyHomePageState extends State { }); } - // void _incrementCounter() { - // setState(() { - // // This call to setState tells the Flutter framework that something has - // // changed in this State, which causes it to rerun the build method below - // // so that the display can reflect the updated values. If we changed - // // _counter without calling setState(), then the build method would not be - // // called again, and so nothing would appear to happen. - // _counter++; - // isVisible = !isVisible; - // }); - // } + @override + void initState() { + getSharePreferenceData(); + super.initState(); + } + + void getSharePreferenceData() async { + SharedPreferences _prefs = await SharedPreferences.getInstance(); + setState(() { + _counter = _prefs.getInt('counter'); + }); + } + void setSharePreferenceData() async { + SharedPreferences _prefs = await SharedPreferences.getInstance(); + _prefs.setInt('counter', (_prefs.getInt('counter') + 1)); + getSharePreferenceData(); + } + @override Widget build(BuildContext context) { @@ -169,6 +179,10 @@ class _MyHomePageState extends State { style: Theme.of(context).textTheme.headline4, ); }), + Text( + 'Button tapped $_counter time${_counter == 1 ? '' : 's'}.\n\n' + 'This should persist across restarts.', + ), Visibility( visible: !isVisible, child: Row( @@ -249,16 +263,16 @@ class _MyHomePageState extends State { ], ), floatingActionButton: FloatingActionButton( - onPressed: () { + onPressed: () { + setSharePreferenceData(); counterMobxStore.increment(); - // FirebaseAuth.instance.signOut(); - // FirebaseAuth.instance.currentUser.delete(); if(FirebaseAuth.instance.currentUser != null){ + SecureStorageDemo secureStorageDemo = SecureStorageDemo(); + secureStorageDemo.writeSecureData("isLogin", false); FirebaseAuth.instance.signOut(); Navigator.of(context).pop(); } }, - // onPressed: _incrementCounter, tooltip: 'Increment', backgroundColor: Colors.orange, child: Icon(Icons.logout), diff --git a/lib/statemanagement/mobxapicall/MobxAPICall.g.dart b/lib/statemanagement/mobxapicall/MobxAPICall.g.dart index 67b654d..201932f 100644 --- a/lib/statemanagement/mobxapicall/MobxAPICall.g.dart +++ b/lib/statemanagement/mobxapicall/MobxAPICall.g.dart @@ -24,11 +24,11 @@ mixin _$MobXAPICallStore on MobXAPICall, Store { }); } - final _$APICallAsyncAction = AsyncAction('MobXAPICall.APICall'); + final _$apiCallAsyncAction = AsyncAction('MobXAPICall.apiCall'); @override Future apiCall() { - return _$APICallAsyncAction.run(() => super.apiCall()); + return _$apiCallAsyncAction.run(() => super.apiCall()); } @override diff --git a/lib/storage/database/DBHelper.dart b/lib/storage/database/DBHelper.dart new file mode 100644 index 0000000..1858126 --- /dev/null +++ b/lib/storage/database/DBHelper.dart @@ -0,0 +1,77 @@ +import 'package:flutter_app/storage/database/notemodel.dart'; +import 'package:path/path.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:sqflite/sqflite.dart'; +import 'dart:async'; +import 'dart:io' as io; + +class DBHelper{ + static Database _db; + static const String ID = 'id'; + static const String TITLE = 'title'; + static const String NOTES = 'notes'; + static const String TABLE = 'Note'; + static const String DB_NAME = 'note1.db'; + + Future get db async { + if (_db != null) { + return _db; + } + _db = await initDb(); + return _db; + } + + initDb() async { + io.Directory documentsDirectory = await getApplicationDocumentsDirectory(); + String path = join(documentsDirectory.path, DB_NAME); + var db = await openDatabase(path, version: 1, onCreate: _onCreate); + return db; + } + + _onCreate(Database db, int version) async { + await db + .execute("CREATE TABLE $TABLE ($ID INTEGER PRIMARY KEY, $TITLE TEXT, $NOTES TEXT)"); + } + + Future save(NoteModel noteModel) async { + var dbClient = await db; + noteModel.id = await dbClient.insert(TABLE, noteModel.toMap()); + return noteModel; + /* + await dbClient.transaction((txn) async { + var query = "INSERT INTO $TABLE ($NAME) VALUES ('" + noteModel.name + "')"; + return await txn.rawInsert(query); + }); + */ + } + + Future> getNotes() async { + var dbClient = await db; + List maps = await dbClient.query(TABLE, columns: [ID, TITLE, NOTES]); + //List maps = await dbClient.rawQuery("SELECT * FROM $TABLE"); + List notes = []; + if (maps.length > 0) { + for (int i = 0; i < maps.length; i++) { + notes.add(NoteModel.fromMap(maps[i])); + } + } + return notes; + } + + Future delete(int id) async { + var dbClient = await db; + return await dbClient.delete(TABLE, where: '$ID = ?', whereArgs: [id]); + } + + Future update(NoteModel noteModel) async { + var dbClient = await db; + return await dbClient.update(TABLE, noteModel.toMap(), + where: '$ID = ?', whereArgs: [noteModel.id]); + } + + Future close() async { + var dbClient = await db; + dbClient.close(); + } + +} \ No newline at end of file diff --git a/lib/storage/database/addNoteScreen.dart b/lib/storage/database/addNoteScreen.dart new file mode 100644 index 0000000..f93b2bb --- /dev/null +++ b/lib/storage/database/addNoteScreen.dart @@ -0,0 +1,208 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/model/data.dart'; +import 'package:flutter_app/storage/database/notemobx.dart'; +import 'package:flutter_app/storage/database/notemodel.dart'; + +class AddNoteScreen extends StatefulWidget { + final NoteModel preFieldModel; + final bool isUpdating; + + AddNoteScreen({Key key, this.preFieldModel, this.isUpdating}) + : super(key: key); + + @override + _AddNoteScreenState createState() => _AddNoteScreenState(); +} + +class _AddNoteScreenState extends State { + NoteMobxStore noteMobxStore = NoteMobxStore(); + final formKey = new GlobalKey(); + TextEditingController titleController = TextEditingController(); + TextEditingController noteController = TextEditingController(); + String title, note; + int curUserId; + bool isUpdating = false, isReadOnly = true, isReadOnlyVisibility = true; + + @override + void initState() { + super.initState(); + isUpdating = widget.isUpdating; + if (widget.preFieldModel.id != 0) { + titleController.text = widget.preFieldModel.title; + noteController.text = widget.preFieldModel.notes; + curUserId = widget.preFieldModel.id; + } else { + setState(() { + isReadOnlyVisibility = false; + isReadOnly = false; + }); + } + } + + clearName() { + titleController.text = ''; + noteController.text = ''; + } + + validate() { + if (formKey.currentState.validate()) { + formKey.currentState.save(); + if (isUpdating) { + NoteModel e = NoteModel(curUserId, title, note); + noteMobxStore.updateNote(e); + } else { + NoteModel e = NoteModel(null, title, note); + noteMobxStore.addNote(e); + } + clearName(); + Navigator.pop(context, Data(text: "Popped Text")); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Add/Update Note"), + ), + body: Container( + padding: EdgeInsets.all(20), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + children: [ + Form( + key: formKey, + child: Column( + children: [ + Visibility( + visible: isReadOnlyVisibility, + child: GestureDetector( + onTap: () { + setState(() { + isReadOnly = false; + isReadOnlyVisibility = false; + }); + }, + child: Container( + alignment: Alignment.topRight, + child: ClipOval( + child: Container( + color: Colors.lightBlue, + padding: EdgeInsets.all(5), + child: Icon( + Icons.edit, + size: 30, + color: Colors.white, + ), + ), + ), + ), + ), + ), + TextFormField( + decoration: new InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.orange, width: 2), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 2), + ), + hintText: 'Enter Title', + labelText: 'Enter Title', + ), + maxLines: 1, + readOnly: isReadOnly, + controller: titleController, + keyboardType: TextInputType.text, + validator: (val) => val.length == 0 ? 'Enter Title' : null, + onSaved: (val) => title = val, + ), + SizedBox( + width: 0, + height: 30, + ), + TextFormField( + decoration: new InputDecoration( + focusedBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.orange, width: 2), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide(color: Colors.red, width: 2), + ), + hintText: 'Enter Note', + labelText: 'Enter Note', + ), + maxLines: 10, + readOnly: isReadOnly, + controller: noteController, + validator: (val) => val.length == 0 ? 'Enter Note' : null, + onSaved: (val) => note = val, + ), + SizedBox( + width: 0, + height: 30, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Visibility( + visible: !isReadOnlyVisibility, + child: FlatButton( + color: Colors.orange, + textColor: Colors.white, + onPressed: validate, + child: + Text((isUpdating ? 'UPDATE' : 'ADD') + ' NOTE'), + ), + ), + FlatButton( + color: Colors.orange, + textColor: Colors.white, + onPressed: () { + Widget okButton = FlatButton( + child: Text("OK"), + onPressed: () { + clearName(); + Navigator.of(context).pop(); // dismiss dialog + Navigator.pop(context, Data(text: "Popped Text")); + }, + ); + + Widget cancleButton = FlatButton( + child: Text("Cancle"), + onPressed: () { + Navigator.of(context).pop(); // dismiss dialog + }, + ); + // set up the AlertDialog + AlertDialog alert = AlertDialog( + title: Text("Are you Sure ?"), + content: Text("Are you Sure ?"), + actions: [ + okButton, + cancleButton + ], + ); + // show the dialog + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); + }, + child: Text('CANCEL'), + ) + ], + ) + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/storage/database/noteApp.dart b/lib/storage/database/noteApp.dart new file mode 100644 index 0000000..b4bf5cf --- /dev/null +++ b/lib/storage/database/noteApp.dart @@ -0,0 +1,219 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/main.dart'; +import 'package:flutter_app/storage/database/addNoteScreen.dart'; +import 'package:flutter_app/storage/database/notemodel.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:flutter_slidable_list_view/flutter_slidable_list_view.dart'; +class NoteAppDemo extends StatefulWidget { + @override + _NoteAppDemoState createState() => _NoteAppDemoState(); +} + +class _NoteAppDemoState extends State { + + getNotes() { + noteCommonObject.displayNotes(); + } + + @override + void initState() { + // TODO: implement initState + super.initState(); + getNotes(); + } + + void choiceAction(String choice){ + if(choice == Constants.light){ + noteCommonObject.changeTheme('light'); + } + else if(choice == Constants.dark){ + noteCommonObject.changeTheme('dark'); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Note App"), + actions: [ + PopupMenuButton( + onSelected: choiceAction, + itemBuilder: (BuildContext context){ + return Constants.choices.map((String choice){ + return PopupMenuItem( + value: choice, + child: Text(choice),); + }).toList(); + } + ,)] + ,), + body: Container( + child: new Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + children: [ + Visibility( + visible: true, + child: Observer( + builder: (context) { + return Expanded( + child: SlideListView( + itemBuilder: (bc, index) { + final cuttentNote = noteCommonObject.noteList[index]; + return GestureDetector( + child: Container( + padding: EdgeInsets.all(10), + child: Card( + child: Column( + children: [ + ListTile( + onTap: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + AddNoteScreen( + preFieldModel: NoteModel( + cuttentNote.id, + cuttentNote.title, + cuttentNote.notes), + isUpdating: true, + ) + ), + ); + setState(() { + getNotes(); + }); + }, + title: Text(noteCommonObject + .noteList[index].title + .toString()), + subtitle: Text(noteCommonObject + .noteList[index].notes), + ) + ], + ), + )), + onTap: () { + print('tap ${cuttentNote.title}'); + }, + behavior: HitTestBehavior.translucent, + ); + }, + actionWidgetDelegate: ActionWidgetDelegate(2, + (actionIndex, listIndex) { + if (actionIndex == 0) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.delete), + Text('delete') + ], + ); + } else { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(Icons.edit), + Text('Edit') + ], + ); + } + }, (int indexInList, int index, + BaseSlideItem item) async { + var cuttentNote = noteCommonObject.noteList[indexInList]; + if (index == 0) { + // set up the button + Widget okButton = FlatButton( + child: Text("OK"), + onPressed: () { + Navigator.of(context).pop(); // dismiss dialog + item.remove(); + noteCommonObject.deleteNote( + noteCommonObject.noteList[indexInList].id); + }, + ); + + Widget cancleButton = FlatButton( + child: Text("Cancle"), + onPressed: () { + Navigator.of(context).pop(); // dismiss dialog + }, + ); + // set up the AlertDialog + AlertDialog alert = AlertDialog( + title: Text("Are you Sure ?"), + content: Text("Are you Sure ?"), + actions: [ + okButton, + cancleButton + ], + ); + // show the dialog + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); + } else { + // item.close(); + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AddNoteScreen( + preFieldModel: NoteModel( + cuttentNote.id, + cuttentNote.title, + cuttentNote.notes), + isUpdating: true, + ) + ), + ); + setState(() { + getNotes(); + }); + } + }, [Colors.redAccent, Colors.blueAccent]), + dataList: noteCommonObject.noteList, + refreshCallback: () async { + setState(() { + getNotes(); + }); + await Future.delayed(Duration(seconds: 2)); + return; + }, + ), + ); + }, + ), + ), + ], + ), + ), + floatingActionButton: FloatingActionButton( + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => AddNoteScreen( + preFieldModel: NoteModel(0, '', ''), + isUpdating: false)), + ); + setState(() { + getNotes(); + }); + }, + tooltip: 'Increment', + backgroundColor: Colors.orange, + child: Icon(Icons.add))); + } +} + +class Constants{ + static const String light = 'Light Theme'; + static const String dark = 'Dark Theme'; + static const List choices = [ light, dark ]; +} diff --git a/lib/storage/database/notemobx.dart b/lib/storage/database/notemobx.dart new file mode 100644 index 0000000..260b439 --- /dev/null +++ b/lib/storage/database/notemobx.dart @@ -0,0 +1,71 @@ + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_app/storage/database/DBHelper.dart'; +import 'package:flutter_app/storage/database/notemodel.dart'; +import 'package:mobx/mobx.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +part 'notemobx.g.dart'; + +class NoteMobxStore = NoteMobx with _$NoteMobxStore; + +abstract class NoteMobx with Store{ + + DBHelper dbHelper = DBHelper(); + + @observable + ThemeData themeData = ThemeData( primarySwatch: Colors.blue, + brightness: Brightness.light); + + @action + Future changeTheme(String currentTheme) async { + SharedPreferences _prefs = await SharedPreferences.getInstance(); + _prefs.setString('currentTheme', currentTheme); + updateCurrentTheme(); + } + + Future updateCurrentTheme () async { + var currentTheme = ''; + SharedPreferences _prefs = await SharedPreferences.getInstance(); + currentTheme = _prefs.getString('currentTheme'); + if(currentTheme == 'light'){ + themeData = ThemeData( primarySwatch: Colors.blue, + brightness: Brightness.light); + } + else if(currentTheme == 'dark'){ + themeData = ThemeData( primarySwatch: Colors.blue, + brightness: Brightness.dark); + } + else { + themeData = ThemeData( primarySwatch: Colors.blue, + brightness: Brightness.light); + } + print(currentTheme + " ff"); + } + + @observable + List noteList = List(); + + @action + Future displayNotes() async { + noteList = (await dbHelper.getNotes()); + } + + @action + Future addNote(NoteModel noteModel) async{ + await dbHelper.save(noteModel); + displayNotes(); + } + + @action + Future updateNote(NoteModel noteModel) async{ + await dbHelper.update(noteModel); + displayNotes(); + } + + @action + Future deleteNote(int noteId) async { + await dbHelper.delete(noteId); + } + +} \ No newline at end of file diff --git a/lib/storage/database/notemobx.g.dart b/lib/storage/database/notemobx.g.dart new file mode 100644 index 0000000..cf484ef --- /dev/null +++ b/lib/storage/database/notemobx.g.dart @@ -0,0 +1,84 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'notemobx.dart'; + +// ************************************************************************** +// StoreGenerator +// ************************************************************************** + +// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic + +mixin _$NoteMobxStore on NoteMobx, Store { + final _$themeDataAtom = Atom(name: 'NoteMobx.themeData'); + + @override + ThemeData get themeData { + _$themeDataAtom.reportRead(); + return super.themeData; + } + + @override + set themeData(ThemeData value) { + _$themeDataAtom.reportWrite(value, super.themeData, () { + super.themeData = value; + }); + } + + final _$noteListAtom = Atom(name: 'NoteMobx.noteList'); + + @override + List get noteList { + _$noteListAtom.reportRead(); + return super.noteList; + } + + @override + set noteList(List value) { + _$noteListAtom.reportWrite(value, super.noteList, () { + super.noteList = value; + }); + } + + final _$changeThemeAsyncAction = AsyncAction('NoteMobx.changeTheme'); + + @override + Future changeTheme(String currentTheme) { + return _$changeThemeAsyncAction.run(() => super.changeTheme(currentTheme)); + } + + final _$displayNotesAsyncAction = AsyncAction('NoteMobx.displayNotes'); + + @override + Future displayNotes() { + return _$displayNotesAsyncAction.run(() => super.displayNotes()); + } + + final _$addNoteAsyncAction = AsyncAction('NoteMobx.addNote'); + + @override + Future addNote(NoteModel noteModel) { + return _$addNoteAsyncAction.run(() => super.addNote(noteModel)); + } + + final _$updateNoteAsyncAction = AsyncAction('NoteMobx.updateNote'); + + @override + Future updateNote(NoteModel noteModel) { + return _$updateNoteAsyncAction.run(() => super.updateNote(noteModel)); + } + + final _$deleteNoteAsyncAction = AsyncAction('NoteMobx.deleteNote'); + + @override + Future deleteNote(int noteId) { + return _$deleteNoteAsyncAction.run(() => super.deleteNote(noteId)); + } + + @override + String toString() { + return ''' +themeData: ${themeData}, +noteList: ${noteList} + '''; + } +} diff --git a/lib/storage/database/notemodel.dart b/lib/storage/database/notemodel.dart new file mode 100644 index 0000000..8b89a3c --- /dev/null +++ b/lib/storage/database/notemodel.dart @@ -0,0 +1,18 @@ +class NoteModel { + int id; + String title; + String notes; + + NoteModel(this.id, this.title, this.notes); + + Map toMap() { + var map = {'id': id, 'title': title, 'notes': notes}; + return map; + } + + NoteModel.fromMap(Map map){ + id = map['id']; + title = map['title']; + notes = map['notes']; + } +} diff --git a/lib/storage/database/sqflitescreen.dart b/lib/storage/database/sqflitescreen.dart new file mode 100644 index 0000000..5101a45 --- /dev/null +++ b/lib/storage/database/sqflitescreen.dart @@ -0,0 +1,165 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_app/storage/database/notemobx.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'notemodel.dart'; + +class SqfLiteScreen extends StatefulWidget { + final String title; + + SqfLiteScreen({Key key, this.title}) : super(key: key); + @override + _SqfLiteScreenState createState() => _SqfLiteScreenState(); +} + +class _SqfLiteScreenState extends State { + NoteMobxStore noteMobxStore = NoteMobxStore(); + TextEditingController controller = TextEditingController(); + String name; + int curUserId; + final formKey = new GlobalKey(); + bool isUpdating; + + @override + void initState() { + super.initState(); + isUpdating = false; + refreshList(); + } + + refreshList() { + noteMobxStore.displayNotes(); + } + + clearName() { + controller.text = ''; + } + + validate() { + if (formKey.currentState.validate()) { + formKey.currentState.save(); + if (isUpdating) { + NoteModel e = NoteModel(curUserId, name, null); + noteMobxStore.updateNote(e); + setState(() { + isUpdating = false; + }); + } else { + NoteModel e = NoteModel(null, name, null); + noteMobxStore.addNote(e); + } + clearName(); + refreshList(); + } + } + + form() { + return Form( + key: formKey, + child: Padding( + padding: EdgeInsets.all(15.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + children: [ + TextFormField( + controller: controller, + keyboardType: TextInputType.text, + decoration: InputDecoration(labelText: 'Name'), + validator: (val) => val.length == 0 ? 'Enter Name' : null, + onSaved: (val) => name = val, + ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + FlatButton( + onPressed: validate, + child: Text(isUpdating ? 'UPDATE' : 'ADD'), + ), + FlatButton( + onPressed: () { + setState(() { + isUpdating = false; + }); + clearName(); + }, + child: Text('CANCEL'), + ) + ], + ), + ], + ), + ), + ); + } + + SingleChildScrollView dataTable(List employees) { + return SingleChildScrollView( + scrollDirection: Axis.vertical, + child: DataTable( + columns: [ + DataColumn( + label: Text('NAME'), + ), + DataColumn( + label: Text('DELETE'), + ) + ], + rows: employees + .map( + (employee) => DataRow(cells: [ + DataCell( + Text(employee.title), + onTap: () { + setState(() { + isUpdating = true; + curUserId = employee.id; + }); + controller.text = employee.title; + }, + ), + DataCell(IconButton( + icon: Icon(Icons.delete), + onPressed: () { + noteMobxStore.deleteNote(employee.id); + refreshList(); + }, + )), + ]), + ) + .toList(), + ), + ); + } + + list() { + + return Observer(builder: (context){ + print(noteMobxStore.noteList.length.toString() + " Final"); + return Expanded(child: dataTable(noteMobxStore.noteList)); + },); + } + + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text('Flutter SQLITE CRUD DEMO'), + ), + body: new Container( + child: new Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + verticalDirection: VerticalDirection.down, + children: [ + form(), + Observer(builder: (context){ + return Expanded(child: dataTable(noteMobxStore.noteList)); + },), + ], + ), + ), + ); + } +} diff --git a/lib/storage/localstorage.dart b/lib/storage/localstorage.dart new file mode 100644 index 0000000..279c5d2 --- /dev/null +++ b/lib/storage/localstorage.dart @@ -0,0 +1,161 @@ +import 'package:flutter/material.dart'; +import 'package:localstorage/localstorage.dart'; + +class LocalStorageDemo extends StatefulWidget { + @override + _LocalStorageDemoState createState() => _LocalStorageDemoState(); +} + +class _LocalStorageDemoState extends State { + final TodoList list = new TodoList(); + final LocalStorage storage = new LocalStorage('todo_app'); + bool initialized = false; + TextEditingController controller = new TextEditingController(); + + _toggleItem(TodoItem item) { + setState(() { + item.done = !item.done; + _saveToStorage(); + }); + } + + _addItem(String title) { + setState(() { + final item = TodoItem(title: title, done: false); + list.items.add(item); + _saveToStorage(); + }); + } + + _saveToStorage() { + storage.setItem('todos', list.toJSONEncodable()); + } + + _clearStorage() async { + await storage.clear(); + + setState(() { + list.items = storage.getItem('todos') ?? []; + }); + } + + void _save() { + _addItem(controller.value.text); + controller.clear(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text('Localstorage demo'), + ), + body: Container( + padding: EdgeInsets.all(10.0), + constraints: BoxConstraints.expand(), + child: FutureBuilder( + future: storage.ready, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.data == null) { + return Center( + child: CircularProgressIndicator(), + ); + } + + if (!initialized) { + var items = storage.getItem('todos'); + + if (items != null) { + list.items = List.from( + (items as List).map( + (item) => TodoItem( + title: item['title'], + done: item['done'], + ), + ), + ); + } + initialized = true; + } + + List widgets = list.items.map((item) { + return CheckboxListTile( + value: item.done, + title: Text(item.title), + selected: item.done, + onChanged: (bool selected) { + _toggleItem(item); + }, + ); + }).toList(); + + return Column( + children: [ + Expanded( + flex: 1, + child: ListView( + children: widgets, + itemExtent: 50.0, + ), + ), + ListTile( + title: TextField( + controller: controller, + decoration: InputDecoration( + labelText: 'What to do?', + ), + onEditingComplete: _save, + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon(Icons.save), + onPressed: _save, + tooltip: 'Save', + ), + IconButton( + icon: Icon(Icons.delete), + onPressed: _clearStorage, + tooltip: 'Clear storage', + ) + ], + ), + ), + ], + ); + }, + )), + ); + } +} + +class TodoItem { + String title; + bool done; + + TodoItem({this.title, this.done}); + + toJSONEncodable() { + Map m = new Map(); + + m['title'] = title; + m['done'] = done; + + return m; + } +} + +class TodoList { + List items; + + TodoList() { + items = new List(); + } + + toJSONEncodable() { + return items.map((item) { + return item.toJSONEncodable(); + }).toList(); + } +} diff --git a/lib/storage/securestorage.dart b/lib/storage/securestorage.dart new file mode 100644 index 0000000..d87a872 --- /dev/null +++ b/lib/storage/securestorage.dart @@ -0,0 +1,20 @@ +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; + +class SecureStorageDemo { + final storage = FlutterSecureStorage(); + + Future writeSecureData(String key, dynamic value) async { + var writeData = await storage.write(key: key, value: value); + return writeData; + } + + Future readSecureData(String key) async { + var readData = await storage.read(key: key); + return readData; + } + + Future deleteSecureData(String key) async { + var deleteData = await storage.delete(key: key); + return deleteData; + } +} diff --git a/pubspec.lock b/pubspec.lock index 52b603b..835ef1e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -342,6 +342,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.11" + flutter_secure_storage: + dependency: "direct main" + description: + name: flutter_secure_storage + url: "https://pub.dartlang.org" + source: hosted + version: "3.3.5" + flutter_slidable_list_view: + dependency: "direct main" + description: + name: flutter_slidable_list_view + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.8" flutter_test: dependency: "direct dev" description: flutter @@ -464,6 +478,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.1.1" + localstorage: + dependency: "direct main" + description: + name: localstorage + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.3+6" logging: dependency: transitive description: @@ -667,6 +688,48 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.24.1" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + url: "https://pub.dartlang.org" + source: hosted + version: "0.5.12+4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.2+4" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+11" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.4" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.2+7" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + url: "https://pub.dartlang.org" + source: hosted + version: "0.0.1+3" shelf: dependency: transitive description: @@ -707,6 +770,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0-nullsafety.2" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.2+1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.2+1" stack_trace: dependency: transitive description: @@ -735,6 +812,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0-nullsafety.1" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.0+2" term_glyph: dependency: transitive description: @@ -806,5 +890,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=2.10.0 <2.11.0" - flutter: ">=1.12.13+hotfix.8 <2.0.0" + dart: ">=2.10.2 <2.11.0" + flutter: ">=1.22.2 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9547d66..8795a8f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -54,6 +54,11 @@ dependencies: flutter_facebook_login: sign_in_with_apple: ^2.5.2 crypto: ^2.1.5 + shared_preferences: ^0.5.12+4 + localstorage: ^3.0.3+6 + flutter_secure_storage: ^3.3.5 + sqflite: ^1.3.2+1 + flutter_slidable_list_view: ^1.2.8 dev_dependencies: flutter_test: