save navigation
This commit is contained in:
parent
9015862f1a
commit
cbbd95ab23
|
|
@ -12,29 +12,31 @@ import android.os.Parcelable
|
|||
|
||||
class MainActivity() : FlutterActivity() {
|
||||
|
||||
var savedModels: MutableMap<String, String> = mutableMapOf()
|
||||
var savedFromFlutter: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
GeneratedPluginRegistrant.registerWith(this)
|
||||
|
||||
MethodChannel(getFlutterView(), "app.channel.shared.data").setMethodCallHandler { call, result ->
|
||||
if (call.method.contentEquals("saveModel")) {
|
||||
savedModels.put(call.argument<String>("key"), call.argument<String>("value"))
|
||||
} else if (call.method.contentEquals("readModel")) {
|
||||
result.success(savedModels.get(call.argument<String>("key")))
|
||||
if (call.method.contentEquals("saveInput")) {
|
||||
savedFromFlutter.put(call.argument<String>("key"), call.argument<String>("value"))
|
||||
} else if (call.method.contentEquals("readInput")) {
|
||||
result.success(savedFromFlutter.get(call.argument<String>("key")))
|
||||
} else if (call.method.contentEquals("wasRestarted")) {
|
||||
result.success(savedInstanceState != null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putParcelable("savedModels", toBundle(savedModels));
|
||||
outState.putParcelable("savedFromFlutter", toBundle(savedFromFlutter));
|
||||
}
|
||||
|
||||
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
|
||||
super.onRestoreInstanceState(savedInstanceState)
|
||||
savedModels = fromBundle(savedInstanceState.getParcelable<Bundle>("savedModels"))
|
||||
savedFromFlutter = fromBundle(savedInstanceState.getParcelable<Bundle>("savedFromFlutter"))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
105
lib/main.dart
105
lib/main.dart
|
|
@ -1,8 +1,44 @@
|
|||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/random_words.dart';
|
||||
import 'dart:async';
|
||||
|
||||
void main() => runApp(new MyApp());
|
||||
|
||||
class Keys {
|
||||
static GlobalKey<RandomWordsState> key = new GlobalKey<RandomWordsState>();
|
||||
}
|
||||
|
||||
class Routes {
|
||||
static Queue<String> routes = new Queue<String>();
|
||||
static var _firstTime = true;
|
||||
|
||||
static save() async {
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
platform.invokeMethod(
|
||||
"saveInput", {"key": "routes", "value": JSON.encode(routes.toList())});
|
||||
}
|
||||
|
||||
static restore(BuildContext context) async {
|
||||
if (!_firstTime) {
|
||||
return;
|
||||
}
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
String s = await platform.invokeMethod("readInput", {"key": "routes"});
|
||||
if (s != null) {
|
||||
routes = new Queue<String>();
|
||||
routes.addAll(JSON.decode(s));
|
||||
}
|
||||
_firstTime = false;
|
||||
for (String route in routes) {
|
||||
Navigator.of(context).pushNamed(route);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
|
@ -11,7 +47,11 @@ class MyApp extends StatelessWidget {
|
|||
theme: new ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: new MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
home: new MyHomePage(title: 'Startup Name Generator'),
|
||||
routes: <String, WidgetBuilder>{
|
||||
'/saved': (BuildContext context) =>
|
||||
new SavedPage(title: 'Saved Suggestions'),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -29,11 +69,70 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Routes.restore(context);
|
||||
return new Scaffold(
|
||||
appBar: new AppBar(
|
||||
title: new Text(widget.title),
|
||||
actions: <Widget>[
|
||||
new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved),
|
||||
],
|
||||
),
|
||||
body: new RandomWords("list"),
|
||||
body: new RandomWords(Keys.key, "list"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _pushSaved() async {
|
||||
Routes.routes.addLast('/saved');
|
||||
await Routes.save();
|
||||
Navigator.of(context).pushNamed('/saved');
|
||||
}
|
||||
}
|
||||
|
||||
class SavedPage extends StatefulWidget {
|
||||
SavedPage({Key key, this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_SavedPageState createState() => new _SavedPageState();
|
||||
}
|
||||
|
||||
class _SavedPageState extends State<SavedPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!Keys.key.currentState.model.isInitialized()) {
|
||||
return new Container();
|
||||
}
|
||||
final tiles = Keys.key.currentState.model.saved.map(
|
||||
(pair) {
|
||||
return new ListTile(
|
||||
title: new Text(
|
||||
pair,
|
||||
style: Keys.key.currentState.biggerFont,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
final divided = ListTile
|
||||
.divideTiles(
|
||||
context: context,
|
||||
tiles: tiles,
|
||||
)
|
||||
.toList();
|
||||
return new Scaffold(
|
||||
appBar: new AppBar(
|
||||
title: new Text('Saved Suggestions'),
|
||||
),
|
||||
body: new WillPopScope(
|
||||
onWillPop: _onWillPop,
|
||||
child: new ListView(children: divided),),
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> _onWillPop() async {
|
||||
Routes.routes.removeLast();
|
||||
await Routes.save();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
abstract class Model {
|
||||
abstract class Restorable {
|
||||
save(String key);
|
||||
Future<Model> restore(String key);
|
||||
Future<Restorable> restore(String key);
|
||||
isInitialized();
|
||||
}
|
||||
|
|
@ -1,34 +1,36 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_app/random_words_input.dart';
|
||||
import 'package:flutter_app/random_words_model.dart';
|
||||
import 'package:english_words/english_words.dart';
|
||||
|
||||
class RandomWords extends StatefulWidget {
|
||||
final String modelKey;
|
||||
final String stateKey;
|
||||
|
||||
RandomWords(this.modelKey);
|
||||
RandomWords(Key key, this.stateKey) :super(key: key);
|
||||
|
||||
@override
|
||||
createState() => new RandomWordsState(modelKey);
|
||||
createState() => new RandomWordsState();
|
||||
}
|
||||
|
||||
class RandomWordsState extends State<RandomWords> {
|
||||
String modelKey;
|
||||
RandomWordsModel model = new RandomWordsModel();
|
||||
RandomWordsInput input = new RandomWordsInput();
|
||||
|
||||
final _biggerFont = const TextStyle(fontSize: 18.0);
|
||||
final biggerFont = const TextStyle(fontSize: 18.0);
|
||||
|
||||
final ScrollController scrollController = new ScrollController();
|
||||
|
||||
RandomWordsState(String stateKey) {
|
||||
this.modelKey = stateKey;
|
||||
RandomWordsState() {
|
||||
_init();
|
||||
}
|
||||
|
||||
_init() async {
|
||||
RandomWordsModel newModel = await model.restore(modelKey);
|
||||
RandomWordsModel newModel = await model.restore(widget.stateKey);
|
||||
RandomWordsInput newInput = await input.restore(widget.stateKey);
|
||||
setState(() {
|
||||
model = newModel;
|
||||
scrollController.jumpTo(model.scrollPosition);
|
||||
input = newInput;
|
||||
scrollController.jumpTo(input.scrollPosition);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +62,7 @@ class RandomWordsState extends State<RandomWords> {
|
|||
for (WordPair pair in newSuggestions) {
|
||||
model.suggestions.add(pair.asPascalCase);
|
||||
}
|
||||
model.save(modelKey);
|
||||
model.save(widget.stateKey);
|
||||
}
|
||||
|
||||
return _buildRow(model.suggestions[index]);
|
||||
|
|
@ -69,16 +71,31 @@ class RandomWordsState extends State<RandomWords> {
|
|||
}
|
||||
|
||||
_onNotification(Notification n) {
|
||||
model.scrollPosition = scrollController.position.pixels;
|
||||
model.save(modelKey);
|
||||
input.scrollPosition = scrollController.position.pixels;
|
||||
input.save(widget.stateKey);
|
||||
}
|
||||
|
||||
Widget _buildRow(String word) {
|
||||
final alreadySaved = model.saved.contains(word);
|
||||
return new ListTile(
|
||||
title: new Text(
|
||||
word,
|
||||
style: _biggerFont,
|
||||
style: biggerFont,
|
||||
),
|
||||
trailing: new Icon(
|
||||
alreadySaved ? Icons.favorite : Icons.favorite_border,
|
||||
color: alreadySaved ? Colors.red : null,
|
||||
),
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (alreadySaved) {
|
||||
model.saved.remove(word);
|
||||
} else {
|
||||
model.saved.add(word);
|
||||
}
|
||||
});
|
||||
model.save(widget.stateKey);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/model.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
part 'random_words_input.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class RandomWordsInput extends Object with _$RandomWordsInputSerializerMixin implements Restorable {
|
||||
double scrollPosition = -1.0;
|
||||
|
||||
RandomWordsInput();
|
||||
|
||||
factory RandomWordsInput.fromJson(Map<String, dynamic> json) => _$RandomWordsInputFromJson(json);
|
||||
|
||||
save(String key) async {
|
||||
String json = JSON.encode(this);
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
platform.invokeMethod("saveInput", {"key": key, "value": json});
|
||||
}
|
||||
|
||||
Future<RandomWordsInput> restore(String key) async {
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
String s = await platform.invokeMethod("readInput", {"key" : key});
|
||||
|
||||
if (s != null) {
|
||||
var restoredModel = new RandomWordsInput.fromJson(JSON.decode(s));
|
||||
scrollPosition = restoredModel.scrollPosition;
|
||||
} else {
|
||||
_empty();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
_empty() {
|
||||
scrollPosition = 0.0;
|
||||
}
|
||||
|
||||
bool isInitialized() {
|
||||
return scrollPosition >= 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'random_words_input.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// Generator: JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
RandomWordsInput _$RandomWordsInputFromJson(Map<String, dynamic> json) =>
|
||||
new RandomWordsInput()
|
||||
..scrollPosition = (json['scrollPosition'] as num)?.toDouble();
|
||||
|
||||
abstract class _$RandomWordsInputSerializerMixin {
|
||||
double get scrollPosition;
|
||||
Map<String, dynamic> toJson() =>
|
||||
<String, dynamic>{'scrollPosition': scrollPosition};
|
||||
}
|
||||
|
|
@ -1,15 +1,16 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_app/model.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
part 'random_words_model.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class RandomWordsModel extends Object with _$RandomWordsModelSerializerMixin implements Model {
|
||||
class RandomWordsModel extends Object with _$RandomWordsModelSerializerMixin implements Restorable {
|
||||
var suggestions;
|
||||
double scrollPosition = 0.0;
|
||||
var saved;
|
||||
|
||||
RandomWordsModel();
|
||||
|
||||
|
|
@ -17,24 +18,38 @@ class RandomWordsModel extends Object with _$RandomWordsModelSerializerMixin imp
|
|||
|
||||
save(String key) async {
|
||||
String json = JSON.encode(this);
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
platform.invokeMethod("saveModel", {"key": key, "value": json});
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setString(key, json);
|
||||
print(suggestions);
|
||||
}
|
||||
|
||||
Future<RandomWordsModel> restore(String key) async {
|
||||
const platform = const MethodChannel('app.channel.shared.data');
|
||||
String s = await platform.invokeMethod("readModel", {"key": key});
|
||||
bool wasRestarted = await platform.invokeMethod("wasRestarted");
|
||||
|
||||
if (!wasRestarted) {
|
||||
_empty();
|
||||
return this;
|
||||
}
|
||||
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
String s = prefs.getString(key);
|
||||
|
||||
if (s != null) {
|
||||
var restoredModel = new RandomWordsModel.fromJson(JSON.decode(s));
|
||||
suggestions = restoredModel.suggestions;
|
||||
scrollPosition = restoredModel.scrollPosition;
|
||||
saved = restoredModel.saved;
|
||||
} else {
|
||||
suggestions = <String>[];
|
||||
_empty();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
_empty() {
|
||||
suggestions = <String>[];
|
||||
saved = <String>[];
|
||||
}
|
||||
|
||||
bool isInitialized() {
|
||||
return suggestions != null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,14 +8,13 @@ part of 'random_words_model.dart';
|
|||
|
||||
RandomWordsModel _$RandomWordsModelFromJson(Map<String, dynamic> json) =>
|
||||
new RandomWordsModel()
|
||||
..suggestions = json['suggestions']
|
||||
..scrollPosition = (json['scrollPosition'] as num)?.toDouble();
|
||||
..suggestions =
|
||||
(json['suggestions'] as List)?.map((e) => e as String)?.toList()
|
||||
..saved = (json['saved'] as List)?.map((e) => e as String)?.toList();
|
||||
|
||||
abstract class _$RandomWordsModelSerializerMixin {
|
||||
dynamic get suggestions;
|
||||
double get scrollPosition;
|
||||
Map<String, dynamic> toJson() => <String, dynamic>{
|
||||
'suggestions': suggestions,
|
||||
'scrollPosition': scrollPosition
|
||||
};
|
||||
List<String> get suggestions;
|
||||
List<String> get saved;
|
||||
Map<String, dynamic> toJson() =>
|
||||
<String, dynamic>{'suggestions': suggestions, 'saved': saved};
|
||||
}
|
||||
|
|
|
|||
10
pubspec.lock
10
pubspec.lock
|
|
@ -354,6 +354,13 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.28.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.0"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -500,4 +507,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.1.13"
|
||||
sdks:
|
||||
dart: ">=2.0.0-dev.23.0 <=2.0.0-edge.0d5cf900b021bf5c9fa593ffa12b15bcd1cc5fe0"
|
||||
dart: ">=2.0.0-dev.28.0 <=2.0.0-edge.0d5cf900b021bf5c9fa593ffa12b15bcd1cc5fe0"
|
||||
flutter: ">=0.1.4 <2.0.0"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ dependencies:
|
|||
english_words: ^3.1.0
|
||||
build_runner: ^0.7.6
|
||||
json_serializable: ^0.3.2
|
||||
shared_preferences: ^0.4.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
|
|||
Loading…
Reference in New Issue