[shared_preferences] Adds new clearWithParameters and getAllWithParameters methods to all platforms. (#4262)

Adds new `clearWithParameters` and `getAllWithParameters` methods.

part of https://github.com/flutter/flutter/issues/128948

precursor to https://github.com/flutter/packages/pull/3794

awaiting https://github.com/flutter/packages/pull/4261

## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [relevant style guides] and ran the
auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages
repo does use `dart format`.)
- [x] I signed the [CLA].
- [x] The title of the PR starts with the name of the package surrounded
by square brackets, e.g. `[shared_preferences]`
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated `pubspec.yaml` with an appropriate new version according
to the [pub versioning philosophy], or this PR is [exempt from version
changes].
- [x] I updated `CHANGELOG.md` to add a description of the change,
[following repository CHANGELOG style].
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md
[Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene
[relevant style guides]:
https://github.com/flutter/packages/blob/main/CONTRIBUTING.md#style
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes
[Discord]: https://github.com/flutter/flutter/wiki/Chat
[pub versioning philosophy]: https://dart.dev/tools/pub/versioning
[exempt from version changes]:
https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#version-and-changelog-updates
[following repository CHANGELOG style]:
https://github.com/flutter/flutter/wiki/Contributing-to-Plugins-and-Packages#changelog-style
[test-exempt]:
https://github.com/flutter/flutter/wiki/Tree-hygiene#tests
This commit is contained in:
Tarrin Neal
2023-06-29 11:05:13 -07:00
committed by GitHub
parent d4752c4069
commit d61537115c
40 changed files with 2436 additions and 783 deletions

View File

@ -1,5 +1,6 @@
## NEXT ## 2.2.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.1.4 ## 2.1.4

View File

@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved. // Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.4), do not edit directly. // Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
package io.flutter.plugins.sharedpreferences; package io.flutter.plugins.sharedpreferences;
@ -75,10 +75,10 @@ public class Messages {
Boolean setStringList(@NonNull String key, @NonNull List<String> value); Boolean setStringList(@NonNull String key, @NonNull List<String> value);
/** Removes all properties from shared preferences data set with matching prefix. */ /** Removes all properties from shared preferences data set with matching prefix. */
@NonNull @NonNull
Boolean clearWithPrefix(@NonNull String prefix); Boolean clear(@NonNull String prefix, @Nullable List<String> allowList);
/** Gets all properties from shared preferences data set with matching prefix. */ /** Gets all properties from shared preferences data set with matching prefix. */
@NonNull @NonNull
Map<String, Object> getAllWithPrefix(@NonNull String prefix); Map<String, Object> getAll(@NonNull String prefix, @Nullable List<String> allowList);
/** The codec used by SharedPreferencesApi. */ /** The codec used by SharedPreferencesApi. */
static @NonNull MessageCodec<Object> getCodec() { static @NonNull MessageCodec<Object> getCodec() {
@ -263,7 +263,7 @@ public class Messages {
BasicMessageChannel<Object> channel = BasicMessageChannel<Object> channel =
new BasicMessageChannel<>( new BasicMessageChannel<>(
binaryMessenger, binaryMessenger,
"dev.flutter.pigeon.SharedPreferencesApi.clearWithPrefix", "dev.flutter.pigeon.SharedPreferencesApi.clear",
getCodec(), getCodec(),
taskQueue); taskQueue);
if (api != null) { if (api != null) {
@ -272,8 +272,9 @@ public class Messages {
ArrayList<Object> wrapped = new ArrayList<Object>(); ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message; ArrayList<Object> args = (ArrayList<Object>) message;
String prefixArg = (String) args.get(0); String prefixArg = (String) args.get(0);
List<String> allowListArg = (List<String>) args.get(1);
try { try {
Boolean output = api.clearWithPrefix(prefixArg); Boolean output = api.clear(prefixArg, allowListArg);
wrapped.add(0, output); wrapped.add(0, output);
} catch (Throwable exception) { } catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception); ArrayList<Object> wrappedError = wrapError(exception);
@ -290,7 +291,7 @@ public class Messages {
BasicMessageChannel<Object> channel = BasicMessageChannel<Object> channel =
new BasicMessageChannel<>( new BasicMessageChannel<>(
binaryMessenger, binaryMessenger,
"dev.flutter.pigeon.SharedPreferencesApi.getAllWithPrefix", "dev.flutter.pigeon.SharedPreferencesApi.getAll",
getCodec(), getCodec(),
taskQueue); taskQueue);
if (api != null) { if (api != null) {
@ -299,8 +300,9 @@ public class Messages {
ArrayList<Object> wrapped = new ArrayList<Object>(); ArrayList<Object> wrapped = new ArrayList<Object>();
ArrayList<Object> args = (ArrayList<Object>) message; ArrayList<Object> args = (ArrayList<Object>) message;
String prefixArg = (String) args.get(0); String prefixArg = (String) args.get(0);
List<String> allowListArg = (List<String>) args.get(1);
try { try {
Map<String, Object> output = api.getAllWithPrefix(prefixArg); Map<String, Object> output = api.getAll(prefixArg, allowListArg);
wrapped.add(0, output); wrapped.add(0, output);
} catch (Throwable exception) { } catch (Throwable exception) {
ArrayList<Object> wrappedError = wrapError(exception); ArrayList<Object> wrappedError = wrapError(exception);

View File

@ -9,6 +9,7 @@ import android.content.SharedPreferences;
import android.util.Base64; import android.util.Base64;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.BinaryMessenger; import io.flutter.plugin.common.BinaryMessenger;
@ -21,6 +22,7 @@ import java.io.ObjectOutputStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -111,18 +113,20 @@ public class SharedPreferencesPlugin implements FlutterPlugin, SharedPreferences
} }
@Override @Override
public @NonNull Map<String, Object> getAllWithPrefix(@NonNull String prefix) public @NonNull Map<String, Object> getAll(
throws RuntimeException { @NonNull String prefix, @Nullable List<String> allowList) throws RuntimeException {
return getAllPrefs(prefix); final Set<String> allowSet = allowList == null ? null : new HashSet<>(allowList);
return getAllPrefs(prefix, allowSet);
} }
@Override @Override
public @NonNull Boolean clearWithPrefix(@NonNull String prefix) throws RuntimeException { public @NonNull Boolean clear(@NonNull String prefix, @Nullable List<String> allowList)
throws RuntimeException {
SharedPreferences.Editor clearEditor = preferences.edit(); SharedPreferences.Editor clearEditor = preferences.edit();
Map<String, ?> allPrefs = preferences.getAll(); Map<String, ?> allPrefs = preferences.getAll();
ArrayList<String> filteredPrefs = new ArrayList<>(); ArrayList<String> filteredPrefs = new ArrayList<>();
for (String key : allPrefs.keySet()) { for (String key : allPrefs.keySet()) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
filteredPrefs.add(key); filteredPrefs.add(key);
} }
} }
@ -133,12 +137,14 @@ public class SharedPreferencesPlugin implements FlutterPlugin, SharedPreferences
} }
// Gets all shared preferences, filtered to only those set with the given prefix. // Gets all shared preferences, filtered to only those set with the given prefix.
// Optionally filtered also to only those items in the optional [allowList].
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private @NonNull Map<String, Object> getAllPrefs(@NonNull String prefix) throws RuntimeException { private @NonNull Map<String, Object> getAllPrefs(
@NonNull String prefix, @Nullable Set<String> allowList) throws RuntimeException {
Map<String, ?> allPrefs = preferences.getAll(); Map<String, ?> allPrefs = preferences.getAll();
Map<String, Object> filteredPrefs = new HashMap<>(); Map<String, Object> filteredPrefs = new HashMap<>();
for (String key : allPrefs.keySet()) { for (String key : allPrefs.keySet()) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix) && (allowList == null || allowList.contains(key))) {
filteredPrefs.put(key, transformPref(key, allPrefs.get(key))); filteredPrefs.put(key, transformPref(key, allPrefs.get(key)));
} }
} }

View File

@ -67,12 +67,12 @@ public class SharedPreferencesTest {
} }
@Test @Test
public void getAllWithPrefix() { public void getAll() {
assertEquals(plugin.getAllWithPrefix("").size(), 0); assertEquals(plugin.getAll("", null).size(), 0);
addData(); addData();
Map<String, Object> flutterData = plugin.getAllWithPrefix("flutter."); Map<String, Object> flutterData = plugin.getAll("flutter.", null);
assertEquals(flutterData.size(), 5); assertEquals(flutterData.size(), 5);
assertEquals(flutterData.get("flutter.Language"), "Java"); assertEquals(flutterData.get("flutter.Language"), "Java");
@ -81,17 +81,43 @@ public class SharedPreferencesTest {
assertEquals(flutterData.get("flutter.Names"), Arrays.asList("Flutter", "Dart")); assertEquals(flutterData.get("flutter.Names"), Arrays.asList("Flutter", "Dart"));
assertEquals(flutterData.get("flutter.NewToFlutter"), false); assertEquals(flutterData.get("flutter.NewToFlutter"), false);
Map<String, Object> allData = plugin.getAllWithPrefix(""); Map<String, Object> allData = plugin.getAll("", null);
assertEquals(allData, data); assertEquals(allData, data);
} }
@Test
public void allowList() {
assertEquals(plugin.getAll("", null).size(), 0);
addData();
final List<String> allowList = Arrays.asList("flutter.Language");
Map<String, Object> allData = plugin.getAll("flutter.", allowList);
assertEquals(allData.size(), 1);
assertEquals(allData.get("flutter.Language"), "Java");
assertEquals(allData.get("flutter.Counter"), null);
allData = plugin.getAll("", allowList);
assertEquals(allData.size(), 1);
assertEquals(allData.get("flutter.Language"), "Java");
assertEquals(allData.get("flutter.Counter"), null);
allData = plugin.getAll("prefix.", allowList);
assertEquals(allData.size(), 0);
assertEquals(allData.get("flutter.Language"), null);
}
@Test @Test
public void setString() { public void setString() {
final String key = "language"; final String key = "language";
final String value = "Java"; final String value = "Java";
plugin.setString(key, value); plugin.setString(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix(""); Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value); assertEquals(flutterData.get(key), value);
} }
@ -100,7 +126,7 @@ public class SharedPreferencesTest {
final String key = "Counter"; final String key = "Counter";
final Long value = 0L; final Long value = 0L;
plugin.setInt(key, value); plugin.setInt(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix(""); Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value); assertEquals(flutterData.get(key), value);
} }
@ -109,7 +135,7 @@ public class SharedPreferencesTest {
final String key = "Pie"; final String key = "Pie";
final double value = 3.14; final double value = 3.14;
plugin.setDouble(key, value); plugin.setDouble(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix(""); Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value); assertEquals(flutterData.get(key), value);
} }
@ -118,7 +144,7 @@ public class SharedPreferencesTest {
final String key = "Names"; final String key = "Names";
final List<String> value = Arrays.asList("Flutter", "Dart"); final List<String> value = Arrays.asList("Flutter", "Dart");
plugin.setStringList(key, value); plugin.setStringList(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix(""); Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value); assertEquals(flutterData.get(key), value);
} }
@ -127,30 +153,41 @@ public class SharedPreferencesTest {
final String key = "NewToFlutter"; final String key = "NewToFlutter";
final boolean value = false; final boolean value = false;
plugin.setBool(key, value); plugin.setBool(key, value);
Map<String, Object> flutterData = plugin.getAllWithPrefix(""); Map<String, Object> flutterData = plugin.getAll("", null);
assertEquals(flutterData.get(key), value); assertEquals(flutterData.get(key), value);
} }
@Test @Test
public void clearWithPrefix() { public void clearWithNoAllowList() {
addData(); addData();
assertEquals(plugin.getAllWithPrefix("").size(), 15); assertEquals(plugin.getAll("", null).size(), 15);
plugin.clearWithPrefix("flutter."); plugin.clear("flutter.", null);
assertEquals(plugin.getAllWithPrefix("").size(), 10); assertEquals(plugin.getAll("", null).size(), 10);
}
@Test
public void clearWithAllowList() {
addData();
assertEquals(plugin.getAll("", null).size(), 15);
plugin.clear("flutter.", Arrays.asList("flutter.Language"));
assertEquals(plugin.getAll("", null).size(), 14);
} }
@Test @Test
public void clearAll() { public void clearAll() {
addData(); addData();
assertEquals(plugin.getAllWithPrefix("").size(), 15); assertEquals(plugin.getAll("", null).size(), 15);
plugin.clearWithPrefix(""); plugin.clear("", null);
assertEquals(plugin.getAllWithPrefix("").size(), 0); assertEquals(plugin.getAll("", null).size(), 0);
} }
@Test @Test
@ -158,9 +195,9 @@ public class SharedPreferencesTest {
final String key = "NewToFlutter"; final String key = "NewToFlutter";
final boolean value = true; final boolean value = true;
plugin.setBool(key, value); plugin.setBool(key, value);
assert (plugin.getAllWithPrefix("").containsKey(key)); assert (plugin.getAll("", null).containsKey(key));
plugin.remove(key); plugin.remove(key);
assertFalse(plugin.getAllWithPrefix("").containsKey(key)); assertFalse(plugin.getAll("", null).containsKey(key));
} }
private void addData() { private void addData() {

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -47,14 +48,20 @@ void main() {
preferences = SharedPreferencesStorePlatform.instance; preferences = SharedPreferencesStorePlatform.instance;
}); });
tearDown(() { tearDown(() async {
// ignore: deprecated_member_use await preferences.clearWithParameters(
preferences.clearWithPrefix(''); ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('reading', (WidgetTester _) async {
// ignore: deprecated_member_use final Map<String, Object> values = await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], isNull); expect(values['String'], isNull);
expect(values['Bool'], isNull); expect(values['Bool'], isNull);
expect(values['Int'], isNull); expect(values['Int'], isNull);
@ -62,6 +69,35 @@ void main() {
expect(values['StringList'], isNull); expect(values['StringList'], isNull);
}); });
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
testWidgets('getAllWithPrefix', (WidgetTester _) async { testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await Future.wait(<Future<bool>>[
preferences.setValue( preferences.setValue(
@ -94,68 +130,160 @@ void main() {
expect(values['prefix.StringList'], allTestValues['prefix.StringList']); expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
}); });
testWidgets('clearWithPrefix', (WidgetTester _) async { group('withPrefix', () {
await Future.wait(<Future<bool>>[ testWidgets('clearWithPrefix', (WidgetTester _) async {
preferences.setValue( await Future.wait(<Future<bool>>[
'String', 'prefix.String', allTestValues['prefix.String']!), preferences.setValue(
preferences.setValue( 'String', 'prefix.String', allTestValues['prefix.String']!),
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!), preferences.setValue(
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!), 'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue( preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!), 'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue('StringList', 'prefix.StringList', preferences.setValue(
allTestValues['prefix.StringList']!), 'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue( preferences.setValue('StringList', 'prefix.StringList',
'String', 'flutter.String', allTestValues['flutter.String']!), allTestValues['prefix.StringList']!),
preferences.setValue( preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), 'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue( preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!), 'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue( preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!), 'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue('StringList', 'flutter.StringList', preferences.setValue(
allTestValues['flutter.StringList']!) 'Double', 'flutter.Double', allTestValues['flutter.Double']!),
]); preferences.setValue('StringList', 'flutter.StringList',
// ignore: deprecated_member_use allTestValues['flutter.StringList']!)
await preferences.clearWithPrefix('prefix.'); ]);
Map<String, Object> values = // ignore: deprecated_member_use
// ignore: deprecated_member_use await preferences.clearWithPrefix('prefix.');
await preferences.getAllWithPrefix('prefix.'); Map<String, Object> values =
expect(values['prefix.String'], null); // ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
testWidgets('get all with prefix', (WidgetTester _) async {
await addData();
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
await addData();
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null); expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null); expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null); expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null); expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('getAllWithNoPrefix', (WidgetTester _) async { testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await addData();
preferences.setValue('String', 'String', allTestValues['String']!), final Map<String, Object> values = await preferences.getAllWithParameters(
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!), GetAllParameters(
preferences.setValue('Int', 'Int', allTestValues['Int']!), filter: PreferencesFilter(prefix: ''),
preferences.setValue('Double', 'Double', allTestValues['Double']!), ),
preferences.setValue( );
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']); expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']); expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']); expect(values['Int'], allTestValues['Int']);
@ -168,29 +296,84 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']); expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('clearWithParameters', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{
'prefix.Double',
'prefix.Int',
'prefix.Bool',
'prefix.String',
},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async { testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await addData();
preferences.setValue('String', 'String', allTestValues['String']!), await preferences.clearWithParameters(
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!), ClearParameters(
preferences.setValue('Int', 'Int', allTestValues['Int']!), filter: PreferencesFilter(prefix: ''),
preferences.setValue('Double', 'Double', allTestValues['Double']!), ),
preferences.setValue( );
'StringList', 'StringList', allTestValues['StringList']!), final Map<String, Object> values = await preferences.getAllWithParameters(
preferences.setValue( GetAllParameters(
'String', 'flutter.String', allTestValues['flutter.String']!), filter: PreferencesFilter(prefix: ''),
preferences.setValue( ),
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), );
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null); expect(values['String'], null);
expect(values['Bool'], null); expect(values['Bool'], null);
expect(values['Int'], null); expect(values['Int'], null);
@ -204,18 +387,16 @@ void main() {
}); });
testWidgets('getAll', (WidgetTester _) async { testWidgets('getAll', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await preferences.setValue(
preferences.setValue( 'String', 'flutter.String', allTestValues['flutter.String']!);
'String', 'flutter.String', allTestValues['flutter.String']!), await preferences.setValue(
preferences.setValue( 'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), await preferences.setValue(
preferences.setValue( 'Int', 'flutter.Int', allTestValues['flutter.Int']!);
'Int', 'flutter.Int', allTestValues['flutter.Int']!), await preferences.setValue(
preferences.setValue( 'Double', 'flutter.Double', allTestValues['flutter.Double']!);
'Double', 'flutter.Double', allTestValues['flutter.Double']!), await preferences.setValue('StringList', 'flutter.StringList',
preferences.setValue('StringList', 'flutter.StringList', allTestValues['flutter.StringList']!);
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values = await preferences.getAll(); final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -235,8 +416,11 @@ void main() {
await preferences.setValue( await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!); 'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key); await preferences.remove(key);
// ignore: deprecated_member_use final Map<String, Object> values = await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull); expect(values[key], isNull);
}); });
@ -270,8 +454,11 @@ void main() {
// All writes should succeed. // All writes should succeed.
expect(result.where((bool element) => !element), isEmpty); expect(result.where((bool element) => !element), isEmpty);
// The last write should win. // The last write should win.
// ignore: deprecated_member_use final Map<String, Object> values = await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['Int'], writeCount); expect(values['Int'], writeCount);
}); });
@ -279,8 +466,11 @@ void main() {
(WidgetTester _) async { (WidgetTester _) async {
const String key = 'akey'; const String key = 'akey';
const String value = 'a string value'; const String value = 'a string value';
// ignore: deprecated_member_use await preferences.clearWithParameters(
await preferences.clearWithPrefix(''); ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
// Special prefixes used to store datatypes that can't be stored directly // Special prefixes used to store datatypes that can't be stored directly
// in SharedPreferences as strings instead. // in SharedPreferences as strings instead.
@ -296,8 +486,11 @@ void main() {
expect(preferences.setValue('String', key, prefix + value), expect(preferences.setValue('String', key, prefix + value),
throwsA(isA<PlatformException>())); throwsA(isA<PlatformException>()));
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use await preferences.getAllWithParameters(
await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], null); expect(values[key], null);
} }
}); });

View File

@ -16,7 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on # The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
shared_preferences_platform_interface: ^2.0.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_driver: flutter_driver:

View File

@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'src/messages.g.dart'; import 'src/messages.g.dart';
@ -52,23 +53,50 @@ class SharedPreferencesAndroid extends SharedPreferencesStorePlatform {
} }
@override @override
Future<bool> clear() { Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
return _api.clearWithPrefix(prefix); return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
} }
@override @override
Future<Map<String, Object>> getAll() { Future<bool> clearWithParameters(ClearParameters parameters) async {
return getAllWithPrefix(_defaultPrefix); final PreferencesFilter filter = parameters.filter;
return _api.clear(
filter.prefix,
filter.allowList?.toList(),
);
}
@override
Future<Map<String, Object>> getAll() async {
return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
final Map<String?, Object?> data = await _api.getAllWithPrefix(prefix); return getAllWithParameters(
GetAllParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String?, Object?> data =
await _api.getAll(filter.prefix, filter.allowList?.toList());
return data.cast<String, Object>(); return data.cast<String, Object>();
} }
} }

View File

@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved. // Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.4), do not edit directly. // Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
@ -190,12 +190,12 @@ class SharedPreferencesApi {
} }
/// Removes all properties from shared preferences data set with matching prefix. /// Removes all properties from shared preferences data set with matching prefix.
Future<bool> clearWithPrefix(String arg_prefix) async { Future<bool> clear(String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.SharedPreferencesApi.clearWithPrefix', codec, 'dev.flutter.pigeon.SharedPreferencesApi.clear', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList = await channel
await channel.send(<Object?>[arg_prefix]) as List<Object?>?; .send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -218,12 +218,13 @@ class SharedPreferencesApi {
} }
/// Gets all properties from shared preferences data set with matching prefix. /// Gets all properties from shared preferences data set with matching prefix.
Future<Map<String?, Object?>> getAllWithPrefix(String arg_prefix) async { Future<Map<String?, Object?>> getAll(
String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.SharedPreferencesApi.getAllWithPrefix', codec, 'dev.flutter.pigeon.SharedPreferencesApi.getAll', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList = await channel
await channel.send(<Object?>[arg_prefix]) as List<Object?>?; .send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',

View File

@ -41,9 +41,15 @@ abstract class SharedPreferencesApi {
/// Removes all properties from shared preferences data set with matching prefix. /// Removes all properties from shared preferences data set with matching prefix.
@TaskQueue(type: TaskQueueType.serialBackgroundThread) @TaskQueue(type: TaskQueueType.serialBackgroundThread)
bool clearWithPrefix(String prefix); bool clear(
String prefix,
List<String>? allowList,
);
/// Gets all properties from shared preferences data set with matching prefix. /// Gets all properties from shared preferences data set with matching prefix.
@TaskQueue(type: TaskQueueType.serialBackgroundThread) @TaskQueue(type: TaskQueueType.serialBackgroundThread)
Map<String, Object> getAllWithPrefix(String prefix); Map<String, Object> getAll(
String prefix,
List<String>? allowList,
);
} }

View File

@ -2,7 +2,7 @@ name: shared_preferences_android
description: Android implementation of the shared_preferences plugin description: Android implementation of the shared_preferences plugin
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.1.4 version: 2.2.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"
@ -20,7 +20,7 @@ flutter:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences_platform_interface: ^2.2.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_android/shared_preferences_android.dart'; import 'package:shared_preferences_android/shared_preferences_android.dart';
import 'package:shared_preferences_android/src/messages.g.dart'; import 'package:shared_preferences_android/src/messages.g.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
TestWidgetsFlutterBinding.ensureInitialized(); TestWidgetsFlutterBinding.ensureInitialized();
@ -80,6 +81,61 @@ void main() {
expect(all.length, 0); expect(all.length, 0);
}); });
test('clearWithParameters', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 0);
});
test('clearWithParameters with allow list', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 4);
});
test('getAll', () async { test('getAll', () async {
for (final String key in flutterTestValues.keys) { for (final String key in flutterTestValues.keys) {
api.items[key] = flutterTestValues[key]!; api.items[key] = flutterTestValues[key]!;
@ -89,15 +145,56 @@ void main() {
expect(all, flutterTestValues); expect(all, flutterTestValues);
}); });
test('getAllWithPrefix', () async { test('getAllWithNoPrefix', () async {
for (final String key in allTestValues.keys) { for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!; api.items[key] = allTestValues[key]!;
} }
final Map<String?, Object?> all = await plugin.getAllWithPrefix('prefix.'); final Map<String?, Object?> all = await plugin.getAllWithPrefix('');
expect(all.length, 15);
expect(all, allTestValues);
});
test('clearWithNoPrefix', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithPrefix('');
expect(all.length, 15);
await plugin.clearWithPrefix('');
all = await plugin.getAllWithPrefix('');
expect(all.length, 0);
});
test('getAllWithParameters', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5); expect(all.length, 5);
expect(all, prefixTestValues); expect(all, prefixTestValues);
}); });
test('getAllWithParameters with allow list', () async {
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], true);
});
test('setValue', () async { test('setValue', () async {
expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue); expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
expect(api.items['flutter.Bool'], true); expect(api.items['flutter.Bool'], true);
@ -124,7 +221,11 @@ void main() {
for (final String key in allTestValues.keys) { for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!; api.items[key] = allTestValues[key]!;
} }
final Map<String?, Object?> all = await plugin.getAllWithPrefix(''); final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15); expect(all.length, 15);
expect(all, allTestValues); expect(all, allTestValues);
}); });
@ -134,10 +235,22 @@ void main() {
api.items[key] = allTestValues[key]!; api.items[key] = allTestValues[key]!;
} }
Map<String?, Object?> all = await plugin.getAllWithPrefix(''); Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15); expect(all.length, 15);
await plugin.clearWithPrefix(''); await plugin.clearWithParameters(
all = await plugin.getAllWithPrefix(''); ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 0); expect(all.length, 0);
}); });
} }
@ -146,10 +259,19 @@ class _FakeSharedPreferencesApi implements SharedPreferencesApi {
final Map<String, Object> items = <String, Object>{}; final Map<String, Object> items = <String, Object>{};
@override @override
Future<Map<String?, Object?>> getAllWithPrefix(String prefix) async { Future<Map<String?, Object?>> getAll(
String prefix,
List<String?>? allowList,
) async {
Set<String?>? allowSet;
if (allowList != null) {
allowSet = Set<String>.from(allowList);
}
return <String?, Object?>{ return <String?, Object?>{
for (final String key in items.keys) for (final String key in items.keys)
if (key.startsWith(prefix)) key: items[key] if (key.startsWith(prefix) &&
(allowSet == null || allowSet.contains(key)))
key: items[key]
}; };
} }
@ -172,9 +294,10 @@ class _FakeSharedPreferencesApi implements SharedPreferencesApi {
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clear(String prefix, List<String?>? allowList) async {
items.keys.toList().forEach((String key) { items.keys.toList().forEach((String key) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix) &&
(allowList == null || allowList.contains(key))) {
items.remove(key); items.remove(key);
} }
}); });

View File

@ -1,5 +1,6 @@
## NEXT ## 2.3.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported macOS version to 10.14. * Updates minimum supported macOS version to 10.14.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.

View File

@ -22,8 +22,8 @@ public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
UserDefaultsApiSetup.setUp(binaryMessenger: messenger, api: instance) UserDefaultsApiSetup.setUp(binaryMessenger: messenger, api: instance)
} }
func getAllWithPrefix(prefix: String) -> [String? : Any?] { func getAll(prefix: String, allowList: [String]?) -> [String? : Any?] {
return getAllPrefs(prefix: prefix) return getAllPrefs(prefix: prefix, allowList: allowList)
} }
func setBool(key: String, value: Bool) { func setBool(key: String, value: Bool) {
@ -42,20 +42,26 @@ public class SharedPreferencesPlugin: NSObject, FlutterPlugin, UserDefaultsApi {
UserDefaults.standard.removeObject(forKey: key) UserDefaults.standard.removeObject(forKey: key)
} }
func clearWithPrefix(prefix: String) { func clear(prefix: String, allowList: [String]?) -> Bool {
let defaults = UserDefaults.standard let defaults = UserDefaults.standard
for (key, _) in getAllPrefs(prefix: prefix) { for (key, _) in getAllPrefs(prefix: prefix, allowList: allowList) {
defaults.removeObject(forKey: key) defaults.removeObject(forKey: key)
} }
return true
} }
/// Returns all preferences stored with specified prefix. /// Returns all preferences stored with specified prefix.
func getAllPrefs(prefix: String) -> [String: Any] { /// If [allowList] is included, only items included will be returned.
func getAllPrefs(prefix: String, allowList: [String]?) -> [String: Any] {
var filteredPrefs: [String: Any] = [:] var filteredPrefs: [String: Any] = [:]
var allowSet: Set<String>?;
if let allowList {
allowSet = Set(allowList)
}
if let appDomain = Bundle.main.bundleIdentifier, if let appDomain = Bundle.main.bundleIdentifier,
let prefs = UserDefaults.standard.persistentDomain(forName: appDomain) let prefs = UserDefaults.standard.persistentDomain(forName: appDomain)
{ {
for (key, value) in prefs where key.hasPrefix(prefix) { for (key, value) in prefs where (key.hasPrefix(prefix) && (allowSet == nil || allowSet!.contains(key))) {
filteredPrefs[key] = value filteredPrefs[key] = value
} }
} }

View File

@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved. // Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.4), do not edit directly. // Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
import Foundation import Foundation
@ -42,8 +42,8 @@ protocol UserDefaultsApi {
func setBool(key: String, value: Bool) throws func setBool(key: String, value: Bool) throws
func setDouble(key: String, value: Double) throws func setDouble(key: String, value: Double) throws
func setValue(key: String, value: Any) throws func setValue(key: String, value: Any) throws
func getAllWithPrefix(prefix: String) throws -> [String?: Any?] func getAll(prefix: String, allowList: [String]?) throws -> [String?: Any?]
func clearWithPrefix(prefix: String) throws func clear(prefix: String, allowList: [String]?) throws -> Bool
} }
/// Generated setup class from Pigeon to handle messages through the `binaryMessenger`. /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@ -114,35 +114,37 @@ class UserDefaultsApiSetup {
} else { } else {
setValueChannel.setMessageHandler(nil) setValueChannel.setMessageHandler(nil)
} }
let getAllWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix", binaryMessenger: binaryMessenger) let getAllChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.getAll", binaryMessenger: binaryMessenger)
if let api = api { if let api = api {
getAllWithPrefixChannel.setMessageHandler { message, reply in getAllChannel.setMessageHandler { message, reply in
let args = message as! [Any] let args = message as! [Any]
let prefixArg = args[0] as! String let prefixArg = args[0] as! String
let allowListArg: [String]? = nilOrValue(args[1])
do { do {
let result = try api.getAllWithPrefix(prefix: prefixArg) let result = try api.getAll(prefix: prefixArg, allowList: allowListArg)
reply(wrapResult(result)) reply(wrapResult(result))
} catch { } catch {
reply(wrapError(error)) reply(wrapError(error))
} }
} }
} else { } else {
getAllWithPrefixChannel.setMessageHandler(nil) getAllChannel.setMessageHandler(nil)
} }
let clearWithPrefixChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix", binaryMessenger: binaryMessenger) let clearChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.UserDefaultsApi.clear", binaryMessenger: binaryMessenger)
if let api = api { if let api = api {
clearWithPrefixChannel.setMessageHandler { message, reply in clearChannel.setMessageHandler { message, reply in
let args = message as! [Any] let args = message as! [Any]
let prefixArg = args[0] as! String let prefixArg = args[0] as! String
let allowListArg: [String]? = nilOrValue(args[1])
do { do {
try api.clearWithPrefix(prefix: prefixArg) let result = try api.clear(prefix: prefixArg, allowList: allowListArg)
reply(wrapResult(nil)) reply(wrapResult(result))
} catch { } catch {
reply(wrapError(error)) reply(wrapError(error))
} }
} }
} else { } else {
clearWithPrefixChannel.setMessageHandler(nil) clearChannel.setMessageHandler(nil)
} }
} }
} }

View File

@ -25,7 +25,7 @@ class RunnerTests: XCTestCase {
plugin.setValue(key: "\(aPrefix)aString", value: "hello world") plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"]) plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
let storedValues = plugin.getAllWithPrefix(prefix: aPrefix) let storedValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true) XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
XCTAssertEqual(storedValues["\(aPrefix)aDouble"] as! Double, 3.14, accuracy: 0.0001) XCTAssertEqual(storedValues["\(aPrefix)aDouble"] as! Double, 3.14, accuracy: 0.0001)
XCTAssertEqual(storedValues["\(aPrefix)anInt"] as? Int, 42) XCTAssertEqual(storedValues["\(aPrefix)anInt"] as? Int, 42)
@ -34,6 +34,25 @@ class RunnerTests: XCTestCase {
} }
} }
func testGetWithAllowList() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
plugin.setBool(key: "\(aPrefix)aBool", value: true)
plugin.setDouble(key: "\(aPrefix)aDouble", value: 3.14)
plugin.setValue(key: "\(aPrefix)anInt", value: 42)
plugin.setValue(key: "\(aPrefix)aString", value: "hello world")
plugin.setValue(key: "\(aPrefix)aStringList", value: ["hello", "world"])
let storedValues = plugin.getAll(prefix: aPrefix, allowList: ["\(aPrefix)aBool"])
XCTAssertEqual(storedValues["\(aPrefix)aBool"] as? Bool, true)
XCTAssertNil(storedValues["\(aPrefix)aDouble"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)anInt"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)aString"] ?? nil)
XCTAssertNil(storedValues["\(aPrefix)aStringList"] ?? nil)
}
}
func testRemove() throws { func testRemove() throws {
for aPrefix in prefixes { for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin() let plugin = SharedPreferencesPlugin()
@ -41,33 +60,50 @@ class RunnerTests: XCTestCase {
plugin.setValue(key: testKey, value: 42) plugin.setValue(key: testKey, value: 42)
// Make sure there is something to remove, so the test can't pass due to a set failure. // Make sure there is something to remove, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix) let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42) XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
// Then verify that removing it works. // Then verify that removing it works.
plugin.remove(key: testKey) plugin.remove(key: testKey)
let finalValues = plugin.getAllWithPrefix(prefix: aPrefix) let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertNil(finalValues[testKey] as Any?) XCTAssertNil(finalValues[testKey] as Any?)
} }
} }
func testClearWithNoAllowlist() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
func testClear() throws { // Make sure there is something to clear, so the test can't pass due to a set failure.
for aPrefix in prefixes { let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
let plugin = SharedPreferencesPlugin() XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
// Make sure there is something to clear, so the test can't pass due to a set failure. // Then verify that clearing works.
let preRemovalValues = plugin.getAllWithPrefix(prefix: aPrefix) plugin.clear(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
// Then verify that clearing works. let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
plugin.clearWithPrefix(prefix: aPrefix) XCTAssertNil(finalValues[testKey] as Any?)
}
let finalValues = plugin.getAllWithPrefix(prefix: aPrefix) }
XCTAssertNil(finalValues[testKey] as Any?)
func testClearWithAllowlist() throws {
for aPrefix in prefixes {
let plugin = SharedPreferencesPlugin()
let testKey = "\(aPrefix)foo"
plugin.setValue(key: testKey, value: 42)
// Make sure there is something to clear, so the test can't pass due to a set failure.
let preRemovalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(preRemovalValues[testKey] as? Int, 42)
plugin.clear(prefix: aPrefix, allowList: ["\(aPrefix)notfoo"])
let finalValues = plugin.getAll(prefix: aPrefix, allowList: nil)
XCTAssertEqual(finalValues[testKey] as? Int, 42)
}
} }
}
} }

View File

@ -5,6 +5,7 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@ -46,175 +47,375 @@ void main() {
preferences = SharedPreferencesStorePlatform.instance; preferences = SharedPreferencesStorePlatform.instance;
}); });
tearDown(() { tearDown(() async {
// ignore: deprecated_member_use await preferences.clearWithParameters(
preferences.clearWithPrefix(''); ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
}); });
testWidgets('reading', (WidgetTester _) async { group('withPrefix', () {
// ignore: deprecated_member_use testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithPrefix(''); final Map<String, Object> values =
expect(values['String'], isNull); // ignore: deprecated_member_use
expect(values['Bool'], isNull); await preferences.getAllWithPrefix('');
expect(values['Int'], isNull); expect(values['String'], isNull);
expect(values['Double'], isNull); expect(values['Bool'], isNull);
expect(values['StringList'], isNull); expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
});
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
}); });
testWidgets('getAllWithPrefix', (WidgetTester _) async { group('withParameters', () {
await Future.wait(<Future<bool>>[ testWidgets('reading', (WidgetTester _) async {
preferences.setValue( final Map<String, Object> values =
'String', 'prefix.String', allTestValues['prefix.String']!), await preferences.getAllWithParameters(
preferences.setValue( GetAllParameters(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!), filter: PreferencesFilter(prefix: ''),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!), ),
preferences.setValue( );
'Double', 'prefix.Double', allTestValues['prefix.Double']!), expect(values['String'], isNull);
preferences.setValue('StringList', 'prefix.StringList', expect(values['Bool'], isNull);
allTestValues['prefix.StringList']!), expect(values['Int'], isNull);
preferences.setValue( expect(values['Double'], isNull);
'String', 'flutter.String', allTestValues['flutter.String']!), expect(values['StringList'], isNull);
preferences.setValue( });
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async { Future<void> addData() async {
await Future.wait(<Future<bool>>[ await preferences.setValue(
preferences.setValue( 'String', 'String', allTestValues['String']!);
'String', 'prefix.String', allTestValues['prefix.String']!), await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
preferences.setValue( await preferences.setValue('Int', 'Int', allTestValues['Int']!);
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!), await preferences.setValue(
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!), 'Double', 'Double', allTestValues['Double']!);
preferences.setValue( await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!), 'StringList', 'StringList', allTestValues['StringList']!);
preferences.setValue('StringList', 'prefix.StringList', await preferences.setValue(
allTestValues['prefix.StringList']!), 'String', 'prefix.String', allTestValues['prefix.String']!);
preferences.setValue( await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!), 'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
preferences.setValue( await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), 'Int', 'prefix.Int', allTestValues['prefix.Int']!);
preferences.setValue( await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!), 'Double', 'prefix.Double', allTestValues['prefix.Double']!);
preferences.setValue( await preferences.setValue('StringList', 'prefix.StringList',
'Double', 'flutter.Double', allTestValues['flutter.Double']!), allTestValues['prefix.StringList']!);
preferences.setValue('StringList', 'flutter.StringList', await preferences.setValue(
allTestValues['flutter.StringList']!) 'String', 'flutter.String', allTestValues['flutter.String']!);
]); await preferences.setValue(
// ignore: deprecated_member_use 'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.clearWithPrefix('prefix.'); await preferences.setValue(
Map<String, Object> values = 'Int', 'flutter.Int', allTestValues['flutter.Int']!);
// ignore: deprecated_member_use await preferences.setValue(
await preferences.getAllWithPrefix('prefix.'); 'Double', 'flutter.Double', allTestValues['flutter.Double']!);
expect(values['prefix.String'], null); await preferences.setValue('StringList', 'flutter.StringList',
expect(values['prefix.Bool'], null); allTestValues['flutter.StringList']!);
expect(values['prefix.Int'], null); }
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
// ignore: deprecated_member_use
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async { testWidgets('get all with prefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await addData();
preferences.setValue('String', 'String', allTestValues['String']!), final Map<String, Object> values =
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!), await preferences.getAllWithParameters(
preferences.setValue('Int', 'Int', allTestValues['Int']!), GetAllParameters(
preferences.setValue('Double', 'Double', allTestValues['Double']!), filter: PreferencesFilter(prefix: 'prefix.'),
preferences.setValue( ),
'StringList', 'StringList', allTestValues['StringList']!), );
preferences.setValue( expect(values['prefix.String'], allTestValues['prefix.String']);
'String', 'flutter.String', allTestValues['flutter.String']!), expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
preferences.setValue( expect(values['prefix.Int'], allTestValues['prefix.Int']);
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), expect(values['prefix.Double'], allTestValues['prefix.Double']);
preferences.setValue( expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
'Int', 'flutter.Int', allTestValues['flutter.Int']!), });
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async { testWidgets('get all with allow list', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await addData();
preferences.setValue('String', 'String', allTestValues['String']!), final Map<String, Object> values =
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!), await preferences.getAllWithParameters(
preferences.setValue('Int', 'Int', allTestValues['Int']!), GetAllParameters(
preferences.setValue('Double', 'Double', allTestValues['Double']!), filter: PreferencesFilter(
preferences.setValue( prefix: 'prefix.',
'StringList', 'StringList', allTestValues['StringList']!), allowList: <String>{'prefix.String'},
preferences.setValue( ),
'String', 'flutter.String', allTestValues['flutter.String']!), ),
preferences.setValue( );
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), expect(values['prefix.String'], allTestValues['prefix.String']);
preferences.setValue( expect(values['prefix.Bool'], null);
'Int', 'flutter.Int', allTestValues['flutter.Int']!), expect(values['prefix.Int'], null);
preferences.setValue( expect(values['prefix.Double'], null);
'Double', 'flutter.Double', allTestValues['flutter.Double']!), expect(values['prefix.StringList'], null);
preferences.setValue('StringList', 'flutter.StringList', });
allTestValues['flutter.StringList']!)
]); testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
// ignore: deprecated_member_use await addData();
await preferences.clearWithPrefix(''); final Map<String, Object> values =
// ignore: deprecated_member_use await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
expect(values['String'], null); filter: PreferencesFilter(prefix: ''),
expect(values['Bool'], null); ),
expect(values['Int'], null); );
expect(values['Double'], null); expect(values['String'], allTestValues['String']);
expect(values['StringList'], null); expect(values['Bool'], allTestValues['Bool']);
expect(values['flutter.String'], null); expect(values['Int'], allTestValues['Int']);
expect(values['flutter.Bool'], null); expect(values['Double'], allTestValues['Double']);
expect(values['flutter.Int'], null); expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.Double'], null); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.StringList'], null); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
}); });
testWidgets('getAll', (WidgetTester _) async { testWidgets('getAll', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await preferences.setValue(
preferences.setValue( 'String', 'flutter.String', allTestValues['flutter.String']!);
'String', 'flutter.String', allTestValues['flutter.String']!), await preferences.setValue(
preferences.setValue( 'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), await preferences.setValue(
preferences.setValue( 'Int', 'flutter.Int', allTestValues['flutter.Int']!);
'Int', 'flutter.Int', allTestValues['flutter.Int']!), await preferences.setValue(
preferences.setValue( 'Double', 'flutter.Double', allTestValues['flutter.Double']!);
'Double', 'flutter.Double', allTestValues['flutter.Double']!), await preferences.setValue('StringList', 'flutter.StringList',
preferences.setValue('StringList', 'flutter.StringList', allTestValues['flutter.StringList']!);
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values = await preferences.getAll(); final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], allTestValues['flutter.String']); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
@ -234,8 +435,11 @@ void main() {
await preferences.setValue( await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!); 'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key); await preferences.remove(key);
// ignore: deprecated_member_use final Map<String, Object> values = await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull); expect(values[key], isNull);
}); });
@ -269,8 +473,11 @@ void main() {
// All writes should succeed. // All writes should succeed.
expect(result.where((bool element) => !element), isEmpty); expect(result.where((bool element) => !element), isEmpty);
// The last write should win. // The last write should win.
// ignore: deprecated_member_use final Map<String, Object> values = await preferences.getAllWithParameters(
final Map<String, Object> values = await preferences.getAllWithPrefix(''); GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['Int'], writeCount); expect(values['Int'], writeCount);
}); });
}); });

View File

@ -16,7 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on # The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
shared_preferences_platform_interface: ^2.0.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_driver: flutter_driver:

View File

@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved. // Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.4), do not edit directly. // Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
@ -109,12 +109,13 @@ class UserDefaultsApi {
} }
} }
Future<Map<String?, Object?>> getAllWithPrefix(String arg_prefix) async { Future<Map<String?, Object?>> getAll(
String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec, 'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList = await channel
await channel.send(<Object?>[arg_prefix]) as List<Object?>?; .send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -136,12 +137,12 @@ class UserDefaultsApi {
} }
} }
Future<void> clearWithPrefix(String arg_prefix) async { Future<bool> clear(String arg_prefix, List<String?>? arg_allowList) async {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec, 'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
binaryMessenger: _binaryMessenger); binaryMessenger: _binaryMessenger);
final List<Object?>? replyList = final List<Object?>? replyList = await channel
await channel.send(<Object?>[arg_prefix]) as List<Object?>?; .send(<Object?>[arg_prefix, arg_allowList]) as List<Object?>?;
if (replyList == null) { if (replyList == null) {
throw PlatformException( throw PlatformException(
code: 'channel-error', code: 'channel-error',
@ -153,8 +154,13 @@ class UserDefaultsApi {
message: replyList[1] as String?, message: replyList[1] as String?,
details: replyList[2], details: replyList[2],
); );
} else if (replyList[0] == null) {
throw PlatformException(
code: 'null-error',
message: 'Host platform returned null value for non-null return value.',
);
} else { } else {
return; return (replyList[0] as bool?)!;
} }
} }
} }

View File

@ -4,6 +4,7 @@
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'messages.g.dart'; import 'messages.g.dart';
typedef _Setter = Future<void> Function(String key, Object value); typedef _Setter = Future<void> Function(String key, Object value);
@ -12,7 +13,7 @@ typedef _Setter = Future<void> Function(String key, Object value);
class SharedPreferencesFoundation extends SharedPreferencesStorePlatform { class SharedPreferencesFoundation extends SharedPreferencesStorePlatform {
final UserDefaultsApi _api = UserDefaultsApi(); final UserDefaultsApi _api = UserDefaultsApi();
static const String _defautPrefix = 'flutter.'; static const String _defaultPrefix = 'flutter.';
late final Map<String, _Setter> _setters = <String, _Setter>{ late final Map<String, _Setter> _setters = <String, _Setter>{
'Bool': (String key, Object value) { 'Bool': (String key, Object value) {
@ -40,24 +41,50 @@ class SharedPreferencesFoundation extends SharedPreferencesStorePlatform {
@override @override
Future<bool> clear() async { Future<bool> clear() async {
return clearWithPrefix(_defautPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
await _api.clearWithPrefix(prefix); return clearWithParameters(
return true; ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
return _api.clear(
filter.prefix,
filter.allowList?.toList(),
);
} }
@override @override
Future<Map<String, Object>> getAll() async { Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defautPrefix); return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
final Map<String?, Object?> result = await _api.getAllWithPrefix(prefix); return getAllWithParameters(
return result.cast<String, Object>(); GetAllParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String?, Object?> data =
await _api.getAll(filter.prefix, filter.allowList?.toList());
return data.cast<String, Object>();
} }
@override @override

View File

@ -20,6 +20,6 @@ abstract class UserDefaultsApi {
void setValue(String key, Object value); void setValue(String key, Object value);
// TODO(stuartmorgan): Make these non-nullable once // TODO(stuartmorgan): Make these non-nullable once
// https://github.com/flutter/flutter/issues/97848 is fixed. // https://github.com/flutter/flutter/issues/97848 is fixed.
Map<String?, Object?> getAllWithPrefix(String prefix); Map<String?, Object?> getAll(String prefix, List<String>? allowList);
void clearWithPrefix(String prefix); bool clear(String prefix, List<String>? allowList);
} }

View File

@ -2,7 +2,7 @@ name: shared_preferences_foundation
description: iOS and macOS implementation of the shared_preferences plugin. description: iOS and macOS implementation of the shared_preferences plugin.
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_foundation
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.2.2 version: 2.3.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"
@ -24,7 +24,7 @@ flutter:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences_platform_interface: ^2.2.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -6,6 +6,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:shared_preferences_foundation/shared_preferences_foundation.dart'; import 'package:shared_preferences_foundation/shared_preferences_foundation.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'test_api.g.dart'; import 'test_api.g.dart';
@ -13,10 +14,19 @@ class _MockSharedPreferencesApi implements TestUserDefaultsApi {
final Map<String, Object> items = <String, Object>{}; final Map<String, Object> items = <String, Object>{};
@override @override
Map<String?, Object?> getAllWithPrefix(String prefix) { Map<String?, Object?> getAll(
String prefix,
List<String?>? allowList,
) {
Set<String?>? allowSet;
if (allowList != null) {
allowSet = Set<String>.from(allowList);
}
return <String?, Object?>{ return <String?, Object?>{
for (final String key in items.keys) for (final String key in items.keys)
if (key.startsWith(prefix)) key: items[key] if (key.startsWith(prefix) &&
(allowSet == null || allowSet.contains(key)))
key: items[key]
}; };
} }
@ -41,12 +51,14 @@ class _MockSharedPreferencesApi implements TestUserDefaultsApi {
} }
@override @override
void clearWithPrefix(String prefix) { bool clear(String prefix, List<String?>? allowList) {
items.keys.toList().forEach((String key) { items.keys.toList().forEach((String key) {
if (key.startsWith(prefix)) { if (key.startsWith(prefix) &&
(allowList == null || allowList.contains(key))) {
items.remove(key); items.remove(key);
} }
}); });
return true;
} }
} }
@ -124,6 +136,63 @@ void main() {
expect(all.length, 0); expect(all.length, 0);
}); });
test('clearWithParameters', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 0);
});
test('clearWithParameters with allow list', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
all = await plugin.getAll();
expect(all.length, 5);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 4);
});
test('getAll', () async { test('getAll', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation(); final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in flutterTestValues.keys) { for (final String key in flutterTestValues.keys) {
@ -144,6 +213,37 @@ void main() {
expect(all, prefixTestValues); expect(all, prefixTestValues);
}); });
test('getAllWithParameters', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(all.length, 5);
expect(all, prefixTestValues);
});
test('getAllWithParameters with allow list', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('setValue', () async { test('setValue', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation(); final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue); expect(await plugin.setValue('Bool', 'flutter.Bool', true), isTrue);
@ -190,4 +290,43 @@ void main() {
all = await plugin.getAllWithPrefix(''); all = await plugin.getAllWithPrefix('');
expect(all.length, 0); expect(all.length, 0);
}); });
test('getAllWithNoPrefix with param', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
final Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
expect(all, allTestValues);
});
test('clearWithNoPrefix with param', () async {
final SharedPreferencesFoundation plugin = SharedPreferencesFoundation();
for (final String key in allTestValues.keys) {
api.items[key] = allTestValues[key]!;
}
Map<String?, Object?> all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 15);
await plugin.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
all = await plugin.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(all.length, 0);
});
} }

View File

@ -1,7 +1,7 @@
// Copyright 2013 The Flutter Authors. All rights reserved. // Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// Autogenerated from Pigeon (v9.2.4), do not edit directly. // Autogenerated from Pigeon (v9.2.5), do not edit directly.
// See also: https://pub.dev/packages/pigeon // See also: https://pub.dev/packages/pigeon
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
// ignore_for_file: avoid_relative_lib_imports // ignore_for_file: avoid_relative_lib_imports
@ -26,9 +26,9 @@ abstract class TestUserDefaultsApi {
void setValue(String key, Object value); void setValue(String key, Object value);
Map<String?, Object?> getAllWithPrefix(String prefix); Map<String?, Object?> getAll(String prefix, List<String?>? allowList);
void clearWithPrefix(String prefix); bool clear(String prefix, List<String?>? allowList);
static void setup(TestUserDefaultsApi? api, static void setup(TestUserDefaultsApi? api,
{BinaryMessenger? binaryMessenger}) { {BinaryMessenger? binaryMessenger}) {
@ -131,7 +131,7 @@ abstract class TestUserDefaultsApi {
} }
{ {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix', codec, 'dev.flutter.pigeon.UserDefaultsApi.getAll', codec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger _testBinaryMessengerBinding!.defaultBinaryMessenger
@ -141,20 +141,22 @@ abstract class TestUserDefaultsApi {
.setMockDecodedMessageHandler<Object?>(channel, .setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async { (Object? message) async {
assert(message != null, assert(message != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null.'); 'Argument for dev.flutter.pigeon.UserDefaultsApi.getAll was null.');
final List<Object?> args = (message as List<Object?>?)!; final List<Object?> args = (message as List<Object?>?)!;
final String? arg_prefix = (args[0] as String?); final String? arg_prefix = (args[0] as String?);
assert(arg_prefix != null, assert(arg_prefix != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.getAllWithPrefix was null, expected non-null String.'); 'Argument for dev.flutter.pigeon.UserDefaultsApi.getAll was null, expected non-null String.');
final List<String?>? arg_allowList =
(args[1] as List<Object?>?)?.cast<String?>();
final Map<String?, Object?> output = final Map<String?, Object?> output =
api.getAllWithPrefix(arg_prefix!); api.getAll(arg_prefix!, arg_allowList);
return <Object?>[output]; return <Object?>[output];
}); });
} }
} }
{ {
final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>( final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
'dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix', codec, 'dev.flutter.pigeon.UserDefaultsApi.clear', codec,
binaryMessenger: binaryMessenger); binaryMessenger: binaryMessenger);
if (api == null) { if (api == null) {
_testBinaryMessengerBinding!.defaultBinaryMessenger _testBinaryMessengerBinding!.defaultBinaryMessenger
@ -164,13 +166,15 @@ abstract class TestUserDefaultsApi {
.setMockDecodedMessageHandler<Object?>(channel, .setMockDecodedMessageHandler<Object?>(channel,
(Object? message) async { (Object? message) async {
assert(message != null, assert(message != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null.'); 'Argument for dev.flutter.pigeon.UserDefaultsApi.clear was null.');
final List<Object?> args = (message as List<Object?>?)!; final List<Object?> args = (message as List<Object?>?)!;
final String? arg_prefix = (args[0] as String?); final String? arg_prefix = (args[0] as String?);
assert(arg_prefix != null, assert(arg_prefix != null,
'Argument for dev.flutter.pigeon.UserDefaultsApi.clearWithPrefix was null, expected non-null String.'); 'Argument for dev.flutter.pigeon.UserDefaultsApi.clear was null, expected non-null String.');
api.clearWithPrefix(arg_prefix!); final List<String?>? arg_allowList =
return <Object?>[]; (args[1] as List<Object?>?)?.cast<String?>();
final bool output = api.clear(arg_prefix!, arg_allowList);
return <Object?>[output];
}); });
} }
} }

View File

@ -1,5 +1,6 @@
## NEXT ## 2.3.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.2.0 ## 2.2.0

View File

@ -5,101 +5,335 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart'; import 'package:shared_preferences_linux/shared_preferences_linux.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesLinux', () { group('SharedPreferencesLinux', () {
const Map<String, Object> kTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.bool': true,
'flutter.int': 42,
'flutter.double': 3.14159,
'flutter.List': <String>['foo', 'bar'],
};
const Map<String, Object> kTestValues2 = <String, Object>{
'flutter.String': 'goodbye world',
'flutter.bool': false,
'flutter.int': 1337,
'flutter.double': 2.71828,
'flutter.List': <String>['baz', 'quox'],
};
late SharedPreferencesLinux preferences; late SharedPreferencesLinux preferences;
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world',
'flutter.Bool': true,
'flutter.Int': 42,
'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world',
'prefix.Bool': true,
'prefix.Int': 42,
'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'],
};
const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world',
'Bool': true,
'Int': 42,
'Double': 3.14159,
'StringList': <String>['foo', 'bar'],
};
final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
setUp(() async { setUp(() async {
preferences = SharedPreferencesLinux(); preferences = SharedPreferencesLinux();
await addData();
}); });
tearDown(() { tearDown(() async {
preferences.clear(); await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('getAll', (WidgetTester _) async {
final Map<String, Object> all = await preferences.getAll(); final Map<String, Object> values = await preferences.getAll();
expect(all['flutter.String'], isNull); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(all['flutter.bool'], isNull); expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(all['flutter.int'], isNull); expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(all['flutter.double'], isNull); expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(all['flutter.List'], isNull); expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('writing', (WidgetTester _) async { group('withPrefix', () {
await Future.wait(<Future<bool>>[ testWidgets('remove', (WidgetTester _) async {
preferences.setValue( const String key = 'flutter.String';
'String', 'flutter.String', kTestValues2['flutter.String']!), await preferences.remove(key);
preferences.setValue( final Map<String, Object> values =
'Bool', 'flutter.bool', kTestValues2['flutter.bool']!), await preferences.getAllWithPrefix('');
preferences.setValue( expect(values[key], isNull);
'Int', 'flutter.int', kTestValues2['flutter.int']!), });
preferences.setValue(
'Double', 'flutter.double', kTestValues2['flutter.double']!), testWidgets('clear', (WidgetTester _) async {
preferences.setValue( await preferences.clear();
'StringList', 'flutter.List', kTestValues2['flutter.List']!) final Map<String, Object> values = await preferences.getAll();
]); expect(values['flutter.String'], null);
final Map<String, Object> all = await preferences.getAll(); expect(values['flutter.Bool'], null);
expect(all['flutter.String'], kTestValues2['flutter.String']); expect(values['flutter.Int'], null);
expect(all['flutter.bool'], kTestValues2['flutter.bool']); expect(values['flutter.Double'], null);
expect(all['flutter.int'], kTestValues2['flutter.int']); expect(values['flutter.StringList'], null);
expect(all['flutter.double'], kTestValues2['flutter.double']); });
expect(all['flutter.List'], kTestValues2['flutter.List']);
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('');
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
}); });
testWidgets('removing', (WidgetTester _) async { group('withParameters', () {
const String key = 'flutter.testKey'; testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
await Future.wait(<Future<bool>>[ testWidgets('clear', (WidgetTester _) async {
preferences.setValue('String', key, kTestValues['flutter.String']!), await preferences.clear();
preferences.setValue('Bool', key, kTestValues['flutter.bool']!), final Map<String, Object> values = await preferences.getAll();
preferences.setValue('Int', key, kTestValues['flutter.int']!), expect(values['flutter.String'], null);
preferences.setValue('Double', key, kTestValues['flutter.double']!), expect(values['flutter.Bool'], null);
preferences.setValue('StringList', key, kTestValues['flutter.List']!) expect(values['flutter.Int'], null);
]); expect(values['flutter.Double'], null);
await preferences.remove(key); expect(values['flutter.StringList'], null);
final Map<String, Object> all = await preferences.getAll(); });
expect(all[key], isNull);
});
testWidgets('clearing', (WidgetTester _) async { testWidgets('get all with prefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ final Map<String, Object> values =
preferences.setValue( await preferences.getAllWithParameters(
'String', 'flutter.String', kTestValues['flutter.String']!), GetAllParameters(
preferences.setValue( filter: PreferencesFilter(prefix: 'prefix.'),
'Bool', 'flutter.bool', kTestValues['flutter.bool']!), ),
preferences.setValue('Int', 'flutter.int', kTestValues['flutter.int']!), );
preferences.setValue( expect(values['prefix.String'], allTestValues['prefix.String']);
'Double', 'flutter.double', kTestValues['flutter.double']!), expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
preferences.setValue( expect(values['prefix.Int'], allTestValues['prefix.Int']);
'StringList', 'flutter.List', kTestValues['flutter.List']!) expect(values['prefix.Double'], allTestValues['prefix.Double']);
]); expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
await preferences.clear(); });
final Map<String, Object> all = await preferences.getAll();
expect(all['flutter.String'], null); testWidgets('get all with allow list', (WidgetTester _) async {
expect(all['flutter.bool'], null); final Map<String, Object> values =
expect(all['flutter.int'], null); await preferences.getAllWithParameters(
expect(all['flutter.double'], null); GetAllParameters(
expect(all['flutter.List'], null); filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
}); });
}); });
} }

View File

@ -16,6 +16,7 @@ dependencies:
# The example app is bundled with the plugin so we use a path dependency on # The example app is bundled with the plugin so we use a path dependency on
# the parent directory to use the current plugin's version. # the parent directory to use the current plugin's version.
path: ../ path: ../
shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_driver: flutter_driver:

View File

@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart' show debugPrint, visibleForTesting;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider_linux/path_provider_linux.dart'; import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The Linux implementation of [SharedPreferencesStorePlatform]. /// The Linux implementation of [SharedPreferencesStorePlatform].
/// ///
@ -94,26 +95,52 @@ class SharedPreferencesLinux extends SharedPreferencesStorePlatform {
@override @override
Future<bool> clear() async { Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> preferences = await _readPreferences(); final Map<String, Object> preferences = await _readPreferences();
preferences.removeWhere((String key, _) => key.startsWith(prefix)); preferences.removeWhere((String key, _) =>
key.startsWith(filter.prefix) &&
(filter.allowList == null || filter.allowList!.contains(key)));
return _writePreferences(preferences); return _writePreferences(preferences);
} }
@override @override
Future<Map<String, Object>> getAll() async { Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix); return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
return getAllWithParameters(
GetAllParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> withPrefix = final Map<String, Object> withPrefix =
Map<String, Object>.from(await _readPreferences()); Map<String, Object>.from(await _readPreferences());
withPrefix.removeWhere((String key, _) => !key.startsWith(prefix)); withPrefix.removeWhere((String key, _) => !(key.startsWith(filter.prefix) &&
(filter.allowList?.contains(key) ?? true)));
return withPrefix; return withPrefix;
} }

View File

@ -2,7 +2,7 @@ name: shared_preferences_linux
description: Linux implementation of the shared_preferences plugin description: Linux implementation of the shared_preferences plugin
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_linux
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.2.0 version: 2.3.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"
@ -22,7 +22,7 @@ dependencies:
path: ^1.8.0 path: ^1.8.0
path_provider_linux: ^2.0.0 path_provider_linux: ^2.0.0
path_provider_platform_interface: ^2.0.0 path_provider_platform_interface: ^2.0.0
shared_preferences_platform_interface: ^2.2.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -10,6 +10,7 @@ import 'package:path_provider_linux/path_provider_linux.dart';
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:shared_preferences_linux/shared_preferences_linux.dart'; import 'package:shared_preferences_linux/shared_preferences_linux.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
void main() { void main() {
late MemoryFileSystem fs; late MemoryFileSystem fs;
@ -98,6 +99,35 @@ void main() {
expect(values, prefixTestValues); expect(values, prefixTestValues);
}); });
test('getAllWithParameters', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values, hasLength(5));
expect(values, prefixTestValues);
});
test('getAllWithParameters with allow list', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String?, Object?> all = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('remove', () async { test('remove', () async {
await writeTestFile('{"key1":"one","key2":2}'); await writeTestFile('{"key1":"one","key2":2}');
final SharedPreferencesLinux prefs = getPreferences(); final SharedPreferencesLinux prefs = getPreferences();
@ -155,6 +185,74 @@ void main() {
final Map<String, Object> noValues = await prefs.getAllWithPrefix(''); final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
expect(noValues, hasLength(0)); expect(noValues, hasLength(0));
}); });
test('clearWithParameters', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(0));
final Map<String, Object> values = await prefs.getAll();
expect(values, hasLength(5));
expect(values, flutterTestValues);
});
test('clearWithParameters with allow list', () async {
await writeTestFile(json.encode(prefixTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
final Map<String, Object> someValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(someValues, hasLength(4));
});
test('getAllWithNoPrefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesLinux prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values, hasLength(15));
expect(values, allTestValues);
});
test('clearWithNoPrefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesLinux prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(noValues, hasLength(0));
});
} }
/// Fake implementation of PathProviderLinux that returns hard-coded paths, /// Fake implementation of PathProviderLinux that returns hard-coded paths,

View File

@ -1,5 +1,6 @@
## NEXT ## 2.2.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.1.0 ## 2.1.0

View File

@ -8,6 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart'; import 'package:shared_preferences_platform_interface/method_channel_shared_preferences.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'package:shared_preferences_web/shared_preferences_web.dart'; import 'package:shared_preferences_web/shared_preferences_web.dart';
const Map<String, dynamic> kTestValues = <String, dynamic>{ const Map<String, dynamic> kTestValues = <String, dynamic>{
@ -21,94 +22,124 @@ const Map<String, dynamic> kTestValues = <String, dynamic>{
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesPlugin', () { setUp(() {
setUp(() { html.window.localStorage.clear();
html.window.localStorage.clear(); });
});
testWidgets('registers itself', (WidgetTester tester) async { testWidgets('registers itself', (WidgetTester tester) async {
SharedPreferencesStorePlatform.instance = SharedPreferencesStorePlatform.instance =
MethodChannelSharedPreferencesStore(); MethodChannelSharedPreferencesStore();
expect(SharedPreferencesStorePlatform.instance, expect(SharedPreferencesStorePlatform.instance,
isNot(isA<SharedPreferencesPlugin>())); isNot(isA<SharedPreferencesPlugin>()));
SharedPreferencesPlugin.registerWith(null); SharedPreferencesPlugin.registerWith(null);
expect(SharedPreferencesStorePlatform.instance, expect(SharedPreferencesStorePlatform.instance,
isA<SharedPreferencesPlugin>()); isA<SharedPreferencesPlugin>());
}); });
const Map<String, Object> flutterTestValues = <String, Object>{ const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world', 'flutter.String': 'hello world',
'flutter.Bool': true, 'flutter.Bool': true,
'flutter.Int': 42, 'flutter.Int': 42,
'flutter.Double': 3.14159, 'flutter.Double': 3.14159,
'flutter.StringList': <String>['foo', 'bar'], 'flutter.StringList': <String>['foo', 'bar'],
}; };
const Map<String, Object> prefixTestValues = <String, Object>{ const Map<String, Object> prefixTestValues = <String, Object>{
'prefix.String': 'hello world', 'prefix.String': 'hello world',
'prefix.Bool': true, 'prefix.Bool': true,
'prefix.Int': 42, 'prefix.Int': 42,
'prefix.Double': 3.14159, 'prefix.Double': 3.14159,
'prefix.StringList': <String>['foo', 'bar'], 'prefix.StringList': <String>['foo', 'bar'],
}; };
const Map<String, Object> nonPrefixTestValues = <String, Object>{ const Map<String, Object> nonPrefixTestValues = <String, Object>{
'String': 'hello world', 'String': 'hello world',
'Bool': true, 'Bool': true,
'Int': 42, 'Int': 42,
'Double': 3.14159, 'Double': 3.14159,
'StringList': <String>['foo', 'bar'], 'StringList': <String>['foo', 'bar'],
}; };
final Map<String, Object> allTestValues = <String, Object>{}; final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues); allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues); allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues); allTestValues.addAll(nonPrefixTestValues);
late SharedPreferencesStorePlatform preferences; late SharedPreferencesStorePlatform preferences;
setUp(() async {
preferences = SharedPreferencesStorePlatform.instance;
});
tearDown(() async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
});
testWidgets('reading', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAll();
expect(values.length, 0);
});
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue(
'StringList', 'prefix.StringList', allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
testWidgets('clear', (WidgetTester _) async {
await addData();
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
group('withPrefix', () {
setUp(() async { setUp(() async {
preferences = SharedPreferencesStorePlatform.instance; await addData();
}); });
tearDown(() { testWidgets('remove', (WidgetTester _) async {
// ignore: deprecated_member_use const String key = 'flutter.String';
preferences.clearWithPrefix(''); await preferences.remove(key);
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values[key], isNull);
}); });
testWidgets('reading', (WidgetTester _) async { testWidgets('get all with prefix', (WidgetTester _) async {
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], isNull);
expect(values['Bool'], isNull);
expect(values['Int'], isNull);
expect(values['Double'], isNull);
expect(values['StringList'], isNull);
});
testWidgets('getAllWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
final Map<String, Object> values = final Map<String, Object> values =
// ignore: deprecated_member_use // ignore: deprecated_member_use
await preferences.getAllWithPrefix('prefix.'); await preferences.getAllWithPrefix('prefix.');
@ -119,28 +150,23 @@ void main() {
expect(values['prefix.StringList'], allTestValues['prefix.StringList']); expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
}); });
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async { testWidgets('clearWithPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!),
preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!),
preferences.setValue('Int', 'prefix.Int', allTestValues['prefix.Int']!),
preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!),
preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use // ignore: deprecated_member_use
await preferences.clearWithPrefix('prefix.'); await preferences.clearWithPrefix('prefix.');
Map<String, Object> values = Map<String, Object> values =
@ -160,27 +186,76 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']); expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('getAllWithNoPrefix', (WidgetTester _) async { testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[
preferences.setValue('String', 'String', allTestValues['String']!),
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!),
preferences.setValue('Int', 'Int', allTestValues['Int']!),
preferences.setValue('Double', 'Double', allTestValues['Double']!),
preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!),
preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!),
preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use // ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix(''); await preferences.clearWithPrefix('');
final Map<String, Object> values =
// ignore: deprecated_member_use
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
group('withParameters', () {
setUp(() async {
await addData();
});
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']); expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']); expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']); expect(values['Int'], allTestValues['Int']);
@ -193,29 +268,77 @@ void main() {
expect(values['flutter.StringList'], allTestValues['flutter.StringList']); expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list', (WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async { testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ await preferences.clearWithParameters(
preferences.setValue('String', 'String', allTestValues['String']!), ClearParameters(
preferences.setValue('Bool', 'Bool', allTestValues['Bool']!), filter: PreferencesFilter(prefix: ''),
preferences.setValue('Int', 'Int', allTestValues['Int']!), ),
preferences.setValue('Double', 'Double', allTestValues['Double']!), );
preferences.setValue( final Map<String, Object> values = await preferences.getAllWithParameters(
'StringList', 'StringList', allTestValues['StringList']!), GetAllParameters(
preferences.setValue( filter: PreferencesFilter(prefix: ''),
'String', 'flutter.String', allTestValues['flutter.String']!), ),
preferences.setValue( );
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!),
preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!),
preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!),
preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!)
]);
// ignore: deprecated_member_use
await preferences.clearWithPrefix('');
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['String'], null); expect(values['String'], null);
expect(values['Bool'], null); expect(values['Bool'], null);
expect(values['Int'], null); expect(values['Int'], null);
@ -227,77 +350,23 @@ void main() {
expect(values['flutter.Double'], null); expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null); expect(values['flutter.StringList'], null);
}); });
});
testWidgets('getAll', (WidgetTester _) async { testWidgets('simultaneous writes', (WidgetTester _) async {
await Future.wait(<Future<bool>>[ final List<Future<bool>> writes = <Future<bool>>[];
preferences.setValue( const int writeCount = 100;
'String', 'flutter.String', allTestValues['flutter.String']!), for (int i = 1; i <= writeCount; i++) {
preferences.setValue( writes.add(preferences.setValue('Int', 'Int', i));
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!), }
preferences.setValue( final List<bool> result = await Future.wait(writes, eagerError: true);
'Int', 'flutter.Int', allTestValues['flutter.Int']!), // All writes should succeed.
preferences.setValue( expect(result.where((bool element) => !element), isEmpty);
'Double', 'flutter.Double', allTestValues['flutter.Double']!), // The last write should win.
preferences.setValue('StringList', 'flutter.StringList', final Map<String, Object> values = await preferences.getAllWithParameters(
allTestValues['flutter.StringList']!) GetAllParameters(
]); filter: PreferencesFilter(prefix: ''),
final Map<String, Object> values = await preferences.getAll(); ),
expect(values['flutter.String'], allTestValues['flutter.String']); );
expect(values['flutter.Bool'], allTestValues['flutter.Bool']); expect(values['Int'], writeCount);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('remove', (WidgetTester _) async {
const String key = 'testKey';
await preferences.setValue(
'String', key, allTestValues['flutter.String']!);
await preferences.setValue('Bool', key, allTestValues['flutter.Bool']!);
await preferences.setValue('Int', key, allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', key, allTestValues['flutter.Double']!);
await preferences.setValue(
'StringList', key, allTestValues['flutter.StringList']!);
await preferences.remove(key);
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('simultaneous writes', (WidgetTester _) async {
final List<Future<bool>> writes = <Future<bool>>[];
const int writeCount = 100;
for (int i = 1; i <= writeCount; i++) {
writes.add(preferences.setValue('Int', 'Int', i));
}
final List<bool> result = await Future.wait(writes, eagerError: true);
// All writes should succeed.
expect(result.where((bool element) => !element), isEmpty);
// The last write should win.
// ignore: deprecated_member_use
final Map<String, Object> values = await preferences.getAllWithPrefix('');
expect(values['Int'], writeCount);
});
}); });
} }

View File

@ -8,7 +8,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences_platform_interface: ^2.0.0 shared_preferences_platform_interface: ^2.3.0
shared_preferences_web: shared_preferences_web:
path: ../ path: ../

View File

@ -8,6 +8,7 @@ import 'dart:html' as html;
import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:flutter_web_plugins/flutter_web_plugins.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The web implementation of [SharedPreferencesStorePlatform]. /// The web implementation of [SharedPreferencesStorePlatform].
/// ///
@ -22,27 +23,52 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform {
@override @override
Future<bool> clear() async { Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
// IMPORTANT: Do not use html.window.localStorage.clear() as that will // IMPORTANT: Do not use html.window.localStorage.clear() as that will
// remove _all_ local data, not just the keys prefixed with // remove _all_ local data, not just the keys prefixed with
// _prefix // _prefix
_getStoredFlutterKeys(prefix).forEach(html.window.localStorage.remove); _getFilteredKeys(filter.prefix, allowList: filter.allowList)
.forEach(html.window.localStorage.remove);
return true; return true;
} }
@override @override
Future<Map<String, Object>> getAll() async { Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix); return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
return getAllWithParameters(
GetAllParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> allData = <String, Object>{}; final Map<String, Object> allData = <String, Object>{};
for (final String key in _getStoredFlutterKeys(prefix)) { for (final String key
in _getFilteredKeys(filter.prefix, allowList: filter.allowList)) {
allData[key] = _decodeValue(html.window.localStorage[key]!); allData[key] = _decodeValue(html.window.localStorage[key]!);
} }
return allData; return allData;
@ -60,9 +86,12 @@ class SharedPreferencesPlugin extends SharedPreferencesStorePlatform {
return true; return true;
} }
Iterable<String> _getStoredFlutterKeys(String prefix) { Iterable<String> _getFilteredKeys(
return html.window.localStorage.keys String prefix, {
.where((String key) => key.startsWith(prefix)); Set<String>? allowList,
}) {
return html.window.localStorage.keys.where((String key) =>
key.startsWith(prefix) && (allowList?.contains(key) ?? true));
} }
String _encodeValue(Object? value) { String _encodeValue(Object? value) {

View File

@ -2,7 +2,7 @@ name: shared_preferences_web
description: Web platform implementation of shared_preferences description: Web platform implementation of shared_preferences
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_web
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.1.0 version: 2.2.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"
@ -21,7 +21,7 @@ dependencies:
sdk: flutter sdk: flutter
flutter_web_plugins: flutter_web_plugins:
sdk: flutter sdk: flutter
shared_preferences_platform_interface: ^2.2.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -1,5 +1,6 @@
## NEXT ## 2.3.0
* Adds `clearWithParameters` and `getAllWithParameters` methods.
* Updates minimum supported SDK version to Flutter 3.3/Dart 2.18. * Updates minimum supported SDK version to Flutter 3.3/Dart 2.18.
## 2.2.0 ## 2.2.0

View File

@ -4,95 +4,336 @@
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart'; import 'package:shared_preferences_windows/shared_preferences_windows.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();
group('SharedPreferencesWindows', () { group('SharedPreferencesWindows', () {
const Map<String, Object> kTestValues = <String, Object>{ late SharedPreferencesWindows preferences;
const Map<String, Object> flutterTestValues = <String, Object>{
'flutter.String': 'hello world', 'flutter.String': 'hello world',
'flutter.bool': true, 'flutter.Bool': true,
'flutter.int': 42, 'flutter.Int': 42,
'flutter.double': 3.14159, 'flutter.Double': 3.14159,
'flutter.List': <String>['foo', 'bar'], 'flutter.StringList': <String>['foo', 'bar'],
}; };
const Map<String, Object> kTestValues2 = <String, Object>{ const Map<String, Object> prefixTestValues = <String, Object>{
'flutter.String': 'goodbye world', 'prefix.String': 'hello world',
'flutter.bool': false, 'prefix.Bool': true,
'flutter.int': 1337, 'prefix.Int': 42,
'flutter.double': 2.71828, 'prefix.Double': 3.14159,
'flutter.List': <String>['baz', 'quox'], 'prefix.StringList': <String>['foo', 'bar'],
}; };
testWidgets('reading', (WidgetTester _) async { const Map<String, Object> nonPrefixTestValues = <String, Object>{
final SharedPreferencesWindows preferences = SharedPreferencesWindows(); 'String': 'hello world',
await preferences.clear(); 'Bool': true,
final Map<String, Object> values = await preferences.getAll(); 'Int': 42,
expect(values['String'], isNull); 'Double': 3.14159,
expect(values['bool'], isNull); 'StringList': <String>['foo', 'bar'],
expect(values['int'], isNull); };
expect(values['double'], isNull);
expect(values['List'], isNull); final Map<String, Object> allTestValues = <String, Object>{};
allTestValues.addAll(flutterTestValues);
allTestValues.addAll(prefixTestValues);
allTestValues.addAll(nonPrefixTestValues);
Future<void> addData() async {
await preferences.setValue('String', 'String', allTestValues['String']!);
await preferences.setValue('Bool', 'Bool', allTestValues['Bool']!);
await preferences.setValue('Int', 'Int', allTestValues['Int']!);
await preferences.setValue('Double', 'Double', allTestValues['Double']!);
await preferences.setValue(
'StringList', 'StringList', allTestValues['StringList']!);
await preferences.setValue(
'String', 'prefix.String', allTestValues['prefix.String']!);
await preferences.setValue(
'Bool', 'prefix.Bool', allTestValues['prefix.Bool']!);
await preferences.setValue(
'Int', 'prefix.Int', allTestValues['prefix.Int']!);
await preferences.setValue(
'Double', 'prefix.Double', allTestValues['prefix.Double']!);
await preferences.setValue('StringList', 'prefix.StringList',
allTestValues['prefix.StringList']!);
await preferences.setValue(
'String', 'flutter.String', allTestValues['flutter.String']!);
await preferences.setValue(
'Bool', 'flutter.Bool', allTestValues['flutter.Bool']!);
await preferences.setValue(
'Int', 'flutter.Int', allTestValues['flutter.Int']!);
await preferences.setValue(
'Double', 'flutter.Double', allTestValues['flutter.Double']!);
await preferences.setValue('StringList', 'flutter.StringList',
allTestValues['flutter.StringList']!);
}
setUp(() async {
preferences = SharedPreferencesWindows();
await addData();
}); });
testWidgets('writing', (WidgetTester _) async { tearDown(() async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows(); await preferences.clearWithParameters(
await preferences.clear(); ClearParameters(
await preferences.setValue( filter: PreferencesFilter(prefix: ''),
'String', 'flutter.String', kTestValues2['flutter.String']!); ),
await preferences.setValue( );
'Bool', 'flutter.bool', kTestValues2['flutter.bool']!);
await preferences.setValue(
'Int', 'flutter.int', kTestValues2['flutter.int']!);
await preferences.setValue(
'Double', 'flutter.double', kTestValues2['flutter.double']!);
await preferences.setValue(
'StringList', 'flutter.List', kTestValues2['flutter.List']!);
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], kTestValues2['flutter.String']);
expect(values['flutter.bool'], kTestValues2['flutter.bool']);
expect(values['flutter.int'], kTestValues2['flutter.int']);
expect(values['flutter.double'], kTestValues2['flutter.double']);
expect(values['flutter.List'], kTestValues2['flutter.List']);
}); });
testWidgets('removing', (WidgetTester _) async { testWidgets('getAll', (WidgetTester _) async {
final SharedPreferencesWindows preferences = SharedPreferencesWindows();
await preferences.clear();
const String key = 'flutter.testKey';
await preferences.setValue('String', key, kTestValues['flutter.String']!);
await preferences.setValue('Bool', key, kTestValues['flutter.bool']!);
await preferences.setValue('Int', key, kTestValues['flutter.int']!);
await preferences.setValue('Double', key, kTestValues['flutter.double']!);
await preferences.setValue(
'StringList', key, kTestValues['flutter.List']!);
await preferences.remove(key);
final Map<String, Object> values = await preferences.getAll(); final Map<String, Object> values = await preferences.getAll();
expect(values[key], isNull); expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(values['flutter.StringList'], allTestValues['flutter.StringList']);
}); });
testWidgets('clearing', (WidgetTester _) async { group('withPrefix', () {
final SharedPreferencesWindows preferences = SharedPreferencesWindows(); testWidgets('remove', (WidgetTester _) async {
await preferences.clear(); const String key = 'flutter.String';
await preferences.setValue( await preferences.remove(key);
'String', 'flutter.String', kTestValues['flutter.String']!); final Map<String, Object> values =
await preferences.setValue( await preferences.getAllWithPrefix('');
'Bool', 'flutter.bool', kTestValues['flutter.bool']!); expect(values[key], isNull);
await preferences.setValue( });
'Int', 'flutter.int', kTestValues['flutter.int']!);
await preferences.setValue( testWidgets('clear', (WidgetTester _) async {
'Double', 'flutter.double', kTestValues['flutter.double']!); await preferences.clear();
await preferences.setValue( final Map<String, Object> values = await preferences.getAll();
'StringList', 'flutter.List', kTestValues['flutter.List']!); expect(values['flutter.String'], null);
await preferences.clear(); expect(values['flutter.Bool'], null);
final Map<String, Object> values = await preferences.getAll(); expect(values['flutter.Int'], null);
expect(values['flutter.String'], null); expect(values['flutter.Double'], null);
expect(values['flutter.bool'], null); expect(values['flutter.StringList'], null);
expect(values['flutter.int'], null); });
expect(values['flutter.double'], null);
expect(values['flutter.List'], null); testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('prefix.');
Map<String, Object> values =
await preferences.getAllWithPrefix('prefix.');
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithPrefix('flutter.');
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithPrefix('');
final Map<String, Object> values =
await preferences.getAllWithPrefix('');
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
});
group('withParameters', () {
testWidgets('remove', (WidgetTester _) async {
const String key = 'flutter.String';
await preferences.remove(key);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values[key], isNull);
});
testWidgets('clear', (WidgetTester _) async {
await preferences.clear();
final Map<String, Object> values = await preferences.getAll();
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
testWidgets('get all with prefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], allTestValues['prefix.StringList']);
});
testWidgets('get all with allow list', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.String'},
),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
});
testWidgets('getAllWithNoPrefix', (WidgetTester _) async {
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], allTestValues['String']);
expect(values['Bool'], allTestValues['Bool']);
expect(values['Int'], allTestValues['Int']);
expect(values['Double'], allTestValues['Double']);
expect(values['StringList'], allTestValues['StringList']);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], null);
expect(values['prefix.Bool'], null);
expect(values['prefix.Int'], null);
expect(values['prefix.Double'], null);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithParameters with allow list',
(WidgetTester _) async {
await addData();
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
Map<String, Object> values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values['prefix.String'], allTestValues['prefix.String']);
expect(values['prefix.Bool'], allTestValues['prefix.Bool']);
expect(values['prefix.Int'], allTestValues['prefix.Int']);
expect(values['prefix.Double'], allTestValues['prefix.Double']);
expect(values['prefix.StringList'], null);
values = await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'flutter.'),
),
);
expect(values['flutter.String'], allTestValues['flutter.String']);
expect(values['flutter.Bool'], allTestValues['flutter.Bool']);
expect(values['flutter.Int'], allTestValues['flutter.Int']);
expect(values['flutter.Double'], allTestValues['flutter.Double']);
expect(
values['flutter.StringList'], allTestValues['flutter.StringList']);
});
testWidgets('clearWithNoPrefix', (WidgetTester _) async {
await preferences.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> values =
await preferences.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values['String'], null);
expect(values['Bool'], null);
expect(values['Int'], null);
expect(values['Double'], null);
expect(values['StringList'], null);
expect(values['flutter.String'], null);
expect(values['flutter.Bool'], null);
expect(values['flutter.Int'], null);
expect(values['flutter.Double'], null);
expect(values['flutter.StringList'], null);
});
}); });
}); });
} }

View File

@ -9,6 +9,7 @@ environment:
dependencies: dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
shared_preferences_platform_interface: ^2.3.0
shared_preferences_windows: shared_preferences_windows:
# When depending on this package from a real application you should use: # When depending on this package from a real application you should use:
# shared_preferences_windows: ^x.y.z # shared_preferences_windows: ^x.y.z

View File

@ -11,6 +11,7 @@ import 'package:flutter/foundation.dart' show debugPrint, visibleForTesting;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:path_provider_windows/path_provider_windows.dart'; import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
/// The Windows implementation of [SharedPreferencesStorePlatform]. /// The Windows implementation of [SharedPreferencesStorePlatform].
/// ///
@ -100,26 +101,52 @@ class SharedPreferencesWindows extends SharedPreferencesStorePlatform {
@override @override
Future<bool> clear() async { Future<bool> clear() async {
return clearWithPrefix(_defaultPrefix); return clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<bool> clearWithPrefix(String prefix) async { Future<bool> clearWithPrefix(String prefix) async {
return clearWithParameters(
ClearParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<bool> clearWithParameters(ClearParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> preferences = await _readPreferences(); final Map<String, Object> preferences = await _readPreferences();
preferences.removeWhere((String key, _) => key.startsWith(prefix)); preferences.removeWhere((String key, _) =>
key.startsWith(filter.prefix) &&
(filter.allowList == null || filter.allowList!.contains(key)));
return _writePreferences(preferences); return _writePreferences(preferences);
} }
@override @override
Future<Map<String, Object>> getAll() async { Future<Map<String, Object>> getAll() async {
return getAllWithPrefix(_defaultPrefix); return getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: _defaultPrefix),
),
);
} }
@override @override
Future<Map<String, Object>> getAllWithPrefix(String prefix) async { Future<Map<String, Object>> getAllWithPrefix(String prefix) async {
return getAllWithParameters(
GetAllParameters(filter: PreferencesFilter(prefix: prefix)));
}
@override
Future<Map<String, Object>> getAllWithParameters(
GetAllParameters parameters) async {
final PreferencesFilter filter = parameters.filter;
final Map<String, Object> withPrefix = final Map<String, Object> withPrefix =
Map<String, Object>.from(await _readPreferences()); Map<String, Object>.from(await _readPreferences());
withPrefix.removeWhere((String key, _) => !key.startsWith(prefix)); withPrefix.removeWhere((String key, _) => !(key.startsWith(filter.prefix) &&
(filter.allowList?.contains(key) ?? true)));
return withPrefix; return withPrefix;
} }

View File

@ -2,7 +2,7 @@ name: shared_preferences_windows
description: Windows implementation of shared_preferences description: Windows implementation of shared_preferences
repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows repository: https://github.com/flutter/packages/tree/main/packages/shared_preferences/shared_preferences_windows
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+shared_preferences%22
version: 2.2.0 version: 2.3.0
environment: environment:
sdk: ">=2.18.0 <4.0.0" sdk: ">=2.18.0 <4.0.0"
@ -22,7 +22,7 @@ dependencies:
path: ^1.8.0 path: ^1.8.0
path_provider_platform_interface: ^2.0.0 path_provider_platform_interface: ^2.0.0
path_provider_windows: ^2.0.0 path_provider_windows: ^2.0.0
shared_preferences_platform_interface: ^2.2.0 shared_preferences_platform_interface: ^2.3.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -10,6 +10,7 @@ import 'package:path/path.dart' as path;
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart'; import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
import 'package:path_provider_windows/path_provider_windows.dart'; import 'package:path_provider_windows/path_provider_windows.dart';
import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart'; import 'package:shared_preferences_platform_interface/shared_preferences_platform_interface.dart';
import 'package:shared_preferences_platform_interface/types.dart';
import 'package:shared_preferences_windows/shared_preferences_windows.dart'; import 'package:shared_preferences_windows/shared_preferences_windows.dart';
void main() { void main() {
@ -99,6 +100,35 @@ void main() {
expect(values, prefixTestValues); expect(values, prefixTestValues);
}); });
test('getAllWithParameters with Prefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(values, hasLength(5));
expect(values, prefixTestValues);
});
test('getAllWithParameters with Prefix with allow list', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String?, Object?> all = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.Bool'},
),
),
);
expect(all.length, 1);
expect(all['prefix.Bool'], prefixTestValues['prefix.Bool']);
});
test('remove', () async { test('remove', () async {
await writeTestFile('{"key1":"one","key2":2}'); await writeTestFile('{"key1":"one","key2":2}');
final SharedPreferencesWindows prefs = getPreferences(); final SharedPreferencesWindows prefs = getPreferences();
@ -156,6 +186,74 @@ void main() {
final Map<String, Object> noValues = await prefs.getAllWithPrefix(''); final Map<String, Object> noValues = await prefs.getAllWithPrefix('');
expect(noValues, hasLength(0)); expect(noValues, hasLength(0));
}); });
test('clearWithParameters with Prefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(0));
final Map<String, Object> values = await prefs.getAll();
expect(values, hasLength(5));
expect(values, flutterTestValues);
});
test('clearWithParameters with allow list', () async {
await writeTestFile(json.encode(prefixTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(
prefix: 'prefix.',
allowList: <String>{'prefix.StringList'},
),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: 'prefix.'),
),
);
expect(noValues, hasLength(4));
});
test('getAllWithNoPrefix', () async {
await writeTestFile(json.encode(allTestValues));
final SharedPreferencesWindows prefs = getPreferences();
final Map<String, Object> values = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(values, hasLength(15));
expect(values, allTestValues);
});
test('clearWithNoPrefix', () async {
await writeTestFile(json.encode(flutterTestValues));
final SharedPreferencesWindows prefs = getPreferences();
await prefs.clearWithParameters(
ClearParameters(
filter: PreferencesFilter(prefix: ''),
),
);
final Map<String, Object> noValues = await prefs.getAllWithParameters(
GetAllParameters(
filter: PreferencesFilter(prefix: ''),
),
);
expect(noValues, hasLength(0));
});
} }
/// Fake implementation of PathProviderWindows that returns hard-coded paths, /// Fake implementation of PathProviderWindows that returns hard-coded paths,