Skip to content

Commit

Permalink
store [nfc]: Offer singleton global store on binding
Browse files Browse the repository at this point in the history
This will be useful in the context of showing a notification, where
there may not exist an element tree at all (because we may be in a
background isolate), and even if there happens to be one (because we
happen to be in the foreground) it doesn't otherwise relate to
anything the code is doing.
  • Loading branch information
gnprice authored and chrisbobbe committed Oct 18, 2024
1 parent 26c2aa0 commit fc80be1
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 11 deletions.
31 changes: 23 additions & 8 deletions lib/model/binding.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:device_info_plus/device_info_plus.dart' as device_info_plus;
import 'package:file_picker/file_picker.dart' as file_picker;
import 'package:firebase_core/firebase_core.dart' as firebase_core;
Expand Down Expand Up @@ -74,14 +76,20 @@ abstract class ZulipBinding {
_instance = this;
}

/// Prepare the app's [GlobalStore], loading the necessary data.
/// Get the app's singleton [GlobalStore],
/// calling [loadGlobalStore] if not already loaded.
///
/// Generally the app should call this function only once.
/// Where possible, use [GlobalStoreWidget.of] to get access to a [GlobalStore].
/// Use this method only in contexts like notifications where
/// a widget tree may not exist.
Future<GlobalStore> getGlobalStore();

/// Like [getGlobalStore], but assert this method was not previously called.
///
/// This is part of the implementation of [GlobalStoreWidget].
/// In application code, use [GlobalStoreWidget.of] to get access
/// to a [GlobalStore].
Future<GlobalStore> loadGlobalStore();
/// This is used by the implementation of [GlobalStoreWidget],
/// so that our test framework code can detect some cases where
/// a widget test neglects to clean up with `testBinding.reset`.
Future<GlobalStore> getGlobalStoreUniquely();

/// Checks whether the platform can launch [url], via package:url_launcher.
///
Expand Down Expand Up @@ -324,9 +332,16 @@ class LiveZulipBinding extends ZulipBinding {
}

@override
Future<GlobalStore> loadGlobalStore() {
return LiveGlobalStore.load();
Future<GlobalStore> getGlobalStore() => _globalStore ??= LiveGlobalStore.load();
Future<GlobalStore>? _globalStore;

@override
Future<GlobalStore> getGlobalStoreUniquely() {
assert(!_debugCalledGetGlobalStoreUniquely);
assert(_debugCalledGetGlobalStoreUniquely = true);
return getGlobalStore();
}
bool _debugCalledGetGlobalStoreUniquely = false;

@override
Future<bool> canLaunchUrl(Uri url) => url_launcher.canLaunchUrl(url);
Expand Down
2 changes: 1 addition & 1 deletion lib/widgets/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class _GlobalStoreWidgetState extends State<GlobalStoreWidget> {
void initState() {
super.initState();
(() async {
final store = await ZulipBinding.instance.loadGlobalStore();
final store = await ZulipBinding.instance.getGlobalStoreUniquely();
setState(() {
this.store = store;
});
Expand Down
7 changes: 5 additions & 2 deletions test/model/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ class TestZulipBinding extends ZulipBinding {
}

@override
Future<GlobalStore> loadGlobalStore() {
Future<GlobalStore> getGlobalStore() => Future.value(globalStore);

@override
Future<GlobalStore> getGlobalStoreUniquely() {
assert(() {
if (_debugAlreadyLoadedStore) {
throw FlutterError.fromParts([
Expand All @@ -121,7 +124,7 @@ class TestZulipBinding extends ZulipBinding {
_debugAlreadyLoadedStore = true;
return true;
}());
return Future.value(globalStore);
return getGlobalStore();
}

/// The value that `ZulipBinding.instance.canLaunchUrl()` should return.
Expand Down

0 comments on commit fc80be1

Please sign in to comment.