Skip to content

Instantly share code, notes, and snippets.

@arafaysaleem
Last active April 19, 2024 04:50
Show Gist options
  • Save arafaysaleem/afd3a33ff912d2f0e19379b762b0e0a7 to your computer and use it in GitHub Desktop.
Save arafaysaleem/afd3a33ff912d2f0e19379b762b0e0a7 to your computer and use it in GitHub Desktop.
Key Value Storage Service
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/services.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// Base class containing a unified API for key-value pairs' storage.
/// This class provides low level methods for storing:
/// - Sensitive keys using [FlutterSecureStorage]
/// - Insensitive keys using [SharedPreferences]
class KeyValueStorageBase {
/// Instance of shared preferences
static SharedPreferences? _sharedPrefs;
/// Instance of flutter secure storage
static FlutterSecureStorage? _secureStorage;
/// Singleton instance of KeyValueStorage Helper
static KeyValueStorageBase? _instance;
/// Get instance of this class
factory KeyValueStorageBase() => _instance ??= const KeyValueStorageBase._();
/// Private constructor
const KeyValueStorageBase._();
/// Initializer for shared prefs and flutter secure storage
/// Should be called in main before runApp and
/// after WidgetsBinding.FlutterInitialized(), to allow for synchronous tasks
/// when possible.
static Future<void> init() async {
_sharedPrefs ??= await SharedPreferences.getInstance();
_secureStorage ??= const FlutterSecureStorage();
}
/// Reads the value for the key from common preferences storage
T? getCommon<T>(String key) {
try {
switch (T) {
case String:
return _sharedPrefs!.getString(key) as T?;
case int:
return _sharedPrefs!.getInt(key) as T?;
case bool:
return _sharedPrefs!.getBool(key) as T?;
case double:
return _sharedPrefs!.getDouble(key) as T?;
default:
return _sharedPrefs!.get(key) as T?;
}
} on Exception catch (ex) {
debugPrint('$ex');
return null;
}
}
/// Reads the decrypted value for the key from secure storage
Future<String?> getEncrypted(String key) {
try {
return _secureStorage!.read(key: key);
} on PlatformException catch (ex) {
debugPrint('$ex');
return Future<String?>.value();
}
}
/// Sets the value for the key to common preferences storage
Future<bool> setCommon<T>(String key, T value) {
switch (T) {
case String:
return _sharedPrefs!.setString(key, value as String);
case int:
return _sharedPrefs!.setInt(key, value as int);
case bool:
return _sharedPrefs!.setBool(key, value as bool);
case double:
return _sharedPrefs!.setDouble(key, value as double);
default:
return _sharedPrefs!.setString(key, value as String);
}
}
/// Sets the encrypted value for the key to secure storage
Future<bool> setEncrypted(String key, String value) {
try {
_secureStorage!.write(key: key, value: value);
return Future.value(true);
} on PlatformException catch (ex) {
debugPrint('$ex');
return Future.value(false);
}
}
/// Erases common preferences keys
Future<bool> clearCommon() => _sharedPrefs!.clear();
/// Erases encrypted keys
Future<bool> clearEncrypted() async {
try {
await _secureStorage!.deleteAll();
return true;
} on PlatformException catch (ex) {
debugPrint('$ex');
return false;
}
}
}
import 'dart:convert';
// Services
import 'key_value_storage_base.dart';
// Models
import '../../features/profile/models/student_model.codegen.dart';
// Helpers
import '../../helpers/typedefs.dart';
/// A service class for providing methods to store and retrieve key-value data
/// from common or secure storage.
class KeyValueStorageService {
/// The name of auth token key
static const _authTokenKey = 'authToken';
/// The name of user password key
static const _authPasswordKey = 'authPasswordKey';
/// The name of user model key
static const _authUserKey = 'authUserKey';
/// Instance of key-value storage base class
final _keyValueStorage = KeyValueStorageBase();
/// Returns logged in user password
Future<String> getAuthPassword() async {
return await _keyValueStorage.getEncrypted(_authPasswordKey) ?? '';
}
/// Returns last authenticated user
StudentModel? getAuthUser() {
final user = _keyValueStorage.getCommon<String>(_authUserKey);
if (user == null) return null;
return StudentModel.fromJson(jsonDecode(user) as JSON);
}
/// Returns last authentication token
Future<String> getAuthToken() async {
return await _keyValueStorage.getEncrypted(_authTokenKey) ?? '';
}
/// Sets the authentication password to this value. Even though this method is
/// asynchronous, we don't care about it's completion which is why we don't
/// use `await` and let it execute in the background.
void setAuthPassword(String password) {
_keyValueStorage.setEncrypted(_authPasswordKey, password);
}
/// Sets the authenticated user to this value. Even though this method is
/// asynchronous, we don't care about it's completion which is why we don't
/// use `await` and let it execute in the background.
void setAuthUser(StudentModel user) {
_keyValueStorage.setCommon<String>(_authUserKey, jsonEncode(user.toJson()));
}
/// Sets the authentication token to this value. Even though this method is
/// asynchronous, we don't care about it's completion which is why we don't
/// use `await` and let it execute in the background.
void setAuthToken(String token) {
_keyValueStorage.setEncrypted(_authTokenKey, token);
}
/// Resets the authentication. Even though these methods are asynchronous, we
/// don't care about their completion which is why we don't use `await` and
/// let them execute in the background.
void resetKeys() {
_keyValueStorage
..clearCommon()
..clearEncrypted();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment