From 4877c06149792bfe7a9f86a6ed189f2faaecce80 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Thu, 29 Oct 2015 14:25:20 -0700 Subject: [PATCH] Add PageStorage support to Navigator2 --- packages/flutter/lib/src/widgets/page.dart | 9 +- .../flutter/lib/src/widgets/page_storage.dart | 102 ++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 packages/flutter/lib/src/widgets/page_storage.dart diff --git a/packages/flutter/lib/src/widgets/page.dart b/packages/flutter/lib/src/widgets/page.dart index 4e1341a886a..874e3974bc7 100644 --- a/packages/flutter/lib/src/widgets/page.dart +++ b/packages/flutter/lib/src/widgets/page.dart @@ -8,6 +8,7 @@ import 'basic.dart'; import 'framework.dart'; import 'navigator2.dart'; import 'overlay.dart'; +import 'page_storage.dart'; import 'transitions.dart'; // TODO(abarth): Should we add a type for the result? @@ -81,8 +82,9 @@ class _PageState extends State<_Page> { Widget build(BuildContext context) { if (config.route._offstage) { return new OffStage( - child: new KeyedSubtree( + child: new PageStorage( key: _subtreeKey, + bucket: config.route._storageBucket, child: _invokeBuilder() ) ); @@ -93,8 +95,9 @@ class _PageState extends State<_Page> { child: new FadeTransition( performance: config.route.performance, opacity: _opacity, - child: new KeyedSubtree( + child: new PageStorage( key: _subtreeKey, + bucket: config.route._storageBucket, child: _invokeBuilder() ) ) @@ -132,6 +135,8 @@ class PageRoute extends TransitionRoute { Duration get transitionDuration => const Duration(milliseconds: 150); List createWidgets() => [ new _Page(key: pageKey, route: this) ]; + final PageStorageBucket _storageBucket = new PageStorageBucket(); + bool get offstage => _offstage; bool _offstage = false; void set offstage (bool value) { diff --git a/packages/flutter/lib/src/widgets/page_storage.dart b/packages/flutter/lib/src/widgets/page_storage.dart new file mode 100644 index 00000000000..051c765fe5d --- /dev/null +++ b/packages/flutter/lib/src/widgets/page_storage.dart @@ -0,0 +1,102 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'framework.dart'; + +class _StorageEntryIdentifier { + Type clientType; + List keys; + void addKey(Key key) { + assert(key != null); + assert(key is! GlobalKey); + keys ??= []; + keys.add(key); + } + GlobalKey scopeKey; + bool operator ==(dynamic other) { + if (other is! _StorageEntryIdentifier) + return false; + final _StorageEntryIdentifier typedOther = other; + if (clientType != typedOther.clientType || + scopeKey != typedOther.scopeKey || + keys?.length != typedOther.keys?.length) + return false; + if (keys != null) { + for (int index = 0; index < keys.length; index += 1) { + if (keys[index] != typedOther.keys[index]) + return false; + } + } + return true; + } + int get hashCode { + int value = 373; + value = 37 * value + clientType.hashCode; + value = 37 * value + scopeKey.hashCode; + if (keys != null) { + for (Key key in keys) + value = 37 * value + key.hashCode; + } + return value; + } +} + +class PageStorageBucket { + _StorageEntryIdentifier _computeStorageIdentifier(BuildContext context) { + _StorageEntryIdentifier result = new _StorageEntryIdentifier(); + result.clientType = context.widget.runtimeType; + Key lastKey = context.widget.key; + if (lastKey is! GlobalKey) { + context.visitAncestorElements((Element element) { + if (element.widget.key is GlobalKey) { + lastKey = element.widget.key; + return false; + } else if (element.widget.key != null) { + result.addKey(element.widget.key); + } + return true; + }); + return result; + } + assert(lastKey is GlobalKey); + result.scopeKey = lastKey; + return result; + } + + Map<_StorageEntryIdentifier, dynamic> _storage; + void writeState(BuildContext context, dynamic data) { + _storage ??= <_StorageEntryIdentifier, dynamic>{}; + _storage[_computeStorageIdentifier(context)] = data; + } + dynamic readState(BuildContext context) { + return _storage != null ? _storage[_computeStorageIdentifier(context)] : null; + } +} + +class PageStorage extends StatelessComponent { + PageStorage({ + Key key, + this.child, + this.bucket + }) : super(key: key); + + final Widget child; + final PageStorageBucket bucket; + + /// Might return null if there is no PageStorage in this context. + static PageStorageBucket of(BuildContext context) { + PageStorageBucket result; + context.visitAncestorElements((Element element) { + Widget widget = element.widget; + if (widget is PageStorage) { + result = widget.bucket; + return false; + } + return true; + }); + return result; + } + + Widget build(BuildContext context) => child; +}