2023-01-19

[Flutter] Katana Prefs

Hello. My name is Masaru Hirose.

New auto-generated packages have been created.

In a nutshell,

Packages that allow type-safe use of Shared Preferences.

I’ve put together some instructions on how to use it, so if you’re interested, go ahead and give it a try!

katana_prefs

The base part of the package for type-safe use of retrieving and storing Shared Preferences values, defining data in a Freezed-like fashion.
https://pub.devhttps://pub.dev
title
Building system for katana prefs packages. The package for type-safe use of retrieving and storing Shared Preferences values, defining data in a Freezed-like fashion.
https://pub.devhttps://pub.dev
title

Introduction

Shared Preferences is a useful plugin.

I think this plugin is the best way to store simple data for the application.

However, I have the following complaints when using the system.

  • Need to remember the key because the key will be a String type.
  • The type of value to be retrieved also depends on the key and must be remembered.
  • Instances of SharedPreferences need to be retrieved asynchronously

In most cases, I think they are wrapped in a separate class or something to make them easier to use.

I have created the following package to solve the above problems.

  • Automatic generation of classes to read/write SharedPreferences data with Freezed-like notation
  • Parameter types and keys are predefined, allowing type-safe implementation
  • Cache instances of SharedPreferences so that data can be retrieved synchronously
  • Inherits from ChangeNotifier, so it is possible to detect a change in value and do something with it.

For example, the following statement is used

@prefs
class PrefsValue with _$PrefsValue, ChangeNotifier {
  factory PrefsValue({
    String? userToken,
    required double volumeSetting,
  }) = _PrefsValue;
}

When build_runner is run with this, a class that can read and write SharedPreferences data is automatically generated.

By defining this, data can be read and written anywhere.

final appPrefs = PrefsValue(volumeSetting: 0.5);

class PrefsPage extends StatefulWidget {
  const PrefsPage({super.key});

  @override
  State<StatefulWidget> createState() => PrefsPageState();
}

class PrefsPageState extends State<PrefsPage> {

  @override
  void initState() {
    super.initState();
    prefs.addListener(() {
      setState(() {});
    });
    appPrefs.load();
  }

  @override
  Widget build(BuildContext context, WidgetRef ref){
    final volumeSetting = appPrefs.volumeSetting.get();

    ~~~~
    appPrefs.volumeSetting.set(1.0); // At this time, appPrefs is also notified of the change and the widget is re-updated.
    ~~~~
  }
}

Installation

Import the following package for code generation using build_runner.

flutter pub add katana_prefs
flutter pub add --dev build_runner
flutter pub add --dev katana_prefs_builder

Implementation

Make a Class

Create a class as follows

Add part '(filename).prefs.dart';.

Annotate the defined class with @prefs and mixin _$(defined class name) and ChangeNotifier.

The constructor is created in the factory and defines the values to be used in the parameters.

(Required values are marked required; if required is not marked, leave it as it is.)

After the constructor, write = _(defined class name).

// prefs_value.dart

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

part 'prefs_value.prefs.dart';

@prefs
class PrefsValue with _$PrefsValue, ChangeNotifier {
  factory PrefsValue({
    String? userToken,
    required double volumeSetting,
  }) = _PrefsValue;
}

Code Generation

Automatic code generation is performed by entering the following command.

flutter pub run build_runner build --delete-conflicting-outputs

How to use

Define values globally.

When creating an object, enter the value specified in required. This will be the initial value.

final appPrefs = PrefsValue(volumeSetting: 0.5);

Before loading the first value, it executes the load() method and waits for it to finish.

(It is also possible to wait for the end by monitoring the loading field.)

@override
void initState() {
  super.initState();
  appPrefs.load();
}

The state can be monitored with addListener if necessary.

@override
void initState() {
  super.initState();
  prefs.addListener(() {
    setState(() {});
  });
  appPrefs.load();
}

It is possible to retrieve data from SharedPreference with appPrefs.(defined value).get().

final volumeSetting = appPrefs.volumeSetting.get();

Data can be stored in SharedPreference with appPrefs.(defined value).set(value).

When the save is complete, notifyListeners() is called to execute the callback monitored by addListener.

appPrefs.volumeSetting.set(1.0);

Conclusion

I made it for my own use, but if you think it fits your implementation philosophy, by all means, use it!

Also, I releasing the source here, so issues and PullRequests are welcome!

If you have any further work requests, please contact me directly through my Twitter or website!

Offers app development and apps using Flutter and Unity. Includes information on music and videos created by the company. Distribution of images and video materials. We also accept orders for work.
https://mathru.nethttps://mathru.net
title

GitHub Sponsors

Sponsors are always welcome. Thank you for your support!

Developed the katana/masamune framework, which has dramatically improved the overall efficiency of Flutter-based application development.
https://github.comhttps://github.com
title