Skip to content

Instantly share code, notes, and snippets.

@Kounex
Last active July 31, 2023 09:18
Show Gist options
  • Save Kounex/f301a5174e04343d9beaa2c0b7991d45 to your computer and use it in GitHub Desktop.
Save Kounex/f301a5174e04343d9beaa2c0b7991d45 to your computer and use it in GitHub Desktop.
Firedart with Hive
import 'package:firedart/firedart.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
/// Using this enum to keep track of our [Hive] boxes and have a unified way
/// to use names used for [Hive.openBox(...)] and the [typeId] as used by the
/// adapters for [Hive]
enum HiveBox {
token;
int get typeId => index;
String get boxName => name;
}
/// [TokenStore] is an abstract class provided by the firedart package. To be
/// able to use the [FirebaseAuth.initialize(...)] later on, we need to have
/// an implementation of this class. The idea behind [TokenStore] is to have a
/// unified API to persist and retrieve the the token we receive by Firebase
/// later on. For the persisting part, we are going to use [Hive]
class HiveTokenStore extends TokenStore {
/// The key used in the [Token] box since [Hive] is a key-value store
static const _keyToken = "auth_token";
/// Our singleton of this class
static HiveTokenStore? _instance;
/// We omitted the default constructor in place for a asynchronous [instance]
/// function which will take care of making the used [Hive] box ready and
/// initializing this class and keeping it as a singleton while returning
/// this instance
static Future<HiveTokenStore> instance() async {
if (_instance == null) {
/// Here we can see our enum in action. [Hive.openBox(...)] expects a
/// String as the identifier for the box (key-value store) to open.
/// With such an enum, we can make sure to be able to have an overview of
/// all active stores and have a type-safe way to access them (especially
/// because these names need to be unique)
var box = await Hive.openBox<Token>(
HiveBox.token.boxName,
compactionStrategy: (entries, deletedEntries) => deletedEntries > 50,
);
_instance = HiveTokenStore._internal(box);
}
return _instance!;
}
/// The [Hive] box which is being used to interact with the persistance of
/// our [Token]
final Box<Token> _box;
/// Only private constructor to be able to instantiate this class but only
/// from within - allows for the singleton approach
HiveTokenStore._internal(this._box);
@override
Token? read() => _box.get(_keyToken);
@override
void write(Token? token) {
if (token != null) {
_box.put(_keyToken, token);
}
/// We could throw an error here if we want
}
@override
void delete() => _box.delete(_keyToken);
}
/// The [TypeAdapter] for the [Token] class. Since [Token] is exposed by the
/// firedart package, we are not able to make use of the [Hive] annotations.
/// Usually when declaring a class which will serve as a persisted store, we
/// can make use of [Hive] annotations which with the help of code generation
/// will create such adapters automatically. But since this class is already
/// defined in the package, we need to create the adapter by ourself
class TokenAdapter extends TypeAdapter<Token> {
/// Same usage of the enum as for the name in the [Hive.openBox(...)]
/// function - a typesafe way to distribute unique typeIds
@override
final typeId = HiveBox.token.typeId;
@override
void write(BinaryWriter writer, Token obj) => writer.writeMap(obj.toMap());
@override
Token read(BinaryReader reader) => Token.fromMap(
reader.readMap().map<String, dynamic>(
(key, value) => MapEntry<String, dynamic>(key, value),
),
);
}
void main() {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
late Future<void> _init;
@override
void initState() {
super.initState();
_init = _initApp();
}
/// Since we should generally not encourage to have a asynchronous main
/// function (since it will block the UI because in main we are not in the
/// [runApp(...)] part of our app) we have a wrapper widget [App] which can
/// handle this asynchronous task in a [FutureBuilder]
Future<void> _initApp() async {
final appDir = await getApplicationDocumentsDirectory();
Hive.init(appDir.path);
Hive.registerAdapter(TokenAdapter());
final tokenStore = await HiveTokenStore.instance();
/// TODO: add your API key here
FirebaseAuth.initialize('API_KEY', tokenStore);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: FutureBuilder(
future: _init,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done && !snapshot.hasError) {
return const HomeView();
}
if (snapshot.hasError) {
return Scaffold(
body: Center(
child: Text('Oh oh\n\n${snapshot.error!.toString()}'),
),
);
}
return const Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
),
);
}
}
class HomeView extends StatelessWidget {
const HomeView({super.key});
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text('Test'),
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment