diff --git a/android/.settings/org.eclipse.buildship.core.prefs b/android/.settings/org.eclipse.buildship.core.prefs new file mode 100644 index 00000000..c835726a --- /dev/null +++ b/android/.settings/org.eclipse.buildship.core.prefs @@ -0,0 +1,13 @@ +arguments=--init-script /var/folders/0h/1wd_6skn0h3gppnj15t0tbl40000gn/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle +auto.sync=false +build.scans.enabled=false +connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.4.2)) +connection.project.dir= +eclipse.preferences.version=1 +gradle.user.home= +java.home=/Library/Java/JavaVirtualMachines/jdk-23.jdk/Contents/Home +jvm.arguments= +offline.mode=false +override.workspace.settings=true +show.console.view=true +show.executions.view=true diff --git a/android/build.gradle b/android/build.gradle index 2feed78f..602d47dc 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.android.tools.build:gradle:8.1.0' } } @@ -20,13 +20,14 @@ rootProject.allprojects { } apply plugin: 'com.android.library' - android { - compileSdkVersion 30 - + namespace "flutter.plugins.contactsservice.contactsservice" + compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion defaultConfig { minSdkVersion 16 targetSdkVersion 30 + compileSdkVersion 35 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/android/gradle.properties b/android/gradle.properties index 8bd86f68..e60119f3 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,4 @@ org.gradle.jvmargs=-Xmx1536M +android.useAndroidX=true +android.enableJetifier=true + diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index c5a6358e..72eb3ce4 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip diff --git a/android/src/main/java/flutter/plugins/contactsservice/contactsservice/ContactsServicePlugin.java b/android/src/main/java/flutter/plugins/contactsservice/contactsservice/ContactsServicePlugin.java index 8c69de78..35114428 100644 --- a/android/src/main/java/flutter/plugins/contactsservice/contactsservice/ContactsServicePlugin.java +++ b/android/src/main/java/flutter/plugins/contactsservice/contactsservice/ContactsServicePlugin.java @@ -287,16 +287,21 @@ public boolean onActivityResult(int requestCode, int resultCode, Intent intent) return true; } Uri contactUri = intent.getData(); - if (intent != null){ - Cursor cursor = contentResolver.query(contactUri, null, null, null, null); - if (cursor.moveToFirst()) { - String id = contactUri.getLastPathSegment(); - getContacts("openDeviceContactPicker", id, false, false, false, localizedLabels, this.result); + if (intent != null) { + Cursor cursor = contentResolver.query(contactUri, null, null, null, null); + if (cursor != null && cursor.moveToFirst()) { + String id = contactUri.getLastPathSegment(); + getContacts("openDeviceContactPicker", id, false, false, false, localizedLabels, this.result); + } else { + Log.e(LOG_TAG, "onActivityResult - cursor.moveToFirst() returns false"); + finishWithResult(FORM_OPERATION_CANCELED); + } + if (cursor != null) { + cursor.close(); + } } else { - Log.e(LOG_TAG, "onActivityResult - cursor.moveToFirst() returns false"); - finishWithResult(FORM_OPERATION_CANCELED); - }}else{return true;} - cursor.close(); + return true; + } return true; } diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index f8e8aad1..139a942b 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -15,8 +15,10 @@ apply plugin: 'com.android.application' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 30 + namespace "flutter.plugins.contactsservice.contactsserviceexample" + compileSdk flutter.compileSdkVersion + ndkVersion flutter.ndkVersion lintOptions { disable 'InvalidPackage' } @@ -26,6 +28,7 @@ android { applicationId "flutter.plugins.contactsservice.contactsserviceexample" minSdkVersion 16 targetSdkVersion 30 + compileSdkVersion 35 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/example/lib/contacts_list_page.dart b/example/lib/contacts_list_page.dart index 5f6b773e..de89d062 100644 --- a/example/lib/contacts_list_page.dart +++ b/example/lib/contacts_list_page.dart @@ -1,8 +1,6 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:contacts_service_example/main.dart'; - import 'package:contacts_service/contacts_service.dart'; +import 'package:contacts_service_example/main.dart'; +import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; class ContactListPage extends StatefulWidget { @@ -11,7 +9,7 @@ class ContactListPage extends StatefulWidget { } class _ContactListPageState extends State { - List _contacts; + List? _contacts; @override void initState() { @@ -39,8 +37,9 @@ class _ContactListPageState extends State { } void updateContact() async { - Contact ninja = _contacts - .firstWhere((contact) => contact.familyName.startsWith("Ninja")); + Contact ninja = _contacts?.firstWhere( + (contact) => contact.familyName?.startsWith("Ninja") ?? false) ?? + Contact(); ninja.avatar = null; await ContactsService.updateContact(ninja); @@ -90,7 +89,7 @@ class _ContactListPageState extends State { ? ListView.builder( itemCount: _contacts?.length ?? 0, itemBuilder: (BuildContext context, int index) { - Contact c = _contacts?.elementAt(index); + Contact c = _contacts?.elementAt(index) ?? Contact(); return ListTile( onTap: () { Navigator.of(context).push(MaterialPageRoute( @@ -100,8 +99,8 @@ class _ContactListPageState extends State { contactOnDeviceHasBeenUpdated, ))); }, - leading: (c.avatar != null && c.avatar.length > 0) - ? CircleAvatar(backgroundImage: MemoryImage(c.avatar)) + leading: (c.avatar != null && ((c.avatar?.length ?? 0) > 0)) + ? CircleAvatar(backgroundImage: MemoryImage(c.avatar!)) : CircleAvatar(child: Text(c.initials())), title: Text(c.displayName ?? ""), ); @@ -116,14 +115,14 @@ class _ContactListPageState extends State { void contactOnDeviceHasBeenUpdated(Contact contact) { this.setState(() { - var id = _contacts.indexWhere((c) => c.identifier == contact.identifier); - _contacts[id] = contact; + var id = _contacts?.indexWhere((c) => c.identifier == contact.identifier); + _contacts?[id ?? 0] = contact; }); } } class ContactDetailsPage extends StatelessWidget { - ContactDetailsPage(this._contact, {this.onContactDeviceSave}); + ContactDetailsPage(this._contact, {required this.onContactDeviceSave}); final Contact _contact; final Function(Contact) onContactDeviceSave; @@ -132,9 +131,7 @@ class ContactDetailsPage extends StatelessWidget { try { var contact = await ContactsService.openExistingContact(_contact, iOSLocalizedLabels: iOSLocalizedLabels); - if (onContactDeviceSave != null) { - onContactDeviceSave(contact); - } + onContactDeviceSave(contact); Navigator.of(context).pop(); } on FormOperationException catch (e) { switch (e.errorCode) { @@ -202,7 +199,8 @@ class ContactDetailsPage extends StatelessWidget { ListTile( title: Text("Birthday"), trailing: Text(_contact.birthday != null - ? DateFormat('dd-MM-yyyy').format(_contact.birthday) + ? DateFormat('dd-MM-yyyy') + .format(_contact.birthday ?? DateTime.now()) : ""), ), ListTile( @@ -219,9 +217,9 @@ class ContactDetailsPage extends StatelessWidget { ? _contact.androidAccountType.toString() : ""), ), - AddressesTile(_contact.postalAddresses), - ItemsTile("Phones", _contact.phones), - ItemsTile("Emails", _contact.emails) + AddressesTile(_contact.postalAddresses ?? []), + ItemsTile("Phones", _contact.phones ?? []), + ItemsTile("Emails", _contact.emails ?? []) ], ), ), @@ -323,7 +321,7 @@ class _AddContactPageState extends State { actions: [ TextButton( onPressed: () { - _formKey.currentState.save(); + _formKey.currentState?.save(); contact.postalAddresses = [address]; ContactsService.addContact(contact); Navigator.of(context).pop(); @@ -407,7 +405,7 @@ class _AddContactPageState extends State { } class UpdateContactsPage extends StatefulWidget { - UpdateContactsPage({@required this.contact}); + UpdateContactsPage({required this.contact}); final Contact contact; @@ -416,7 +414,7 @@ class UpdateContactsPage extends StatefulWidget { } class _UpdateContactsPageState extends State { - Contact contact; + Contact? contact; PostalAddress address = PostalAddress(label: "Home"); final GlobalKey _formKey = GlobalKey(); @@ -438,9 +436,9 @@ class _UpdateContactsPageState extends State { color: Colors.white, ), onPressed: () async { - _formKey.currentState.save(); - contact.postalAddresses = [address]; - await ContactsService.updateContact(contact); + _formKey.currentState?.save(); + contact?.postalAddresses = [address]; + await ContactsService.updateContact(contact ?? Contact()); Navigator.of(context).pushReplacement( MaterialPageRoute(builder: (context) => ContactListPage())); }, @@ -454,51 +452,51 @@ class _UpdateContactsPageState extends State { child: ListView( children: [ TextFormField( - initialValue: contact.givenName ?? "", + initialValue: contact?.givenName ?? "", decoration: const InputDecoration(labelText: 'First name'), - onSaved: (v) => contact.givenName = v, + onSaved: (v) => contact?.givenName = v, ), TextFormField( - initialValue: contact.middleName ?? "", + initialValue: contact?.middleName ?? "", decoration: const InputDecoration(labelText: 'Middle name'), - onSaved: (v) => contact.middleName = v, + onSaved: (v) => contact?.middleName = v, ), TextFormField( - initialValue: contact.familyName ?? "", + initialValue: contact?.familyName ?? "", decoration: const InputDecoration(labelText: 'Last name'), - onSaved: (v) => contact.familyName = v, + onSaved: (v) => contact?.familyName = v, ), TextFormField( - initialValue: contact.prefix ?? "", + initialValue: contact?.prefix ?? "", decoration: const InputDecoration(labelText: 'Prefix'), - onSaved: (v) => contact.prefix = v, + onSaved: (v) => contact?.prefix = v, ), TextFormField( - initialValue: contact.suffix ?? "", + initialValue: contact?.suffix ?? "", decoration: const InputDecoration(labelText: 'Suffix'), - onSaved: (v) => contact.suffix = v, + onSaved: (v) => contact?.suffix = v, ), TextFormField( decoration: const InputDecoration(labelText: 'Phone'), onSaved: (v) => - contact.phones = [Item(label: "mobile", value: v)], + contact?.phones = [Item(label: "mobile", value: v)], keyboardType: TextInputType.phone, ), TextFormField( decoration: const InputDecoration(labelText: 'E-mail'), onSaved: (v) => - contact.emails = [Item(label: "work", value: v)], + contact?.emails = [Item(label: "work", value: v)], keyboardType: TextInputType.emailAddress, ), TextFormField( - initialValue: contact.company ?? "", + initialValue: contact?.company ?? "", decoration: const InputDecoration(labelText: 'Company'), - onSaved: (v) => contact.company = v, + onSaved: (v) => contact?.company = v, ), TextFormField( - initialValue: contact.jobTitle ?? "", + initialValue: contact?.jobTitle ?? "", decoration: const InputDecoration(labelText: 'Job'), - onSaved: (v) => contact.jobTitle = v, + onSaved: (v) => contact?.jobTitle = v, ), TextFormField( initialValue: address.street ?? "", diff --git a/example/lib/contacts_picker_page.dart b/example/lib/contacts_picker_page.dart index e3ebaadd..0a230d82 100644 --- a/example/lib/contacts_picker_page.dart +++ b/example/lib/contacts_picker_page.dart @@ -1,15 +1,14 @@ +import 'package:contacts_service/contacts_service.dart'; import 'package:contacts_service_example/main.dart'; import 'package:flutter/material.dart'; -import 'package:contacts_service/contacts_service.dart'; - class ContactPickerPage extends StatefulWidget { @override _ContactPickerPageState createState() => _ContactPickerPageState(); } class _ContactPickerPageState extends State { - Contact _contact; + Contact? _contact; @override void initState() { @@ -18,7 +17,7 @@ class _ContactPickerPageState extends State { Future _pickContact() async { try { - final Contact contact = await ContactsService.openDeviceContactPicker( + final Contact? contact = await ContactsService.openDeviceContactPicker( iOSLocalizedLabels: iOSLocalizedLabels); setState(() { _contact = contact; @@ -40,7 +39,7 @@ class _ContactPickerPageState extends State { onPressed: _pickContact, ), if (_contact != null) - Text('Contact selected: ${_contact.displayName}'), + Text('Contact selected: ${_contact?.displayName}'), ], )), ); diff --git a/example/pubspec.yaml b/example/pubspec.yaml index f2c15eb8..515e05a9 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -1,15 +1,15 @@ name: contacts_service_example description: Demonstrates how to use the contacts_service plugin. environment: - sdk: '>=2.10.0 <3.0.0' + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. - cupertino_icons: ^1.0.2 - intl: ^0.17.0 + cupertino_icons: ^1.0.8 + intl: ^0.20.2 dev_dependencies: flutter_test: