Skip to content

Commit 151c416

Browse files
committed
NOMERGE page: Implement MultiAccountPageProvider / MultiAccountPageController
1 parent b8a68f9 commit 151c416

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

lib/widgets/page.dart

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
import 'package:flutter/material.dart';
33

4+
import '../model/store.dart';
45
import 'store.dart';
56
import 'text.dart';
67
import 'theme.dart';
@@ -266,3 +267,104 @@ class PageBodyEmptyContentPlaceholder extends StatelessWidget {
266267
child: child)));
267268
}
268269
}
270+
271+
/// A [ChangeNotifier] that tracks a nullable account-ID selection.
272+
///
273+
/// Maintains a listener on [GlobalStore] and will clear the selection
274+
/// if the account no longer exists because it was logged out.
275+
///
276+
/// Use [selectedAccountId] to read the selection
277+
/// and [selectAccount] to update it.
278+
class MultiAccountPageController extends ChangeNotifier {
279+
factory MultiAccountPageController.init(GlobalStore globalStore) {
280+
281+
final result = MultiAccountPageController._(globalStore);
282+
globalStore.addListener(result._globalStoreChanged);
283+
// TODO initialize selectedAccountId to last-visited?
284+
result._reconcile();
285+
return result;
286+
}
287+
288+
MultiAccountPageController._(this._globalStore);
289+
290+
final GlobalStore _globalStore;
291+
292+
int? get selectedAccountId => _selectedAccountId;
293+
int? _selectedAccountId;
294+
295+
void selectAccount(int accountId) {
296+
_selectedAccountId = accountId;
297+
_reconcile();
298+
notifyListeners();
299+
}
300+
301+
void _globalStoreChanged() {
302+
_reconcile();
303+
}
304+
305+
void _reconcile() {
306+
if (_selectedAccountId == null) return;
307+
if (_globalStore.accountIds.contains(_selectedAccountId)) return;
308+
_selectedAccountId = null;
309+
notifyListeners();
310+
}
311+
312+
@override
313+
void dispose() {
314+
_globalStore.removeListener(_globalStoreChanged);
315+
super.dispose();
316+
}
317+
}
318+
319+
/// A widget that can efficiently provide a [MultiAccountPageController]
320+
/// to its descendants, via [BuildContext.dependOnInheritedWidgetOfExactType].
321+
class MultiAccountPageProvider extends StatefulWidget {
322+
const MultiAccountPageProvider({super.key, required this.child});
323+
324+
final Widget child;
325+
326+
/// The [MultiAccountPageController] of an assumed
327+
/// [MultiAccountPageProvider] ancestor.
328+
///
329+
/// Creates a dependency on the controller via [InheritedNotifier].
330+
static MultiAccountPageController of(BuildContext context) {
331+
final widget = context.dependOnInheritedWidgetOfExactType<_MultiAccountPageControllerInheritedWidget>();
332+
assert(widget != null, 'No MultiAccountPageProvider ancestor');
333+
return widget!.controller;
334+
}
335+
336+
@override
337+
State<MultiAccountPageProvider> createState() => _MultiAccountPageProviderState();
338+
}
339+
340+
class _MultiAccountPageProviderState extends State<MultiAccountPageProvider> {
341+
GlobalStore? _globalStore;
342+
343+
MultiAccountPageController? _controller;
344+
345+
@override
346+
void didChangeDependencies() {
347+
super.didChangeDependencies();
348+
349+
final store = GlobalStoreWidget.of(context);
350+
if (_globalStore != store) {
351+
_controller?.dispose();
352+
_controller = MultiAccountPageController.init(store);
353+
}
354+
}
355+
356+
@override
357+
Widget build(BuildContext context) {
358+
return _MultiAccountPageControllerInheritedWidget(
359+
controller: _controller!, child: widget.child);
360+
}
361+
}
362+
363+
class _MultiAccountPageControllerInheritedWidget extends InheritedNotifier<MultiAccountPageController> {
364+
const _MultiAccountPageControllerInheritedWidget({
365+
required MultiAccountPageController controller,
366+
required super.child,
367+
}) : super(notifier: controller);
368+
369+
MultiAccountPageController get controller => notifier!;
370+
}

0 commit comments

Comments
 (0)