cogane64
cogane64

Reputation: 13

How to implement a process that uses flutter_secure_storage package to read and write the data [with Provider package]

I'm new to Flutter and Dart. I made a simple Todos app with Provider package and Consumer. I'm trying to implement a process that uses flutter_secure_storage package to read and write the list data on the device. But I don't know how to implement it.

Checkbox widget requires a bool, while secure_storage requires the type of String. Therefore, it is necessary to convert both types. This also confuses me a little.

The code is below. I would be happy if you could give me some advice.

main.dart

// Todos app example

import 'package:consumer_samp/list_model.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: ChangeNotifierProvider<ListModel>(
        create: (context) => ListModel(),
        child: MyHomePage('Todos app example'),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage(this.title);

  final String title;

  final TextEditingController eCtrl = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(10),
              child: Row(
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: 'Enter your ToDo item',
                      ),
                      controller: eCtrl,
                    ),
                  ),
                  Consumer<ListModel>(
                    builder: (_, listModel, __) => FlatButton(
                      child: Text('Add'),
                      onPressed: () {
                        if (eCtrl.text != '') {
                          Map<String, dynamic> item = {
                            'value': false,
                            'text': eCtrl.text
                          };
                          listModel.addItem(item);
                          eCtrl.clear();
                        }
                      },
                    ),
                  ),
                ],
              ),
            ),
            Center(
              child: Consumer<ListModel>(builder: (_, listModel, __) {
                var items = listModel.getItems;
                return Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Container(
                      height: 300,
                      child: ListView.builder(
                        itemCount: items.length,
                        itemBuilder: (BuildContext context, int idx) =>
                            Container(
                          padding: const EdgeInsets.all(5),
                          color: Colors.green,
                          child: Row(
                            children: <Widget>[
                              Checkbox(
                                  value: items[idx]['value'],
                                  onChanged: (val) {
                                    listModel.toggleValue(idx, val);
                                  }),
                              Text(
                                items[idx]['text'],
                                style: TextStyle(
                                    fontSize: 21, color: Colors.white),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ],
                );
              }),
            ),
          ],
        ),
      ),
    );
  }
}

list_model.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class ListModel with ChangeNotifier {
  List<Map<String, dynamic>> _items = [];

  List<Map<String, dynamic>> get getItems => _items;

  void addItem(Map<String, dynamic> item) {
    _items.add(item);
    notifyListeners();
  }

  void toggleValue(int idx, bool val) {
    _items[idx]['value'] = val;
    notifyListeners();
  }
}

Upvotes: 1

Views: 3047

Answers (2)

Abilash S
Abilash S

Reputation: 245

As mentioned in the readme files by the following link

https://pub.dev/packages/flutter_secure_storage

The following code instantiate the storage, and the following code's must be in a async method as this returns a future.

final storage = new FlutterSecureStorage();

And you can pass the _items list as a value and you can set some key name

await storage.write(key: key, value: _items);

And then you could get that value by using the key name (which is set while storing)

List<Map<String, dynamic>> _value = await storage.read(key: key);

And then you could map the _value you get from storage and you can store it in _items. And then you could do various operations and queries inside your app now with all data you have.

Make a note! I haven't tried this approach in my code base. Just I said what I thought. Please try this in your code and comment me please.

The following code executes correctly use this in model, for storing data:

Future<void> _storingData() async {
    final storage = new FlutterSecureStorage();

    for (int i = 0; i < _items.length; i++) {
        await storage
              .write(key: _items[i]['text'], value: "${_items[i]['value']}")
              .then((value) => print("success"));
    }
}

For retrieving data:

Future<void> retrivingData() async {
    final storage = new FlutterSecureStorage();
    Map<String, String> allValues = await storage.readAll();

    print(allValues);

    allValues.forEach((key, value) {
        bool val = bool.fromEnvironment(value, defaultValue: false);
        Map<String, dynamic> item = {'value': val, 'text': key};
        addItem(item);
    });
}

and finally I stored all values again to a list.

You should do some changes in your code in main.dart according to the above methods based on your usage.

Upvotes: 0

chunhunghan
chunhunghan

Reputation: 54397

You can copy paste run full code below
You can use class TodoItem and save/load with JSON String
Provider logic for secure storage is in full code, too long to describe detail
code snippet

List<TodoItem> todoItemFromJson(String str) =>
    List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));

String todoItemToJson(List<TodoItem> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class TodoItem {
  TodoItem({
    this.item,
    this.checked,
  });

  String item;
  bool checked;

  factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
        item: json["item"],
        checked: json["checked"],
      );

  Map<String, dynamic> toJson() => {
        "item": item,
        "checked": checked,
      };
}

working demo

enter image description here

full code

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

import 'dart:convert';

List<TodoItem> todoItemFromJson(String str) =>
    List<TodoItem>.from(json.decode(str).map((x) => TodoItem.fromJson(x)));

String todoItemToJson(List<TodoItem> data) =>
    json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class TodoItem {
  TodoItem({
    this.item,
    this.checked,
  });

  String item;
  bool checked;

  factory TodoItem.fromJson(Map<String, dynamic> json) => TodoItem(
        item: json["item"],
        checked: json["checked"],
      );

  Map<String, dynamic> toJson() => {
        "item": item,
        "checked": checked,
      };
}

class ListModel with ChangeNotifier {
  FlutterSecureStorage _storage;

  List<TodoItem> _items = [];

  List<TodoItem> get getItems => _items;

  initilaize() async {
    print("initialize");
    String jsonString = await _storage.read(key: "todo");
    if (jsonString != null) {
      _items = todoItemFromJson(jsonString);
      notifyListeners();
    }
  }

  ListModel.init(FlutterSecureStorage storage) {
    print("init");
    _storage = storage;
    initilaize();
  }

  void update(FlutterSecureStorage storage) {
    print("update");
    _storage = storage;
  }

  void addItem(TodoItem item) {
    _items.add(item);
    notifyListeners();
  }

  void toggleValue(int idx, bool val) {
    _items[idx].checked = val;
    notifyListeners();
  }
}

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MultiProvider(
        providers: [
          Provider<FlutterSecureStorage>(create: (_) => FlutterSecureStorage()),
          ChangeNotifierProxyProvider<FlutterSecureStorage, ListModel>(
            create: (_) {
              return ListModel.init(
                  Provider.of<FlutterSecureStorage>(_, listen: false));
            },
            update: (_, storage, listModel) => listModel..update(storage),
          ),
        ],
        child: MyHomePage('Todos app example'),
      ),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage(this.title);

  final String title;

  final TextEditingController eCtrl = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
        actions: <Widget>[
          Consumer2<ListModel, FlutterSecureStorage>(
              builder: (_, listModel, storage, __) => IconButton(
                    icon: Icon(Icons.save),
                    onPressed: () async {
                      await storage.write(
                          key: "todo", value: todoItemToJson(listModel._items));
                      print("save done");
                    },
                  ))
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(10),
              child: Row(
                children: <Widget>[
                  Expanded(
                    child: TextField(
                      decoration: InputDecoration(
                        border: InputBorder.none,
                        hintText: 'Enter your ToDo item',
                      ),
                      controller: eCtrl,
                    ),
                  ),
                  Consumer<ListModel>(
                    builder: (_, listModel, __) => FlatButton(
                      child: Text('Add'),
                      onPressed: () {
                        if (eCtrl.text != '') {
                          Map<String, dynamic> item = {
                            'value': false,
                            'text': eCtrl.text
                          };
                          listModel.addItem(
                              TodoItem(item: eCtrl.text, checked: false));
                          eCtrl.clear();
                        }
                      },
                    ),
                  ),
                ],
              ),
            ),
            Center(
              child: Consumer<ListModel>(builder: (_, listModel, __) {
                var items = listModel.getItems;
                return Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Container(
                      height: 300,
                      child: ListView.builder(
                        itemCount: items.length,
                        itemBuilder: (BuildContext context, int idx) =>
                            Container(
                          padding: const EdgeInsets.all(5),
                          color: Colors.green,
                          child: Row(
                            children: <Widget>[
                              Checkbox(
                                  value: items[idx].checked,
                                  onChanged: (val) {
                                    listModel.toggleValue(idx, val);
                                  }),
                              Text(
                                items[idx].item,
                                style: TextStyle(
                                    fontSize: 21, color: Colors.white),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ],
                );
              }),
            ),
          ],
        ),
      ),
    );
  }
}

Upvotes: 1

Related Questions