I need to delete the users profile from firebase, thing is I have 3 collections petfiles, petsdetails and users which need to be deleted. As in when a user signs up, they can create a pet and create records for their pet. But when having to delete the user, it should delete all the pets and records the pet has (it could be up to any amount)
I havent tried anything as I dont really know how to solve this but this is my code
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:image_picker/image_picker.dart';
import 'package:vet_bookr/oScreens/petFiles.dart';
import '../constant.dart';
class UserDetails extends StatefulWidget {
UserDetails({Key? key, required this.details}) : super(key: key);
Map<String, dynamic> details;
#override
State<UserDetails> createState() => _UserDetailsState();
}
class _UserDetailsState extends State<UserDetails> {
List<String> labels = ["Email", "Phone Number"];
bool editableText = false;
String imageUrl = "";
List<String> petIds = [];
#override
void initState() {
// TODO: implement initState
nameController.text = widget.details["name"];
ageController.text = widget.details["age"];
super.initState();
}
Future<void> uploadImages({required String path}) async {
try {
final imageRef = storageRef.child(
"Users/${FirebaseAuth.instance.currentUser?.uid}/${widget.details["id"]}");
await imageRef.putFile(File(path));
imageUrl = await imageRef.getDownloadURL();
setState(() {});
//print(imageRef.getDownloadURL());
} on FirebaseException catch (e) {
print("Function does work");
SnackBar snackBar = SnackBar(content: Text(e.message!));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
bool isLoading = false;
final nameController = TextEditingController();
final ageController = TextEditingController();
XFile? profilePic;
ImagePicker imagePicker = ImagePicker();
final storageRef = FirebaseStorage.instance.ref();
TextEditingController controllerChanger(index) {
if (index == 0) {
return nameController;
}
if (index == 1) {
return ageController;
}
return TextEditingController();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
},
child: Scaffold(
appBar: AppBar(
systemOverlayStyle: SystemUiOverlayStyle.dark,
backgroundColor: Colors.transparent,
elevation: 0,
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.black,
),
onPressed: () {
Navigator.pop(context);
},
),
actions: [
Padding(
padding: EdgeInsets.only(right: 5.sp),
child: PopupMenuButton(
icon: Icon(
Icons.more_vert,
color: Colors.black,
),
itemBuilder: (context) {
return [
PopupMenuItem<int>(
value: 0,
child: Text("Edit Profile"),
),
PopupMenuItem<int>(
value: 1,
child: Text("Delete Profile"),
),
];
},
onSelected: (value) async {
if (value == 0) {
setState(() {
editableText = true;
});
print(editableText);
} else if (value == 1) {
setState(() {
isLoading = true;
});
final ref = storageRef.child(
"Users/${FirebaseAuth.instance.currentUser?.uid}/${widget.details["id"]}");
await ref.delete();
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.delete();
DocumentSnapshot<Map<dynamic, dynamic>> snap =
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.get();
await FirebaseFirestore.instance
.collection("petDetails")
.doc(FirebaseAuth.instance.currentUser?.uid)
.update({
'pets': FieldValue.arrayRemove(snap.data()!["pets"]!),
});
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.update({
'pets': FieldValue.arrayUnion(snap.data()!["pets"]!),
});
setState(() {
isLoading = false;
});
Navigator.pop(context);
}
},
))
],
),
extendBodyBehindAppBar: true,
backgroundColor: kBackgroundColor,
body: isLoading
? Container(
width: 1.sw,
height: 0.4.sh,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 15.sp,
width: 15.sp,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Color(0xffFF8B6A),
),
),
],
),
)
: SafeArea(
child: Container(
//alignment: Alignment.center,
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(15.sp),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// sBox(h: 10),
Text(
'Pet Information',
style: TextStyle(
color: Color(0xffF08519), fontSize: 0.05.sw),
),
// myPetTile()
SizedBox(
height: 0.05.sh,
),
Stack(
children: [
CircleAvatar(
radius: 0.095.sh,
backgroundColor: Color(0xffFF8B6A),
backgroundImage: profilePic == null
? NetworkImage(
widget.details["profilePicture"],
)
: null,
child: profilePic == null
? Container(
width: 0,
height: 0,
)
: ClipRRect(
borderRadius:
BorderRadius.circular(100),
child: Image.file(
File(
"${profilePic?.path}",
),
),
),
),
editableText
? Positioned(
right: 0.025.sw,
bottom: 0.005.sh,
child: GestureDetector(
onTap: () async {
profilePic = await ImagePicker()
.pickImage(
source: ImageSource.gallery);
setState(() {});
},
child: CircleAvatar(
backgroundColor: Color(0xffFF8B6A),
radius: 0.02.sh,
child: Icon(
Icons.camera_alt_outlined,
size: 0.05.sw,
color: Colors.white,
),
),
),
)
: Container(
width: 0,
height: 0,
)
],
),
SizedBox(
height: 0.02.sh,
),
...List.generate(
2,
(index) => Padding(
padding: EdgeInsets.only(
top: 0.02.sh, left: 0.05.sw, right: 0.05.sw),
child: TextField(
enabled: editableText,
controller: controllerChanger(index),
style: TextStyle(fontSize: 0.017.sh),
cursorColor: Colors.black,
decoration: InputDecoration(
label: Text(labels[index],
style: TextStyle(fontSize: 0.02.sh)),
labelStyle: TextStyle(color: Colors.black54),
focusedBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10.sp),
borderSide:
BorderSide(color: Color(0xffFF8B6A))),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.sp),
),
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(10.sp),
borderSide:
BorderSide(color: Color(0xffFF8B6A))),
contentPadding:
EdgeInsets.symmetric(horizontal: 10.sp),
hintStyle: TextStyle(color: Colors.grey),
),
),
),
),
buttonWidget()
],
),
),
),
),
),
),
);
}
bool isLoadingEdit = false;
Widget buttonWidget() {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 0.4.sw,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.zero,
backgroundColor: Color(0xffFF8B6A),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.sp),
),
),
onPressed: () async {
if (editableText) {
setState(() {
isLoadingEdit = true;
});
if (profilePic != null) {
final ref = storageRef.child(
"Users/${FirebaseAuth.instance.currentUser?.uid}/${widget.details["id"]}");
await ref.delete();
await uploadImages(path: profilePic!.path);
}
await FirebaseFirestore.instance
.collection("petsDetails")
.doc(widget.details["id"])
.update({
'name': nameController.text,
'age': ageController.text,
'breed': breedController.text,
'weight': weightController.text,
'profilePicture': profilePic != null
? imageUrl
: widget.details["profilePicture"],
'lastVaccinationDate':
widget.details["lastVaccinationDate"]
});
DocumentSnapshot<Map<String, dynamic>> snap =
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.get();
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.update({
'pets': FieldValue.arrayRemove(snap.data()!["pets"]!)
});
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.update({
'pets': FieldValue.arrayRemove(snap.data()!["pets"]!),
});
await FirebaseFirestore.instance
.collection("users")
.doc(FirebaseAuth.instance.currentUser?.uid)
.update({
'pets': FieldValue.arrayUnion(snap.data()!["pets"]!),
});
Navigator.pop(context);
setState(() {
isLoadingEdit = false;
editableText = false;
});
const snackBar = SnackBar(
content: Text("Your pet's details have been changed"),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PetFiles(
petId: widget.details["id"],
),
),
);
}
},
child: isLoadingEdit
? Container(
height: 15.sp,
width: 15.sp,
child: CircularProgressIndicator(
color: Colors.white,
strokeWidth: 2.sp,
),
)
: Text(
editableText ? "Save Changes" : "Pet Health Records",
style:
TextStyle(color: Colors.white, fontSize: 0.03.sw),
),
),
),
],
),
SizedBox(
height: 0.01.sh,
),
],
);
}
}
You can check out their official docs for deleting collections here.
Or you can upgrade your project to blaze plan and use this extension which takes care of it for you.
Alternatively you can use NodeJS and FirebaseFunctions to do this task for you. Use this code snippet
async function deleteCollection(db, collectionPath, batchSize) {
const collectionRef = db.collection(collectionPath);
const query = collectionRef.orderBy('__name__').limit(batchSize);
return new Promise((resolve, reject) => {
deleteQueryBatch(db, query, resolve).catch(reject);
});
}
async function deleteQueryBatch(db, query, resolve) {
const snapshot = await query.get();
const batchSize = snapshot.size;
if (batchSize === 0) {
// When there are no documents left, we are done
resolve();
return;
}
// Delete documents in a batch
const batch = db.batch();
snapshot.docs.forEach((doc) => {
batch.delete(doc.ref);
});
await batch.commit();
// Recurse on the next process tick, to avoid
// exploding the stack.
process.nextTick(() => {
deleteQueryBatch(db, query, resolve);
});
}
index.js
Related
This is a Flutter app that I wrote long ago which pushes a user-selected image to Firebase and generates output using an ML model on the server.
I want to modify the same app. It is a completely offline app, so Firebase is not an option. So there are just 4 images that the user will be using as input. The app must be hardcoded to display a predefined output depending on which image is uploaded.
The possible methods I thought of were,
Store those images as assets in the app. Compare the input image's name to that of the asset images. Display output is there is a match.
Use image comparison algorithms using packages like image_compare.
None of the above methods worked, maybe I am doing it wrong. Please help me out.
Also, sorry for the non systematic code below.
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:firebase_storage/firebase_storage.dart' as firebase_storage;
import 'package:del04/splashscreen.dart';
import 'package:del04/page/info_page.dart';
import 'package:del04/data.dart';
import 'package:dotted_border/dotted_border.dart';
import 'package:iconsax/iconsax.dart';
import 'package:path/path.dart';
import 'package:file_picker/file_picker.dart';
import 'package:file_support/file_support.dart';
late String name, path , domain , phylum , clas , order , family , genus , species ;
File? _photo;
// ignore: prefer_typing_uninitialized_variables
var image;
File a= File('assets/images/1.jpg'), b= File('assets/images/2.jpg'), c= File('assets/images/3.jpg'), d= File('assets/images/4.jpg');
var which=-1;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => const Splash_screen(),
'/home': (context) => ImageUploads(),
'/home/info_page': (context) => Info_page()
}
)
);
}
class ImageUploads extends StatefulWidget {
const ImageUploads({Key? key}) : super(key: key);
#override
// ignore: library_private_types_in_public_api
_ImageUploadsState createState() => _ImageUploadsState();
}
class _ImageUploadsState extends State<ImageUploads> {
//firebase_storage.FirebaseStorage storage = firebase_storage.FirebaseStorage.instance;
Future imgFromGallery() async {
final FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf'],
);
setState(() {
if (result != null) {
_photo= result as File;
String? filename= FileSupport().getFileNameWithoutExtension(_photo!);
image= _photo as Image;
} else {
if (kDebugMode) {
print('No image selected.');
}
}
});
}
/* Future imgFromCamera() async {
final pickedFile = await _picker.pickImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_photo = File(pickedFile.path);
image= _photo;
} else {
// ignore: avoid_print
print('No image selected.');
}
});
} //from Camera
Future uploadFile() async {
//if (_photo == null) return;
//const destination = 'Abhinav/';
try {
final ref = firebase_storage.FirebaseStorage.instance
.ref(destination)
.child('file/');
await ref.putFile(_photo!);
}
catch (e) {
if (kDebugMode) {
print('Error occurred, try again.');
}
}
}*/
void _onLoading() {
/*showDialog(
context: this.context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(height: 80, width: 80),
CircularProgressIndicator(),
Text(" Analyzing..."),
],
),
);
},
);*/
//douploadingshit();
Future.delayed(const Duration(seconds: 2), () async {
if(image.readAsBytesSync().lengthInBytes != a.readAsBytesSync().lengthInBytes)which= 1;
else if(image.readAsBytesSync().lengthInBytes == b.readAsBytesSync().lengthInBytes)which= 2;
else if(image.readAsBytesSync().lengthInBytes == c.readAsBytesSync().lengthInBytes)which= 3;
else if(image.readAsBytesSync().lengthInBytes == d.readAsBytesSync().lengthInBytes)which= 4;
else which= 99;
//pop dialog
//final ref = FirebaseDatabase.instance.ref();
//final snapshot = await ref.child('/').get();
//name = (snapshot.value) as String;
const Data().setData();
//Navigator.pop(this.context); //pop dialog
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
/*if(which==99){
fetch_errorM();
}
else{
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
}*/
});
}
/* Future<void> douploadingshit() async {
uploadFile();
DatabaseReference ref = FirebaseDatabase.instance.ref("");
await ref.update({
"confirm/state": "yes",
});
}*/
void fetch_errorM() {
showDialog(
context: this.context,
barrierDismissible: false,
builder: (BuildContext context) {
return Dialog(
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
SizedBox(height: 80, width: 30),
Text("Could not analyze sample.\nPlease Retry or try another Image."),
],
),
);
},
);
Future.delayed(const Duration(seconds: 2), () async {
Navigator.pop(this.context); //pop dialog
});
}
//----------------------------------------------------------------------------
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('\t Baclens'),
backgroundColor: Colors.blueGrey.shade900,
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
const SizedBox(height: 80,),
Text('Upload your image file', style: TextStyle(fontSize: 25, color: Colors.grey.shade800, fontWeight: FontWeight.bold),),
const SizedBox(height: 10,),
Text('File should be jpg or png only', style: TextStyle(fontSize: 15, color: Colors.grey.shade500),),
const SizedBox(height: 20,),
GestureDetector(
onTap: () {
_showPicker(context);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 40.0, vertical: 20.0),
child: DottedBorder(
borderType: BorderType.RRect,
radius: const Radius.circular(10),
dashPattern: const [10, 5],
strokeCap: StrokeCap.round,
color: Colors.grey.shade900,
child: Container(
width: double.infinity,
height: 150,
decoration: BoxDecoration(
color: Colors.blue.shade50.withOpacity(.3),
borderRadius: BorderRadius.circular(10)
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Iconsax.document_upload5, color: Colors.grey.shade900, size: 40,),
const SizedBox(height: 15,),
Text('Click to choose image', style: TextStyle(fontSize: 15, color: Colors.grey.shade400),),
],
),
),
)
),
),
_photo != null
? Container(
padding: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(' Selected File:',
style: TextStyle(color: Colors.grey.shade400, fontSize: 15, ),),
const SizedBox(height:10),
Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(1),
color: Colors.transparent,
),
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(2),
child: Image.file(_photo!, width: 200, height: 200, fit: BoxFit.fitWidth)
),
)
),
const SizedBox(height: 30,),
MaterialButton(
minWidth: double.infinity,
height: 50,
onPressed: () {
_onLoading();
////////////////////////////////////////////////////////////////////////////////
setState((){
const Data().setData();
Navigator.pop(this.context); //pop dialog
Navigator.of(this.context).push(MaterialPageRoute(builder: (context)=>Info_page()));
});
},
color: Colors.blueGrey.shade900,
child: const Text('Upload', style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),),
)
],
))
: Container(),
const SizedBox(height: 150,),
],
),
),
);
}
void _showPicker(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext bc) {
return SafeArea(
child: Wrap(
children: <Widget>[
ListTile(
leading: const Icon(Icons.photo_library),
title: const Text('Gallery'),
onTap: () {
imgFromGallery();
Navigator.of(context).pop();
}),
/*ListTile(
leading: const Icon(Icons.photo_camera),
title: const Text('Camera'),
onTap: () {
imgFromCamera();
Navigator.of(context).pop();
},
),*/
],
),
);
});
}
}
If I understood correctly (but clearly I don't) when you need a var available when you build the widget you need to call the function in the initState(). The function is 'void getDevices()'
I need var _documentsIds to build DropdownMenuItem.
var _documentsIds is docs ID from a query I make to FirebaseFirestore
How do I make _documentsIds available to be used in my Widget?
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:safegaurd/constants.dart';
import 'package:flutter_time_picker_spinner/flutter_time_picker_spinner.dart';
import 'package:safegaurd/screens/log_in_page.dart';
import 'package:safegaurd/components/buttons_navigate.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'new_device_page.dart';
class DeviceSelectionPage extends StatefulWidget {
const DeviceSelectionPage({Key? key}) : super(key: key);
static const String id = 'device_selection_page';
#override
State<DeviceSelectionPage> createState() => _DeviceSelectionPageState();
}
class _DeviceSelectionPageState extends State<DeviceSelectionPage> {
final _auth = FirebaseAuth.instance;
User? loggedInUser;
final firestoreInstance = FirebaseFirestore.instance;
final String devices = 'devices';
List? _documentsIds;
bool showSpinner = false;
String? selectedValue;
final bool checkOne = false;
Color sDeviceAlways = Colors.white54;
Color sDeviceTime = Colors.white54;
FontWeight sDeviceAlwaysW = FontWeight.normal;
FontWeight sDeviceTimeW = FontWeight.normal;
#override
void initState() {
super.initState();
getCurrentUser();
getDevices();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
getDevices();
};
} catch (e) {
print(e);
}
}
void getDevices() async {
var firebaseUser = FirebaseAuth.instance.currentUser?.email;
print('firebaseUser: $firebaseUser');
var query = await firestoreInstance
.collection(devices)
.where('email', isEqualTo: '$firebaseUser')
.get();
var _documentsIds = query.docs.map((doc) => doc.id).toList();
print('_documentsIds: $_documentsIds');
}
#override
Widget build(BuildContext context) {
print('_documentsIds: $_documentsIds');
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
onPressed: () {
_auth.signOut();
Navigator.pop(context);
},
icon: Icon(Icons.close))
],
title: const Text('Device Selection page'),
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 40,
child: Text(
'SAFEGAURD',
style: kAppTextStyle,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 380,
padding: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightBlueAccent, width: 1.0),
borderRadius: kBorderRadius),
child: DropdownButtonHideUnderline(
child: DropdownButton(
hint: const Text(
'Safegaurd Devices',
style: TextStyle(color: Colors.white54, fontSize: 25),
),
style:
const TextStyle(color: Colors.orange, fontSize: 25),
borderRadius: kBorderRadius,
iconSize: 40,
elevation: 16,
onChanged: (value) {
setState(() {
selectedValue = value.toString();
setState(() {
selectedValue;
print(selectedValue);
});
});
},
value: selectedValue,
items: _documentsIds?.map((itemsList) {
return DropdownMenuItem<String>(
value: itemsList,
child: Text(itemsList),
);
}).toList(),
),
),
)
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Save Settings',
onPressed: () {},
width: 200,
),
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Claim new Device',
onPressed: () {
Navigator.pushNamed(context, NewDevicePage.id);
},
width: 200,
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Buttons_Navigate(
colour: Colors.orange,
title: 'Back',
onPressed: () {
Navigator.pushNamed(context, LogInPage.id);
},
width: 40)
],
)
],
)),
));
}
}
wall, you can use futureBuilder and show A CircularProgressBar until the query is done check the documentation here: FutureBuilder
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:safegaurd/constants.dart';
//import 'package:flutter_time_picker_spinner/flutter_time_picker_spinner.dart';
import 'package:safegaurd/screens/log_in_page.dart';
import 'package:safegaurd/components/buttons_navigate.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'new_device_page.dart';
class DeviceSelectionPage extends StatefulWidget {
const DeviceSelectionPage({Key? key}) : super(key: key);
static const String id = 'device_selection_page';
#override
State<DeviceSelectionPage> createState() => _DeviceSelectionPageState();
}
class _DeviceSelectionPageState extends State<DeviceSelectionPage> {
final _auth = FirebaseAuth.instance;
User? loggedInUser;
final firestoreInstance = FirebaseFirestore.instance;
final String devices = 'devices';
List? _documentsIds;
bool showSpinner = false;
//bool _isSelected1 = false;
//bool _isSelected2 = false;
//DateTime _dateTime = DateTime.now();
String? selectedValue;
final bool checkOne = false;
Color sDeviceAlways = Colors.white54;
Color sDeviceTime = Colors.white54;
FontWeight sDeviceAlwaysW = FontWeight.normal;
FontWeight sDeviceTimeW = FontWeight.normal;
#override
void initState() {
super.initState();
getCurrentUser();
getDevices();
}
void getCurrentUser() async {
try {
final user = await _auth.currentUser;
if (user != null) {
getDevices();
};
} catch (e) {
print(e);
}
}
Future<List<dynamic>> getDevices() async {
var firebaseUser = FirebaseAuth.instance.currentUser?.email;
print('firebaseUser: $firebaseUser');
var query = await firestoreInstance
.collection(devices)
.where('email', isEqualTo: '$firebaseUser')
.get();
List<String> _documentsIds = query.docs.map((doc) => doc.id).toList();
print('_documentsIds: $_documentsIds');
return _documentsIds;
}
#override
Widget build(BuildContext context) {
print('_documentsIds: $_documentsIds');
return Scaffold(
appBar: AppBar(
leading: null,
actions: [
IconButton(
onPressed: () {
_auth.signOut();
Navigator.pop(context);
},
icon: Icon(Icons.close))
],
title: const Text('Device Selection page'),
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(
height: 40,
child: Text(
'SAFEGAURD',
style: kAppTextStyle,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 380,
padding: const EdgeInsets.symmetric(horizontal: 24.0),
decoration: BoxDecoration(
border: Border.all(
color: Colors.lightBlueAccent, width: 1.0),
borderRadius: kBorderRadius),
child: DropdownButtonHideUnderline(
child: FutureBuilder<List> (
future: getDevices(),
builder: (BuildContext context, AsyncSnapshot<List> snapshot){
if (!snapshot.hasData) {
return const Text('Waiting Devices',style: TextStyle(color: Colors.white54, fontSize: 25));
} else {
return DropdownButton(
hint: const Text(
'Safegaurd Devices',
style: TextStyle(color: Colors.white54, fontSize: 25),
),
style:
const TextStyle(color: Colors.orange, fontSize: 25),
borderRadius: kBorderRadius,
iconSize: 40,
elevation: 16,
onChanged: (value) {
setState(() {
selectedValue = value.toString();
setState(() {
selectedValue;
print(selectedValue);
});
});
},
value: selectedValue,
items: snapshot.data?.map((_documentsIds) =>
DropdownMenuItem<String>(
value: _documentsIds,
child: Text(_documentsIds),
)
).toList(),
);
}
}
)
),
)
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Save Settings',
onPressed: () {},
width: 200,
),
],
),
Row(
children: [
Buttons_Navigate(
colour: Colors.teal,
title: 'Claim new Device',
onPressed: () {
Navigator.pushNamed(context, NewDevicePage.id);
},
width: 200,
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Buttons_Navigate(
colour: Colors.orange,
title: 'Back',
onPressed: () {
Navigator.pushNamed(context, LogInPage.id);
},
width: 40)
],
)
],
)),
));
}
I integrated Agora in Flutter Application with the help of agora_rtc_engine 4.0.7, but upon making a video call for the very first time the local camera view is not working. When we disconnect the call and call back again then everything works fine, the local camera view started working.
Again when we kill the application from Phone memory and rerun it then also the same problem occurs for the first time.
VideoCallingScreen.dart file
class VideoCallingScreen extends StatefulWidget {
String doctorId;
String bookingId;
VideoCallingScreen(this.doctorId, this.bookingId);
#override
_VideoCallingScreenState createState() => _VideoCallingScreenState();
}
class _VideoCallingScreenState extends State<VideoCallingScreen> {
int? _remoteUid;
RtcEngine? _engine;
bool isJoined = false,
switchCamera = true,
switchRender = true,
muteAudio = false,
muteVideo = false;
bool remoteUserMicMute = false, remoteUserVideoMute = false;
bool resizeVideo = false;
ServerHandler _serverHandler = ServerHandler();
String? token;
String? channelName;
String? channelId;
late user.Details userDetails;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
void initState() {
super.initState();
getAgoraToken().then((value) {
if (value) {
initForAgora();
} else {
_showMyDialog();
}
});
// initForAgora();
}
Future<void> _showMyDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: const Text('No Channel Found'),
content: SingleChildScrollView(
child: ListBody(
children: const <Widget>[
Text('No video channel has been created by the Doctor'),
],
),
),
actions: <Widget>[
TextButton(
child: const Text('Ok'),
onPressed: () async {
// int count = 0;
Navigator.pop(context);
Navigator.pop(_scaffoldKey.currentContext!);
},
),
],
);
},
);
}
Future<bool> getAgoraToken() async {
await Screen.keepOn(true);
var tokenBody = await _serverHandler.joinAgoraChannel(
widget.doctorId, widget.bookingId);
print('token Body from videoPage' + tokenBody.toString());
if (tokenBody['success'] == 1) {
setState(() {
token = tokenBody['channel']['access_token_patient'];
channelName = tokenBody['channel']['channel_name'];
print('**********Token Set********' + token!);
channelId = tokenBody['channel']['id'].toString();
});
return true;
} else {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
"Unable to get Video Call Token, Please check your internet Connection and try again."),
));
return false;
}
}
Future<void> initForAgora() async {
// retrieve permissions
await [Permission.microphone, Permission.camera].request();
userDetails = await _serverHandler.getUserProfile();
//create the engine
_engine = await RtcEngine.create(appId);
await _engine?.enableVideo();
_engine?.setEventHandler(
RtcEngineEventHandler(
joinChannelSuccess: (String channel, int uid, int elapsed) async {
print("local user $uid joined");
// await _engine!.enableVideo();
},
userJoined: (int uid, int elapsed) {
print("remote user $uid joined");
setState(() {
_remoteUid = uid;
});
},
tokenPrivilegeWillExpire: (token) async {
await getAgoraToken();
await _engine?.renewToken(token);
},
userOffline: (int uid, UserOfflineReason reason) {
print("remote user $uid left channel");
// _engine!.enableVideo();
setState(() {
_remoteUid = null;
});
_userLeftTheCall();
},
userMuteVideo: (int uid, bool isMute) {
print('Audio Mutted');
setState(() {
remoteUserVideoMute = isMute;
});
},
userMuteAudio: (int uid, bool isMute) {
print('Audio Mutted');
setState(() {
remoteUserMicMute = isMute;
});
},
),
);
await getAgoraToken();
await _engine?.joinChannel(token, channelName!, null, userDetails.id!);
}
// Create UI with local view and remote view
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _scaffoldKey,
body: SafeArea(
child: Stack(
children: [
Center(
child:
resizeVideo ? _renderLocalPreview() : _renderRemoteVideo(),
),
if (remoteUserVideoMute)
BackdropFilter(
filter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Padding(
padding: const EdgeInsets.only(bottom: 32),
child: Center(
child: Text(
'Doctor video Paused',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
),
if (remoteUserMicMute)
Padding(
padding: const EdgeInsets.only(top: 32),
child: Center(
child: Text(
'Doctor Mic Muted',
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
),
Positioned(
top: 8,
left: 8,
child: InkWell(
//Uncomment it to unable resize
// onTap: () {
// setState(() {
// resizeVideo = !resizeVideo;
// });
// },
child: Container(
width: 100,
height: 120,
child: Stack(
children: [
ImageFiltered(
imageFilter: muteVideo
? ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0)
: ImageFilter.blur(sigmaX: 0, sigmaY: 0),
child: resizeVideo
? _renderRemoteVideo()
: _renderLocalPreview(), // Widget that is blurred
),
if (muteVideo)
Positioned(
top: 4,
left: 4,
child: Icon(
Icons.videocam_off_outlined,
color: Colors.white,
size: 32,
),
),
if (muteAudio)
Positioned(
bottom: 4,
right: 4,
child: Icon(
Icons.mic_off_outlined,
color: Colors.white,
size: 32,
),
),
],
),
),
),
),
Positioned(
bottom: 32,
right: 8,
left: 8,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
InkWell(
onTap: () async {
await Screen.keepOn(false);
await _engine?.leaveChannel();
await _serverHandler.leaveChannel(channelId!);
Navigator.pop(_scaffoldKey.currentContext!);
},
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.red),
child: Icon(
Icons.call_end,
color: Colors.white,
),
),
),
InkWell(
onTap: this._switchCamera,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
Icons.flip_camera_android_rounded,
color: Colors.black87,
),
),
),
InkWell(
onTap: this._onToggleMuteVideo,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
muteVideo
? Icons.videocam_off_outlined
: Icons.videocam_outlined,
color: Colors.black87,
),
),
),
InkWell(
onTap: this._onToggleMute,
child: Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white),
child: Icon(
muteAudio
? Icons.mic_off_outlined
: Icons.mic_none_outlined,
color: Colors.black87,
),
),
),
],
),
)
],
),
),
),
);
}
// current user video
Widget _renderLocalPreview() {
return RtcLocalView.SurfaceView();
}
// remote user video
Widget _renderRemoteVideo() {
// return RtcRemoteView.SurfaceView(uid: 70);
if (_remoteUid != null) {
return RtcRemoteView.SurfaceView(uid: _remoteUid!);
} else {
return Text(
'Please wait, doctor is joining shortly',
style: TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
);
}
}
_switchCamera() {
_engine?.switchCamera().then((value) {
setState(() {
switchCamera = !switchCamera;
});
}).catchError((err) {
log('switchCamera $err');
});
}
void _onToggleMute() {
setState(() {
muteAudio = !muteAudio;
});
_engine!.muteLocalAudioStream(muteAudio);
}
void _onToggleMuteVideo() {
setState(() {
muteVideo = !muteVideo;
});
_engine!.muteLocalVideoStream(muteVideo);
}
Future<bool> _onWillPop() async {
return (await showDialog(
context: _scaffoldKey.currentContext!,
builder: (context) => new AlertDialog(
title: new Text('Are you sure?'),
content: new Text('Do you want to exit exit Video Call?'),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.pop(_scaffoldKey.currentContext!),
child: new Text('No'),
),
TextButton(
onPressed: () async {
await Screen.keepOn(false);
await _serverHandler.leaveChannel(channelId!);
await _engine?.leaveChannel();
Navigator.pop(_scaffoldKey.currentContext!);
Navigator.pop(_scaffoldKey.currentContext!);
},
child: new Text('Yes'),
),
],
),
)) ??
false;
}
_userLeftTheCall() async {
return (await showDialog(
context: _scaffoldKey.currentContext!,
builder: (context) => new AlertDialog(
title: new Text('Doctor Left'),
content: new Text('Doctor left this call please join Again'),
actions: <Widget>[
TextButton(
onPressed: () async {
// await _serverHandler.leaveChannel(channelId!);
await Screen.keepOn(false);
await _engine?.leaveChannel();
Navigator.pop(_scaffoldKey.currentContext!);
Navigator.pop(_scaffoldKey.currentContext!);
// Navigator.of(context).pop(true);
},
child: new Text('Okay'),
),
],
),
)) ?? false;
}
}
Please ignore things which are not relevent. Also the log is too long to share, the log keeps on running during the entire video call.
Mobile Screenshot
Thank You
The app itself works well. The product is added to the cart, but when you go to the cart page, this error appears. Maybe someone came across. I looked at similar errors, but my solution did not help.
The getter 'totalCartPrice' was called on null. Receiver: null Tried calling: totalCartPrice
enter code here
import 'package:flutter/material.dart';
import 'package:food_course/scr/helpers/order.dart';
import 'package:food_course/scr/helpers/style.dart';
import 'package:food_course/scr/models/cart_item.dart';
import 'package:food_course/scr/models/products.dart';
import 'package:food_course/scr/providers/app.dart';
import 'package:food_course/scr/providers/user.dart';
import 'package:food_course/scr/widgets/custom_text.dart';
import 'package:food_course/scr/widgets/loading.dart';
import 'package:provider/provider.dart';
import 'package:uuid/uuid.dart';
class CartScreen extends StatefulWidget {
#override
_CartScreenState createState() => _CartScreenState();
}
class _CartScreenState extends State<CartScreen> {
final _key = GlobalKey<ScaffoldState>();
OrderServices _orderServices = OrderServices();
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
final app = Provider.of<AppProvider>(context);
return Scaffold(
key: _key,
appBar: AppBar(
iconTheme: IconThemeData(color: black),
backgroundColor: white,
elevation: 0.0,
title: CustomText(text: "Shopping Cart"),
leading: IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pop(context);
}),
),
backgroundColor: white,
body: app.isLoading ? Loading() : ListView.builder(
itemCount: user.userModel.cart.length,
itemBuilder: (_, index) {
return Padding(
padding: const EdgeInsets.all(16),
child: Container(
height: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: white,
boxShadow: [
BoxShadow(
color: red.withOpacity(0.2),
offset: Offset(3, 2),
blurRadius: 30)
]),
child: Row(
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
topLeft: Radius.circular(20),
),
child: Image.network(
user.userModel.cart[index].image,
height: 120,
width: 140,
fit: BoxFit.fill,
),
),
SizedBox(
width: 10,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RichText(
text: TextSpan(children: [
TextSpan(
text: user.userModel.cart[index].name+ "\n",
style: TextStyle(
color: black,
fontSize: 20,
fontWeight: FontWeight.bold)),
TextSpan(
text: "\$${user.userModel.cart[index].price / 100} \n\n",
style: TextStyle(
color: black,
fontSize: 18,
fontWeight: FontWeight.w300)),
TextSpan(
text: "Quantity: ",
style: TextStyle(
color: grey,
fontSize: 16,
fontWeight: FontWeight.w400)),
TextSpan(
text: user.userModel.cart[index].quantity.toString(),
style: TextStyle(
color: primary,
fontSize: 16,
fontWeight: FontWeight.w400)),
]),
),
IconButton(
icon: Icon(
Icons.delete,
color: red,
),
onPressed: ()async{
app.changeLoading();
bool value = await user.removeFromCart(cartItem: user.userModel.cart[index]);
if(value){
user.reloadUserModel();
print("Item added to cart");
_key.currentState.showSnackBar(
SnackBar(content: Text("Removed from Cart!"))
);
app.changeLoading();
return;
}else{
print("ITEM WAS NOT REMOVED");
app.changeLoading();
}
})
],
),
)
],
),
),
);
}),
bottomNavigationBar: Container(
height: 70,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
RichText(
text: TextSpan(children: [
TextSpan(
text: "Total: ",
style: TextStyle(
color: grey,
fontSize: 22,
fontWeight: FontWeight.w400)),
TextSpan(
text: " \$${user.userModel.totalCartPrice / 100}",
style: TextStyle(
color: primary,
fontSize: 22,
fontWeight: FontWeight.normal)),
]),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: primary),
child: FlatButton(
onPressed: () {
if(user.userModel.totalCartPrice == 0){
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)), //this right here
child: Container(
height: 200,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Your cart is emty', textAlign: TextAlign.center,),
],
),
],
),
),
),
);
});
return;
}
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20.0)), //this right here
child: Container(
height: 200,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('You will be charged \$${user.userModel.totalCartPrice / 100} upon delivery!', textAlign: TextAlign.center,),
SizedBox(
width: 320.0,
child: RaisedButton(
onPressed: () async{
var uuid = Uuid();
String id = uuid.v4();
_orderServices.createOrder(
userId: user.user.uid,
id: id,
description: "Some random description",
status: "complete",
totalPrice: user.userModel.totalCartPrice,
cart: user.userModel.cart
);
for(CartItemModel cartItem in user.userModel.cart){
bool value = await user.removeFromCart(cartItem: cartItem);
if(value){
user.reloadUserModel();
print("Item added to cart");
_key.currentState.showSnackBar(
SnackBar(content: Text("Removed from Cart!"))
);
}else{
print("ITEM WAS NOT REMOVED");
}
}
_key.currentState.showSnackBar(
SnackBar(content: Text("Order created!"))
);
Navigator.pop(context);
},
child: Text(
"Accept",
style: TextStyle(color: Colors.white),
),
color: const Color(0xFF1BC0C5),
),
),
SizedBox(
width: 320.0,
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Reject",
style: TextStyle(color: Colors.white),
),
color: red
),
)
],
),
),
),
);
});
},
child: CustomText(
text: "Check out",
size: 20,
color: white,
weight: FontWeight.normal,
)),
)
],
),
),
),
);
}
}
USER.dart
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:food_course/scr/helpers/order.dart';
import 'package:food_course/scr/helpers/user.dart';
import 'package:food_course/scr/models/cart_item.dart';
import 'package:food_course/scr/models/order.dart';
import 'package:food_course/scr/models/products.dart';
import 'package:food_course/scr/models/user.dart';
import 'package:uuid/uuid.dart';
enum Status{Uninitialized, Authenticated, Authenticating, Unauthenticated}
class UserProvider with ChangeNotifier{
FirebaseAuth _auth;
FirebaseUser _user;
Status _status = Status.Uninitialized;
Firestore _firestore = Firestore.instance;
UserServices _userServicse = UserServices();
OrderServices _orderServices = OrderServices();
UserModel _userModel;
// getter
UserModel get userModel => _userModel;
Status get status => _status;
FirebaseUser get user => _user;
// public variables
List<OrderModel> orders = [];
final formkey = GlobalKey<FormState>();
TextEditingController email = TextEditingController();
TextEditingController password = TextEditingController();
TextEditingController name = TextEditingController();
UserProvider.initialize(): _auth = FirebaseAuth.instance{
_auth.onAuthStateChanged.listen(_onStateChanged);
}
Future<bool> signIn()async{
try{
_status = Status.Authenticating;
notifyListeners();
await _auth.signInWithEmailAndPassword(email: email.text.trim(), password: password.text.trim());
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
Future<bool> signUp()async{
try{
_status = Status.Authenticating;
notifyListeners();
await _auth.createUserWithEmailAndPassword(email: email.text.trim(), password: password.text.trim()).then((result){
_firestore.collection('users').document(result.user.uid).setData({
'name':name.text,
'email':email.text,
'uid':result.user.uid,
"likedFood": [],
"likedRestaurants": []
});
});
return true;
}catch(e){
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
Future signOut()async{
_auth.signOut();
_status = Status.Unauthenticated;
notifyListeners();
return Future.delayed(Duration.zero);
}
void clearController(){
name.text = "";
password.text = "";
email.text = "";
}
Future<void> reloadUserModel()async{
_userModel = await _userServicse.getUserById(user.uid);
notifyListeners();
}
Future<void> _onStateChanged(FirebaseUser firebaseUser) async{
if(firebaseUser == null){
_status = Status.Unauthenticated;
}else{
_user = firebaseUser;
_status = Status.Authenticated;
_userModel = await _userServicse.getUserById(user.uid);
}
notifyListeners();
}
Future<bool> addToCard({ProductModel product, int quantity})async{
print("THE PRODUC IS: ${product.toString()}");
print("THE qty IS: ${quantity.toString()}");
try{
var uuid = Uuid();
String cartItemId = uuid.v4();
List cart = _userModel.cart;
// bool itemExists = false;
Map cartItem ={
"id": cartItemId,
"name": product.name,
"image": product.image,
"restaurantId": product.restaurantId,
"totalRestaurantSale": product.price * quantity,
"productId": product.id,
"price": product.price,
"quantity": quantity
};
CartItemModel item = CartItemModel.fromMap(cartItem);
// if(!itemExists){
print("CART ITEMS ARE: ${cart.toString()}");
_userServicse.addToCart(userId: _user.uid, cartItem: item);
// }
return true;
}catch(e){
print("THE ERROR ${e.toString()}");
return false;
}
}
getOrders()async{
orders = await _orderServices.getUserOrders(userId: _user.uid);
notifyListeners();
}
Future<bool> removeFromCart({CartItemModel cartItem})async{
print("THE PRODUC IS: ${cartItem.toString()}");
try{
_userServicse.removeFromCart(userId: _user.uid, cartItem: cartItem);
return true;
}catch(e){
print("THE ERROR ${e.toString()}");
return false;
}
}
}
main.dart
import 'package:flutter/material.dart';
import 'package:food_course/scr/providers/app.dart';
import 'package:food_course/scr/providers/category.dart';
import 'package:food_course/scr/providers/product.dart';
import 'package:food_course/scr/providers/restaurant.dart';
import 'package:food_course/scr/providers/user.dart';
import 'package:food_course/scr/screens/home.dart';
import 'package:food_course/scr/screens/login.dart';
import 'package:food_course/scr/screens/splash.dart';
import 'package:food_course/scr/widgets/loading.dart';
import 'package:provider/provider.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(MultiProvider(
providers: [
ChangeNotifierProvider.value(value: AppProvider()),
ChangeNotifierProvider.value(value: UserProvider.initialize()),
ChangeNotifierProvider.value(value: CategoryProvider.initialize()),
ChangeNotifierProvider.value(value: RestaurantProvider.initialize()),
ChangeNotifierProvider.value(value: ProductProvider.initialize()),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Food App',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: ScreensController())));
}
class ScreensController extends StatelessWidget {
#override
Widget build(BuildContext context) {
final auth = Provider.of<UserProvider>(context);
switch (auth.status) {
case Status.Uninitialized:
return Splash();
case Status.Unauthenticated:
case Status.Authenticating:
return LoginScreen();
case Status.Authenticated:
return Home();
default:
return LoginScreen();
}
}
}
Im doing an integration test in Flutter and in the application I open the camera, but I don't know how to tap on the button to do the photo, anyone know how can I search for this button?
Here is the code if the app where you can choose between pic a photo with the camera or choose one picture of your gallery
import 'dart:io';
import 'package:permission_handler/permission_handler.dart';
import 'package:random_string/random_string.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:image_cropper/image_cropper.dart';
import 'package:image_picker/image_picker.dart';
import 'package:modal_progress_hud/modal_progress_hud.dart';
import 'package:rosita/language/firebase_remote.dart';
import 'package:rosita/api/api_provider.dart';
import 'package:rosita/constants/common.dart';
import 'package:rosita/model/image_object.dart';
import 'package:rosita/model/senior_user.dart';
import 'package:rosita/modules/widgets/button_ui.dart';
import 'package:rosita/rosita.dart';
class AddProfileImageScreen extends StatefulWidget {
const AddProfileImageScreen({Key key, this.seniorUser}) : super(key: key);
final SeniorUser seniorUser;
#override
_AddProfileImageScreenState createState() => _AddProfileImageScreenState();
}
class _AddProfileImageScreenState extends State<AddProfileImageScreen> {
bool _isProcessing = false;
File _image;
bool _enableButton = false;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: ModalProgressHUD(
inAsyncCall: _isProcessing,
color: Colors.transparent,
progressIndicator: const CircularProgressIndicator(
strokeWidth: 2.0,
),
child: Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
constraints: BoxConstraints(
minHeight: MediaQuery.of(context).size.height,
minWidth: MediaQuery.of(context).size.width),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
darkSubtitleText('choose_profile_picture', context),
Expanded(
child: Center(
child: SizedBox(
width: 100,
height: 100,
child: Card(
shape: RoundedRectangleBorder(
side: const BorderSide(
color: AppTheme.purpleColor,
width: 4,
),
borderRadius: BorderRadius.circular(60.0),
),
elevation: 0,
color: Theme.of(context).dividerColor,
child: _image == null
? (widget.seniorUser != null &&
widget.seniorUser.profileImage != null &&
widget.seniorUser.profileImage.imageUrl !=
'')
? CachedNetworkImage(
imageUrl:
widget.seniorUser.profileImage.imageUrl,
placeholder:
(BuildContext context, String url) =>
Image.asset(ConstantsData.appIcon),
errorWidget: (BuildContext context,
String url, error) =>
const Icon(Icons.error),
fit: BoxFit.cover,
)
: Image.asset(ConstantsData.appIcon)
: Image.file(_image),
),
),
),
),
ButtonUI(
buttonName: 'ProfilePhotoFromCameraButton',
key: const Key(Keys.cameraButton),
isTrack: true,
color: AppTheme.primaryColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('take_a_photo_with_your_camera'),
textAlign: TextAlign.center,
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
getImage(isGallery: false);
},
),
verticalSpacer(),
ButtonUI(
buttonName: 'ProfilePhotoFromGalleryButton',
key: const Key(Keys.galleryButton),
isTrack: true,
color: AppTheme.primaryColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('choose_from_gallery'),
textAlign: TextAlign.center,
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
getImage(isGallery: true);
},
),
verticalSpacer(),
if (_image != null || _enableButton)
ButtonUI(
buttonName: 'ProfilePhotoUploadButton',
key: const Key(Keys.uploadButton),
isTrack: true,
color: AppTheme.purpleColor,
body: Center(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
FireText.of('continue_txt'),
style: Theme.of(context)
.primaryTextTheme
.subtitle2
.copyWith(
color: Theme.of(context).backgroundColor,
),
),
),
),
onTap: () {
_uploadAllInformation();
},
),
],
),
),
),
),
);
}
Future<void> getImage({bool isGallery = true}) async {
await <Permission>[Permission.camera, Permission.storage].request();
if (await Permission.storage.status != PermissionStatus.granted) {
setState(() {
_enableButton = true;
});
return;
}
if (!isGallery &&
await Permission.camera.status != PermissionStatus.granted) {
setState(() {
_enableButton = true;
});
return;
}
final image = await ImagePicker.pickImage(
source: isGallery ? ImageSource.gallery : ImageSource.camera);
if (image == null) return;
final cropimage = await cropImage(image);
if (cropimage == null) return;
setState(() {
_image = cropimage;
});
}
Future<File> cropImage(File imageFile) async {
final croppedFile = await ImageCropper.cropImage(
androidUiSettings: AndroidUiSettings(
statusBarColor: Theme.of(context).primaryColor,
toolbarColor: Theme.of(context).primaryColor,
toolbarWidgetColor: Theme.of(context).backgroundColor,
),
sourcePath: imageFile.path,
cropStyle: CropStyle.circle,
aspectRatio: const CropAspectRatio(ratioX: 1, ratioY: 1),
maxWidth: 420,
maxHeight: 420,
);
return croppedFile;
}
Future<void> _uploadAllInformation() async {
setState(() {
_isProcessing = true;
});
widget.seniorUser.documentId =
(await FirebaseAuth.instance.currentUser()).uid;
widget.seniorUser.referralCode =
'RO-' + randomAlphaNumeric(8).toUpperCase();
widget.seniorUser.enterReferralCode = deepLinkReferralCode;
await ApiProvider().createSeniorUserProfile(widget.seniorUser);
endRegister = true;
if (!_enableButton) {
final imageData = await updateProfilePic(widget.seniorUser);
await ApiProvider()
.updateRositaProfileImage(imageData, widget.seniorUser.documentId);
}
setState(() {
_isProcessing = false;
});
Rosita.restartApp(context);
}
Future<ImageObject> updateProfilePic(SeniorUser user) async {
final imagename = DateTime.now().millisecondsSinceEpoch.toString() + '.jpg';
final url = await ApiProvider()
.updateProfilePic('rositapics/${user.documentId}/' + imagename, _image);
final profileImage = ImageObject();
profileImage.imageUrl = url.toString();
profileImage.firebaseStoregPath =
'rositapics/${user.documentId}/' + imagename;
profileImage.imageName = imagename;
return profileImage;
}
}