Reputation: 482
Resume of the problem: After app restart, preferences are null.
I´m building a login screen with one Settings button on the AppBar and every time I restart the app, the saved preferences appear to be "deleted". I´m using Bloc library.
I would also like to have some suggestions for code improvement :).
BloC State
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
@immutable
abstract class WebApiConfigsState extends Equatable {
WebApiConfigsState([List props = const []]) : super(props);
}
//Load(ing)
class WebApiConfigsLoading extends WebApiConfigsState {
final WebApiConfigs webApiConfigs;
WebApiConfigsLoading({this.webApiConfigs}) : super([webApiConfigs]);
@override
String toString() => 'WebApiConfigsLoading';
}
//Load
class WebApiConfigsLoaded extends WebApiConfigsState {
final WebApiConfigs webApiConfigs;
WebApiConfigsLoaded({this.webApiConfigs}) : super([webApiConfigs]);
@override
String toString() => 'WebApiConfigsLoaded';
}
//Save
class WebApiConfigsSaving extends WebApiConfigsState {
final WebApiConfigs webApiConfigs;
WebApiConfigsSaving({this.webApiConfigs}) : super([webApiConfigs]);
@override
String toString() => 'WebApiConfigsSaving';
}
//Save(d)
class WebApiConfigsSaved extends WebApiConfigsState {
final WebApiConfigs webApiConfigs;
WebApiConfigsSaved({this.webApiConfigs}) : super([webApiConfigs]);
@override
String toString() => 'WebApiConfigsSaving';
}
//Erro
class WebApiConfigsError extends WebApiConfigsState {
final String error;
WebApiConfigsError({@required this.error}) : super([error]);
@override
String toString() => 'WebApiConfigsError { error: $error }';
}
BloC Event
import 'package:equatable/equatable.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
abstract class WebApiConfigsEvent extends Equatable {}
//Load
class LoadWebApiConfigsEvent extends WebApiConfigsEvent {
WebApiConfigs webApiConfigs;
LoadWebApiConfigsEvent(this.webApiConfigs);
@override
String toString() => 'LoadWebApiConfigsEvent';
}
//Save
class SaveWebApiConfigsEvent extends WebApiConfigsEvent {
final WebApiConfigs webApiConfigs;
SaveWebApiConfigsEvent(this.webApiConfigs);
@override
String toString() => 'SaveWebApiConfigsEvent { URL: ${webApiConfigs.url} }';
}
BloC Bloc
import 'package:bloc/bloc.dart';
import 'package:visiogate/vg_blocs/webApiConfigs/webApiConfigs.dart';
import 'package:visiogate/vg_blocs/simple_bloc_delegate.dart';
import 'package:visiogate/vg_models/persistent_data/persistent_data.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
void main() {
BlocSupervisor.delegate = SimpleBlocDelegate();
}
class WebApiConfigsBloc extends Bloc<WebApiConfigsEvent, WebApiConfigsState> {
PersistentData _persistentData = new PersistentData();
WebApiConfigs _wac = new WebApiConfigs("", "", "", "", "", "");
@override
WebApiConfigsState get initialState =>
WebApiConfigsLoading(webApiConfigs: _wac);
@override
Stream<WebApiConfigsState> mapEventToState(
WebApiConfigsEvent event,
) async* {
//Load
if (event is LoadWebApiConfigsEvent) {
try {
final WebApiConfigs _wac = await _persistentData.getApiConfigs();
yield WebApiConfigsLoaded(webApiConfigs: _wac);
} catch (error) {
yield WebApiConfigsError(error: error.toString());
}
}
//Save
if (event is SaveWebApiConfigsEvent) {
try {
yield WebApiConfigsSaving(webApiConfigs: event.webApiConfigs);
yield WebApiConfigsSaved(webApiConfigs: event.webApiConfigs);
} catch (error) {
yield WebApiConfigsError(error: error.toString());
}
}
}
}
The Form
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:visiogate/vg_blocs/webApiConfigs/webApiConfigs.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
class ConfigsForm extends StatefulWidget {
final WebApiConfigsBloc webApiConfigsBloc;
const ConfigsForm({Key key, @required this.webApiConfigsBloc})
: super(key: key);
@override
_ConfigsFormState createState() => _ConfigsFormState();
}
class _ConfigsFormState extends State<ConfigsForm> {
final _urlController = TextEditingController();
final _companyController = TextEditingController();
WebApiConfigsBloc get _webApiConfigsBloc => widget.webApiConfigsBloc;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<WebApiConfigsEvent, WebApiConfigsState>(
bloc: _webApiConfigsBloc,
builder: (
BuildContext context,
WebApiConfigsState state,
) {
if (state is WebApiConfigsError) {
_onWidgetDidBuild(() {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('${state.error}'),
backgroundColor: Colors.red,
),
);
});
} else if (state is WebApiConfigsLoading) {
_webApiConfigsBloc
.dispatch(LoadWebApiConfigsEvent(state.webApiConfigs));
} else if (state is WebApiConfigsLoaded) {
_urlController.text = state.webApiConfigs.url;
_companyController.text = state.webApiConfigs.company;
//TODO: showSnackBar
} else if (state is WebApiConfigsSaved) {
_urlController.text = state.webApiConfigs.url;
_companyController.text = state.webApiConfigs.company;
//TODO: showSnackBar
}
return Column(
children: <Widget>[
Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'url'),
controller: _urlController,
),
TextFormField(
decoration: InputDecoration(labelText: 'company'),
controller: _companyController,
),
RaisedButton(
onPressed: state is! WebApiConfigsLoading
? _onSaveConfigsButtonPressed
: null,
child: Text('save'),
),
Container(
child: state is WebApiConfigsLoading
? CircularProgressIndicator()
: null,
),
],
),
),
],
);
},
);
}
void _onWidgetDidBuild(Function callback) {
WidgetsBinding.instance.addPostFrameCallback((_) {
callback();
});
}
_onSaveConfigsButtonPressed() {
//TODO: fazer restantes controlos
WebApiConfigs _wac = new WebApiConfigs(
_urlController.text,
_companyController.text,
"default",
"bearer",
"professional",
"password");
_webApiConfigsBloc.dispatch(SaveWebApiConfigsEvent(
_wac,
));
}
}
SharedPreferences
import 'package:shared_preferences/shared_preferences.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
import 'package:visiogate/vg_models/token/token.dart';
class PersistentData {
String _apiUrl = "api_url";
String _apiCompany = "api_company";
String _apiInstance = "api_instance";
String _apiAuthorization = "api_authorization";
String _apiLine = "api_line";
String _apiGrantType = "api_grant_type";
Future<void> setApiConfigs(WebApiConfigs webapi) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString(_apiUrl, webapi.url);
prefs.setString(_apiCompany, webapi.company);
prefs.setString(_apiInstance, webapi.instance);
prefs.setString(_apiAuthorization, webapi.authorization);
prefs.setString(_apiLine, webapi.line);
prefs.setString(_apiGrantType, webapi.grantType);
return;
}
Future<WebApiConfigs> getApiConfigs() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String _ur = prefs.getString(_apiUrl) ?? "";
String _co = prefs.getString(_apiCompany) ?? "";
String _ins = prefs.getString(_apiInstance) ?? "D";
String _au = prefs.getString(_apiAuthorization) ?? "bearer";
String _ln = prefs.getString(_apiLine) ?? "pro";
String _gt = prefs.getString(_apiGrantType) ?? "pwd";
WebApiConfigs webapi = new WebApiConfigs(_ur, _co, _ins, _au, _ln, _gt);
return webapi;
}
}
If I do not restart the app, all the "saved" configs are there! What am I doing wrong? It´s probably just a simple line but...it´s driving me crazy!
TY in andvance.
Upvotes: 2
Views: 2254
Reputation: 482
After some coffee and fresh air on my face…
The problem was on the Form and on the Bloc. Here is the code so that no other soul gets crazy and also my contribution to the community:
BloC Bloc
import 'package:bloc/bloc.dart';
import 'package:visiogate/vg_blocs/webApiConfigs/webApiConfigs.dart';
import 'package:visiogate/vg_blocs/simple_bloc_delegate.dart';
import 'package:visiogate/vg_models/persistent_data/persistent_data.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
void main() {
BlocSupervisor.delegate = SimpleBlocDelegate();
}
class WebApiConfigsBloc extends Bloc<WebApiConfigsEvent, WebApiConfigsState> {
PersistentData _persistentData = new PersistentData();
WebApiConfigs _wac = new WebApiConfigs("", "", "", "", "", "");
@override
WebApiConfigsState get initialState =>
WebApiConfigsLoading(webApiConfigs: _wac);
@override
Stream<WebApiConfigsState> mapEventToState(
WebApiConfigsEvent event,
) async* {
//Load
if (event is LoadWebApiConfigsEvent) {
try {
event.webApiConfigs = await _persistentData.getApiConfigs();
yield WebApiConfigsLoaded(webApiConfigs: event.webApiConfigs);
} catch (error) {
yield WebApiConfigsError(error: error.toString());
}
}
//Save
if (event is SaveWebApiConfigsEvent) {
try {
_persistentData.setApiConfigs(event.webApiConfigs);
yield WebApiConfigsSaving(webApiConfigs: event.webApiConfigs);
yield WebApiConfigsLoaded(webApiConfigs: event.webApiConfigs);
} catch (error) {
yield WebApiConfigsError(error: error.toString());
}
}
}
}
Form
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:visiogate/vg_blocs/webApiConfigs/webApiConfigs.dart';
import 'package:visiogate/vg_models/webApiConfigs/webapi_model.dart';
class ConfigsForm extends StatefulWidget {
final WebApiConfigsBloc webApiConfigsBloc;
const ConfigsForm({Key key, @required this.webApiConfigsBloc})
: super(key: key);
@override
_ConfigsFormState createState() => _ConfigsFormState();
}
class _ConfigsFormState extends State<ConfigsForm> {
final _urlController = TextEditingController();
final _companyController = TextEditingController();
WebApiConfigsBloc get _webApiConfigsBloc => widget.webApiConfigsBloc;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<WebApiConfigsEvent, WebApiConfigsState>(
bloc: _webApiConfigsBloc,
builder: (
BuildContext context,
WebApiConfigsState state,
) {
if (state is WebApiConfigsError) {
_onWidgetDidBuild(() {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text('${state.error}'),
backgroundColor: Colors.red,
),
);
});
} else if (state is WebApiConfigsLoading) {
_webApiConfigsBloc
.dispatch(LoadWebApiConfigsEvent(state.webApiConfigs));
} else if (state is WebApiConfigsSaving) {
_urlController.text = state.webApiConfigs.url;
_companyController.text = state.webApiConfigs.company;
//TODO: showSnackBar
} else if (state is WebApiConfigsLoaded) {
_urlController.text = state.webApiConfigs.url;
_companyController.text = state.webApiConfigs.company;
//TODO: showSnackBar
}
return Column(
children: <Widget>[
Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'url'),
controller: _urlController,
),
TextFormField(
decoration: InputDecoration(labelText: 'company'),
controller: _companyController,
),
RaisedButton(
onPressed: (state is! WebApiConfigsLoading)
? _onSaveConfigsButtonPressed
: null,
child: Text('save'),
),
Container(
child: (state is WebApiConfigsLoading)
? CircularProgressIndicator()
: null,
),
],
),
),
],
);
},
);
}
void _onWidgetDidBuild(Function callback) {
WidgetsBinding.instance.addPostFrameCallback((_) {
callback();
});
}
_onSaveConfigsButtonPressed() {
WebApiConfigs _wac = new WebApiConfigs(
_urlController.text,
_companyController.text,
"d",
"bearer",
"pro",
"pwd");
_webApiConfigsBloc.dispatch(SaveWebApiConfigsEvent(
_wac,
));
}
}
The main issue was that I was using "_wac" variable instead of "event.webApiConfigs" on the BloC. Also removed the State "WebApiConfigsSaved" because it has the same final has "WebApiConfigsLoaded".
Cheers.
Upvotes: 1