Flutter image_picker package returns null when trying to retrieve a video from the gallery - flutter

I am trying to build an app that lets users select videos and upload them, so for this, I am using the image_picker package. However, I am currently running tests and whenever I try to select a video from the gallery, instead of getting a file back I get null. I don't know if the problem is with how I am using the package or with permissions, although according to the package you don't need permissions for android.
Below the function in my code that is giving me trouble:
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
The complete code (minus completely irrelevant things):
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:golfapp/data/course_data.dart';
import 'package:golfapp/data/user_data.dart';
import 'package:provider/provider.dart';
import 'package:image_picker/image_picker.dart';
import 'package:uuid/uuid.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:golfapp/data/semana_data.dart';
import 'package:golfapp/widgets/chewie_item.dart';
final StorageReference storageRef = FirebaseStorage.instance.ref();
final postsRef = Firestore.instance.collection('posts');
final DateTime timestamp = DateTime.now();
class DetailScreen extends StatefulWidget {
final int index;
final String photoUrl;
final String videoUrl;
DetailScreen({this.index, this.photoUrl, this.videoUrl});
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
bool isUploading = false;
bool selected = false;
List<File> files = [];
String postId = Uuid().v4();
TextEditingController captionController = TextEditingController();
showError() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Row(
children: [
Padding(
padding: EdgeInsets.only(right: 10.0),
child: Text('Error'),
),
Icon(Icons.error_outline, size: 60.0),
],
),
content: SingleChildScrollView(
child: ListBody(
children: [
Text(
'Hubo un error con el video seleccionado.',
style: TextStyle(
fontFamily: 'Montserrat',
fontWeight: FontWeight.w600,
fontSize: 17.0,
),
),
],
),
),
);
},
);
}
clearImage() {
setState(() {
this.selected = false;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File fileTaken = await ImagePicker.pickVideo(
source: ImageSource.camera,
maxDuration: Duration(seconds: 90),
);
setState(() {
if (fileTaken != null) {
this.files.add(fileTaken);
this.selected = true;
} else {
showError();
}
});
}
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
);
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
selectImage(parentContext) {
return showDialog(
context: parentContext,
builder: (context) {
return SimpleDialog(
title: Text("Seleccionar video"),
children: <Widget>[
SimpleDialogOption(
child: Text("Tomar video"),
onPressed: handleTakePhoto,
),
SimpleDialogOption(
child: Text("Video de la galerĂ­a"),
onPressed: handleChooseFromGallery,
),
SimpleDialogOption(
child: Text("Cancelar"),
onPressed: () => Navigator.pop(context),
)
],
);
},
);
}
Future<String> uploadVideo(imageFile) async {
StorageUploadTask uploadTask = storageRef
.child(Provider.of<UserData>(context, listen: false).user.id)
.child(Provider.of<CourseData>(context, listen: false).course.uid)
.child(Provider.of<SemanaData>(context, listen: false).semana.uid)
.putFile(imageFile, StorageMetadata(contentType: 'video/mp4'));
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
createPostInFirestore({List<String> mediaUrl, String description}) {
postsRef
.document(Provider.of<UserData>(context, listen: false).user.id)
.collection("userPosts")
.document(Provider.of<CourseData>(context, listen: false).course.uid)
.setData({
"semana": Provider.of<SemanaData>(context, listen: false).semana.uid,
"postId": postId,
"ownerId": Provider.of<UserData>(context, listen: false).user.id,
"username": Provider.of<UserData>(context, listen: false).user.username,
"mediaUrl": mediaUrl,
"description": description,
"timestamp": timestamp,
"likes": {},
});
}
handleSubmit() async {
setState(() {
isUploading = true;
});
List<String> mediaUrlS = [];
for (File fileLoop in files) {
String mediaUrl = await uploadVideo(fileLoop);
mediaUrlS.add(mediaUrl);
}
createPostInFirestore(
mediaUrl: mediaUrlS,
description: captionController.text,
);
captionController.clear();
setState(() {
files = [];
isUploading = false;
postId = Uuid().v4();
selected = false;
});
}
Scaffold buildUploadForm() {
return Scaffold(
appBar: AppBar(
title: Text(
"Tu video",
style: TextStyle(color: Colors.black),
),
actions: [
FlatButton(
onPressed: files.length < 2 ? selectImage(context) : null,
child: Text(
'Seleccionar otro video',
),
),
FlatButton(
onPressed: isUploading ? null : () => handleSubmit(),
child: Text(
"Mandar",
),
),
],
),
body: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: files.length,
itemBuilder: (BuildContext context, int index) {
final File fileBuilder = files[index];
return Container(
height: 220.0,
width: MediaQuery.of(context).size.width * 0.8,
child: Center(
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
child: ChewieListItem(
videoUrl: fileBuilder.path,
network: false,
file: fileBuilder,
),
),
),
),
);
}),
);
}
Widget buildNormalScreen () {
return Container(
child: GestureDetector(
onTap: () {
selectImage(context);
},
child: Container(
height: 50.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30.0),
color: Theme.of(context).accentColor,
),
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Subir videos',
style: TextStyle(
fontFamily: 'Comfortaa',
fontSize: 17.0,
color: Colors.white,
),
),
],
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return !selected
? buildNormalScreen()
: buildUploadForm();
}
}
In the function at the top, I also tried doing something like ImagePicker.pickVideo().then((file){...}) but it didn't work.
I also added <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> to my "android/app/src/main/AndroidManifest.xml" file.
I also tried adding android:requestLegacyExternalStorage="true" inside the <application> tag in my "android/app/src/main/AndroidManifest.xml" file, but then I get an error:
I don't know what I should be changing either in my code or in one of the files in the android folder, any help is deeply appreciated.
Thank you very much in advance

Put the condition in the same function.
handleChooseFromGallery() async {
Navigator.pop(context);
File filePicked = await ImagePicker.pickVideo(
source: ImageSource.gallery,
maxDuration: Duration(seconds: 90),
//This line always returns false
print({'is file not null': filePicked != null});
setState(() {
if (filePicked != null) {
this.files.add(filePicked);
this.selected = true;
} else {
showError();
}
});
}
);

Related

How to show downloading status of file in percentage in flutter by using dio plugin?

How to use dio plugin for file downloading ? also, if file is already downloaded then user can directly view it without download. if it is not then user can download and also see progress indicator with downloaded percentage.
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:external_path/external_path.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:get/get.dart';
import 'package:nb_utils/nb_utils.dart';
import 'package:path_provider/path_provider.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:world_virtual_coin/services/app_utils.dart';
import 'package:world_virtual_coin/services/theme.dart';
import 'package:world_virtual_coin/widget/colors.dart';
import '../services/size_config.dart';
class DownloadCtrl {
String progressString = "0";
late String localPath;
ReceivePort _port = ReceivePort();
StreamController<int> indexController = StreamController<int>.broadcast();
String downloadTaskId = '';
DownloadCtrl();
init() {
IsolateNameServer.registerPortWithName(
_port.sendPort,
'invoice_send_port',
);
_port.listen((dynamic data) {
String id = data[0];
DownloadTaskStatus status = data[1];
int progress = data[2];
if (status == DownloadTaskStatus.complete) {
Future.delayed(const Duration(seconds: 1), () {
Get.back();
// indexController.add(100);
// downloadTaskId = id;
FlutterDownloader.open(taskId: id);
});
}
progressString = progress.toString();
});
FlutterDownloader.registerCallback(downloadCallback);
}
Future _findLocalPath() async {
var directory;
if (Platform.isAndroid) {
// directory = await getExternalStorageDirectory();
directory = await ExternalPath.getExternalStoragePublicDirectory(ExternalPath.DIRECTORY_DOWNLOADS);
} else {
directory = await getApplicationDocumentsDirectory();
}
return directory is String ? directory : directory.path;
}
Future download(String url, BuildContext context) async {
var androidVersion;
final DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin();
var deviceData = <String, dynamic>{};
try {
if (Platform.isAndroid) {
AndroidDeviceInfo deviceInfo = await deviceInfoPlugin.androidInfo;
androidVersion = num.parse(deviceInfo.version.release.toString());
// androidVersion = 9;
// print("Device version" + androidVersion.toString());
}
} on PlatformException {
deviceData = <String, dynamic>{'Error:': 'Failed to get platform version.'};
}
_checkPermission().then((hasGranted) async {
if (hasGranted) {
localPath = await _findLocalPath();
final savedDir = Directory(localPath);
bool hasExisted = await savedDir.exists();
if (!hasExisted) {
savedDir.create();
}
String pathOfFile = '$localPath/${url.split('/').last}';
File file = File(pathOfFile);
if (await file.exists() && Platform.isAndroid) {
_performVersionSpecificOperation(file, androidVersion, url, localPath, context);
} else {
_proceedDownload(url, localPath, context);
}
}
});
}
Future showLoadingBottomSheet(context, path) async {
showModalBottomSheet(
backgroundColor: Colors.transparent,
context: context,
isDismissible: false,
builder: (BuildContext context) {
return WillPopScope(
onWillPop: () {
return Future.value();
},
child: Container(
color: Colors.black87.withOpacity(0.7),
width: w(100),
height: h(20),
child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
StreamBuilder(
stream: indexController.stream,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return (snapshot.hasData && snapshot.data! < 100)
? Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(colorPrimary),
),
5.height,
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
text('Downloading ', textColor: colorPrimary, fontFamily: fontBold, fontSize: 17.0),
10.width,
text(
snapshot.hasData ? '${snapshot.data} %' : '',
textColor: colorPrimary,
fontFamily: fontBold,
fontSize: 17.0,
),
],
),
],
)
: SizedBox.shrink();
},
),
5.height,
StreamBuilder(
stream: indexController.stream,
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
return (snapshot.hasData && snapshot.data == 100)
? Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: [
Expanded(
flex: 27,
child: text(
'File saved at:',
textColor: colorPrimary,
fontSize: 16.0,
),
),
Expanded(
flex: 73,
child: text(
'$path',
textColor: whiteColor,
fontFamily: fontMedium,
fontSize: 17.0,
),
),
],
),
),
5.height,
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(
color: colorPrimary.withOpacity(0.15),
width: 2.5,
),
),
child: text(
'Open',
textColor: whiteColor,
fontFamily: fontBold,
).paddingSymmetric(
vertical: 2,
horizontal: 10,
),
).onTap(() {
Future.delayed(Duration(seconds: 1), () {
Get.back();
FlutterDownloader.open(taskId: downloadTaskId);
});
}),
],
)
: SizedBox.shrink();
},
)
],
),
const Align(
alignment: Alignment.topRight,
child: Icon(
Icons.cancel_presentation,
color: Colors.red,
size: 25,
),
).onTap(() {
Get.back();
}),
],
),
),
);
},
);
}
Future<bool> _checkPermission() async {
PermissionStatus status = await Permission.storage.status;
// Either the permission was already granted before or the user just granted it.
if (status.isGranted) {
return true;
} else {
bool permission = await Permission.storage.request().isGranted;
if (permission) {
return true;
} else {
return false;
}
}
}
static void downloadCallback(
String id,
DownloadTaskStatus status,
int progress,
) {
final SendPort? send = IsolateNameServer.lookupPortByName('invoice_send_port');
send!.send([id, status, progress]);
}
void dispose() {
IsolateNameServer.removePortNameMapping('invoice_send_port');
indexController.close();
}
_proceedDownload(url, path, context) async {
showLoadingBottomSheet(context, path);
await FlutterDownloader.enqueue(
url: url,
savedDir: localPath,
showNotification: true,
openFileFromNotification: true,
saveInPublicStorage: true,
);
}
_performVersionSpecificOperation(File file, androidVersion, url, path, context) async {
if (androidVersion <= 9) {
try {
await file.delete();
} catch (e) {
return 0;
}
_proceedDownload(url, path, context);
}
// else if (androidVersion == 10) {
// AppUtils.showErrorSnackBar('You have already downloaded this File');
// }
else {
_proceedDownload(url, path, context);
}
}
}
I made above class for download pdf. and below button has mathod to download it.
CustomButton(
onPressed: () {
DownloadCtrl().download("https://www.clickdimensions.com/links/TestPDFfile.pdf", context);
},
label: 'Save Pdf',
),
Now the problem is, initially pdf will download on click of button butif user tap second time it should check first file is already exist in device or not. if it is exist direct open it else proceed for download.
for that, I haved below plugins,
flutter_downloader: ^1.10.1+2
permission_handler: ^10.2.0
device_info_plus:
external_path: ^1.0.3

Flutter: Bad state Error: cannot get a field on a DocumentSnapshotPlatform which does not exist

I'm new to Flutter and getting this issue.
Trying to develop a social media app which includes a chat feature. However, it says DocumentSnapshot is not exist.
Of course I understood that one thing is missing, it is clear. But I couldn't understand what is that missing thing and how to solve it.
I examined a lot of posts about this but I couldn't solve my issue. There is no misspelling between Cloud Firestore and my code. I couldn't understand am I missing key or something like this?
It looks like this
Sometimes it also can not upload the profile picture of person.
Here are my codes,
Thanks for helping.
I got this error when I try to type a message:
class Conversation extends StatefulWidget {
final String userId;
final String chatId;
const Conversation({required this.userId, required this.chatId});
#override
_ConversationState createState() => _ConversationState();
}
class _ConversationState extends State<Conversation> {
FocusNode focusNode = FocusNode();
ScrollController scrollController = ScrollController();
TextEditingController messageController = TextEditingController();
bool isFirst = false;
String? chatId;
#override
void initState() {
super.initState();
scrollController.addListener(() {
focusNode.unfocus();
});
print(widget.chatId);
if (widget.chatId == 'newChat') {
isFirst = true;
}
chatId = widget.chatId;
messageController.addListener(() {
if (focusNode.hasFocus && messageController.text.isNotEmpty) {
setTyping(true);
} else if (!focusNode.hasFocus ||
(focusNode.hasFocus && messageController.text.isEmpty)) {
setTyping(false);
}
});
}
setTyping(typing) {
//here
UserViewModel viewModel =
Provider.of<UserViewModel>(context, listen: false);
viewModel.setUser();
//here
var user = Provider.of<UserViewModel>(context, listen: false).user;
Provider.of<ConversationViewModel>(context, listen: false)
.setUserTyping(widget.chatId, user, typing);
}
#override
Widget build(BuildContext context) {
UserViewModel viewModel =
Provider.of<UserViewModel>(context, listen: false);
viewModel.setUser();
var user = Provider.of<UserViewModel>(context, listen: true).user;
return Consumer<ConversationViewModel>(
builder: (BuildContext context, viewModel, Widget? child) {
return Scaffold(
key: viewModel.scaffoldKey,
appBar: AppBar(
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.keyboard_backspace,
),
),
elevation: 0.0,
titleSpacing: 0,
title: buildUserName(),
),
body: Container(
height: MediaQuery.of(context).size.height,
child: Column(
children: [
Flexible(
child: StreamBuilder<QuerySnapshot>(
stream: messageListStream(widget.chatId),
builder: (context, snapshot) {
if (snapshot.hasData) {
//snapshot.hasData
//print(snapshot.data);
print(viewModel);
List messages = snapshot.data!.docs;
viewModel.setReadCount(
widget.chatId, user, messages.length);
return ListView.builder(
controller: scrollController,
padding: EdgeInsets.symmetric(horizontal: 10.0),
itemCount: messages.length,
reverse: true,
itemBuilder: (BuildContext context, int index) {
Message message = Message.fromJson(
messages.reversed.toList()[index].data(),
);
print(message.content);
print(message.senderUid);
print(message.time);
print(message.type);
return ChatBubble(
message: '${message.content}',
time: message.time!,
isMe: message.senderUid == user!.uid,
type: message.type!,
);
},
);
} else {
return Center(child: circularProgress(context));
}
},
),
),
Align(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 10.0,
child: Container(
constraints: BoxConstraints(maxHeight: 100.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
IconButton(
icon: Icon(
CupertinoIcons.photo_on_rectangle,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () => showPhotoOptions(viewModel, user),
),
Flexible(
child: TextField(
controller: messageController,
focusNode: focusNode,
style: TextStyle(
fontSize: 15.0,
color:
Theme.of(context).textTheme.headline6!.color,
),
decoration: InputDecoration(
contentPadding: EdgeInsets.all(10.0),
enabledBorder: InputBorder.none,
border: InputBorder.none,
hintText: "Type your message",
hintStyle: TextStyle(
color: Theme.of(context)
.textTheme
.headline6!
.color,
),
),
maxLines: null,
),
),
IconButton(
icon: Icon(
Ionicons.send,
color: Theme.of(context).colorScheme.secondary,
),
onPressed: () {
if (messageController.text.isNotEmpty) {
sendMessage(viewModel, user);
}
},
),
],
),
),
),
)
],
),
),
);
});
}
_buildOnlineText(
var user,
bool typing,
) {
if (user.isOnline) {
if (typing) {
return "typing...";
} else {
return "online";
}
} else {
return 'last seen ${timeago.format(user.lastSeen.toDate())}';
}
}
buildUserName() {
return StreamBuilder(
stream: usersRef.doc('${widget.userId}').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
DocumentSnapshot documentSnapshot =
snapshot.data as DocumentSnapshot<Object?>;
UserModel user = UserModel.fromJson(
documentSnapshot.data() as Map<String, dynamic>,
);
return InkWell(
child: Row(
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 10.0, right: 10.0),
child: Hero(
tag: user.email!,
child: CircleAvatar(
radius: 25.0,
backgroundImage: CachedNetworkImageProvider(
'${user.photoUrl}',
),
),
),
),
SizedBox(width: 10.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'${user.username}',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15.0,
),
),
SizedBox(height: 5.0),
StreamBuilder(
stream: chatRef.doc('${widget.chatId}').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
DocumentSnapshot? snap =
snapshot.data as DocumentSnapshot<Object?>;
Map? data = snap.data() as Map<dynamic, dynamic>?;
Map? usersTyping = data?['typing'] ?? {};
return Text(
_buildOnlineText(
user,
usersTyping![widget.userId] ?? false,
),
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 11,
),
);
} else {
return SizedBox();
}
},
),
],
),
),
],
),
onTap: () {},
);
} else {
return Center(child: CircularProgressIndicator());
}
},
);
}
showPhotoOptions(ConversationViewModel viewModel, var user) {
showModalBottomSheet(
context: context,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(10.0),
),
),
builder: (context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Text("Camera"),
onTap: () {
sendMessage(viewModel, user, imageType: 0, isImage: true);
},
),
ListTile(
title: Text("Gallery"),
onTap: () {
sendMessage(viewModel, user, imageType: 1, isImage: true);
},
),
],
);
},
);
}
sendMessage(ConversationViewModel viewModel, var user,
{bool isImage = false, int? imageType}) async {
String msg;
if (isImage) {
msg = await viewModel.pickImage(
source: imageType!,
context: context,
chatId: widget.chatId,
);
} else {
msg = messageController.text.trim();
messageController.clear();
}
Message message = Message(
content: '$msg',
senderUid: user?.uid,
type: isImage ? MessageType.IMAGE : MessageType.TEXT,
time: Timestamp.now(),
);
if (msg.isNotEmpty) {
if (isFirst) {
print("FIRST");
String id = await viewModel.sendFirstMessage(widget.userId, message);
setState(() {
isFirst = false;
chatId = id;
});
} else {
viewModel.sendMessage(
widget.chatId,
message,
);
}
}
}
Stream<QuerySnapshot> messageListStream(String documentId) {
return chatRef
.doc(documentId)
.collection('messages')
.orderBy('time')
.snapshots();
}
}
Also here is the ViewModel codes if I did something wrong here:
class ConversationViewModel extends ChangeNotifier {
GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
ChatService chatService = ChatService();
bool uploadingImage = false;
final picker = ImagePicker();
File? image;
sendMessage(String chatId, Message message) {
chatService.sendMessage(
message,
chatId,
);
}
Future<String> sendFirstMessage(String recipient, Message message) async {
String newChatId = await chatService.sendFirstMessage(
message,
recipient,
);
return newChatId;
}
setReadCount(String chatId, var user, int count) {
chatService.setUserRead(chatId, user, count);
}
setUserTyping(String chatId, var user, bool typing) {
chatService.setUserTyping(chatId, user, typing);
}
pickImage({int? source, BuildContext? context, String? chatId}) async {
PickedFile? pickedFile = source == 0
? await picker.getImage(
source: ImageSource.camera,
)
: await picker.getImage(
source: ImageSource.gallery,
);
if (pickedFile != null) {
CroppedFile? croppedFile = await ImageCropper().cropImage(
sourcePath: pickedFile.path,
aspectRatioPresets: [
CropAspectRatioPreset.square,
CropAspectRatioPreset.ratio3x2,
CropAspectRatioPreset.original,
CropAspectRatioPreset.ratio4x3,
CropAspectRatioPreset.ratio16x9
],
uiSettings: [
AndroidUiSettings(
toolbarTitle: 'Crop image',
toolbarColor: Theme.of(context!).appBarTheme.backgroundColor,
toolbarWidgetColor: Theme.of(context).iconTheme.color,
initAspectRatio: CropAspectRatioPreset.original,
lockAspectRatio: false,
),
IOSUiSettings(
minimumAspectRatio: 1.0,
),
],
);
Navigator.of(context).pop();
if (croppedFile != null) {
uploadingImage = true;
image = File(croppedFile.path);
notifyListeners();
showInSnackBar("Uploading image...", context);
String imageUrl = await chatService.uploadImage(image!, chatId!);
return imageUrl;
}
}
}
void showInSnackBar(String value, context) {
ScaffoldMessenger.of(context).removeCurrentSnackBar();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(value),
),
);
}
}
Here is the ChatService code:
class ChatService {
FirebaseStorage storage = FirebaseStorage.instance;
sendMessage(Message message, String chatId) async {
//will send message to chats collection with the usersId
await chatRef.doc("$chatId").collection("messages").add(message.toJson());
//will update "lastTextTime" to the last time a text was sent
await chatRef.doc("$chatId").update({"lastTextTime": Timestamp.now()});
}
Future<String> sendFirstMessage(Message message, String recipient) async {
User user = firebaseAuth.currentUser!;
DocumentReference ref = await chatRef.add({
'users': [recipient, user.uid],
});
await sendMessage(message, ref.id);
return ref.id;
}
Future<String> uploadImage(File image, String chatId) async {
Reference storageReference =
storage.ref().child("chats").child(chatId).child(uuid.v4());
UploadTask uploadTask = storageReference.putFile(image);
await uploadTask.whenComplete(() => null);
String imageUrl = await storageReference.getDownloadURL();
return imageUrl;
}
//determine if a user has read a chat and updates how many messages are unread
setUserRead(String chatId, User user, int count) async {
DocumentSnapshot snap = await chatRef.doc(chatId).get();
Map reads = snap.get('reads') ?? {};
reads[user.uid] = count;
await chatRef.doc(chatId).update({'reads': reads});
}
//determine when a user has start typing a message
setUserTyping(String chatId, User user, bool userTyping) async {
DocumentSnapshot snap = await chatRef.doc(chatId).get();
Map typing = snap.get('typing');
typing[user.uid] = userTyping;
await chatRef.doc(chatId).update({
'typing': typing,
});
}
}

Flutter: SharedPreferences showing null value?

eg: details about the questions ............................................................................................i have set a address in home page using SharedPreferences but when i get that value in SearchModulePage showing null. i have tried many more times always showing null
Home Page:-
import 'dart:convert';
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:double_back_to_close_app/double_back_to_close_app.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:geocoder/geocoder.dart';
import 'package:http/http.dart' as http;
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:newbharatbiz/Model%20Class/category_model.dart';
import 'package:newbharatbiz/Screens/SearchServiceProvider.dart';
import 'package:newbharatbiz/Screens/SubCategoryPage.dart';
import 'package:newbharatbiz/Utils/NavDrawer.dart';
import 'package:newbharatbiz/Utils/Serverlinks.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../Model Class/banner_model.dart';
import 'VendorRegistrationPage.dart';
import 'package:location/location.dart';
import 'package:flutter/services.dart';
var addressLine;
var getaddressLine;
var androidDeviceInfo;
var token;
var identifier;
var user_id;
var phone;
var name;
class HomePage extends StatefulWidget {
#override
_YourWidgetState createState() => _YourWidgetState();
}
class _YourWidgetState extends State<HomePage> {
Future<BannerModel> BannerList() async {
final response = await http.get(Uri.parse(Serverlinks.all_banner));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
print(response);
return BannerModel.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
Future<CategoryModel> CategoryList() async {
final response = await http.get(Uri.parse(Serverlinks.category_list));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
print(response);
return CategoryModel.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
// late DateTime currentBackPressTime;
List<String> imagesList = [];
var currentLocation;
int currentIndexPage = 0;
#override
void initState() {
super.initState();
getUserLocation();
getdeviceid();
gettoken();
Setsharedpreferencevalue();
Getsharedpreferencevalue();
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.deepOrangeAccent,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VendorRegistrationPage(),
),
);
},
),
drawer: NavDrawer(),
appBar:
AppBar(title: Text('New Bharat Biz'), centerTitle: true, actions: [
IconButton(
onPressed: () async {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SearchServiceProvider(),
),
);
},
icon: Icon(Icons.search),
),
]),
body: DoubleBackToCloseApp(
child: SingleChildScrollView(
child: Column(mainAxisAlignment: MainAxisAlignment.start, children: [
FutureBuilder<BannerModel>(
future: BannerList(),
builder: (BuildContext context, snapshot) {
if (snapshot.hasData) {
print((snapshot.data));
snapshot.data!.banner.forEach((e) {
imagesList.add(snapshot.data!.imgPath + e.image);
print(imagesList.length);
});
return CarouselSlider(
//add return keyword here
options: CarouselOptions(
height: 160,
aspectRatio: 16 / 9,
viewportFraction: 0.8,
initialPage: 0,
enableInfiniteScroll: true,
reverse: false,
autoPlay: true,
autoPlayInterval: const Duration(seconds: 3),
autoPlayAnimationDuration:
const Duration(milliseconds: 800),
autoPlayCurve: Curves.fastOutSlowIn,
enlargeCenterPage: true,
),
items: imagesList
.map(
(item) => Center(
child: Image.network(item,
fit: BoxFit.cover, width: 1000)),
)
.toList(),
);
}
return const Center(
/*
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
),
*/
);
}
// By default, show a loading spinner.
),
FutureBuilder<CategoryModel>(
future: CategoryList(),
builder: (BuildContext context, snapshot) {
//_getId();
if (snapshot.hasData) {
List<Result> data = snapshot.data!.result;
print((snapshot.data));
return GridView.builder(
itemCount: data.length,
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 0,
mainAxisSpacing: 0,
),
//padding: EdgeInsets.all(1),
itemBuilder: (ctx, index) {
return Padding(
padding: EdgeInsets.all(0.0),
child: new GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SubCategoryPage(
data[index].id,
),
),
);
},
child: new Container(
margin: const EdgeInsets.all(0),
padding: const EdgeInsets.all(0),
decoration: BoxDecoration(
border: Border.all(
width: 0.5,
color: Colors.grey,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
SizedBox(
height: 25,
),
Image.network(
snapshot.data!.imgPath + data[index].coverPic,
height: 55,
width: 55,
),
SizedBox(
height: 10,
),
Expanded(
child: Text(
data[index].name,
style: TextStyle(
color: Colors.black,
fontSize: 15,
),
textAlign: TextAlign.center,
),
)
],
),
),
),
);
},
);
} else {
return const Center(
child: SizedBox(
width: 16,
height: 16,
child: CircularProgressIndicator(
strokeWidth: 2,
valueColor: AlwaysStoppedAnimation(Colors.blue),
),
),
);
}
},
),
]),
),
snackBar: const SnackBar(
content: Text('Tap back again to leave'),
),
),
);
}
/*
Future<bool> onWillPop() {
DateTime now = DateTime.now();
if (currentBackPressTime == null ||
now.difference(currentBackPressTime) > Duration(seconds: 2)) {
currentBackPressTime = now;
return Future.value(false);
}
return Future.value(true);
}
*/
void getUserLocation() async {
//call this async method from whereever you need
LocationData? myLocation;
String error;
Location location = new Location();
try {
myLocation = await location.getLocation();
} on PlatformException catch (e) {
if (e.code == 'PERMISSION_DENIED') {
error = 'please grant permission';
print(error);
}
if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
error = 'permission denied- please enable it from app settings';
print(error);
}
myLocation = null;
}
currentLocation = myLocation;
final coordinates =
new Coordinates(myLocation?.latitude, myLocation?.longitude);
var addresses =
await Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = addresses.first;
String adminArea = first.adminArea;
String locality = first.locality;
String subLocality = first.subLocality;
String subAdminArea = first.subAdminArea;
addressLine = first.addressLine;
String featureName = first.featureName;
String thoroughfare = first.thoroughfare;
String subThoroughfare = first.subThoroughfare;
/* print(' ${first.locality}, ${first.adminArea},${first.subLocality}, ${first.subAdminArea},${first.addressLine}, ${first.featureName},${first.thoroughfare}, ${first.subThoroughfare}');
return first;*/
}
gettoken() async {
//token = await FirebaseMessaging.instance.getToken();
FirebaseMessaging.instance.getToken().then((token) {
token = token.toString();
// do whatever you want with the token here
});
}
getdeviceid() async {
final DeviceInfoPlugin deviceInfoPlugin = new DeviceInfoPlugin();
if (Platform.isAndroid) {
AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
androidDeviceInfo = androidInfo.id!; //UUID for Android
} else if (Platform.isIOS) {
IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
androidDeviceInfo = iosInfo.identifierForVendor; //UUID for Android
}
}
void Setsharedpreferencevalue() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('addressLine', addressLine);
prefs.setString('deviceID', androidDeviceInfo);
await prefs.setString("token", token!);
});
}
void Getsharedpreferencevalue() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
androidDeviceInfo = prefs.getString('deviceID');
getaddressLine = prefs.getString('addressLine');
token = prefs.getString('token');
user_id = prefs.getString('user_id');
phone = prefs.getString('phone');
name = prefs.getString('name');
print("info : ${androidDeviceInfo}");
});
}
}
SearchModulePage:-
import 'dart:convert';
import 'package:flutter_mapbox_autocomplete/flutter_mapbox_autocomplete.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:newbharatbiz/Screens/SubCategoryPage.dart';
import 'package:shared_preferences/shared_preferences.dart';
var addressLine;
TextEditingController Locality = TextEditingController();
class SearchModulePage extends StatefulWidget {
String id;
String catId;
String serviceName;
String image;
String imgPath;
SearchModulePage(
this.id, this.catId, this.serviceName, this.image, this.imgPath);
#override
_YourWidgetState createState() =>
_YourWidgetState(id, catId, serviceName, image, imgPath);
}
class _YourWidgetState extends State<SearchModulePage> {
String id;
String catId;
String serviceName;
String image;
String imgPath;
_YourWidgetState(
this.id, this.catId, this.serviceName, this.image, this.imgPath);
#override
void initState() {
super.initState();
getshareddprefernces();
}
#override
Widget build(BuildContext context) {
// getsharedprefernces();
return WillPopScope(
onWillPop: () async => true,
child: new Scaffold(
appBar: new AppBar(
title: new Text(serviceName),
leading: new IconButton(
icon: new Icon(Icons.arrow_back_outlined),
onPressed: () {
Navigator.pop(
context, true); // It worked for me instead of above line
/* Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => SubCategoryPage(
catId,
)),
);*/
}),
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 30),
Image.network(
imgPath + image,
width: 60.0,
height: 60.0,
),
// Padding(padding: EdgeInsets.only(top: 15.0)),
const SizedBox(height: 20),
Text(serviceName,
style: TextStyle(color: Colors.black, fontSize: 15)),
// Padding(padding: EdgeInsets.only(top: 30.0)),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(20.0),
child: TextFormField(
controller: Locality,
readOnly: true,
// initialValue: addressLine,
// set it to a string by default
decoration: InputDecoration(
hintText: "Search your locality",
hintStyle: TextStyle(
color: Color(0xff323131),
),
suffixIcon: Icon(
Icons.location_on_rounded,
color: Color(0xFF00796B),
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MapBoxAutoCompleteWidget(
apiKey:
"pk.eyJ1IjoibmV3YmhhcmF0Yml6IiwiYSI6ImNrbWJqb3B5ZzIyZnUyd254M2JndmhnNnQifQ.Km7hMjBHD_kwHWL7x7Y-Jg",
hint: "Search your locality",
onSelect: (place) {
// TODO : Process the result gotten
Locality.text = place.placeName!;
},
limit: 10,
),
),
);
},
),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// FocusScope.of(context).requestFocus(FocusNode());
addressLine = Locality.text;
if (addressLine == "") {
Fluttertoast.showToast(
msg: "Enter your locality",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.black54,
textColor: Colors.white,
fontSize: 16.0);
/* var snackBar = SnackBar(content: Text('Enter your locality'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);*/
} else {
// String locality = Locality.text;
}
},
child: Text("Submit"),
style: ElevatedButton.styleFrom(
primary: Color(0xFF00796B),
padding:
EdgeInsets.symmetric(horizontal: 100, vertical: 10),
textStyle:
TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
],
),
),
),
);
}
void getshareddprefernces() async {
setState(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
addressLine = await prefs.getString('addressLine');
Locality.text = addressLine.toString();
Fluttertoast.showToast(
msg: addressLine,
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.black54,
textColor: Colors.white,
fontSize: 16.0);
});
}
}
You have to wait till all asynchronous process is over, then after that when all values (here address, deviceId and token) are set to variables, then you can save or set values to shared preferences.
Here is the sample code for you:
#override
void initState() {
super.initState();
initializeVariables().then((boolValue){
Setsharedpreferencevalue();
});
// ..
}
Future<Boolean> initializeVariables() async {
await getUserLocation();
await getdeviceid();
await gettoken();
return true;
}

How to deal with infinite size

I was coding my flutter project when I fall under this error. I do not understand because I have tried all the available solution online and still it is not working. The craziest thing is I have the exact same code on the other page and it is working perfectly.
And If I restart the app it works. The first problem was a Material app which is the main function and even if I wrap the column with a scaffold it still doesn't work
Below is the error
The following assertion was thrown during performLayout():
RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
This probably means that it is a render object that tries to be as big as possible, but it was put inside another render object that allows its children to pick their own size.
The nearest ancestor providing an unbounded height constraint is: _RenderSingleChildViewport#20590 relayoutBoundary=up10 NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
... needs compositing
... parentData: <none> (can use size)
... constraints: BoxConstraints(w=358.0, 0.0<=h<=731.0)
... layer: OffsetLayer#17148
... engine layer: OffsetEngineLayer#48e1c
... handles: 2
... offset: Offset(16.0, 63.0)
... size: Size(358.0, 731.0)
The constraints that applied to the RenderCustomMultiChildLayoutBox were: BoxConstraints(0.0<=w<=358.0, 0.0<=h<=Infinity)
The exact size it was given was: Size(358.0, Infinity)
Below this I have form that receives data from another one
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:loading_overlay/loading_overlay.dart';
import 'package:tembea/components/rounded_button.dart';
import 'package:tembea/components/show_toast.dart';
import 'package:tembea/components/time_pick.dart';
import 'package:tembea/screens/admin/admin_screens/restaurant/dashboard_restaurant.dart';
import '../../../../../constants.dart';
import 'package:carousel_slider/carousel_slider.dart';
import 'package:tembea/components/square_button.dart';
import 'dart:io' ;
import 'package:firebase_storage/firebase_storage.dart';
import 'add_images.dart';
class RestaurantSecondaryForm extends StatefulWidget {
const RestaurantSecondaryForm({
Key? key,
required this.name,
required this.location,
required this.price,
required this.description,
}) : super(key: key);
final String name;
final String location;
final String price;
final String description;
#override
_RestaurantSecondaryFormState createState() => _RestaurantSecondaryFormState();
}
class _RestaurantSecondaryFormState extends State<RestaurantSecondaryForm> {
bool showSpinner = false;
String selectedOpeningTime = '8:00 AM';
String selectedClosingTime = '17:00 PM';
String ? selectedTime;
final List<String> defaultImageList = [
'assets/images/image.png',
'assets/images/image.png',
'assets/images/image.png',
];
List<String> imageList =[];
List<File> files = [];
List<String> ? imageUrl;
TaskSnapshot? snap;
String ? photoUrl;
String ? photoUrl2;
String ? photoUrl3;
String selectedType = 'Restaurant';
#override
Widget build(BuildContext context) {
Future<void> openTimePicker(context) async {
final TimeOfDay? t =
await showTimePicker(
context: context, initialTime: TimeOfDay.now());
if(t != null){
setState(() {
selectedTime = t.format(context);
});
}
}
goToAddImage() async{
List<String> imgUrl = await Navigator.push(context, MaterialPageRoute(builder:(context){
return const AddImages();
}));
setState(() {
imageUrl = imgUrl;
});
}
if(imageUrl?.isNotEmpty == true){
setState(() {
photoUrl = imageUrl?[0];
photoUrl2 = imageUrl?[1];
photoUrl3 = imageUrl?[2];
imageList.add(photoUrl!);
imageList.add(photoUrl2!);
imageList.add(photoUrl3!);
});
}
else{
setState(() {
photoUrl = '';
photoUrl2 = '';
photoUrl3 = '';
});
}
return LoadingOverlay(
isLoading: showSpinner,
opacity: 0.5,
color: Colors.green,
progressIndicator: const CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.green),
),
child: Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text('Add Restaurant'),
backgroundColor: kBackgroundColor.withOpacity(0.3),
),
body: Padding(
padding: const EdgeInsets.all(40.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CarouselSlider(
options: CarouselOptions(
enlargeCenterPage: true,
enableInfiniteScroll: false,
autoPlay: false,
),
items:imageList.isEmpty ? defaultImageList.map((e) => ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Stack(
fit: StackFit.expand,
children: [
Image.asset(
e,
width: 1000,
height: 300,
fit: BoxFit.fill,
)
],
),
)).toList()
: imageList.map((e) => ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Stack(
fit: StackFit.expand,
children: [
Image.network(
e,
width: 1000,
height: 300,
fit: BoxFit.fill,
)
],
),
)).toList(),
),
const SizedBox(
height: 20,
),
Column(
children: [
DateButton(
text: 'Upload Images',
onPressed: () {
goToAddImage();
},
),
],
),
Column(
children: [
TimePick(
label: 'Opens at',
labelColor: Colors.green,
time: selectedOpeningTime,
onPressed: (){
openTimePicker(context).then((value) {
setState(() {
selectedOpeningTime = selectedTime!;
});
});
},
),
const SizedBox(
height: 20,
),
TimePick(
label: 'Closes at',
labelColor: Colors.red,
time: selectedClosingTime,
onPressed: (){
openTimePicker(context).then((value) {
setState(() {
selectedClosingTime = selectedTime!;
});
});
}
),
],
),
RoundedButton(
buttonName: 'Add Restaurant',
color: Colors.green,
onPressed: () async{
setState(() {
showSpinner = true;
});
final time = DateTime.now();
await FirebaseFirestore.instance.collection('activities').doc().set({
'Name' : widget.name,
'Location': widget.location,
'Description' : widget.description,
'Price' : widget.price,
'OpeningTime' : selectedOpeningTime,
'ClosingTime' : selectedClosingTime,
'PhotoUrl' : photoUrl,
'PhotoUrl2' : photoUrl2,
'PhotoUrl3' : photoUrl3,
'Type' : selectedType,
'ts' : time,
}).then((value) {
setState(() {
showSpinner = false;
});
showToast(message: 'Restaurant Added',
color: Colors.green
);
Navigator.pushNamedAndRemoveUntil(context, DashboardRestaurant.id, (r) => false);
});
}
),
],
),
),
),
);
}
}
which is supposed to navigate back to this view that brings the error
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:tembea/components/add_button.dart';
import 'package:tembea/components/responsive.dart';
import 'package:tembea/components/show_dialog.dart';
import 'package:tembea/components/show_toast.dart';
import 'package:tembea/screens/admin/admin_screens/view_data.dart';
import 'event_form.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class DashboardEvent extends StatefulWidget {
const DashboardEvent({Key? key}) : super(key: key);
static String id = 'dashboard_event';
#override
_DashboardEventState createState() => _DashboardEventState();
}
class _DashboardEventState extends State<DashboardEvent> {
final Stream<QuerySnapshot> activities = FirebaseFirestore
.instance.collection('activities')
.where('Type', isEqualTo: 'Event')
.orderBy('ts', descending: true)
.snapshots();
#override
Widget build(BuildContext context) {
return Column(
children: [
AddButton(
title: 'Events',
addLabel: 'Add Events',
onPressed: (){
Navigator.pushNamed(context, EventForm.id);
},),
const SizedBox(
height: 16.0,
),
const Divider(
color: Colors.white70,
height:40.0,
),
StreamBuilder<QuerySnapshot>(
stream: activities,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return const Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(Colors.green),
),
);
}
final data = snapshot.requireData;
if(data != null){
return ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index){
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Colors.transparent,
radius: 40,
child:Image.network(
data.docs[index]['PhotoUrl'],
),
),
Text( data.docs[index]['Name'], style:const TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold),
),
if(Responsive.isWeb(context))
const SizedBox(
width: 50,
),
Responsive.isWeb(context) ? ButtonBlue(
addLabel: 'View Event',
color: Colors.green,
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context){
return ViewData(item: data.docs[index],);
}));
},
icon: const Icon(IconData(61161, fontFamily: 'MaterialIcons')),
) : InkWell(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context){
return ViewData(item: data.docs[index],);
}));
},
child: const Icon(IconData(61161, fontFamily: 'MaterialIcons')),
),
Responsive.isWeb(context) ? ButtonBlue(
addLabel: 'Delete Event',
color: Colors.red,
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context){
return ShowDialog(
deleteFunction: () async{
await FirebaseFirestore.instance.runTransaction((Transaction myTransaction) async {
FirebaseStorage.instance.refFromURL(data.docs[index]['PhotoUrl']).delete();
myTransaction.delete(snapshot.data!.docs[index].reference);
}).then((value) => Navigator.pop(context));
},
dialogTitle: "Delete",
dialogContent: "Do you really want to delete ${data.docs[index]['Name']} event?",
);
});
},
icon: const Icon(Icons.delete_outline,),
): InkWell(
onTap: (){
if(defaultTargetPlatform == TargetPlatform.iOS){
showCupertinoDialog(
context: context,
builder: (BuildContext context){
return ShowDialog(
deleteFunction: () async{
await FirebaseFirestore.instance.runTransaction((Transaction myTransaction) async {
FirebaseStorage.instance.refFromURL(data.docs[index]['PhotoUrl']).delete();
myTransaction.delete(snapshot.data!.docs[index].reference);
}).then((value) => Navigator.pop(context));
},
dialogTitle: "Delete",
dialogContent: "Do you really want to delete ${data.docs[index]['Name']} event?",
);
});
}
else if((defaultTargetPlatform == TargetPlatform.android)){
showDialog(
context: context,
builder: (BuildContext context){
return ShowDialog(
deleteFunction: () async{
await FirebaseFirestore.instance.runTransaction((Transaction myTransaction) async {
FirebaseStorage.instance.refFromURL(data.docs[index]['PhotoUrl']).delete();
myTransaction.delete(snapshot.data!.docs[index].reference);
}).then((value) => Navigator.pop(context));
},
dialogTitle: "Delete",
dialogContent: "Do you really want to delete ${data.docs[index]['Name']} event?",
);
});
}
else{
showDialog(
context: context,
builder: (BuildContext context){
return ShowDialog(
deleteFunction: () async{
await FirebaseFirestore.instance.runTransaction((Transaction myTransaction) async {
FirebaseStorage.instance.refFromURL(data.docs[index]['PhotoUrl']).delete();
myTransaction.delete(snapshot.data!.docs[index].reference);
Navigator.pop(context);
showToast(message: 'Deleted Successfully', color: Colors.green);
}).then((value) => Navigator.pop(context));
},
dialogTitle: "Delete",
dialogContent: "Do you really want to delete ${data.docs[index]['Name']} event?",
);
});
}
},
child: const Icon(Icons.delete_outline,),
),
],
),
const Divider(
color: Colors.white70,
height:40.0,
),
],
);
});
}
return const Center(
child: CircularProgressIndicator(),
);
},
)
],
);
}
}
I have been on this the entire day but in vain but in the same product, I have another view details with the same code that works
Please assist me on this

file_picker - onPressed does not delete a card neither refresh the view

I am using File_Picker.dart
I am having an issue with one of the function I have written. When I press on the icon delete, the record is not deleted, and the screen is not refreshed. What I mean is that the card is still displayed.
Also, what I am trying to do it to be able to add a file one by one, without removing the file previously selected. But each time I am clicking on the button 'Open File picker' which is calling '_openFileExplorer()', the file selected previously is removed from the screen. I have not find how to stop this to happen.
If you can help me to solve this it would be appreciated. Many thanks.
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_storage/firebase_storage.dart';
class FilePickerDemo extends StatefulWidget {
#override
_FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State<FilePickerDemo> {
//FirebaseStorage storage = FirebaseStorage.instance;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
late String _fileName;
List<PlatformFile>? _paths;
bool _loadingPath = false;
bool _multiPick = true;
FileType _fileType = FileType.media;
/*
#override
void initState() {
super.initState();
Firebase.initializeApp();
}
*/
void _openPictureFileExplorer() async {
setState(() => _loadingPath = true);
/*
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
*/
try {
_paths = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
}
void _openDocumentFileExplorer() async {
setState(() => _loadingPath = true);
try{
var files = (await FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
))
?.files;
_paths = _paths!..addAll(files!.map((e) => e));
_loadingPath = false;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
/*
try {
_paths = (await FilePicker.platform.pickFiles(
type: FileType.custom,
allowMultiple: _multiPick,
allowedExtensions: ['pdf','docx'],
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print('$ex');
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.last.name);
_fileName = _paths != null ?
_paths!.map((e) => e.name).toString() : '...';
});
*/
}
void _clearCachedFiles() {
FilePicker.platform.clearTemporaryFiles().then((result) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: result! ? Colors.green : Colors.red,
content: Text((result
? 'Temporary files removed with success.'
: 'Failed to clean temporary files')),
),
);
});
}
// Select and image from the gallery or take a picture with the camera
// Then upload to Firebase Storage
/*
Future<void> _upload() async {
try {
final String fileName = _fileName;
File imageFile = File(_paths.toString());
try {
// Uploading the selected image with some custom meta data
await storage.ref(fileName).putFile(
imageFile,
);
// Refresh the UI
setState(() {});
} on FirebaseException catch (error) {
print(error);
}
} catch (err) {
print(err);
}
}
*/
// Delete the selected image
// This function is called when a trash icon is pressed
void _delete(int index) {
if(_paths!=null || _paths!.length> 1) {
_paths!.removeAt(index);
setState(() {});
print ('2:' +_paths!.length.toString());
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker example app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child:Card(
child:
Container(
// color: Colors.red,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children:[
//Attachement
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.attach_file),
Text('Attachement'),
],
)
),
onTap: () {
},
),
),
//Photo
FlatButton(
onPressed: () { },
child:
InkWell(
child: Container(
// color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.add_a_photo_rounded),
Text('Photo'),
],
)
),
onTap: () {_openPictureFileExplorer(); },
),
),
],
),
)),
),
Builder(
builder: (BuildContext context) => _loadingPath ?
Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child:const CircularProgressIndicator(),
)
: _paths != null && _paths!.isNotEmpty
? Container(
padding: const EdgeInsets.only(bottom: 30.0),
height:
MediaQuery.of(context).size.height * 0.50,
child: Scrollbar(
child: ListView.separated(
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder:
(BuildContext context, int index) {
final bool isMultiPath =
_paths != null && _paths!.isNotEmpty;
final String name =
(isMultiPath
? _paths!
.map((e) => e.name)
.toList()[index]
: _fileName ?? '...');
final path = _paths!
.map((e) => e.path)
.toList()[index]
.toString();
return Container(
height: 114,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 10,
child: ClipPath(
clipper: ShapeBorderClipper(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15))),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
height: 113,width: 113,
child: Image.file(File(path),
fit: BoxFit.fill,
width: double.infinity,),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(name,
style: TextStyle(fontWeight: FontWeight.bold),),
),
),
Padding(
padding: const EdgeInsets.only(right:25.0),
child: IconButton(onPressed: (){
//delete a record and the card displaying this record
_delete(index);
},
icon:Icon (Icons.delete, color: Colors.red,),),
)
],
),
),
//subtitle: Text(path),
),
);
},
separatorBuilder:
(BuildContext context, int index) =>
const SizedBox(),)),)
:const SizedBox(child:Text('No documents')),
),
],
),
),
)),
),
);
}
}
The problem here is that the paths variable is made up of a list of PlatformFile and you are trying to remove a string value which doesn't exist in that list.
You can see this if you print the value of paths in your _delete() method. It should show [Instance of 'PlatformFile', Instance of 'PlatformFile'].
In a nutshell what you're trying to do could be visualized as such
[PlatformFile(), PlatformFile()].remove("some/path/string/value")
There can be a simple fix for this assuming the list isn't sorted, you can just send the index as the reference from the onTap .
It would look like this
void _delete(int ref) {
// remove the element at the passed index
_paths!.removeAt(ref);
setState(() {});
}
... some code...
itemBuilder: (BuildContext context, int index) {
... some code...
IconButton(
onPressed: () {
_delete(index);
setState(() {});
},
icon: Icon(
Icons.delete,
color: Colors.red,
),
... some code...
);
}
Alternatively if you can't be sure of the positions of the elements in the path list, this would be the best approach.
void _delete(String ref) {
var _platformFileObject = _paths!.where((element) => element.path == ref).first;
_paths!.remove(_platformFileObject);
setState(() {});
}
Edit to answer the second question;
In your _openFileExplorer() method, you are reassigning the new file objects rather than adding them to the _paths list. The solution would be to add the new file objects to the list.
FilePickerResult? filePickerResult = await
FilePicker.platform.pickFiles(
type: _fileType,
allowMultiple: _multiPick,
);
_paths?.addAll(filePickerResult!.files.map((e) => e));
Edited to answer the third question
The error you stated occurs because of this [lines 150-153]
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1
So when it goes to the builder it is trying build a list item but there's nothing to get since the list is actually empty. You should change 1 to 0.
In order to show a text when the _paths list is empty, you should try something like this.
Scrollbar(
child: !_paths!.isEmpty
? ListView.separated(
itemCount: _paths!.length,
itemBuilder: (BuildContext context, int index) {
return Container();
},
separatorBuilder: (BuildContext context, int index) {
return Container();
},
)
: Text("Text to display when _paths is empty"),
);
Additionally, I would recommend that you refactor your code for better readability.