display "location services denied" pop up with setting - flutter

i'm using permission_handler package to get the location
i want to display this message is the user denied the location
like this image
check image
this is the code
Future<bool> getUserLocation() async {
final loc = await Permission.location.request();
final locWhenUse = await Permission.locationWhenInUse.request();
try {
if (loc == PermissionStatus.permanentlyDenied ||
locWhenUse == PermissionStatus.permanentlyDenied) {
//i want to show the pop up like image here
setState(() {
error = "Please enable location permission".tr;
});
return false;
}
if (await userLocation.getUserLocation() == null) {
throw Exception();
}
} on Exception {
setState(() {
error = "Something went wrong".tr;
});
return false;
} catch (e) {
setState(() {
error = "Error Happened while Getting your Location".tr;
});
return false;
}
return true;
}

getLocation() async {
Location location = Location();
bool _serviceEnabled;
PermissionStatus _permissionGranted;
LocationData _locationData;
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
_serviceEnabled = await location.requestService();
if (!_serviceEnabled) {
return;
}
}
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied) {
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted) {
return;
}
}
_locationData = await location.getLocation();
print(_locationData.longitude)
}

i solved the problem by create a custom dialog like the image i attached
so if the premission is denied, i will show this dialog
Future<bool> showAlertDialog({
required BuildContext context,
}) async {
if (!Platform.isIOS) {
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Location Services Disabled'),
content: const Text('You need to enable Location Services in Setting'),
actions: <Widget>[
TextButton(
child: const Text('Cancel'),
onPressed: () => Navigator.of(context).pop(false),
),
TextButton(
child: const Text('Setting'),
onPressed: () {
openAppSettings();
Navigator.of(context).pop(false);
},
),
],
),
);
}
// todo : showDialog for ios
return await showCupertinoDialog(
context: context,
builder: (context) => CupertinoAlertDialog(
title: const Text('Location Services Disabled'),
content: const Text('You need to enable location services in setting'),
actions: <Widget>[
CupertinoDialogAction(
child: const Text('Cancel'),
onPressed: () => Navigator.of(context).pop(false),
),
CupertinoDialogAction(
child: const Text('Setting'),
onPressed: () {
openAppSettings();
Navigator.of(context).pop(false);
},
),
],
),
);
}

Related

error dart migration tool - Expected a value of type '(UserCredential) => FutureOr<UserCredential>', but got one of type '(dynamic) => Future<Null>'

I try to figure out, how I can get my database request "signUpUser" to work again. Before I used null-safety my code worked fine, but now after using the dart migration tool I am getting the error:
Expected a value of type '(UserCredential) => FutureOr<UserCredential>', but got one of type '(dynamic) => Future<Null>'
How can I fix this error? I am really desperate, I don't understand this error and I need to have a working code. If I can't fix this error, then I must use a not null-safety code, so I hope you can help me.
The registration works fine, just the database request is throwing an error.
Database request:
Future<bool> signUpUser(String username, String email, String password,
String firstName, String lastName, String? birthday, String? gender) async {
try {
_status = Status.Authenticating;
notifyListeners(); //changing status
FirebaseApp secondaryApp = await Firebase.initializeApp(
name: 'Secondary',
options: Firebase.app().options,
);
try {
UserCredential credential = await FirebaseAuth.instanceFor(
app: secondaryApp)
.createUserWithEmailAndPassword(email: email, password: password)
.then((result) async {
//User user = result.user;
_userServices.createUser(
uid: result.user!.uid,
username: username,
email: email,
firstName: firstName,
lastName: lastName,
birthday: birthday,
gender: gender,
status: 'aktiv',
role: 'User',
);
}as FutureOr<UserCredential> Function(UserCredential));
if (credential.user == null) {
throw 'An error occured. Please try again.';
}
await credential.user!.sendEmailVerification();
} on FirebaseAuthException catch (e) {
print(e);
}
await secondaryApp.delete();
return true;
} catch (e) {
_status = Status.Unauthenticated;
notifyListeners();
print(e.toString());
return false;
}
}
registration:
InkWell(
onTap: () async {
final Formkey = _formKeys.currentState;
print('pw confirmed:' +
passwordConfirmedController.text.trim());
print('pw:' + passwordController.text.trim());
//password and passworconfirm check
if (passwordConfirmedController.text.trim() ==
passwordController.text.trim()) {
//checking if all textfields are not empty
if (usernameController.text.trim() != null &&
emailController.text.trim() != null &&
passwordController.text.trim() != null &&
passwordConfirmedController.text.trim() !=
null &&
firstNameController.text.trim() != null &&
lastNameController.text.trim() != null &&
isDateSelected != false &&
_genderSelected != null) {
// checking if all textfields are valid
if (Formkey!.validate()) {
print('validate okok');
// input is the authProvider.emailController, which provides the written email
// output are all the user informations in a Map<String, dynamic>
// used to check the status and role of the user
mapUserinformations =
await authProvider.getUserByEmail(
emailController.text.trim());
//when email exist, then check status
if (mapUserinformations!.isNotEmpty) {
print('email is already existing');
mapUsernameExist = await authProvider.UsernameExist(mapUserinformations!['username']);
//if username already exist, then print error otherwise it is free
if (mapUsernameExist!.isEmpty){
print('username is free');
//checking if status is deleted
if (mapUserinformations!['status'] ==
'gelöscht') {
print('email is deleted');
//recreate the deleted user
try {
//update user informations
await authProvider.updateUserSignup(
mapUserinformations!['uid'],
mapUserinformations!['username'],
mapUserinformations!['email'],
mapUserinformations!['firstName'],
mapUserinformations!['lastName'],
_birthDateInString,
_genderSelected,
'User');
//input: emailcontroller, output: send password reset link
try {
await FirebaseAuth.instance
.sendPasswordResetEmail(
email: emailController.text
.trim());
} on FirebaseAuthException catch (e) {
print(e);
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(
e.message.toString()),
);
});
}
clearController();
isDateSelected = false;
_genderSelected = null;
// deleted user got recreated - now print a message that the registration process is completed
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Registration abgeschlossen.\nDein Account war gelöscht, daher wurde dir eine E-Mail zum zurücksetzen deines persönlichen Passworts zugesendet.\nNachdem du das Passwort abgeändert hast, kannst du "
"dich nun in unserer App einloggen.",
textAlign:
TextAlign.center),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context)
.pop();
},
)
],
);
});
} catch (e) {
print(e);
}
}
// email is already existing and the status is not deleted
else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Error: Es existiert schon ein Account mit dieser E-Mail Adresse."),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context)
.pop();
},
)
],
);
});
}
}else{
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Error: Der Username wird bereits verwendet. Bitte benutze einen anderen."),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
}
// email not existing in database -> mapUserinformations = null
else {
try {
print('email existiert noch nicht');
// sign up user in database with the birthday and gender + all controllers from authProvider
await authProvider.signUpUser(
usernameController.text.trim(),
emailController.text.trim(),
passwordController.text.trim(),
firstNameController.text.trim(),
lastNameController.text.trim(),
_birthDateInString,
_genderSelected);
clearController();
isDateSelected = false;
_genderSelected = null;
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Registration abgeschlossen. Du kannst dich nun in unserer App einloggen."),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context)
.pop();
},
)
],
);
});
} catch (e) {
print(e);
}
}
} else {
print('validate email notgoodatall');
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Error: Bitte überprüfe, ob alle deine Eingaben ein gültiges Format aufweisen."),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
}
// not all Textfields/Buttons are filled
else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Error: Registration gescheitert! Bitte alle Felder ausfüllen."),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
return;
}
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text(
"Error: Passwort und Passwort wiederholen müssen gleich sein!"),
actions: [
TextButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
}
},
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(20)),
alignment: Alignment.center,
width: double.maxFinite,
padding: EdgeInsets.symmetric(vertical: 16),
child: Text(
"Registrieren",
style: TextStyle(
color: Colors.white,
),
))),
#jamesdlin Answered my question. The edited database request looks like this:
Future<bool> signUp(
String username,String email,String password,String firstName,
String lastName,String? birthday,String? gender,String? role) async {
try {
FirebaseApp secondaryApp = await Firebase.initializeApp(
name: 'Secondary',
options: Firebase.app().options,
);
try {
UserCredential? credential = await FirebaseAuth.instanceFor(
app: secondaryApp)
.createUserWithEmailAndPassword(email: email, password: password);
_userServices.createUser(
uid: await credential.user!.uid,
username: username,
email: email,
firstName: firstName,
lastName: lastName,
birthday: birthday,
gender: gender,
status: 'aktiv',
role: role,
);
if (credential.user == null) {
throw 'An error occured. Please try again.';
}
await credential.user!.sendEmailVerification();
print('send verfication');
await secondaryApp.delete();
print('deleted instance');
} on FirebaseAuthException catch (e) {
print(e);
}
return true;
} catch (e) {
print(e.toString());
return false;
}
}

Flutter response after scan

I need help regrading the scan using qr_code_scanner, the scanner successful but don't know how to call response either success or not. here example.
void _onQRViewCreated(QRViewController controller) {
this.controller = controller;
controller.scannedDataStream.listen((scanData) async {
controller.pauseCamera();
var response = await ScanApi.scan(scanData.code);
print(response);
result = scanData;
setState(() {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("check"),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text('Data: ${scanData.code}'),
],
),
),
actions: <Widget>[
TextButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
).then((value) => controller.resumeCamera());
and my example api post to get reponse.
static Future<dynamic> scan() async {
final url = Uri.parse(url);
final response = await http.post(url);
if (response.statusCode == 200) {
final String msg = json.decode(response.body)["status"];
print(msg);
return msg;
} else {
throw Exception();
}}
code like this and calling this class into widget.
class ScanResponse {
String status;
ScanResponse({this.status});
factory ScanResponse.fromJson(Map<String, dynamic> jsonData) {
return ScanResponse(
status: jsonData['status'],
);
}
}

How to open a link automatically after Scanning QR Code in Flutter without clicking some Button

I have a little question about QR Code Scanning in Flutter. How to open a URL website after successfully reading data from the QR Code?
I use this package for using QR Code, and this for open a URL and this is my function to checking the value of data from QR code is a URL or not and if it's a URL, then run the function to open the website.
checkingValue() {
if (_result != null || _result != "") {
if (_result.contains("https") || _result.contains("http")) {
return _launchURL(_result);
} else {
Toast.show("Invalide URL", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
}
} else {
return null;
}
}
_launchURL(String urlQRCode) async {
String url = urlQRCode;
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
The _result variable is a String to get a value from QR code data.
And this is the full of my code:
class _ScannerPageState extends State<ScannerPage> {
String _password;
String _result = "";
Future _scanQR() async {
try {
String qrResult = await BarcodeScanner.scan();
setState(() {
_result = qrResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.CameraAccessDenied) {
setState(() {
_result = "Camera permission was denied";
Toast.show(_result, context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
});
} else {
setState(() {
_result = "Unknown Error $ex";
Toast.show(_result, context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
});
}
} on FormatException {
setState(() {
_result = "You pressed the back button before scanning anything";
Toast.show(_result, context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
});
} catch (ex) {
setState(() {
_result = "Unknown Error $ex";
Toast.show(_result, context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
});
}
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () {
return showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return PopUp(
content: "Are you sure want to exit?",
cancelText: "No",
acceptText: "Yes",
onTapCancel: () => Navigator.of(context).pop(),
onTapAccept: () async {
await SessionManager().removeSession();//
await SystemNavigator.pop();
},
);
}
);
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.lock),
onPressed: () {
Navigator.pushNamed(context, '/login');
},
),
],
),
body: Column(
children: <Widget>[
Text(_result.contains("https") || _result.contains("http") ? _result : "Invalid URL"),
],
),
floatingActionButton: FloatingActionButton.extended(
icon: Icon(Icons.camera_alt),
label: Text("Scan"),
onPressed: () => _scanQR(),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
),
);
}
checkingValue() {
if (_result != null || _result != "") {
if (_result.contains("https") || _result.contains("http")) {
return _launchURL(_result);
} else {
Toast.show("Invalide URL", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
}
} else {
return null;
}
}
_launchURL(String urlQRCode) async {
String url = urlQRCode;
if (await canLaunch(url)) {
await launch(url);
} else {
throw 'Could not launch $url';
}
}
}
So, where I put the checkingValue() function for running it after scanning the QR Code?
Pass qrResult to checkingValue method
Future _scanQR() async {
try {
String qrResult = await BarcodeScanner.scan();
checkingValue(qrResult);
//....
}
checkingValue method
checkingValue(String url) {
//...
}
or call checkingValue() after
setState(() {_result = qrResult;});
checkingValue();
//...

How to check user is logged in or not with phone authentication using firebase in flutter?

Here, I'm authenticated through the phone number with OTP code using firebase but
after login succeeded, it navigated through home page but when I click on back
it drags me login Screen.
here, the code I have tried, but it doesn't work
#override
void initState() {
super.initState();
isSignedIn();
}
void isSignedIn() async {
this.setState(() {
isLoading = true;
});
firebaseAuth.currentUser().then((user){
if(user !=null){
Navigator.of(context).pushReplacementNamed('/homepage');
}else{
verifyPhone();
}
});
this.setState(() {
isLoading = false;
});
}
Method for getting OTP code
Future<void> verifyPhone()async{
final PhoneCodeAutoRetrievalTimeout autoRetrieval=(String verId){
this.verificationId=verId;
};
final PhoneCodeSent smsCodeSent=(String verId, [int forceCodeResend]){
this.verificationId=verId;
smsCodeDialog(context).then((value){
print("Signed in");
});
};
final PhoneVerificationCompleted verificationCompleted = (AuthCredential credential) {
print("verified");
};
final PhoneVerificationFailed verfifailed=(AuthException exception){
print("${exception.message}");
};
await firebaseAuth.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieval,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 10),
verificationCompleted: verificationCompleted,
verificationFailed: verfifailed
);
}
here the dialog box for sign in with OTP code
Future<bool> smsCodeDialog(BuildContext context){
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context){
return new AlertDialog(
title: Text('Enter sms Code'),
content: TextField(
onChanged: (value){
this.smsCode=value;
},
),
contentPadding: const EdgeInsets.all(10.0),
actions: <Widget>[
new FlatButton(
child: Text("Done"),
onPressed: (){
firebaseAuth.currentUser().then((user){
if(user !=null){
Navigator.of(context).pop();
Navigator.of(context).pushReplacementNamed('/homepage');
}else{
Navigator.of(context).pop();
signIn();
}
});
},
)
],
);
}
);
}
method for Sign in with phone number
signIn()async{
AuthCredential credential= PhoneAuthProvider.getCredential(
verificationId: verificationId,
smsCode: smsCode
);
await firebaseAuth.signInWithCredential(credential).then((user){
Navigator.of(context).pushReplacementNamed('/homepage');
print('signed in with phone number successful: user -> $user');
}).catchError((onError){
print(onError);
});
}
`
Welcome Shruti Ramnandan Sharma in Stackoverflow and Flutter dev.
Your code seems to working fine with me, I coded for you a one page dart that can test you the whole code with fixing your problem with going back to Login or VerifyPhone page.
Note: I changed your order of code in verifyPhone() method.
And Changed Navigator.of(context).pushReplacementNamed('/homepage'); to
Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => HomeRoute()));
The whole code here
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
void main() => runApp(VerifyPhoneRoute());
class VerifyPhoneRoute extends StatefulWidget {
#override
_VerifyPhoneRouteState createState() {
return _VerifyPhoneRouteState();
}
}
class _VerifyPhoneRouteState extends State<VerifyPhoneRoute> {
bool isLoading = false;
FirebaseAuth firebaseAuth = FirebaseAuth.instance;
String verificationId;
String phoneNo = "Your number here";
String smsCode;
#override
void initState() {
super.initState();
isSignedIn();
}
void isSignedIn() async {
this.setState(() {
isLoading = true;
});
firebaseAuth.currentUser().then((user) {
if (user != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
} else {
verifyPhone();
}
});
this.setState(() {
isLoading = false;
});
}
Future<void> verifyPhone() async {
final PhoneVerificationCompleted verificationCompleted =
(AuthCredential credential) {
print("verified");
};
final PhoneVerificationFailed verifyFailed = (AuthException exception) {
print("${exception.message}");
};
final PhoneCodeSent smsCodeSent = (String verId, [int forceCodeResend]) {
this.verificationId = verId;
smsCodeDialog(context).then((value) {
print("Signed in");
});
};
final PhoneCodeAutoRetrievalTimeout autoRetrieval = (String verId) {
this.verificationId = verId;
};
await firebaseAuth.verifyPhoneNumber(
phoneNumber: this.phoneNo,
codeAutoRetrievalTimeout: autoRetrieval,
codeSent: smsCodeSent,
timeout: const Duration(seconds: 10),
verificationCompleted: verificationCompleted,
verificationFailed: verifyFailed);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Inapp Plugin by dooboolab'),
),
body: Center(
child: RaisedButton(
child: Text("Verify"),
onPressed: () {
verifyPhone();
}),
),
),
);
}
Future<bool> smsCodeDialog(BuildContext context) {
return showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return new AlertDialog(
title: Text('Enter sms Code'),
content: TextField(
onChanged: (value) {
this.smsCode = value;
},
),
contentPadding: const EdgeInsets.all(10.0),
actions: <Widget>[
new FlatButton(
child: Text("Done"),
onPressed: () {
firebaseAuth.currentUser().then((user) {
if (user != null) {
Navigator.of(context).pop();
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
} else {
Navigator.of(context).pop();
signIn();
}
});
},
)
],
);
});
}
signIn() async {
AuthCredential credential = PhoneAuthProvider.getCredential(
verificationId: verificationId, smsCode: smsCode);
await firebaseAuth.signInWithCredential(credential).then((user) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomeRoute()),
);
print('signed in with phone number successful: user -> $user');
}).catchError((onError) {
print(onError);
});
}
}
class HomeRoute extends StatefulWidget {
#override
_HomeRouteState createState() {
return _HomeRouteState();
}
}
class _HomeRouteState extends State<HomeRoute> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Flutter Inapp Plugin by dooboolab'),
),
body: Center(
child: Text("Welcome There."),
),
),
);
}
}
This code works fine with me. So if there's any problem happened with you again, don't be hesitate to comment on this answer. And if this answered your question and solve your problem, please make it as answer.
Use method below by pass verificationID come from API firebase when code sent and code enter by user, so if method return FirebaseUser the code is correct if return null the code enter by user is not correct
Future<FirebaseUser> getUserFromCodePhone(String code, String verificationID) async {
FirebaseAuth mAuth = FirebaseAuth.instance;
AuthCredential phoneAuthCredential = PhoneAuthProvider.getCredential(
verificationId: verificationID, smsCode: code);
try {
AuthResult result = await mAuth.signInWithCredential(phoneAuthCredential);
FirebaseUser currentUser = await mAuth.currentUser();
if (currentUser != null && result.user.uid == currentUser.uid) {
return currentUser;
} else {
return null;
}
} on PlatformException catch (_) {}
return null;
}
How it work ? : when use signInWithCredential method if code passed to
AuthCredential is false then the method will throw PlatformException
so out from try block and return null

How to use image_picker in flutter

I am confused about how to use image_picker, this is how I use it in my application (like in many tutorials):
class AddDialogState extends State<AddDialog> {
File galleryFile;
Widget _onlyStatus() {
getLocalImage() async {
var _galleryFile = await ImagePicker.pickImage(
source: ImageSource.gallery
};
setState(() {
galleryFile = _galleryFile;
});
print(_galleryFile.path);
}
return Column(
........
FlatButton.icon(
onPressed: () {
getLocalImage();
}
)
)
}
#override
Widget build(BuildContext context) {
// fullscreen dialog
.........
body: _onlyStatus()
}
}
The problem was, the above code doesn't start ImagePicker, when i click the FlatButton, the above code just produce an error the getter 'path' was called on null, it doesn't start any new activity related to gallery, so what's wrong with my code?
Actually pickImage() is deprecated now. So you have to use ImagePicker.getImage(source: ImageSource.gallery)
Click here for more
void getImage(ImageSource imageSource) async {
PickedFile imageFile = await picker.getImage(source: imageSource);
if (imageFile == null) return;
File tmpFile = File(imageFile.path);
final appDir = await getApplicationDocumentsDirectory();
final fileName = basename(imageFile.path);
tmpFile = await tmpFile.copy('${appDir.path}/$fileName');
setState(() {
_image = tmpFile;
});
}
The code also store image file in device directory. Path pacakage is also used.
Here is my example you only need to call the SelectionItem and pass the required parameters and it's done, also it includes support for Android and iOS.
class SelectionItem {
String text;
GestureTapCallback action;
SelectionItem({
this.text,
this.action,
});
}
Widget _getOptionWidget(SelectionItem item) {
return SimpleDialogOption(
onPressed: item.action,
child: Text(item.text),
);
}
Widget _getCupertinoOptionWidget(SelectionItem item) {
return CupertinoActionSheetAction(
onPressed: item.action,
child: Text(item.text),
);
}
showSelector(
BuildContext context, {
String title,
List<SelectionItem> actions,
}) {
bool isAndroid = Injector.instance.platform == Platform.ANDROID;
if (isAndroid) {
final items = actions.map((action) => _getOptionWidget(action)).toList();
return SimpleDialog(
title: Text(title),
children: items,
);
} else {
final items =
actions.map((action) => _getCupertinoOptionWidget(action)).toList();
return Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
CupertinoActionSheet(
title: Text(title),
actions: items,
cancelButton: CupertinoActionSheetAction(
onPressed: () {
NavigationUtils.pop(context);
},
child: Text("Cancel"),
),
),
],
);
}
}
your showDialog should be something like this:
Container(
width: 300,
height: 300,
child: GestureDetector(
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) => showSelector(
context,
"Select",
actions: [
SelectionItem(
"Camera",
action: () {
getImage(ImageSource.camera);
Navigator.of(context).pop();
},
),
SelectionItem(
"Gallery",
action: () {
getImage(ImageSource.gallery);
Navigator.of(context).pop();
},
)
],
),
);
},
),
)
Here is my code for image_picker: ^0.8.4+4 (flutter 2.8.1)
bool hasImage = false;
File? image;
Future getImage(ImageSource source) async {
try {
final image = await ImagePicker().pickImage(source: source);
if (image == null) return;
final imageTemporary = File(image.path);
setState(() {
this.image = imageTemporary;
hasImage = true;
});
} on PlatformException catch (e) {
debugPrint('Failed to pick image: $e');
}
}