I want to Save Contact Number at Mobile storage using Flutter - flutter

I wrote this function to save contact number, but it can't save on local storage
Future _saveContact() async {
Contact contact = Contact();
contact.familyName = 'FreeZone';
contact.phones = [Item(label: "mobile", value: '01752591591')];
contact.emails = [Item(label: "work", value: 'info#34.71.214.132')];
if (await Permission.contacts.request().isGranted) {
await ContactsService.addContact(contact);
print("Contact added successfully");
return contact;
}
}
dependencies:
contacts_service: ^0.6.3
permission_handler: ^8.3.0
How to save contact according to the above-given Name, Number, Email?

I could see 2 plugins in pub.dev that can do this for you in Android and iOS.
flutter_contact - A Flutter plugin to retrieve, create and save contacts and contact-related events on Android and iOS devices.
contacts_service - A Flutter plugin to retrieve and manage contacts on Android and iOS devices.
Please have a look into them.

Add this :
dependencies:
contacts_service: ^0.6.3
then:
import 'package:contacts_service_example/contacts_list_page.dart';
import 'package:contacts_service_example/contacts_picker_page.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
void main() => runApp(ContactsExampleApp());
// iOS only: Localized labels language setting is equal to CFBundleDevelopmentRegion value (Info.plist) of the iOS project
// Set iOSLocalizedLabels=false if you always want english labels whatever is the CFBundleDevelopmentRegion value.
const iOSLocalizedLabels = false;
class ContactsExampleApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
routes: <String, WidgetBuilder>{
'/add': (BuildContext context) => AddContactPage(),
'/contactsList': (BuildContext context) => ContactListPage(),
'/nativeContactPicker': (BuildContext context) => ContactPickerPage(),
},
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
void initState() {
super.initState();
_askPermissions(null);
}
Future<void> _askPermissions(String routeName) async {
PermissionStatus permissionStatus = await _getContactPermission();
if (permissionStatus == PermissionStatus.granted) {
if (routeName != null) {
Navigator.of(context).pushNamed(routeName);
}
} else {
_handleInvalidPermissions(permissionStatus);
}
}
Future<PermissionStatus> _getContactPermission() async {
PermissionStatus permission = await Permission.contacts.status;
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.permanentlyDenied) {
PermissionStatus permissionStatus = await Permission.contacts.request();
return permissionStatus;
} else {
return permission;
}
}
void _handleInvalidPermissions(PermissionStatus permissionStatus) {
if (permissionStatus == PermissionStatus.denied) {
final snackBar = SnackBar(content: Text('Access to contact data denied'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
} else if (permissionStatus == PermissionStatus.permanentlyDenied) {
final snackBar =
SnackBar(content: Text('Contact data not available on device'));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Contacts Plugin Example')),
body: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
ElevatedButton(
child: const Text('Contacts list'),
onPressed: () => _askPermissions('/contactsList'),
),
ElevatedButton(
child: const Text('Native Contacts picker'),
onPressed: () => _askPermissions('/nativeContactPicker'),
),
],
),
),
);
}
}

I think I solved your problem.
_saveContact () async {
// 'without Future' is working
var newPerson = Contact();
// newPerson uses Contact Package
newPerson.givenName = 'FreeZone';
newPerson.phones = [Item(label: "mobile", value: '01752591591')];
newPerson.emails = [Item(label: "work", value: 'info#34.71.214.132')];
if (await Permission.contacts.status.isGranted) {
await ContactsService.addContact(newPerson);
var contacts = await ContactsService.getContacts();
print("Contact added successfully");
return contacts;
// setState(() {
// //setState isn't necessary, it just shows 'contact' directly on a screen.
// name = contacts;
// // I put 'contacts' in 'name' directly
// });
}
}
Actually, I was in trouble using 'newPerson.phones'.
I was wondering how to put my parameter in 'phone number'.
However, with your code, I could know how to write the code.
Thank you and please accept this answer as a small token of my appreciation.
And it is what I wrote you helped.
addPerson (given,family,number) async {
var newPerson = Contact();
newPerson.givenName = given;
newPerson.familyName = family;
newPerson.phones = [Item(label: "mobile", value: number)];
// I wrote 'newPerson.phones = [number];' and it was wrong.
await ContactsService.addContact(newPerson);
// adding newPerson
var contacts = await ContactsService.getContacts();
// call all of contacts
setState(() {
name = contacts;
});
// to show the contacts directly, I use 'setState'.
}

Related

ChangeNotifierProvider does not update the model

i am quite new with flutter. I am trying to add a ChangeNotifierProvider into my app. I use flutter_azure_b2c to log in a user, in order to handle to login outcome I have the following code:
AzureB2C.registerCallback(B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
(result) async {
if (result.reason == B2COperationState.SUCCESS) {
List<String>? subjects = await AzureB2C.getSubjects();
if (subjects != null && subjects.isNotEmpty) {
B2CAccessToken? token = await AzureB2C.getAccessToken(subjects[0]);
if (!mounted || token == null) return;
final encodedPayload = token.token.split('.')[1];
final payloadData =
utf8.fuse(base64).decode(base64.normalize(encodedPayload));
final claims = Claims.fromJson(jsonDecode(payloadData));
var m = Provider.of<LoginModel>(context);
m.logIn(claims);
}
}
});
The problem is that when it arrives to var m = Provider.of<LoginModel>(context); the execution stops with out errors without executing m.logIn(claims);, so the model is not changed and the consumer is not called.
Any idea?
This is my consumer:
class App extends StatelessWidget {
const App({super.key});
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => LoginModel(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: appTheme,
home: Consumer<LoginModel>(
builder: (context, value, child) =>
value.claims != null ? const Home() : const Login(),
)),
);
}
}
class LoginModel extends ChangeNotifier {
Claims? _claims;
logIn(Claims claims) {
_claims = claims;
notifyListeners();
}
logOut() {
_claims = null;
notifyListeners();
}
Claims? get claims => _claims;
}
My LoginWidget:
class Login extends StatefulWidget {
const Login({super.key});
#override
LoginState createState() => LoginState();
}
class LoginState extends State<Login> {
B2CConfiguration? _configuration;
checkLogin(BuildContext context) async {
List<String>? subjects = await AzureB2C.getSubjects();
if (subjects != null && subjects.isNotEmpty) {
B2CAccessToken? token = await AzureB2C.getAccessToken(subjects[0]);
if (!mounted || token == null) return;
final encodedData = token.token.split('.')[1];
final data =
utf8.fuse(base64).decode(base64.normalize(encodedData));
final claims = Claims.fromJson(jsonDecode(data));
var m = Provider.of<LoginModel>(context, listen: true);
m.logIn(claims); //<-- debugger never reaches this line
}
}
#override
Widget build(BuildContext context) {
// It is possible to register callbacks in order to handle return values
// from asynchronous calls to the plugin
AzureB2C.registerCallback(B2COperationSource.INIT, (result) async {
if (result.reason == B2COperationState.SUCCESS) {
_configuration = await AzureB2C.getConfiguration();
if (!mounted) return;
await checkLogin(context);
}
});
AzureB2C.registerCallback(B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
(result) async {
if (result.reason == B2COperationState.SUCCESS) {
if (!mounted) return;
await checkLogin(context);
}
});
// Important: Remeber to handle redirect states (if you want to support
// the web platform with redirect method) and init the AzureB2C plugin
// before the material app starts.
AzureB2C.handleRedirectFuture().then((_) => AzureB2C.init("auth_config"));
const String assetName = 'assets/images/logo.svg';
final Widget logo = SvgPicture.asset(
assetName,
);
return SafeArea(
child: //omitted,
);
}
}
I opened an issue as well, but it did not help me.
Try this
var m = Provider.of<LoginModel>(context, listen: false)._claims;
You are using the Provider syntax but not doing anything really with it. You need to set it like this Provider.of<LoginModel>(context, listen: false).login(claims) and call it like this Provider.of<LoginModel>(context, listen: false)._claims;
I fixed it, moving the callback registrations from the build method to the initState method.

I am not able to save retrieve data using shared preferences in Flutter

I am using flutter localizations for changing language in my flutter app. I want to change my app's language in real time and have implemented logic for that. Now, I want that when user closes app and restarts it, he gets same language he chose before, i.e. language should not set back to default after user closes the app. For this purpose, I was using shared preferences to save the code of language that user selected and then retrieve it in the beginning of the app.
app_locale.dart -
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class AppLocale extends ChangeNotifier {
Locale? _locale;
Locale get locale => _locale ?? Locale('en');
void getLocale() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('bn')) {
_locale = Locale('bn');
} else if(newLocale==Locale('gu')){
_locale = Locale('gu');
} else if(newLocale==Locale('en')){
_locale = Locale('en');
} else if(newLocale==Locale('pa')){
_locale = Locale('pa');
}
}
void changeLocale(Locale newLocale) async {
if(newLocale == Locale('bn')) {
_locale = Locale('bn');
} else if(newLocale==Locale('gu')){
_locale = Locale('gu');
} else if(newLocale==Locale('en')){
_locale = Locale('en');
} else if(newLocale==Locale('pa')){
_locale = Locale('pa');
}
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString("code", _locale?.countryCode??"en");
notifyListeners();
}
}
I am calling getLocale in main.dart -
class MyApp extends StatelessWidget {
GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey=GlobalKey<ScaffoldMessengerState>();
Locale? defaultLanguage;
#override
Widget build(BuildContext context) {
var language = Provider.of<AppLocale>(context);
language.getLocale();
return Consumer<AppLocale>(
........
........
And in my language selection screen, I am changing language like this -
var language = Provider.of<AppLocale>(context);
child: Column(
children: [
LanguageTile(
shortForm: "Pa",
fullName: "ਪੰਜਾਬੀ",
isSelected: selectedLanguage==0,
onTap: () {
changeSelectedLanguage(0);
language.changeLocale(Locale('pa'));
},
),
LanguageTile(
shortForm: "GU",
fullName: "ગુજરાતી",
isSelected: selectedLanguage==1,
onTap: () {
changeSelectedLanguage(1);
language.changeLocale(Locale('gu'));
},
),
LanguageTile(
shortForm: "বা",
fullName: "বাংলা",
isSelected: selectedLanguage==2,
onTap: () {
changeSelectedLanguage(2);
language.changeLocale(Locale('bn'));
},
),
LanguageTile(
shortForm: "A",
fullName: "English",
isSelected: selectedLanguage==3,
onTap: () {
changeSelectedLanguage(3);
language.changeLocale(Locale('en'));
},
),
//Text(AppLocalizations.of(context)!.helloWorld),
],
),
Please someone guide me for this.
Heading
You have to call the get language method in initState. Or show a loading or pop up while the data is loading in background. Sometimes it happens because data is not loaded yet and build context already create the screen and the ui. I hope this will work.
the data is not coming because when loading data from
SharedPreferences it take time.so method is not in void it in Future.
please paste the below code
Future getLocale() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
String code = prefs.getString("code")??"en";
Locale newLocale = Locale(code);
if(newLocale == Locale('bn')) {
_locale = Locale('bn');
} else if(newLocale==Locale('gu')){
_locale = Locale('gu');
} else if(newLocale==Locale('en')){
_locale = Locale('en');
} else if(newLocale==Locale('pa')){
_locale = Locale('pa');
}
}
class MyApp extends StatelessWidget {
GlobalKey<ScaffoldMessengerState> scaffoldMessengerKey=GlobalKey<ScaffoldMessengerState>();
Locale? defaultLanguage;
var language;
void initmethod(context)async
{
language = await Provider.of<AppLocale>(context).getLocale();
}
#override
Widget build(BuildContext context) {
initmethod(context);
return Consumer<AppLocale>(
........
........
why yout dont use ListView().builder or Grid().builder to habe less code and use a list with all entries and les
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i){
return LanguageTile(
shortForm: list[i].shortForm,
fullName: list[i].fullName,
onSelected: (value) {
changeSelectedLanguage(value);
language.changeLocale(Locale('en'));
},
),
}
},
),

How to show picked image with file_picker in web?

how can I show image picked by file_picker in web while the file path is null in web platform ?
If the path was not null, showing the image is too easy with Image.file(File):
Image.file(context.select<BlogProvider, File>((BlogProvider p) => p.image))
but It can not create File for image in web because browsers don't give file path and It's null.
Future<void> pickImage() async {
/// If [withReadStream] is set, picked files will have its byte data available as a [Stream<List<int>>]
/// which can be useful for uploading and processing large files.
FilePickerResult result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'jpeg'],
withReadStream: true,
);
if (result != null) {
PlatformFile file = result.files.single; //single means I am Picking just One file not more
_blogImage = File(file.path);//Null in web ,but Ok in Android
notifyListeners();
} else {
// User canceled the picker
}
}
When withReadStream is set to true, selected image can be accessed as:
file.readStream.listen((event) {
_blogImage = Image.memory(event);
notifyListeners();
});
but when withReadStream is false:
_blogImage = Image.memory(file.bytes);
notifyListeners();
And although file.path is null in flutter for web, the file.name is set correctly and we can display it.
More info here
Another way (without file_picker package):
import 'dart:html' as html;
// ...
void pickFile() {
final input = html.FileUploadInputElement()..accept = 'image/*';
input.onChange.listen((event) {
if (input.files.isNotEmpty) {
fileName = input.files.first.name; // file name without path!
// synthetic file path can be used with Image.network()
url = html.Url.createObjectUrl(input.files.first);
});
}
});
input.click();
}
You can use Image.memory()
an exemple using the package universal_html
void main() {
runApp(
MaterialApp(
home: Scaffold(
body: DemoApp0(),
),
),
);
}
class DemoApp0 extends StatefulWidget {
DemoApp0({
Key key,
}) : super(key: key);
#override
_DemoApp0State createState() => _DemoApp0State();
}
class _DemoApp0State extends State<DemoApp0> {
final Map<String, Uint8List> files = {};
#override
Widget build(BuildContext context) {
return Center(
child: Column(
children: [
TextButton(
onPressed: ()=>pickWebFile(),
child: Text("select file"),
),
Column(
children: files.entries
.map((e) => Column(
children: [
Text(e.key),
SizedBox(
width: 200,
height: 300,
child: Image.memory(e.value),
)
],
))
.toList(),
)
],
),
);
}
Future<void> pickWebFile() async {
List<html.File> webFiles = [];
html.InputElement uploadInput = html.FileUploadInputElement();
uploadInput.click();
uploadInput.onChange.listen((e) {
webFiles = uploadInput.files;
for (html.File webFile in webFiles) {
var r = new html.FileReader();
Uint8List fileData;
r.readAsArrayBuffer(webFile);
r.onLoadEnd.listen((e) async {
fileData = r.result;
if (webFile.size < 4194304) {
setState(() {
files[webFile.name] = fileData;
});
}
});
}
});
}
}

how to close the application on clicking cancel in local auth and also when maximum tries exceeds in flutter

I'm new in flutter. I wanted to create an application with local biometrics I have used local auth and i need to have help with
close the application on the click of cancel button in local_auth,
close the application when maximum tries are done.
pause the background untill authentication complete
my code is
import 'dart:async';
import 'package:LogInSignIn.dart';
import 'package:flutter/material.dart';
import 'package:cashhub/homescreen.dart';
import 'package:local_auth/local_auth.dart';
import 'package:flutter/services.dart';
void main() {
setupLocator();
runApp(new MaterialApp(
debugShowCheckedModeBanner: false,
home: new SplashScreen(),
routes: <String, WidgetBuilder>{
'/HomeScreen': (BuildContext context) => new LogInSignIn(),
},
));
}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
//final LocalAuthenticationService _localAuth = locator<LocalAuthenticationService>();
final LocalAuthentication auth = LocalAuthentication();
bool _canCheckBiometrics;
List<BiometricType> _availableBiometrics;
String _authorized = 'Not Authorized';
bool _isAuthenticating = false;
startTime() async {
var _duration = new Duration(seconds: 4);
return new Timer(_duration, navigationPage);
}
Future<void> _authenticate() async {
bool authenticated = false;
try {
setState(() {
_isAuthenticating = true;
_authorized = 'Authenticating';
});
authenticated = await auth.authenticateWithBiometrics(
localizedReason: 'Scan your fingerprint to authenticate',
useErrorDialogs: true,
stickyAuth: true);
setState(() {
_isAuthenticating = false;
_authorized = 'Authenticating';
});
} on PlatformException catch (e) {
print(e);
}
if (!mounted) return;
final String message = authenticated ? 'Authorized' : 'Not Authorized';
// if( message == "Not Authorized"){
// SystemNavigator.pop();
// }
setState(() {
_authorized = message;
});
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/HomeScreen');
}
#override
void initState() {
_authenticate();
//autho();
super.initState();
startTime();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new Image.asset('assets/splashlogo.png',
),
),
);
}
}
anyone please help me with this 3 queries..
you can close the app with cancel click like this
setState(() {
if (isAuthorized) {
_authorizedOrNot = "Authorized";
} else {
_authorizedOrNot = "Not Authorized";
exit(0);
}
});
just so you know exit(0) need to impot dart:io

Provider rebuilds the widget, but nothing shows up until a "Hot restart"

I am building a flutter app and I get some data from a future, I also got the same data with a changenotifier. Well the logic is that while some object doesn't have data because its waiting on the future then display a spinning circle. I have already done this in the app and I have a widget called Loading() when the object has not received data. The problem I have run into is that I get the data, but it doesn't display anything.
the data displays correctly until I perform a hot refresh of the app. a capital R instead of a lowercase r. The difference is that it starts the app and deletes all aggregated data.
when this happens it seems that the data fills the object but I hypothesize that it is becoming not null meaning [] which is empty but not null and is displaying the data "too quickly" this in turn displays nothing for this widget until I restart "r" which shows me the above screenshot.
here is the offending code.
import 'package:disc_t/Screens/LoggedIn/Classes/classTile.dart';
import 'package:disc_t/Screens/LoggedIn/Classes/classpage.dart';
import 'package:disc_t/Screens/LoggedIn/Classes/classpageroute.dart';
import 'package:disc_t/Services/database.dart';
import 'package:disc_t/models/user.dart';
import 'package:disc_t/shared/loading.dart';
import 'package:flutter/material.dart';
import 'package:morpheus/page_routes/morpheus_page_route.dart';
import 'package:provider/provider.dart';
class ClassList extends StatefulWidget {
#override
_ClassListState createState() => _ClassListState();
}
class _ClassListState extends State<ClassList> {
#override
void initState() {
ClassDataNotifier classdatanotif =
Provider.of<ClassDataNotifier>(context, listen: false);
// final user = Provider.of<User>(context);
// getTheClasses(classdatanotif);
// List<ClassData> d = classes;
}
#override
Widget build(BuildContext context) {
ClassDataNotifier classdatanotif = Provider.of<ClassDataNotifier>(context);
List<ClassData> cData = Provider.of<List<ClassData>>(context);
bool rebd = false;
Widget checker(bool r) {
if (cData == null) {
return Loading();
} else {
if (rebd == false) {
setState(() {
rebd = true;
});
rebd = true;
return checker(rebd);
// return Text("Still Loading");
} else {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: cData.length,
// controller: PageController(viewportFraction: 0.8),
itemBuilder: (context, index) {
return Hero(
tag: cData[index],
child: GestureDetector(
onTap: () {
// Navigator.of(context).push(ClassPageRoute(cData[index]));
Navigator.push(
context,
MorpheusPageRoute(
builder: (context) =>
ClassPage(data: cData[index]),
transitionToChild: true));
},
child: ClassTile(
classname: cData[index].classname,
description: cData[index].classdescription,
classcode: cData[index].documentID,
),
),
);
});
}
}
}
return checker(rebd);
}
}
here is how the provider is implemented
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
// final DatabaseService ds = DatabaseService();
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(
value: AuthService().user,
// child: MaterialApp(
// home: Wrapper(),
// ),
),
ChangeNotifierProvider<ClassDataNotifier>(
create: (context) => ClassDataNotifier(),
),
FutureProvider(
create: (context) => DatabaseService().fetchClassdata,
)
],
child: MaterialApp(home: Wrapper()),
);
}
}
and here is the function that is ran to get the data
Future<List<ClassData>> get fetchClassdata async {
QuerySnapshot snapshot = await classesCollection.getDocuments();
List<ClassData> _classList = List<ClassData>();
snapshot.documents.forEach((element) async {
QuerySnapshot pre = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Pre")
.getDocuments();
List<Preq> _preList = List<Preq>();
pre.documents.forEach((preClass) {
Preq preqData = Preq.fromMap(preClass.data);
if (preClass.data != null) {
_preList.add(preqData);
}
});
ClassData data =
ClassData.fromMap(element.data, element.documentID, _preList);
if (data != null) {
_classList.add(data);
}
});
return _classList;
}
I think the logic of your provider is fine, the problem lies in the line
snapshot.documents.forEach((element) async {
...
}
The forEach is not a Future (what is inside it's a future because the async, but the method itself not) so the code runs the first time, it reaches the forEach which does its own future on each value and propagate to the next line of code, the return, but the list is empty because the forEach isn't done yet.
There is a special Future.forEach for this case so you can wait for the value method before running the next line
Future<List<ClassData>> get fetchClassdata async {
QuerySnapshot snapshot = await classesCollection.getDocuments();
List<ClassData> _classList = List<ClassData>();
await Future.forEach(snapshot.documents, (element) async {
QuerySnapshot pre = await Firestore.instance
.collection("Classes")
.document(element.documentID)
.collection("Pre")
.getDocuments();
List<Preq> _preList = List<Preq>();
pre.documents.forEach((preClass) {
Preq preqData = Preq.fromMap(preClass.data);
if (preClass.data != null) {
_preList.add(preqData);
}
});
ClassData data =
ClassData.fromMap(element.data, element.documentID, _preList);
if (data != null) {
_classList.add(data);
}
});
return _classList;
}
Here is a similar problem with provider with a forEach. Maybe it can help you understand a bit better