Skip to content

Commit

Permalink
ad withcache impl for flutter
Browse files Browse the repository at this point in the history
  • Loading branch information
alextekartik committed Oct 18, 2024
1 parent 514f17f commit f6b91d3
Show file tree
Hide file tree
Showing 12 changed files with 394 additions and 66 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ pubspec.lock
.idea/
*.iml
.vscode/
/example/tekartik_prefs_flutter_test/.metadata

pubspec_overrides.yaml
1 change: 1 addition & 0 deletions example/tekartik_prefs_flutter_test/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ app.*.map.json
/windows/
/android/
/ios/
.metadata
5 changes: 4 additions & 1 deletion prefs/lib/mixin/prefs_async_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ export 'package:tekartik_prefs/src/prefs_async_mixin.dart'
PrefsAsyncBase,
PrefsAsyncNoImplementationKeyMixin,
PrefsAsyncFactoryMixin,
PrefsAsyncKeyValueMixin;
PrefsAsyncKeyValueMixin,
PrefsAsyncKeyValue,
PrefsAsyncValueMixin,
PrefsAsyncStrictValue;
export 'package:tekartik_prefs/src/prefs_mixin.dart'
show prefsVersionKey, prefsSignatureKey, prefsSignatureValue;
6 changes: 5 additions & 1 deletion prefs/lib/prefs_async.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export 'src/prefs_async.dart'
show PrefsAsync, PrefsAsyncFactory, PrefsAsyncOnVersionChangedFunction;
show
PrefsAsync,
PrefsAsyncFactory,
PrefsAsyncOnVersionChangedFunction,
PrefsAsyncFactoryOptions;
export 'src/prefs_async_memory.dart'
show prefsAsyncFactoryMemory, newPrefsAsyncFactoryMemory;
36 changes: 36 additions & 0 deletions prefs/lib/src/prefs_async.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:async';

import 'package:cv/cv.dart';

/// Common Prefs interface.
abstract class PrefsAsync {
/// The name of the prefs.
Expand All @@ -8,6 +10,9 @@ abstract class PrefsAsync {
/// The version of the prefs.
int get version;

/// The options
PrefsAsyncFactoryOptions get options;

/// Reads a value from persistent storage, null if it's not a
/// bool.
Future<bool?> getBool(String key);
Expand Down Expand Up @@ -67,12 +72,43 @@ abstract class PrefsAsync {

/// Prefs factory.
abstract class PrefsAsyncFactory {
/// Global options
PrefsAsyncFactoryOptions get options;

/// Delete a prefs.
Future<void> deletePreferences(String name);

/// Open a prefs.
Future<PrefsAsync> openPreferences(String name,
{int? version, PrefsAsyncOnVersionChangedFunction? onVersionChanged});

/// Initialize the factory
void init({PrefsAsyncFactoryOptions? options});
}

/// Async factory options
abstract class PrefsAsyncFactoryOptions {
/// No implied conversion between types, matches shared_preferences flutter but not preferred by default
/// and disable extension to generic list and maps
bool get strictType;

/// Default constructor
factory PrefsAsyncFactoryOptions({bool? strictType}) =>
_PrefsAsyncFactoryOptions(strictType: strictType);
}

class _PrefsAsyncFactoryOptions implements PrefsAsyncFactoryOptions {
@override
final bool strictType;

_PrefsAsyncFactoryOptions({bool? strictType})
: strictType = strictType ?? false;

Model toDebugMap() => asModel({
if (strictType) 'strictType': strictType,
});
@override
String toString() => 'PrefsOptions(${toDebugMap()})';
}

/// Prefs on version changed function
Expand Down
4 changes: 3 additions & 1 deletion prefs/lib/src/prefs_async_memory.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import 'package:cv/cv.dart';
import 'package:tekartik_common_utils/common_utils_import.dart';
import 'package:tekartik_prefs/mixin/prefs_async_mixin.dart';
import 'package:tekartik_prefs/prefs_async.dart';
import 'package:tekartik_prefs/src/prefs_async_mixin.dart';

/// Memory implementation of async prefs
class PrefsAsyncMemory extends PrefsAsyncBase
with
PrefsAsyncKeyValueMixin,
PrefsAsyncValueMixin,

// last wins
PrefsAsyncNoImplementationKeyMixin {
final _map = newModel();
Expand Down
165 changes: 159 additions & 6 deletions prefs/lib/src/prefs_async_mixin.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import 'package:cv/utils/value_utils.dart';
import 'package:tekartik_common_utils/common_utils_import.dart';
import 'package:tekartik_prefs/prefs_async.dart';
import 'package:tekartik_prefs/src/prefs_async.dart';

import 'prefs_mixin.dart'
show prefsVersionKey, prefsSignatureKey, prefsSignatureValue;

/// Prefs mixin
abstract mixin class PrefsAsyncFactoryMixin implements PrefsAsyncFactory {
PrefsAsyncFactoryOptions? _options;

@override
PrefsAsyncFactoryOptions get options =>
_options ??= PrefsAsyncFactoryOptions();

/// Lock access
final lock = Lock(reentrant: true);

Expand Down Expand Up @@ -67,6 +75,11 @@ abstract mixin class PrefsAsyncFactoryMixin implements PrefsAsyncFactory {
Future<void> closePreferences(PrefsAsync prefs) async {
allPrefs.remove(prefs.name);
}

@override
void init({PrefsAsyncFactoryOptions? options}) {
_options = options;
}
}

/// Prefs base implementation
Expand All @@ -83,6 +96,12 @@ abstract class PrefsAsyncBase with PrefsAsyncMixin {
PrefsAsyncBase({required this.factory, required this.name});
}

/// Private extension
extension PrefsAsyncMixinExtPrv on PrefsAsyncMixin {
/// The options
PrefsAsyncFactoryOptions get options => this.factory.options;
}

/// mixin to discard any implementation key modification
abstract mixin class PrefsAsyncNoImplementationKeyMixin
implements PrefsAsyncMixin {
Expand All @@ -93,20 +112,139 @@ abstract mixin class PrefsAsyncNoImplementationKeyMixin
String implementationKeyToKey(String implementationKey) => implementationKey;
}

/// Strict value defs
abstract interface class PrefsAsyncStrictValue implements PrefsAsyncMixin {
/// Get double value
Future<double?> getDoubleStrict(String key);

/// Get int value
Future<int?> getIntStrict(String key);

/// Get bool value
Future<bool?> getBoolStrict(String key);

/// Get string value
Future<String?> getStringStrict(String key);

/// Only validate that it is a list
Future<List<String>?> getStringListStrict(String key);
}

/// Value getter helper
abstract mixin class PrefsAsyncValueMixin
implements PrefsAsyncMixin, PrefsAsyncStrictValue, PrefsAsyncKeyValue {
@override
Future<double?> getDouble(String key) async {
if (options.strictType) {
return getDoubleStrict(key);
} else {
return basicTypeToDouble(await getRawValue(key));
}
}

@override
Future<int?> getInt(String key) async {
if (options.strictType) {
return getIntStrict(key);
} else {
return basicTypeToInt(await getRawValue(key));
}
}

// Get bool value
@override
Future<bool?> getBool(String key) async {
if (options.strictType) {
return getBoolStrict(key);
} else {
return basicTypeToBool(await getRawValue(key));
}
}

/// Get string value
@override
Future<String?> getString(String key) async {
if (options.strictType) {
return getStringStrict(key);
} else {
return (await getRawValue(key))?.toString();
}
}

/// Only validate that it is a list
@override
Future<List<String>?> getStringList(String key) async {
if (options.strictType) {
return getStringListStrict(key);
} else {
var list = await getRawValue(key);
if (list is List) {
return list
.map((value) => value is String ? value : null)
.nonNulls
.toList();
}
return null;
}
}

@override
Future<double?> getDoubleStrict(String key) async {
return getValue<double>(key);
}

@override
Future<int?> getIntStrict(String key) async {
return getValue<int>(key);
}

// Get bool value
@override
Future<bool?> getBoolStrict(String key) async {
return getValue<bool>(key);
}

/// Get string value
@override
Future<String?> getStringStrict(String key) async {
return getValue<String>(key);
}

/// Only validate that it is a list
@override
Future<List<String>?> getStringListStrict(String key) async {
return (await getValue<List>(key))?.cast<String>().toList();
}
}

/// Key value abstract interface
abstract interface class PrefsAsyncKeyValue implements PrefsAsync {}

/// Convenient key value mixin
abstract mixin class PrefsAsyncKeyValueMixin implements PrefsAsyncMixin {
abstract mixin class PrefsAsyncKeyValueMixin
implements PrefsAsyncMixin, PrefsAsyncKeyValue {
/// Get a value without key check
Future<T?> getValueNoKeyCheck<T>(String key);

/// Set any value
Future<void> setValueNoKeyCheck<T>(String key, T value);

/// Check and get key
@override
Future<T?> getValue<T>(String key) {
checkKey(key);
return getValueNoKeyCheck<T>(key);
}

Future<Object?> _getRawValueNoKeyCheck<Object>(String key) =>
getValueNoKeyCheck<Object>(key);

@override
Future<Object?> getRawValue(String key) {
checkKey(key);
return _getRawValueNoKeyCheck<Object>(key);
}

/// Check key and set value
Future<void> setValue<T>(String key, T value) {
checkKey(key);
Expand All @@ -126,8 +264,13 @@ abstract mixin class PrefsAsyncKeyValueMixin implements PrefsAsyncMixin {
}

@override
Future<double?> getDouble(String key) async =>
(await getValue<num>(key))?.toDouble();
Future<double?> getDouble(String key) async {
if (options.strictType) {
return getValue<double>(key);
} else {
return (await getNum(key))?.toDouble();
}
}

@override
Future<int?> getInt(String key) async => (await getValue<num>(key))?.round();
Expand Down Expand Up @@ -175,9 +318,19 @@ abstract mixin class PrefsAsyncKeyValueMixin implements PrefsAsyncMixin {

/// Prefs mixin
abstract mixin class PrefsAsyncMixin implements PrefsAsync {
/// Options
@override
late final options = factory.options;

/// To implement
PrefsAsyncFactoryMixin get factory;

/// Get a value (not available for strict type)
Future<T?> getValue<T>(String key);

/// Get a value (not available for strict type)
Future<Object?> getRawValue(String key);

/// Check type
T? checkValueType<T>(Object? value) {
if (value is T) {
Expand Down Expand Up @@ -247,11 +400,11 @@ abstract mixin class PrefsAsyncMixin implements PrefsAsync {
}

/// Check the name
void checkKey(String name) {
if (name.isEmpty) {
void checkKey(String key) {
if (key.isEmpty) {
throw ArgumentError.notNull('prefs key name cannot be empty');
}
if (name.startsWith('_')) {
if (key.startsWith('_')) {
throw ArgumentError('prefs key name cannot start with _');
}
}
Expand Down
2 changes: 1 addition & 1 deletion prefs/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ dependencies:
url: https://github.com/tekartik/common_utils.dart
ref: dart3a
synchronized:
cv: ">=1.1.0+4"
cv: ">=1.1.2-0"
dev_dependencies:
test: ">=1.24.0"
build_runner: ">=2.4.13"
Expand Down
Loading

0 comments on commit f6b91d3

Please sign in to comment.