How to display taken photo correctly? - flutter

I have custom app where I use dialogs to quiz with users to save places. When I take photo file is saved to device but not displayed. Where I have an error in my code where I tried display image?
Code:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as syspaths;
class PlacesListScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _Map();
}
}
class _Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<_Map> {
File _storedImage;
final picker = ImagePicker();
final _titleController = TextEditingController();
Future _takeImage() async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 600,
);
if (pickedFile == null) {
return;
}
_storedImage = File(pickedFile.path);
final appDir = await syspaths.getApplicationDocumentsDirectory();
final fileName = path.basename(_storedImage.path);
await _storedImage.copy('${appDir.path}/$fileName');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Locations'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Do you want add current place to the map?",
textAlign: TextAlign.center,
),
content: TextField(
decoration: InputDecoration(labelText: 'Place title'),
controller: _titleController,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Do you want take photo of current place?",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 100,
decoration: BoxDecoration(
border:
Border.all(width: 1, color: Colors.grey),
),
child: _storedImage != null
? Image.file(
_storedImage,
fit: BoxFit.cover,
width: double.infinity,
)
: Text('No photo taken yet',
textAlign: TextAlign.center),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: _takeImage,
child: Text("Yes"),
),
],
),
);
},
child: Text("Yes"),
),
],
),
);
// Navigator.of(context).pushNamed(AddPlaceScreen.routeName);
},
),
],
),
body: Text("Application Content")
);
}
}
Here is photo not displayed:
Image.file(
_storedImage,
fit: BoxFit.cover,
width: double.infinity,
)
Maybe I have an error on states or on another part of my code?

You can copy paste run full code below
You can use StatefulBuilder and pass StateSetter to _takeImage and call setState
code snippet
Future _takeImage(StateSetter setState) async {
...
setState(() {
_storedImage = File(pickedFile.path);
});
...
return showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context,
StateSetter setState) {
...
FlatButton(
onPressed: () =>
_takeImage(setState),
child: Text("Yes"),
),
working demo
full code
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart' as syspaths;
class PlacesListScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return _Map();
}
}
class _Map extends StatefulWidget {
#override
_MapState createState() => _MapState();
}
class _MapState extends State<_Map> {
File _storedImage;
final picker = ImagePicker();
final _titleController = TextEditingController();
Future _takeImage(StateSetter setState) async {
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 600,
);
if (pickedFile == null) {
return;
}
setState(() {
_storedImage = File(pickedFile.path);
});
final appDir = await syspaths.getApplicationDocumentsDirectory();
final fileName = path.basename(_storedImage.path);
await _storedImage.copy('${appDir.path}/$fileName');
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Locations'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text(
"Do you want add current place to the map?",
textAlign: TextAlign.center,
),
content: TextField(
decoration:
InputDecoration(labelText: 'Place title'),
controller: _titleController,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () {
return showDialog(
context: context,
builder: (ctx) => StatefulBuilder(builder:
(BuildContext context,
StateSetter setState) {
return AlertDialog(
title: Text(
"Do you want take photo of current place?",
textAlign: TextAlign.center,
),
content: Container(
width: 150,
height: 100,
decoration: BoxDecoration(
border: Border.all(
width: 1,
color: Colors.grey),
),
child: _storedImage != null
? Image.file(
_storedImage,
fit: BoxFit.cover,
width: double.infinity,
)
: Text('No photo taken yet',
textAlign:
TextAlign.center),
alignment: Alignment.center,
),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(ctx).pop();
},
child: Text("No"),
),
FlatButton(
onPressed: () =>
_takeImage(setState),
child: Text("Yes"),
),
],
);
}));
},
child: Text("Yes"),
),
],
));
// Navigator.of(context).pushNamed(AddPlaceScreen.routeName);
},
),
],
),
body: Text("Application Content"));
}
}
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: PlacesListScreen(),
);
}
}

Related

how can I make the item made in listview by user clickable into a new page? in flutter

hi I have a page that you can create an item in the listview and give it a name, now I want to when you click on that item, it goes to own dedicated page made with its name on the app bar.
(https://i.stack.imgur.com/5jS0x.png)
here is the listview code:
import 'package:flutter/material.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:attendance/insideList.dart';
class lists extends StatefulWidget {
const lists({super.key});
#override
State<lists> createState() => _listsState();
}
class _listsState extends State<lists> {
List<String> _items = [];
late TextEditingController _textController;
#override
void initState() {
super.initState();
_textController = TextEditingController();
}
#override
void dispose() {
_textController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
_items.sort();
return Scaffold(
body: _items.length > 0
? ListView.separated(
itemCount: _items.length,
itemBuilder: (_, index) {
return ListTile(
leading: const Icon(Icons.school),
trailing: const Icon(Icons.arrow_forward),
title: Center(child: Text('${_items[index]}')),
**//here the attempt I made that didnt work**
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => InsideList(index))));
},
onLongPress: (() async {
await showDialog(
context: context,
builder: ((context) {
return AlertDialog(
title: const Text(
"Are you sure you want to delete this class?",
style: TextStyle(fontSize: 15),
),
actions: [
TextButton(
child: Text("cancel"),
onPressed: (() {
Navigator.pop(context);
})),
TextButton(
child: Text('Delete'),
onPressed: () {
setState(() {
_items.removeAt(index);
Navigator.pop(context);
});
},
),
],
);
}));
}),
);
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(
color: Colors.black,
),
)
: const Center(
child: Text("You currently have no classes. Add from below."),
),
floatingActionButton: SpeedDial(
animatedIcon: AnimatedIcons.menu_arrow,
spacing: 6,
spaceBetweenChildren: 6,
backgroundColor: const Color.fromARGB(255, 22, 37, 50),
foregroundColor: const Color.fromARGB(255, 255, 255, 255),
children: [
SpeedDialChild(
child: const Icon(Icons.group_add), label: "add student"),
SpeedDialChild(
child: const Icon(Icons.school),
label: "add class",
onTap: () async {
final result = await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('Add a new class'),
content: TextField(
controller: _textController,
autofocus: true,
decoration: const InputDecoration(
hintText: "Enter the name of the class."),
),
actions: [
TextButton(
child: Text('Cancel'),
onPressed: () {
Navigator.pop(context);
},
),
TextButton(
child: Text('Add'),
onPressed: () {
Navigator.pop(context, _textController.text);
_textController.clear();
},
),
],
);
},
);
if (result != null) {
result as String;
setState(() {
_items.add(result);
});
}
},
)
],
),
);
}
}
and this is the new dart file I made for the new page:
import 'package:flutter/material.dart';
class InsideList extends StatelessWidget {
final int index;
InsideList(this.index);
List<String> _students = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("attendance"),
centerTitle: true,
backgroundColor: const Color.fromARGB(255, 22, 37, 50),
toolbarHeight: 65,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
bottom: Radius.circular(30),
),
),
),
body: _students.length > 0
? Center(child: Text("hi"))
: Center(
child:
Text("You currently have no students. Add from below.")));
}
}
Instead of passing index, you can pass the item itself,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: ((context) => InsideList(_items[index])),
),
);
},
And
class InsideList extends StatelessWidget {
final String name;
InsideList(this.name); // use key constructor
List<String> _students = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("attendance $name"),

Deleting Item out of List, Listview.build shows wrong data

I have a Stateful widget that i pass a list to (for example 2 items).
After I delete an item, the widget should rebuild itself.
Unfortunately, the deleted item is still displayed and the other one is not.
When I re-enter the widget, the correct item is loaded.
There is a similar problem List not updating on deleting item
but maybe someone can explain me what i did wrong and why provider is helping me here instead of setState?
My code is:
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:trip_planner/util/dialog_box.dart';
import 'package:trip_planner/util/previewUrl.dart';
class BookingPage extends StatefulWidget {
final List toDoList;
BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//text controller
final _controller = TextEditingController();
final _database = FirebaseDatabase.instance.ref();
//Liste is an example what i have in my list
List toDoList2 = [
["https://www.booking.com/Share-Rnv2Kf", true],
["https://www.booking.com/Share-3hKQ0r", true],
];
void initState(){
super.initState();
}
void deleteTask(int index){
setState(() {
widget.toDoList.removeAt(index);
});
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
}
//save new Item
void saveNewItem(){
setState(() {
widget.toDoList.add([_controller.text, false]);
//DatabaseReference _testRef = _database.child("Hotel:");
//_testRef.set(widget.toDoList.toString());
_controller.clear();
});
Navigator.of(context).pop();
}
void createNewItem(){
showDialog(
context: context,
builder: (context){
return DialogBox(
controller: _controller,
onSave: saveNewItem,
onCancel: () => Navigator.of(context).pop(),
);
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Booking Seiten'),
elevation: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: createNewItem,
child: Icon(Icons.add),
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index){
return PreviewUrl(
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);
},
),
);
}
}
i thought setState does the same thing as when i re-enter the widget, but it doesn't.
import 'package:any_link_preview/any_link_preview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:url_launcher/url_launcher.dart';
class PreviewUrl extends StatelessWidget {
final String url2;
//Function(bool?)? onChanged;
Function(BuildContext)? deleteFunction;
PreviewUrl({
super.key,
required this.url2,
required this.deleteFunction,
//required this.onChanged,
});
Future openBrowserURL({
required String url,
bool inApp = false,
}) async {
if(await canLaunch(url)){
await launch(
url,
forceSafariVC: inApp, //iOS
forceWebView: inApp, //Android
enableJavaScript: true, //Android
);
}
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(1.0),
child: Slidable(
endActionPane: ActionPane(
motion: StretchMotion(),
children: [
SlidableAction(
onPressed: deleteFunction,
icon: Icons.delete,
backgroundColor: Colors.red.shade300,
borderRadius: BorderRadius.circular(12),
)
],
),
child: Container(
child: AnyLinkPreview.builder(
link: url2,
itemBuilder: (context, metadata, imageProvider) => Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (imageProvider != null)
GestureDetector(
onTap: () async {
final url = url2;
openBrowserURL(url: url, inApp: true);
},
child: Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.width *0.25,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(12),
topRight: Radius.circular(12)),
image: DecorationImage(
image: imageProvider,
fit: BoxFit.cover,
),
),
),
),
Container(
width: double.infinity,
color: Theme.of(context).primaryColor.withOpacity(0.6),
padding: const EdgeInsets.symmetric(
vertical: 10, horizontal: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (metadata.title != null)
Text(
metadata.title!,
maxLines: 1,
style:
const TextStyle(fontWeight: FontWeight.w500),
),
const SizedBox(height: 5),
if (metadata.desc != null)
Text(
metadata.desc!,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
Text(
metadata.url ?? url2,
maxLines: 1,
style: Theme.of(context).textTheme.bodySmall,
),
],
),
),
],
),
),
),
),
);
}
}
If you run the simplified version of your code in DartPad - it will work:
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
List toDoList = [
["Button 1", true],
["Button 2", true],
];
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: BookingPage(toDoList: toDoList),
),
),
);
}
}
class BookingPage extends StatefulWidget {
final List toDoList;
const BookingPage({
super.key,
required this.toDoList,
});
#override
State<BookingPage> createState() => _BookingPageState();
}
class _BookingPageState extends State<BookingPage> {
//Liste is an example what i have in my list
List toDoList2 = [
["Button 1", true],
["Button 2", true],
];
#override
void initState() {
super.initState();
}
void deleteTask(int index) {
setState(() {
widget.toDoList.removeAt(index);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Booking Seiten'),
elevation: 0,
),
body: ListView.builder(
itemCount: widget.toDoList.length,
itemBuilder: (context, index) {
return ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.lightBlue,
padding: const EdgeInsets.all(12),
textStyle: const TextStyle(fontSize: 22),
),
child: Text(widget.toDoList[index][0]!),
onPressed: () => setState(() => deleteTask(index)),
);
},
),
);
}
}
Which tells me that the problem is your PreviewUrl. My guess is - it is a statful widget, and when the tree rebuilds - it will link the old State object to the first item.
Using Keys might help, something like:
return PreviewUrl(
key: ObjectKey(widget.toDoList[index]),
url2: widget.toDoList[index][0],
deleteFunction: (context) => setState(() => deleteTask(index)),
);

Flutter Sqflite Toggling between Screens based on Login Status creates null operator used on null value error

I am trying to toggle between Login Screen and HomeScreen based on the user status. The logic seems to be working as long as I don't put HomeScreen.
I replaced HomeScreen with a different screen to check and the app works as it should. It displays different screens on hot restart based on the user's login status. But as soon as I try to put HomeScreen I get null operator used on null value error.
Here is the toggle logic.
class Testing extends StatefulWidget {
const Testing({super.key});
#override
State<Testing> createState() => _TestingState();
}
class _TestingState extends State<Testing> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: TodoServiceHelper().checkifLoggedIn(),
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.hasError) {
print(snapshot.hasError);
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
if (snapshot.data!.isNotEmpty) {
print(snapshot.data);
return RegisterPage();
// returning HomePage gives null check operator used on null value error
} else
return Login();
}),
);
}
}
Here is the HomeScreen
class HomePage extends StatefulWidget {
String? username;
HomePage({this.username});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final GlobalKey<FormState> formKey = GlobalKey();
TextEditingController termController = TextEditingController();
void clearText() {
termController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
User loginUser =
User(username: widget.username.toString(), isLoggedIn: false);
TodoServiceHelper().updateUserName(loginUser);
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (BuildContext context) => Login()));
},
icon: Icon(Icons.logout),
color: Colors.white,
)
],
title: FutureBuilder(
future: TodoServiceHelper().getTheUser(widget.username!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
}
return Text(
'Welcome ${snapshot.data!.username}',
style: TextStyle(color: Colors.white),
);
}),
),
body: SingleChildScrollView(
child: Column(children: [
Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
controller: termController,
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
enabledBorder: OutlineInputBorder(),
labelText: 'search todos',
),
),
TextButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ShowingSerachedTitle(
userNamee: widget.username!,
searchTerm: termController.text,
)),
);
print(termController.text);
clearText();
setState(() {});
},
child: Text(
'Search',
)),
Divider(
thickness: 3,
),
],
),
),
),
],
),
Container(
child: Stack(children: [
Positioned(
bottom: 0,
child: Text(
' done Todos',
style: TextStyle(fontSize: 12),
),
),
IconButton(
onPressed: () async {
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CheckingStuff(userNamee: widget.username!)),
);
setState(() {});
},
icon: Icon(Icons.filter),
),
]),
),
Divider(
thickness: 3,
),
Container(
child: TodoListWidget(name: widget.username!),
height: 1000,
width: 380,
)
]),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Color.fromARGB(255, 255, 132, 0),
onPressed: () async {
await showDialog(
barrierDismissible: false,
context: context,
builder: ((context) {
return AddNewTodoDialogue(name: widget.username!);
}),
);
setState(() {});
},
child: Icon(Icons.add),
),
);
}
}
The function used to return user with loginStatus true
Future<List<User>> checkifLoggedIn() async {
final Database db = await initializeDB();
final List<Map<String, Object?>> result = await db.query(
'users',
where: 'isLoggedIn = ?',
whereArgs: ['1'],
);
List<User> filtered = [];
for (var item in result) {
filtered.add(User.fromMap(item));
}
return filtered;
}
the problem is here
you used ! sign on a nullable String , and this string is nullable,
try to use this operation (??) so make it
widget.username??"" by this line you will check if the user name is null it will be replaced by an empty string.

Flutter/dart: Parse Server sdk: ParseUser.currentUser() function returning null on reset

I am using "Parse Server sdk" with "back4app" as a backend in my flutter application and I am having trouble calling the current user on initial start up of the app using the function: "ParseUser.currentUser()" but for some reason even after logging in when I restart the application the function returns null
pubspec.yaml
dependencies:
parse_server_sdk: ^2.1.0
Main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final keyApplicationId = 'xxxxxxxxx';
final keyParseServerUrl = 'https://parseapi.back4app.com';
final keyClientkey = 'xxxxxxxxxx';
await Parse().initialize(
keyApplicationId,
keyParseServerUrl,
clientKey: keyClientkey,
debug: true
);
print('connected to Parse Server');
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Future<bool> hasUserLogged() async {
print('future called');
ParseUser currentUser = await ParseUser.currentUser() as ParseUser;
if (currentUser == null) {
return false;
}
//Validates that the user's session token is valid
final ParseResponse parseResponse =
await ParseUser.getCurrentUserFromServer(
currentUser.get<String>('sessionToken'));
if (!parseResponse.success) {
print('call failed');
//Invalid session. Logout
await currentUser.logout();
return false;
} else {
print('user found');
return true;
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter - Parse Server',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FutureBuilder<bool>(
future: hasUserLogged(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Scaffold(
body: Center(
child: Container(
width: 100,
height: 100,
child: CircularProgressIndicator()),
),
);
default:
if (snapshot.hasData && snapshot.data) {
print('to User');
return UserPage();
} else {
print('to Login');
return LoginPage();
}
}
}),
);
}
}
Log In Page:
class LoginPage extends StatefulWidget {
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
final controllerUsername = TextEditingController();
final controllerPassword = TextEditingController();
bool isLoggedIn = false;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Flutter - Parse Server'),
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 200,
child: Image.network(
'https://blog.back4app.com/wp-content/uploads/2017/11/logo-b4a-1-768x175-1.png'),
),
Center(
child: const Text('Flutter on Back4App',
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
),
SizedBox(
height: 16,
),
TextField(
controller: controllerUsername,
enabled: !isLoggedIn,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.none,
autocorrect: false,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
labelText: 'Username'),
),
SizedBox(
height: 8,
),
TextField(
controller: controllerPassword,
enabled: !isLoggedIn,
obscureText: true,
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.none,
autocorrect: false,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.black)),
labelText: 'Password'),
),
SizedBox(
height: 16,
),
Container(
height: 50,
child: ElevatedButton(
child: const Text('Login'),
onPressed: isLoggedIn ? null : () => doUserLogin(),
),
),
SizedBox(
height: 16,
),
Container(
height: 50,
child: ElevatedButton(
child: const Text('Sign Up'),
onPressed: () => navigateToSignUp(),
),
),
SizedBox(
height: 16,
),
Container(
height: 50,
child: ElevatedButton(
child: const Text('Reset Password'),
onPressed: () => navigateToResetPassword(),
),
)
],
),
),
));
}
void doUserLogin() async {
final username = controllerUsername.text.trim();
final password = controllerPassword.text.trim();
final user = ParseUser(username, password, null);
var response = await user.login();
if (response.success) {
navigateToUser();
} else {
Message.showError(context: context, message: response.error.message);
}
}
void navigateToUser() {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => UserPage()),
(Route<dynamic> route) => false,
);
}
void navigateToSignUp() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignUpPage()),
);
}
void navigateToResetPassword() {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ResetPasswordPage()),
);
}
}
Home Page:
class UserPage extends StatelessWidget {
ParseUser currentUser;
Future<ParseUser> getUser() async {
currentUser = await ParseUser.currentUser() as ParseUser;
return currentUser;
}
#override
Widget build(BuildContext context) {
void doUserLogout() async {
var response = await currentUser.logout();
if (response.success) {
Message.showSuccess(
context: context,
message: 'User was successfully logout!',
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => LoginPage()),
(Route<dynamic> route) => false,
);
});
} else {
Message.showError(context: context, message: response.error.message);
}
}
return Scaffold(
appBar: AppBar(
title: Text('User logged in - Current User'),
),
body: FutureBuilder<ParseUser>(
future: getUser(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
case ConnectionState.waiting:
return Center(
child: Container(
width: 100,
height: 100,
child: CircularProgressIndicator()),
);
break;
default:
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(child: Text('Hello, ${snapshot.data.username}')),
SizedBox(
height: 16,
),
Container(
height: 50,
child: ElevatedButton(
child: const Text('Logout'),
onPressed: () => doUserLogout(),
),
),
],
),
);
}
}));
}
}
when using the app Logging in works fine but when I reload the app it just "ParseServer.currentUser()" in "MyApp" class returns null and sends me to the log in screen. I would appreciate the help if anyone knows what I did wrong.
also the FutureBuilder in "MyApp" class calls the Future twice I'm not sure why and if that may have something to do with it.
For each state of the main Future builder, all the widgets bellow will be recreating, the build function will be called again, and will call again the function inside Future.Builder.
you can use AsyncMemoizer to avoid it. AsyncMemoizer will make a Future be called only once.
You have many ways to solve this.
You can use a StatefullWidget for example and fetch the data on initState() it will be called only once, and the state will remain even if the parent rebuild.
And the best practice would create other layers to fetch your data, and your view is just responsible to show, not to fetch it.
https://pub.dev/packages/async
https://pub.dev/documentation/async/latest/async/AsyncMemoizer-class.html

Showing selected image in alert dialog in flutter

How can i show the selected image in my alert dialog ?
In my app, i added an alert dialog which has the camera button. When user clicks the camera button, another alert dialog asks to select file from gallery. After the user selects image file from gallery, i want to show the image in the alert dialog with the camera button, but the image shows only after reopening the alert dialog.
I have posted my code below. I am new to flutter. Please can someone help me? Thanks in advance.
class Test extends StatefulWidget {
#override
_State createState() => new _State();
}
Future<File> imageFile;
class _State extends State<Test> {
Future<void> _openDailog() async {
return showDialog<void>(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return AlertDialog(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8.0)),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('Click Photo'),
Ink(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24.0),
color: Colors.blue),
child: IconButton(
color: Colors.white,
icon: Icon(Icons.camera_alt),
onPressed: () {
_cameraOptions();
print("test");
},
),
)
],
),
content: SingleChildScrollView(
child: Container(
width: 300.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
showImage(),
InkWell(
child: Container(
margin: EdgeInsets.only(top: 8.0),
child: RaisedButton(
color: Colors.blue,
child: new Text(
"Send",
style: TextStyle(color: Colors.white),
),
onPressed: () {
Navigator.of(context).pop();
print("test");
},
),
)),
],
),
),
),
);
},
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FloatingActionButton(
heroTag: null,
child: Icon(Icons.insert_drive_file),
onPressed: () {
_openDailog();
},
)
],
);
}
Future<void> _cameraOptions() {
return showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
FlatButton(
onPressed: () {
pickImageFromGallery(ImageSource.gallery);
Navigator.of(context).pop();
},
color: Colors.transparent,
child: new Text(
'Select From Gallery',
textAlign: TextAlign.start,
style: new TextStyle(
decoration: TextDecoration.underline,
),
),
),
],
),
),
);
});
}
pickImageFromGallery(ImageSource source) {
setState(() {
imageFile = ImagePicker.pickImage(source: source);
});
}
Widget showImage() {
return FutureBuilder<File>(
future: imageFile,
builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
if (snapshot.connectionState == ConnectionState.done &&
snapshot.data != null) {
return Image.file(
snapshot.data,
width: MediaQuery.of(context).size.width,
height: 100,
);
} else if (snapshot.error != null) {
return const Text(
'Error Picking Image',
textAlign: TextAlign.center,
);
} else {
return const Text(
'No Image Selected',
textAlign: TextAlign.center,
);
}
},
);
}
}
That is because you would need to setState() however you can't do that in an alert dialogue as it doesn't have its own state, the workaround for that would be to have the dialogue be its own stateful widget. Please check out this article as it shows how to do that. If you faced problems let me know!
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(new MaterialApp(
home: new MyHomePage(),
));
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _selectedIndex = 0;
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("StackoverFlow"),
),
body: Container(),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await _dialogCall(context);
},
),
);
}
Future<void> _dialogCall(BuildContext context) {
return showDialog(
context: context,
builder: (BuildContext context) {
return MyDialog();
});
}
}
class MyDialog extends StatefulWidget {
#override
_MyDialogState createState() => new _MyDialogState();
}
class _MyDialogState extends State<MyDialog> {
String imagePath;
Image image;
#override
Widget build(BuildContext context) {
return AlertDialog(
content: new SingleChildScrollView(
child: new ListBody(
children: <Widget>[
Container(child: image!= null? image:null),
GestureDetector(
child: Row(
children: <Widget>[
Icon(Icons.camera),
SizedBox(width: 5),
Text('Take a picture '),
],
),
onTap: () async {
await getImageFromCamera();
setState(() {
});
}),
Padding(
padding: EdgeInsets.all(8.0),
),
],
),
),
);
}
Future getImageFromCamera() async {
var x = await ImagePicker.pickImage(source: ImageSource.camera);
imagePath = x.path;
image = Image(image: FileImage(x));
}
}
Try this solution with GestureDetector() .it works
onTap:()async{
var image = await ImagePicker.pickImage(
source: ImageSource.gallery).whenComplete((){
setState(() {
});
}
);
setState(() {
_image = image;
});
},