I am trying to use Riverpod for Flutter stage management.
I have created a class called UsuarioProvider:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:shared_preferences/shared_preferences.dart';
class UsuarioProvider extends StateNotifier<String> {
UsuarioProvider(): super("No user");
void cambiarUsuario (String nuevo){
state = nuevo;
cambiarEmailUsuarioSP(nuevo);
}
cambiarEmailUsuarioSP(String nuevo) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
state =nuevo;
prefs.setString("email", nuevo);
}
recibirEmailSP() async{
SharedPreferences prefs = await SharedPreferences.getInstance();
String emailActual = prefs.getString("email");
}
}
On main.dart I have declared the use of the riverpod provider as follows:
//riverpod USUARIO
final usuarioProvider = StateNotifierProvider<UsuarioProvider>((ref) {
return UsuarioProvider();
});
void cambiarUsuario(String nueva) {
context.read(usuarioProvider).cambiarUsuario(nueva);
}
Now I need to change the state for UsuarioProvider as follows:
...
cambiarUsuario(parsed['user']['email'].toString());
...
The value for parsed['user']['email'].toString() = 'mimail#gmail.com'
but then, trying to get the state for it:
child: Consumer(builder: (_, ScopedReader watch, __) {
var value = watch(usuarioProvider.state);
print("%%%%%%%%%%%%%%%%%%EMail en Home:"+value.toString());
if (value == "No user") {
value = 'NoClinic'.tr().toString();
}
return Text(
value.toString(),
style: TextStyle(
fontSize: 12.0,
),
);
}),
I am always getting 'No user', not 'mimail#gmail.com'
What am I doing wrong?
the provider file :
import 'package:riverpod/riverpod.dart';
final usuarioProvider = StateNotifierProvider<UsuarioProvider>((ref) {
return UsuarioProvider();
});
class UsuarioProvider extends StateNotifier<String> {
UsuarioProvider() : super("No user");
void cambiarUsuario(String nuevo) {
state = nuevo;
cambiarEmailUsuarioSP(nuevo);
}
cambiarEmailUsuarioSP(String nuevo) async {
await Future.delayed(Duration(seconds: 1));
// this isn't necessary and it will case aditional rebuilt
state = nuevo;
}
}
The screen :
class MyConsumerScreen extends StatelessWidget {
const MyConsumerScreen({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Consumer(
builder: (context, watch, child) {
var value = watch(usuarioProvider.state);
if (value == "No user") {
value = 'NoClinic';
}
return Text(value);
},
),
SizedBox(height: 50),
ElevatedButton(
onPressed: () {
context.read(usuarioProvider).cambiarUsuario("It work !");
},
child: Text("test"),
)
],
),
),
);
}
}
make sure the to add the provider scope :
void main() => runApp(ProviderScope(child: MyApp()));
Related
UPDATE
I was able to solve my problem using the FutureBuilder widget. All the changes were in the file_listing.dart file. Here's the updated file:
start of file_listing.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path/path.dart' as pathpkg;
import 'package:pythonga_expense_estimator/components/bottom_button.dart';
import 'package:pythonga_expense_estimator/services/directory_services.dart';
class FileListing extends StatefulWidget {
FileListing();
#override
State<FileListing> createState() => _FileListingState();
}
class _FileListingState extends State<FileListing> {
Map fileMap = {};
Future<Map> getSavedEstimates() async {
try {
var savedEstimates = await DirectoryHelper.listOfFiles().then((resp) {
return resp;
});
savedEstimates.forEach((key, value) => print(key));
return savedEstimates;
} catch (e) {
throw Exception("Could Not Retrieve list of saved files");
}
}
Future<List<Widget>> fileListMappedAsWidget() async {
var fileHits =
await getSavedEstimates(); //returns Future<Map<dynamic,dynamic>>
List<Widget> newList = [];
fileHits.forEach((k, v) {
newList.add(Row(
children: [
Text(pathpkg.basename(v)),
BottomButton(
buttonTitle: 'Delete',
onPressed: () => () {
setState(() {
k.deleteSync();
fileMap.remove(k);
});
})
],
));
});
// () => newList;
return newList;
// throw ("f");
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: fileListMappedAsWidget(),
// future: testRetrieve,
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
List<Widget> children;
print(snapshot.connectionState);
if (snapshot.hasData) {
List<Widget> childStuff = [];
for (int i = 0; i < snapshot.data!.length; i++) {
childStuff.add(snapshot.data![i]);
}
children = childStuff;
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(Icons.error_outline, color: Colors.red, size: 60),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'))
];
} else {
children = const <Widget>[
SizedBox(
width: 60, height: 60, child: CircularProgressIndicator()),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting Result'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
);
}),
);
}
}
end of file_listing.dart
ORIGINAL QUESTION
I'm trying to create a page for a Flutter app. It will be the first page that the user sees when they launch the app.
The page will display a list of files, cost estimates that the user has saved previously and a button for them to create a new "estimate" which can then also be saved to a file.
The files are being saved on the device, and I'm using the path_provider and path packages to access them. Reading from and writing to the device file system are asynchronous operations.
I cannot get the list of files to appear automatically when the page loads and would like to get advice on how to do this. The results of the async function are futures of data types and I cannot get them to be just data types.
Here's what I have in terms of code:
(1) main.dart
It specifies the home page of the material app to be StartPage().
start of main.dart
import 'package:flutter/material.dart';
import 'constants/text_constants.dart';
import 'pages/start_page.dart';
void main() => runApp(PythongaVisitCostCalculator());
class PythongaVisitCostCalculator extends StatelessWidget {
const PythongaVisitCostCalculator({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: kAppTitle1,
theme: ThemeData(
primarySwatch: Colors.lightBlue,
elevatedButtonTheme: ElevatedButtonThemeData(
style: ButtonStyle(
shape: MaterialStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
),
),
),
),
home: StartPage(title: kYourTripsDescr));
}
}
end of main.dart
(2) start_page.dart
This is the home page (stateful class) for the application, as specified in main.dart. One of the items that appears is a list of files saved by the user using the FileListing() widget, which is created in the file_listing.dart file, which follows.
start of start_page.dart
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:pythonga_expense_estimator/components/round_icon_button.dart';
import 'package:pythonga_expense_estimator/components/file_listing.dart';
import 'package:pythonga_expense_estimator/pages/input_page.dart';
import '../constants/text_constants.dart';
class StartPage extends StatefulWidget {
const StartPage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<StartPage> createState() => _StartPageState();
}
class _StartPageState extends State<StartPage> {
Map fileList = {};
#override
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(kAppTitle2),
centerTitle: true,
automaticallyImplyLeading: false,
),
body: SafeArea(
child: Column(children: [
Text(kYourEstimatesDescr),
FileListing(),
Row(
children: [
Text(kEstimateTripDescr),
RoundIconButton(
icon: FontAwesomeIcons.plus,
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return InputPage(title: 'New Estimate');
}));
})
],
),
]),
),
);
}
}
end of start_page.dart
(3) file_listing.dart
This stateful class returns a widget ,FileListing(), that is used in the StartPage() widget.
start of file_listing.dart
import 'package:flutter/material.dart';
import 'package:path/path.dart' as pathpkg;
import 'package:pythonga_expense_estimator/components/bottom_button.dart';
import 'package:pythonga_expense_estimator/services/directory_services.dart';
class FileListing extends StatefulWidget {
FileListing();
#override
State<FileListing> createState() => _FileListingState();
}
class _FileListingState extends State<FileListing> {
Map fileMap = {};
Future<Map> getSavedEstimates() async {
try {
var savedEstimates = await DirectoryHelper.listOfFiles().then((resp) {
return resp;
});
savedEstimates.forEach((key, value) => print(key));
return savedEstimates;
} catch (e) {
throw Exception("Could Not Retrieve list of saved files");
}
}
Future<List<Widget>> fileListMappedAsWidget() async {
var fileHits = await getSavedEstimates(); //returns Future<Map<dynamic,dynamic>>
List<Widget> newList = [];
fileHits.forEach((k, v) {
newList.add(Row(
children: [
Text(pathpkg.basename(v)),
BottomButton(
buttonTitle: 'Delete',
onPressed: () => () {
setState(() {
k.deleteSync();
fileMap.remove(k);
});
})],
));
});
}
#override
Widget build(BuildContext context) {
// if (fileList.isEmpty) {
if (fileListMappedAsWidget().isEmpty) {
return Container(
child: Row(children: const [
Center(child: Text("No Estimates on File")),
]));
}
return Column(
//children: fileList,
children: fileListMappedAsWidget(),
);
}
}
end of file_listing.dart
Dart Analysis gives me an error on the line:
children: fileListMappedAsWidget(). The error is:
The argument type 'Future<List>' can't be assigned to the parameter type 'List'.
and an error on the line if (fileListMappedAsWidget().isEmpty) {
The error is:
The getter 'isEmpty' isn't defined for the type 'Future<List>
I was expecting to that the return of fileListMappedAsWidget would be a List rather than a Future<List> once the asynchronous method completed and returned its response.
My question is "How can I transform that Future<List> to List so that my page will list the files saved by the user?
(4) directory_services.dart
Here's the code in directory_services.dart that reads the contents of the application data folder and returns a map of {File, filename text}. This code appears to be working correctly.
start of directory_services.dart
import 'dart:io' as io;
import 'package:path_provider/path_provider.dart' as pathprvdrpkg;
import 'package:path/path.dart' as pathpkg;
import '../constants/text_constants.dart';
class DirectoryHelper {
static Future<Map<io.FileSystemEntity, String>> listOfFiles() async {
List<io.FileSystemEntity> fileSystemEntityList =
io.Directory(await localPath()).listSync();
Map<io.FileSystemEntity, String> fileMap = {};
for (int i = 0; i < fileSystemEntityList.length; i++) {
if (pathpkg.extension(fileSystemEntityList[i].path) ==
kEstimateFileExtension) {
fileMap[fileSystemEntityList[i]] = fileSystemEntityList[i].path;
}
}
return fileMap;
}
static localPath() async {
// finds the correct local path using path_provider package
try {
final directory = await pathprvdrpkg.getApplicationDocumentsDirectory();
// print("directory.path in DirectoryPath.localPath");
return directory.path;
} catch (e) {
return Exception('Error: $e');
}
}
}
end of directory_services.dart
Thanks for your help and advice!
I was able to solve my problem using the FutureBuilder widget. All the changes were in the file_listing.dart file. Here's the updated file:
start of file_listing.dart
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:path/path.dart' as pathpkg;
import 'package:pythonga_expense_estimator/components/bottom_button.dart';
import 'package:pythonga_expense_estimator/services/directory_services.dart';
class FileListing extends StatefulWidget {
FileListing();
#override
State<FileListing> createState() => _FileListingState();
}
class _FileListingState extends State<FileListing> {
Map fileMap = {};
Future<Map> getSavedEstimates() async {
try {
var savedEstimates = await DirectoryHelper.listOfFiles().then((resp) {
return resp;
});
savedEstimates.forEach((key, value) => print(key));
return savedEstimates;
} catch (e) {
throw Exception("Could Not Retrieve list of saved files");
}
}
Future<List<Widget>> fileListMappedAsWidget() async {
var fileHits =
await getSavedEstimates(); //returns Future<Map<dynamic,dynamic>>
List<Widget> newList = [];
fileHits.forEach((k, v) {
newList.add(Row(
children: [
Text(pathpkg.basename(v)),
BottomButton(
buttonTitle: 'Delete',
onPressed: () => () {
setState(() {
k.deleteSync();
fileMap.remove(k);
});
})
],
));
});
// () => newList;
return newList;
// throw ("f");
}
#override
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: fileListMappedAsWidget(),
// future: testRetrieve,
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
List<Widget> children;
print(snapshot.connectionState);
if (snapshot.hasData) {
List<Widget> childStuff = [];
for (int i = 0; i < snapshot.data!.length; i++) {
childStuff.add(snapshot.data![i]);
}
children = childStuff;
} else if (snapshot.hasError) {
children = <Widget>[
const Icon(Icons.error_outline, color: Colors.red, size: 60),
Padding(
padding: const EdgeInsets.only(top: 16),
child: Text('Error: ${snapshot.error}'))
];
} else {
children = const <Widget>[
SizedBox(
width: 60, height: 60, child: CircularProgressIndicator()),
Padding(
padding: EdgeInsets.only(top: 16),
child: Text('Awaiting Result'),
)
];
}
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
);
}),
);
}
}
end of file_listing.dart
I decided to study the architecture of BloC. And something really worries me. I was making a login page and noticed that after calling the Emit () function, the TextField () became empty. If I understand correctly, BlocBuilder has rebuilt the entire widget. Is there a way to rebuild only the part that has changed with a single BlocBuilder? Or something smaller.
UI:
P.S:
there is a function generate Form () It returns
Column (
children: [
TextField (),
TextField (),
],
);
class MainAuth extends StatelessWidget {
#override
Widget build(BuildContext context) {
return CustomScaffold(
resizeToAvoidBottomInset: true,
body: SafeArea(
child: BlocBuilder<AuthBloc, AuthState>(
builder: (context, state) {
if (state is AuthMain) {
return mayBe(
regForm: generateForm(context.read<AuthBloc>().loginForm,
authType.login, context),
loginForm: generateForm(context.read<AuthBloc>().regForm,
authType.register, context),
login: state.type == authType.login,
);
} else {
return Container();
}
},
),
),
);
}
}
class mayBe extends StatelessWidget {
final Widget regForm;
final Widget loginForm;
final bool login;
mayBe({required this.regForm, required this.loginForm, required this.login});
#override
Widget build(BuildContext context) {
return ListenableProvider(
create: (c) {},
child: Column(
children: [
Expanded(
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
Column(
children: [
ChangedAnimationBlock(
index: login ? 0 : 1,
children: [
Builder(builder: (c) => loginForm),
regForm,
],
),
],
),
],
),
),
),
],
),
);
}
}
Auth Cubit:
import 'package:bloc/bloc.dart';
import 'package:meta/meta.dart';
import 'package:proj/brain/base_functions/forms_to_form.dart';
import 'package:proj/data/repositories/main_api_repository.dart';
part 'auth_state.dart';
class AuthCubit extends Cubit<AuthState> {
final MainApiRepository mainApiRepository;
authType curType = authType.register;
Map responseRegBody = {};
Map responseLoginBody = {};
AuthCubit({required this.mainApiRepository}) : super(AuthInitial()) {
start();
}
Future<void> start() async {
await getForms();
emit(
AuthMain(),
);
}
Future<void> getForms() async {
await getLoginForm();
await getRegisterForm();
}
void changeType() {
var currentState = state;
if (currentState is AuthMain) {
authType oldAuthType = curType;
authType newAuthType;
if (oldAuthType == authType.login) {
newAuthType = authType.register;
} else {
newAuthType = authType.login;
}
// curType = newAuthType;
emit(
AuthMain(type: newAuthType),
);
}
}
Map loginForm = {};
Map regForm = {};
Future<void> getLoginForm() async {
var response = await mainApiRepository.getAuthFromSettings();
loginForm = searchFormIntoForms(response);
print(response);
print(loginForm);
print("loginForm");
}
Future<void> getRegisterForm() async {
var response = await mainApiRepository.getRegistrationFormSettings();
regForm = searchFormIntoForms(response);
}
}
Auth state:
part of 'auth_cubit.dart';
enum authType {
register,
login,
}
#immutable
abstract class AuthState {}
class AuthInitial extends AuthState {}
class AuthMain extends AuthState {
final authType type;
AuthMain({
this.type = authType.register,
});
}
I have code that I use to write data to a file (such as global settings for an application). I write down the data and see. But the problem is that I do not understand how to take these mini data from another page. For example I wrote the word "Test" and I want and I want to assign that word to some variable in another page. I will be grateful for your help. Here is my code:
import 'dart:io';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Reading and Writing to Storage",
home: Home(
storage: Storage(),
),
);
}
}
class Home extends StatefulWidget {
final Storage storage;
Home({Key key, #required this.storage}) : super(key: key);
#override
HomeState createState() => HomeState();
}
class HomeState extends State<Home> {
TextEditingController controller = TextEditingController();
String state;
Future<Directory> _appDocDir;
#override
void initState() {
super.initState();
widget.storage.readData().then((String value) {
setState(() {
state = value;
});
});
}
Future<File> writeData() async {
setState(() {
state = controller.text;
controller.text = '';
});
return widget.storage.writeData(state);
}
void getAppDirectory() {
setState(() {
_appDocDir = getApplicationDocumentsDirectory();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Reading and Writing Files'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('${state ?? "File is Empty"}'),
TextField(
controller: controller,
),
RaisedButton(
onPressed: writeData,
child: Text('Write to File'),
),
RaisedButton(
child: Text("Get DIR path"),
onPressed: getAppDirectory,
),
FutureBuilder<Directory>(
future: _appDocDir,
builder:
(BuildContext context, AsyncSnapshot<Directory> snapshot) {
Text text = Text('');
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
text = Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
text = Text('Path: ${snapshot.data.path}');
} else {
text = Text('Unavailable');
}
}
return new Container(
child: text,
);
},
)
],
),
),
);
}
}
class Storage {
Future<String> get localPath async {
final dir = await getApplicationDocumentsDirectory();
return dir.path;
}
Future<File> get localFile async {
final path = await localPath;
return File('$path/db.txt');
}
Future<String> readData() async {
try {
final file = await localFile;
String body = await file.readAsString();
return body;
} catch (e) {
return e.toString();
}
}
Future<File> writeData(String data) async {
final file = await localFile;
return file.writeAsString("$data");
}
}
And scrin:
You can pass the value to other page using Navigator and parameter.
class NewScreen extends StatelessWidget {
final String data;
NewScreen({this.data});
...
}
When you move to 'NewScreen' by using Navigator at your 'Home' page,
pass the data what you transfer.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NewScreen(data: 'Test'),
),
);
I was create SharedPreferences to save user loading in logon page. Then data of user will be save in SharedPreferences and move to main page. But my problem now in main page I need use this variable in different places in main page. But I cant do that.
I need to make variable of logindata can use in each places in main page I try to use in drawer to make logout. No I get error as:
Undefined name 'logindata'.
this is my code:
void initial() async {
logindata = await SharedPreferences.getInstance();
setState(() {
username = logindata.getString('username');
return username;
});
}
my full code:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';
import 'addnewtopics.dart';
import 'DetilesOfMainPage.dart';
import 'loginpage.dart';
class MyApp extends StatelessWidget {
final String email;
MyApp({Key key, #required this.email}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('JSON ListView')
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Text('Drawer Header'),
decoration: BoxDecoration(
color: Colors.blue,
),
),
ListTile(
title: Text('Item 1'),
onTap: () {
logindata.setBool('login', true);// here I need to use It ========================
Navigator.pushReplacement(context,
new MaterialPageRoute(builder: (context) => LoginUser()));
Navigator.pop(context);
},
),
ListTile(
title: Text('Item 2'),
onTap: () {
// Navigator.pop(context);
},
),
],
),
),
body: JsonImageList(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => UploadImageDemo()
),);
},
child: Icon(Icons.add),
),
));
}
}
class Flowerdata {
int id;
String flowerName;
String flowerImageURL;
Flowerdata({
this.id,
this.flowerName,
this.flowerImageURL
});
factory Flowerdata.fromJson(Map<String, dynamic> json) {
return Flowerdata(
id: json['id'],
flowerName: json['nametopics'],
flowerImageURL: json['image']
);
}
}
class JsonImageList extends StatefulWidget {
JsonImageListWidget createState() => JsonImageListWidget();
}
class JsonImageListWidget extends State {
SharedPreferences logindata;
String username;
#override
void initState() {
// TODO: implement initState
super.initState();
initial();
}
void initial() async {
logindata = await SharedPreferences.getInstance();
setState(() {
username = logindata.getString('username');
return username;
});
}
final String apiURL = 'http://xxxxxxxxx/getFlowersList.php';
Future<List<Flowerdata>> fetchFlowers() async {
var response = await http.get(apiURL);
if (response.statusCode == 200) {
final items = json.decode(response.body).cast<Map<String, dynamic>>();
List<Flowerdata> listOfFruits = items.map<Flowerdata>((json) {
return Flowerdata.fromJson(json);
}).toList();
return listOfFruits;
}
else {
throw Exception('Failed to load data from Server.');
}
}
getItemAndNavigate(String item, BuildContext context){
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondScreen(itemHolder : item)
)
);
}
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Flowerdata>>(
future: fetchFlowers(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Center(
child: CircularProgressIndicator()
);
return ListView(
children: snapshot.data
.map((data) => Column(children: <Widget>[
GestureDetector(
onTap: ()=>{
getItemAndNavigate(data.flowerName, context)
},
child: Row(
children: [
Container(
width: 200,
height: 100,
margin: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child:
Image.network(data.flowerImageURL,
width: 200, height: 100, fit: BoxFit.cover,))),
Flexible(child:
Text(data.flowerName,
style: TextStyle(fontSize: 18)))
]),),
Divider(color: Colors.black),
],))
.toList(),
);
},
);
}
}
Anyone know how can make that?
You need var keyword, in your case you can directly use
var logindata = await SharedPreferences.getInstance();
You do not need to make it global, because SharedPreferences.getInstance() is Singleton
Every time you use var logindata = await SharedPreferences.getInstance(); will get the same instance
Also there is no performance issue when you call getInstance(), because it's cached, you can see source code snippet below
class SharedPreferences {
SharedPreferences._(this._preferenceCache);
...
static Future<SharedPreferences> getInstance() async {
if (_completer == null) {
_completer = Completer<SharedPreferences>();
try {
final Map<String, Object> preferencesMap =
await _getSharedPreferencesMap();
_completer.complete(SharedPreferences._(preferencesMap));
} on Exception catch (e) {
// If there's an error, explicitly return the future with an error.
// then set the completer to null so we can retry.
_completer.completeError(e);
final Future<SharedPreferences> sharedPrefsFuture = _completer.future;
_completer = null;
return sharedPrefsFuture;
}
}
return _completer.future;
When you declare a String outside of class and does not contain _ before variable name like _localString it become global
String globalString = ""; //global, import can be seen
String _localString = ""; //local and can only be seen in this file, import can not seen
void main() async{
var logindata = await SharedPreferences.getInstance();
runApp(MyApp());
}
You simply need to put your variable outside of any class or method. An example is to create a file globals.dart then put all your globals in it and import the file when you need.
Example
// globals.dart
String globalString;
int globalInt;
bool globalBool;
// in any other file
import 'globals.dart' as globals;
globals.globalString = "Global String";
I am new to flutter and I am having the following problem.
I am trying to use the progressDialog in in a listview, I make the query to my database, I extract the list and pass it to the listview, I am trying to use the progressDialog so when I start loading the list it will run and tell the user to wait, and when I finish loading the list then the progressDialog is hidden, so far it works for me by bringing me the list and the progressDialog is executed saying to wait, but when I put the progressDialog.hide where the loading of the list ends I this is not accepting that line of code (progressDialog .hidde)
image:
enter image description here
import 'dart:convert';
import 'package:fluterproyecto1/Modulos/DetalleUser.dart';
import 'package:flutter/material.dart';
import 'package:progress_dialog/progress_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
String username2 = '';
String profesion = '';
String name = '';
class MemberPage extends StatefulWidget {
MemberPage({Key key}) : super(key: key);
#override
_MemberPageState createState() => _MemberPageState();
}
class _MemberPageState extends State<MemberPage> {
Map data;
List userData;
ProgressDialog progressDialog;
String name = '';
Future getData() async {
http.Response response =
await http.get("http://masciudad.com.co/flutter/getdata.php");
data = json.decode(response.body);
//setState(() {
//progressDialog.show();
userData = data["data"];
//progressDialog.hide();
//});
}
#override
void initState() {
super.initState();
getData();
}
#override
Widget build(BuildContext context) {
progressDialog = ProgressDialog(context, type: ProgressDialogType.Normal);
progressDialog.style(message: 'Por favor espere...');
progressDialog.show();
setState(() {
obtenerPreferencias();
});
return Scaffold(
appBar: AppBar(
title: Text("Bienvenido $username2"),
),
body: ListView.builder(
itemCount: userData == null ? 0 : userData.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Image.asset(
"assets/128.jpg",
width: 30.0,
height: 30.0,
),
//CircleAvatar(
///cuando la imagen es de interntet
//backgroundImage: NetworkImage(
// "https://s3.amazonaws.com/uifaces/faces/twitter/follettkyle/128.jpg"),
//),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"${userData[index]["username"]} - ${userData[index]["profesion"]}",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
),
)
],
),
),
onTap: () => Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new DetalleUser(name: userData[index]["username"]))),
);
},
),
//Navigator.of(context).push(MaterialPageRoute(
// builder: (BuildContext context) => MyHomePage()));
//Navigator.pushReplacementNamed(context, "/MyHomePage");
);
}
Future obtenerPreferencias() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
username2 = preferences.get("username2") ?? "";
profesion = preferences.get("profesion") ?? "";
});
}
Future destruirPreferencias() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.clear();
}
}
You can copy paste run full code below
You can use addPostFrameCallback and put logical in another function getRelatedData()
code snippet
void getRelatedData() async {
progressDialog = ProgressDialog(context, type: ProgressDialogType.Normal);
progressDialog.style(message: 'Por favor espere...');
progressDialog.show();
await getData();
await obtenerPreferencias();
progressDialog.hide();
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
getRelatedData();
});
}
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:progress_dialog/progress_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
String username2 = '';
String profesion = '';
String name = '';
class MemberPage extends StatefulWidget {
MemberPage({Key key}) : super(key: key);
#override
_MemberPageState createState() => _MemberPageState();
}
class _MemberPageState extends State<MemberPage> {
Map data;
List userData;
ProgressDialog progressDialog;
String name = '';
Future getData() async {
http.Response response =
await http.get("http://masciudad.com.co/flutter/getdata.php");
data = json.decode(response.body);
//setState(() {
//progressDialog.show();
userData = data["data"];
print("getData Done");
//progressDialog.hide();
//});
}
void getRelatedData() async {
progressDialog = ProgressDialog(context, type: ProgressDialogType.Normal);
progressDialog.style(message: 'Por favor espere...');
progressDialog.show();
await getData();
await obtenerPreferencias();
progressDialog.hide();
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
getRelatedData();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Bienvenido $username2"),
),
body: ListView.builder(
itemCount: userData == null ? 0 : userData.length,
itemBuilder: (BuildContext context, int index) {
return InkWell(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Row(
children: <Widget>[
Image.network(
"https://picsum.photos/250?image=9",
width: 30.0,
height: 30.0,
),
//CircleAvatar(
///cuando la imagen es de interntet
//backgroundImage: NetworkImage(
// "https://s3.amazonaws.com/uifaces/faces/twitter/follettkyle/128.jpg"),
//),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
"${userData[index]["username"]} - ${userData[index]["profesion"]}",
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w700,
),
),
)
],
),
),
onTap: () {
/*Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new DetalleUser(name: userData[index]["username"])));*/
});
},
),
//Navigator.of(context).push(MaterialPageRoute(
// builder: (BuildContext context) => MyHomePage()));
//Navigator.pushReplacementNamed(context, "/MyHomePage");
);
}
Future obtenerPreferencias() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
setState(() {
username2 = preferences.get("username2") ?? "";
profesion = preferences.get("profesion") ?? "";
});
}
Future destruirPreferencias() async {
SharedPreferences preferences = await SharedPreferences.getInstance();
preferences.clear();
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MemberPage(),
);
}
}
Dear #Yeimer I would suggest read documentation carefully
https://pub.dev/packages/progress_dialog
Add the Package this
dependencies:
progress_dialog: ^1.2.4
1
Initialize your ProgressDialog object
final ProgressDialog prDialog = ProgressDialog(context);
//For normal dialog
prDialog = ProgressDialog(context,type: ProgressDialogType.Normal, isDismissible: true/false, showLogs: true/false);
2 Showing the progress dialog
await pr.show();
3
Dismissing the progress dialog
prDialog.hide().then((isHidden) {
print(isHidden);
});
// or simply
await prDialog.hide();