persistent_state 0.2.0

  • Readme
  • Changelog
  • Example
  • Installing
  • 57

Persistent state #

pub package

Persist state in an Sqlite database across restarts and returns from hibernation

Powered by the KvSql key/value store. The state is saved to an Sqlite database

Usage #

Create your state class:

   import 'dart:async';
   import 'package:flutter/foundation.dart';
   import 'package:persistent_state/persistent_state.dart';


   enum UpdateType { intProp, stringProp, doubleProp, listProp, mapProp }

   class AppState with PersistentState<UpdateType> {

     double get doubleProp => select<double>("double_prop");
     set doubleProp(double v) =>
         mutate<double>("double_prop", v, UpdateType.doubleProp);

     List<int> get listProp => select<List<int>>("list_prop");
     set listProp(List<int> v) =>
         mutate<List<int>>("list_prop", v, UpdateType.listProp);

     Map<String, int> get mapProp => select<Map<String, int>>("map_prop");
     set mapProp(Map<String, int> v) =>
         mutate<Map<String, int>>("map_prop", v, UpdateType.mapProp);
   }

All the mutations will be persisted to the database:

   state.doubleProp = 3.0;

Note: the state reads with select do not hit the database and use an in memory copy of the state

If you already use KvSql you can provide your own store:


   final store = KvStore(inMemory: true);

   class AppState with PersistentState<UpdateType> {
      @override
      KvStore kvStore => store;
   }

Listen to state changes #

A changefeed is available:

   /// [appState] is an [AppState] instance
   appState.changeFeed.listen((StateUpdate change) =>
      print("State update: \n${change.type}");

Example #

An example with Provider is available

Changelog #

0.2.0 #

Refactor to use Kvsql

0.1.0 #

Initial release

example/README.md

Example #

In state.dart:

   import 'dart:async';
   import 'package:flutter/foundation.dart';
   import 'package:persistent_state/persistent_state.dart';

   AppState appState;

   enum UpdateType { intProp, stringProp, doubleProp, listProp, mapProp }

   final StreamController<Store> stateController = StreamController<Store>();

   void updateState({@required UpdateType type, @required dynamic value}) =>
       stateController.sink.add(Store.update(type, value));

   class AppState with PersistentState<UpdateType> {
     int get intProp => select<int>("int_prop");
     set intProp(int v) => mutate<int>("int_prop", v, UpdateType.intProp);

     double get doubleProp => select<double>("double_prop");
     set doubleProp(double v) =>
         mutate<double>("double_prop", v, UpdateType.doubleProp);

     String get stringProp => select<String>("string_prop");
     set stringProp(String v) =>
         mutate<String>("string_prop", v, UpdateType.stringProp);

     List<int> get listProp => select<List<int>>("list_prop");
     set listProp(List<int> v) =>
         mutate<List<int>>("list_prop", v, UpdateType.listProp);

     Map<String, int> get mapProp => select<Map<String, int>>("map_prop");
     set mapProp(Map<String, int> v) =>
         mutate<Map<String, int>>("map_prop", v, UpdateType.mapProp);
   }

   class Store {
     Store();

     AppState state = appState;

     Store.update(UpdateType type, dynamic value) : this.state = appState {
       switch (type) {
         case UpdateType.intProp:
           state.intProp = value as int;
           break;
         case UpdateType.doubleProp:
           state.doubleProp = value as double;
           break;
         case UpdateType.stringProp:
           state.stringProp = value as String;
           break;
         case UpdateType.listProp:
           state.listProp = value as List<int>;
           break;
         case UpdateType.mapProp:
           state.mapProp = value as Map<String, int>;
           break;
       }
     }
   }

In main.dart:

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

   import 'page.dart';
   import 'state.dart';

   void main() {
     runApp(MyApp());
     appState = AppState()..init();
   }

   class MyApp extends StatelessWidget {
     @override
     Widget build(BuildContext context) {
       return StreamProvider<Store>.value(
           initialData: Store(),
           value: stateController.stream,
           child: MaterialApp(
             home: Page(),
             routes: routes,
             debugShowCheckedModeBanner: false,
             title: 'Persistent state example',
           ));
     }
   }

In a page:

   import 'dart:math';

   import 'package:flutter/material.dart';
   import 'package:provider/provider.dart';
   import 'package:persistent_state/persistent_state.dart';
   import 'state.dart';

   Random random = Random();

   class _PageState extends State<Page> {
     bool _ready = false;
     String status = "";

     @override
     void initState() {
       super.initState();

       /// listen to the state changes
       appState.changeFeed.listen((StateUpdate change) =>
           setState(() => status = "State update: \n${change.description}"));

       /// wait for tje state to be ready. This is not necessary
       /// if a [kvStore] argument is provided at state class
       /// initialization
       appState.onReady.then((_) {
         setState(() => _ready = true);
         // set the initial state
         updateState(type: UpdateType.intProp, value: 1);
         updateState(type: UpdateType.doubleProp, value: 1.0);
         updateState(type: UpdateType.stringProp, value: "one");
         updateState(type: UpdateType.listProp, value: <int>[1, 2, 3]);
         updateState(
             type: UpdateType.mapProp, value: <String, int>{"one": 1, "two": 2});
       });
     }

     @override
     Widget build(BuildContext context) {
       final state = Provider.of<Store>(context).state;
       return Scaffold(
         appBar: AppBar(title: const Text("Persistent state")),
         body: _ready
             ? Column(
                 children: <Widget>[
                   const Padding(padding: EdgeInsets.only(top: 20.0)),
                   Text("Int prop: ${state.intProp}"),
                   Text("Double prop: ${state.doubleProp}"),
                   Text("String prop: ${state.stringProp}"),
                   Text("List<int> prop: ${state.listProp}"),
                   Text("Map<String,int> prop: ${state.mapProp}"),
                   const Divider(),
                   RaisedButton(
                     child: const Text("Change int prop"),
                     onPressed: () => updateState(
                         type: UpdateType.intProp, value: random.nextInt(100)),
                   ),
                   RaisedButton(
                     child: const Text("Change double prop"),
                     onPressed: () => updateState(
                         type: UpdateType.doubleProp, value: random.nextDouble()),
                   ),
                   RaisedButton(
                     child: const Text("Change string prop"),
                     onPressed: () => updateState(
                         type: UpdateType.stringProp,
                         value: "string ${random.nextInt(100)}"),
                   ),
                   RaisedButton(
                     child: const Text("Change list prop"),
                     onPressed: () => updateState(
                       type: UpdateType.listProp,
                       value: <int>[random.nextInt(100), random.nextInt(100)],
                     ),
                   ),
                   RaisedButton(
                     child: const Text("Change map prop"),
                     onPressed: () => updateState(
                         type: UpdateType.mapProp,
                         value: <String, int>{
                           "one": random.nextInt(100),
                           "two": random.nextInt(100)
                         }),
                   ),
                   Padding(
                       child: Text(status),
                       padding: const EdgeInsets.only(top: 10.0))
                 ],
               )
             : const Center(child: CircularProgressIndicator()),
       );
     }
   }

   class Page extends StatefulWidget {
     @override
     _PageState createState() => _PageState();
   }

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  persistent_state: ^0.2.0

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:persistent_state/persistent_state.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
17
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
57
Learn more about scoring.

We analyzed this package on Nov 15, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.6.0
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.6

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (kvsql).

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0 <3.0.0
cupertino_icons ^0.1.2 0.1.2
extra_pedantic ^1.1.1+1 1.1.1+3
flutter 0.0.0
kvsql ^0.2.1 0.2.1 0.3.0
pedantic ^1.6.0 1.8.0+1
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7 1.1.8
path 1.6.4
path_provider 1.4.2
platform 2.2.1
sky_engine 0.0.99
sqflite 1.1.7+2
sqlcool 3.2.1 4.1.1
synchronized 2.1.0+1
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test