diff --git a/app/build.gradle b/app/build.gradle index 62994063..bbc59b7b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' +apply plugin: 'kotlin-kapt' android { compileSdkVersion 28 @@ -45,6 +46,10 @@ dependencies { implementation 'joda-time:joda-time:2.9.9' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' implementation 'com.googlecode.ez-vcard:ez-vcard:0.10.4' + + kapt "androidx.room:room-compiler:2.0.0" + implementation "androidx.room:room-runtime:2.0.0" + annotationProcessor "androidx.room:room-compiler:2.0.0" } Properties props = new Properties() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/databases/ContactsDatabase.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/databases/ContactsDatabase.kt new file mode 100644 index 00000000..94b02b27 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/databases/ContactsDatabase.kt @@ -0,0 +1,61 @@ +package com.simplemobiletools.contacts.pro.databases + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase +import androidx.sqlite.db.SupportSQLiteDatabase +import com.simplemobiletools.contacts.pro.helpers.getEmptyLocalContact +import com.simplemobiletools.contacts.pro.interfaces.ContactsDao +import com.simplemobiletools.contacts.pro.models.LocalContact +import com.simplemobiletools.contacts.pro.objects.MyExecutor +import java.util.concurrent.Executors + +@Database(entities = [(LocalContact::class)], version = 1) +abstract class ContactsDatabase : RoomDatabase() { + + abstract fun ContactsDao(): ContactsDao + + companion object { + private val FIRST_CONTACT_ID = 1000000L + + private var db: ContactsDatabase? = null + + fun getInstance(context: Context): ContactsDatabase { + if (db == null) { + synchronized(ContactsDatabase::class) { + if (db == null) { + db = Room.databaseBuilder(context.applicationContext, ContactsDatabase::class.java, "local_contacts.db") + .setQueryExecutor(MyExecutor.myExecutor) + .addCallback(object : Callback() { + override fun onCreate(db: SupportSQLiteDatabase) { + super.onCreate(db) + increaseAutoIncrementId() + } + }) + .build() + db!!.openHelper.setWriteAheadLoggingEnabled(true) + } + } + } + return db!! + } + + fun destroyInstance() { + db = null + } + + // start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts + // Room doesn't seem to have a built in way for it, so just create a contact and delete it + private fun increaseAutoIncrementId() { + Executors.newSingleThreadExecutor().execute { + val emptyContact = getEmptyLocalContact() + emptyContact.id = FIRST_CONTACT_ID + db!!.ContactsDao().apply { + insertOrUpdate(emptyContact) + deleteContactIds(FIRST_CONTACT_ID.toString()) + } + } + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt index 0726550a..58d45128 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt @@ -15,7 +15,9 @@ import com.simplemobiletools.contacts.pro.BuildConfig import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.activities.EditContactActivity import com.simplemobiletools.contacts.pro.activities.ViewContactActivity +import com.simplemobiletools.contacts.pro.databases.ContactsDatabase import com.simplemobiletools.contacts.pro.helpers.* +import com.simplemobiletools.contacts.pro.interfaces.ContactsDao import com.simplemobiletools.contacts.pro.models.Contact import java.io.File @@ -23,6 +25,8 @@ val Context.config: Config get() = Config.newInstance(applicationContext) val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext) +val Context.contactsDB: ContactsDao get() = ContactsDatabase.getInstance(applicationContext).ContactsDao() + fun Context.viewContact(contact: Contact) { Intent(applicationContext, ViewContactActivity::class.java).apply { putExtra(CONTACT_ID, contact.id) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt index 9073d347..ea38a550 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt @@ -1,6 +1,7 @@ package com.simplemobiletools.contacts.pro.helpers import android.provider.ContactsContract.CommonDataKinds +import com.simplemobiletools.contacts.pro.models.LocalContact // shared prefs const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails" @@ -119,3 +120,5 @@ val localAccountTypes = arrayListOf("vnd.sec.contact.phone", const val TELEGRAM_PACKAGE = "org.telegram.messenger" const val SIGNAL_PACKAGE = "org.thoughtcrime.securesms" const val WHATSAPP_PACKAGE = "com.whatsapp" + +fun getEmptyLocalContact() = LocalContact(0, "", "", "", "", "", "", null, "", "", "", false, "", "", "", "", "", "", "") diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/interfaces/ContactsDao.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/interfaces/ContactsDao.kt new file mode 100644 index 00000000..484f072b --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/interfaces/ContactsDao.kt @@ -0,0 +1,22 @@ +package com.simplemobiletools.contacts.pro.interfaces + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.simplemobiletools.contacts.pro.models.LocalContact + +@Dao +interface ContactsDao { + @Query("SELECT * FROM contacts") + fun getContacts(): List + + @Query("SELECT * FROM contacts WHERE id = :id") + fun getContactWithId(id: Long): LocalContact + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insertOrUpdate(contact: LocalContact) + + @Query("DELETE FROM contacts WHERE id IN (:ids)") + fun deleteContactIds(ids: String) +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/LocalContact.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/LocalContact.kt new file mode 100644 index 00000000..4cd51fa5 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/LocalContact.kt @@ -0,0 +1,33 @@ +package com.simplemobiletools.contacts.pro.models + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey + +@Entity(tableName = "contacts", indices = [(Index(value = ["id"], unique = true))]) +data class LocalContact( + @PrimaryKey(autoGenerate = true) var id: Long?, + @ColumnInfo(name = "prefix") var prefix: String, + @ColumnInfo(name = "first_name") var firstName: String, + @ColumnInfo(name = "middle_name") var middleName: String, + @ColumnInfo(name = "surname") var surname: String, + @ColumnInfo(name = "suffix") var suffix: String, + @ColumnInfo(name = "nickname") var nickname: String, + @ColumnInfo(name = "photo", typeAffinity = ColumnInfo.BLOB) var photo: ByteArray?, + @ColumnInfo(name = "phone_numbers") var phoneNumbers: String, + @ColumnInfo(name = "emails") var emails: String, + @ColumnInfo(name = "events") var events: String, + @ColumnInfo(name = "starred") var starred: Boolean, + @ColumnInfo(name = "addresses") var addresses: String, + @ColumnInfo(name = "notes") var notes: String, + @ColumnInfo(name = "groups") var groups: String, + @ColumnInfo(name = "company") var company: String, + @ColumnInfo(name = "job_position") var jobPosition: String, + @ColumnInfo(name = "websites") var websites: String, + @ColumnInfo(name = "ims") var ims: String) { + + companion object { + private const val serialVersionUID = -655314977575622L + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/objects/MyExecutor.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/objects/MyExecutor.kt new file mode 100644 index 00000000..5f32bfd0 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/objects/MyExecutor.kt @@ -0,0 +1,7 @@ +package com.simplemobiletools.contacts.pro.objects + +import java.util.concurrent.Executors + +object MyExecutor { + val myExecutor = Executors.newSingleThreadExecutor() +}