diff --git a/.editorconfig b/.editorconfig
index 1606d61f..c79c990f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -17,7 +17,7 @@ insert_final_newline = true
charset = utf-8
indent_style = space
indent_size = 4
-continuation_indent_size = 8
+continuation_indent_size = 4
[*.xml]
continuation_indent_size = 4
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index bef56379..9bad22a9 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,3 @@
github: [tibbi]
patreon: tiborkaputa
-custom: ["https://www.paypal.me/SimpleMobileTools", "https://www.simplemobiletools.com/donate"]
+custom: ["https://www.paypal.com/paypalme/simplemobiletools", "https://www.simplemobiletools.com/donate"]
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c6c63253..f34d65ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,28 @@
Changelog
==========
+Version 6.14.1 *(2021-02-15)*
+----------------------------
+
+ * Allow customizing the ringtone per contact (Ringtone has to be enabled as a customizable field in the app settings)
+ * Added a White theme with special handling
+ * Added some letter fastscroller related improvements
+ * Some performance, stability and translation related improvements
+ * Please rate the app if you like it :)
+
+Version 6.14.0 *(2021-01-10)*
+----------------------------
+
+ * Always fetch the same contacts, no matter what sorting is set
+ * Fix an organization updating related issue
+ * Merge names into 1 line at the View Details screen
+ * Improve Threema contact handling
+
+Version 6.13.2 *(2021-01-02)*
+----------------------------
+
+ * Added some translation, stability and UX improvements
+
Version 6.13.1 *(2020-10-27)*
----------------------------
diff --git a/README.md b/README.md
index b8cd92e0..7549c8af 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ This app is just one piece of a bigger series of apps. You can find the rest of
diff --git a/app/build.gradle b/app/build.gradle
index d5e6548a..64c4dde3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,8 +17,8 @@ android {
applicationId "com.simplemobiletools.contacts.pro"
minSdkVersion 21
targetSdkVersion 29
- versionCode 77
- versionName "6.13.1"
+ versionCode 80
+ versionName "6.14.1"
setProperty("archivesBaseName", "contacts")
}
@@ -57,13 +57,13 @@ android {
}
dependencies {
- implementation 'com.simplemobiletools:commons:5.31.18'
+ implementation 'com.simplemobiletools:commons:5.33.30'
implementation 'joda-time:joda-time:2.10.1'
implementation 'com.googlecode.ez-vcard:ez-vcard:0.10.5'
- implementation 'com.github.tibbi:IndicatorFastScroll:08f512858a'
+ implementation 'com.github.tibbi:IndicatorFastScroll:c3de1d040a'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
- kapt "androidx.room:room-compiler:2.2.5"
- implementation "androidx.room:room-runtime:2.2.5"
- annotationProcessor "androidx.room:room-compiler:2.2.5"
+ kapt "androidx.room:room-compiler:2.2.6"
+ implementation "androidx.room:room-runtime:2.2.6"
+ annotationProcessor "androidx.room:room-compiler:2.2.6"
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt
index 681458bd..c65bf4b8 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ContactActivity.kt
@@ -1,11 +1,13 @@
package com.simplemobiletools.contacts.pro.activities
+import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
+import android.net.Uri
import android.provider.ContactsContract.CommonDataKinds.*
import android.widget.ImageView
import android.widget.TextView
@@ -24,16 +26,25 @@ import com.simplemobiletools.commons.helpers.letterBackgroundColors
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.contacts.pro.R
import com.simplemobiletools.contacts.pro.extensions.sendEmailIntent
-import com.simplemobiletools.contacts.pro.extensions.sendSMSIntent
import com.simplemobiletools.contacts.pro.extensions.shareContacts
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
import com.simplemobiletools.contacts.pro.models.Contact
import java.util.*
abstract class ContactActivity : SimpleActivity() {
+ protected val PICK_RINGTONE_INTENT_ID = 1500
protected var contact: Contact? = null
protected var currentContactPhotoPath = ""
+ override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
+ super.onActivityResult(requestCode, resultCode, resultData)
+ if (requestCode == PICK_RINGTONE_INTENT_ID && resultCode == RESULT_OK && resultData != null && resultData.dataString != null) {
+ customRingtoneSelected(Uri.decode(resultData.dataString!!))
+ }
+ }
+
+ abstract fun customRingtoneSelected(ringtonePath: String)
+
fun showPhotoPlaceholder(photoView: ImageView) {
val placeholder = BitmapDrawable(resources, getBigLetterPlaceholder(contact?.getNameToDisplay() ?: "A"))
photoView.setImageDrawable(placeholder)
@@ -92,7 +103,7 @@ abstract class ContactActivity : SimpleActivity() {
fun trySendSMS() {
val numbers = contact!!.phoneNumbers
if (numbers.size == 1) {
- sendSMSIntent(numbers.first().value)
+ launchSendSMSIntent(numbers.first().value)
} else if (numbers.size > 1) {
val items = ArrayList()
numbers.forEachIndexed { index, phoneNumber ->
@@ -100,7 +111,7 @@ abstract class ContactActivity : SimpleActivity() {
}
RadioGroupDialog(this, items) {
- sendSMSIntent(it as String)
+ launchSendSMSIntent(it as String)
}
}
}
@@ -189,6 +200,7 @@ abstract class ContactActivity : SimpleActivity() {
isAntiAlias = true
textAlign = Paint.Align.CENTER
textSize = wantedTextSize
+ style = Paint.Style.FILL
}
canvas.drawPaint(circlePaint)
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt
index 60be1956..b3f29e80 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/EditContactActivity.kt
@@ -5,8 +5,8 @@ import android.content.ClipData
import android.content.ContentValues
import android.content.Intent
import android.graphics.Bitmap
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
+import android.media.AudioManager
+import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract.CommonDataKinds
@@ -20,6 +20,7 @@ import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
+import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.RadioItem
@@ -184,6 +185,7 @@ class EditContactActivity : ContactActivity() {
}
setupTypePickers()
+ setupRingtone()
if (contact!!.photoUri.isEmpty() && contact!!.photo == null) {
showPhotoPlaceholder(contact_photo)
@@ -194,7 +196,7 @@ class EditContactActivity : ContactActivity() {
val textColor = config.textColor
arrayOf(contact_name_image, contact_numbers_image, contact_emails_image, contact_addresses_image, contact_ims_image, contact_events_image,
- contact_notes_image, contact_organization_image, contact_websites_image, contact_groups_image, contact_source_image).forEach {
+ contact_notes_image, contact_ringtone_image, contact_organization_image, contact_websites_image, contact_groups_image, contact_source_image).forEach {
it.applyColorFilter(textColor)
}
@@ -380,6 +382,10 @@ class EditContactActivity : ContactActivity() {
val areNotesVisible = showFields and SHOW_NOTES_FIELD != 0
contact_notes.beVisibleIf(areNotesVisible)
contact_notes_image.beVisibleIf(areNotesVisible)
+
+ val isRingtoneVisible = showFields and SHOW_RINGTONE_FIELD != 0
+ contact_ringtone.beVisibleIf(isRingtoneVisible)
+ contact_ringtone_image.beVisibleIf(isRingtoneVisible)
}
private fun setupEditContact() {
@@ -480,6 +486,31 @@ class EditContactActivity : ContactActivity() {
contact_notes.setText(contact!!.notes)
}
+ private fun setupRingtone() {
+ contact_ringtone.setOnClickListener {
+ val currentRingtone = contact!!.ringtone ?: getDefaultAlarmSound(RingtoneManager.TYPE_RINGTONE).uri
+ SelectAlarmSoundDialog(this, currentRingtone, AudioManager.STREAM_RING, PICK_RINGTONE_INTENT_ID, RingtoneManager.TYPE_RINGTONE, true,
+ onAlarmPicked = {
+ contact!!.ringtone = it?.uri
+ contact_ringtone.text = it?.title
+ }, onAlarmSoundDeleted = {}
+ )
+ }
+
+ val ringtone = contact!!.ringtone
+ if (ringtone != null && ringtone.isNotEmpty()) {
+ if (ringtone == SILENT) {
+ contact_ringtone.text = getString(R.string.no_sound)
+ } else {
+ val contactRingtone = RingtoneManager.getRingtone(this, Uri.parse(ringtone))
+ contact_ringtone.text = contactRingtone.getTitle(this)
+ }
+ } else {
+ val default = getDefaultAlarmSound(RingtoneManager.TYPE_RINGTONE)
+ contact_ringtone.text = default.title
+ }
+ }
+
private fun setupOrganization() {
contact_organization_company.setText(contact!!.organization.company)
contact_organization_job_position.setText(contact!!.organization.jobPosition)
@@ -1211,6 +1242,11 @@ class EditContactActivity : ContactActivity() {
}
}
+ override fun customRingtoneSelected(ringtonePath: String) {
+ contact!!.ringtone = ringtonePath
+ contact_ringtone.text = ringtonePath.getFilenameFromPath()
+ }
+
private fun getPhoneNumberTypeId(value: String) = when (value) {
getString(R.string.mobile) -> Phone.TYPE_MOBILE
getString(R.string.home) -> Phone.TYPE_HOME
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/MainActivity.kt
index 62df76f0..b1e93870 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/MainActivity.kt
@@ -59,9 +59,6 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private var isGettingContacts = false
private var ignoredExportContactSources = HashSet()
- private var storedTextColor = 0
- private var storedBackgroundColor = 0
- private var storedPrimaryColor = 0
private var storedShowContactThumbnails = false
private var storedShowPhoneNumbers = false
private var storedStartNameWithSurname = false
@@ -114,29 +111,14 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
}
}
- val configTextColor = config.textColor
- if (storedTextColor != configTextColor) {
- getInactiveTabIndexes(viewpager.currentItem).forEach {
- main_tabs_holder.getTabAt(it)?.icon?.applyColorFilter(configTextColor)
- }
- getAllFragments().forEach {
- it?.textColorChanged(configTextColor)
- }
+ val adjustedPrimaryColor = getAdjustedPrimaryColor()
+ main_tabs_holder.background = ColorDrawable(config.backgroundColor)
+ main_tabs_holder.setSelectedTabIndicatorColor(adjustedPrimaryColor)
+ getAllFragments().forEach {
+ it?.setupColors(config.textColor, adjustedPrimaryColor)
}
- val configBackgroundColor = config.backgroundColor
- if (storedBackgroundColor != configBackgroundColor) {
- main_tabs_holder.background = ColorDrawable(configBackgroundColor)
- }
-
- val configPrimaryColor = config.primaryColor
- if (storedPrimaryColor != configPrimaryColor) {
- main_tabs_holder.setSelectedTabIndicatorColor(getAdjustedPrimaryColor())
- main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
- getAllFragments().forEach {
- it?.primaryColorChanged()
- }
- }
+ updateTabColors()
val configStartNameWithSurname = config.startNameWithSurname
if (storedStartNameWithSurname != configStartNameWithSurname) {
@@ -156,17 +138,13 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
initFragments()
} else {
refreshContacts(ALL_TABS_MASK)
-
- getAllFragments().forEach {
- it?.onActivityResume()
- }
}
}
- val dialpadIcon = resources.getColoredDrawableWithColor(R.drawable.ic_dialpad_vector, getFABIconColor())
+ val dialpadIcon = resources.getColoredDrawableWithColor(R.drawable.ic_dialpad_vector, adjustedPrimaryColor.getContrastColor())
main_dialpad_button.apply {
setImageDrawable(dialpadIcon)
- background.applyColorFilter(getAdjustedPrimaryColor())
+ background.applyColorFilter(adjustedPrimaryColor)
beVisibleIf(config.showDialpadButton)
}
@@ -233,9 +211,6 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
private fun storeStateVariables() {
config.apply {
- storedTextColor = textColor
- storedBackgroundColor = backgroundColor
- storedPrimaryColor = primaryColor
storedShowContactThumbnails = showContactThumbnails
storedShowPhoneNumbers = showPhoneNumbers
storedStartNameWithSurname = startNameWithSurname
@@ -280,6 +255,13 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
})
}
+ private fun updateTabColors() {
+ getInactiveTabIndexes(viewpager.currentItem).forEach {
+ main_tabs_holder.getTabAt(it)?.icon?.applyColorFilter(config.textColor)
+ }
+ main_tabs_holder.getTabAt(viewpager.currentItem)?.icon?.applyColorFilter(getAdjustedPrimaryColor())
+ }
+
private fun getSearchString(): Int {
return when (getCurrentFragment()) {
favorites_fragment -> R.string.search_favorites
@@ -528,7 +510,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
}
private fun exportContactsTo(ignoredContactSources: HashSet, outputStream: OutputStream?) {
- ContactsHelper(this).getContacts(true, ignoredContactSources) { contacts ->
+ ContactsHelper(this).getContacts(true, false, ignoredContactSources) { contacts ->
if (contacts.isEmpty()) {
toast(R.string.no_entries_for_exporting)
} else {
@@ -567,6 +549,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
if (viewpager.adapter == null) {
viewpager.adapter = ViewPagerAdapter(this, tabsList, config.showTabs)
viewpager.currentItem = getDefaultTab()
+ updateTabColors()
}
ContactsHelper(this).getContacts { contacts ->
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt
index d3990529..9b133ccb 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/ViewContactActivity.kt
@@ -2,19 +2,18 @@ package com.simplemobiletools.contacts.pro.activities
import android.content.ContentUris
import android.content.Intent
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
+import android.media.AudioManager
+import android.media.RingtoneManager
+import android.net.Uri
import android.os.Bundle
import android.provider.ContactsContract
import android.view.View
import android.view.WindowManager
import android.widget.RelativeLayout
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
+import com.simplemobiletools.commons.dialogs.SelectAlarmSoundDialog
import com.simplemobiletools.commons.extensions.*
-import com.simplemobiletools.commons.helpers.CONTACT_ID
-import com.simplemobiletools.commons.helpers.IS_PRIVATE
-import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
-import com.simplemobiletools.commons.helpers.ensureBackgroundThread
+import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.contacts.pro.R
import com.simplemobiletools.contacts.pro.dialogs.CallConfirmationDialog
import com.simplemobiletools.contacts.pro.dialogs.ChooseSocialDialog
@@ -175,7 +174,7 @@ class ViewContactActivity : ContactActivity() {
val textColor = config.textColor
arrayOf(contact_name_image, contact_numbers_image, contact_emails_image, contact_addresses_image, contact_events_image, contact_source_image,
- contact_notes_image, contact_organization_image, contact_websites_image, contact_groups_image).forEach {
+ contact_notes_image, contact_ringtone_image, contact_organization_image, contact_websites_image, contact_groups_image).forEach {
it.applyColorFilter(textColor)
}
@@ -217,6 +216,7 @@ class ViewContactActivity : ContactActivity() {
setupGroups()
setupContactSources()
setupNotes()
+ setupRingtone()
setupOrganization()
updateTextColors(contact_scrollview)
}
@@ -255,36 +255,11 @@ class ViewContactActivity : ContactActivity() {
}
private fun setupNames() {
- contact!!.apply {
- contact_prefix.text = prefix
- contact_prefix.beVisibleIf(prefix.isNotEmpty() && showFields and SHOW_PREFIX_FIELD != 0)
- contact_prefix.copyOnLongClick(prefix)
-
- contact_first_name.text = firstName
- contact_first_name.beVisibleIf(firstName.isNotEmpty() && showFields and SHOW_FIRST_NAME_FIELD != 0)
- contact_first_name.copyOnLongClick(firstName)
-
- contact_middle_name.text = middleName
- contact_middle_name.beVisibleIf(middleName.isNotEmpty() && showFields and SHOW_MIDDLE_NAME_FIELD != 0)
- contact_middle_name.copyOnLongClick(middleName)
-
- contact_surname.text = surname
- contact_surname.beVisibleIf(surname.isNotEmpty() && showFields and SHOW_SURNAME_FIELD != 0)
- contact_surname.copyOnLongClick(surname)
-
- contact_suffix.text = suffix
- contact_suffix.beVisibleIf(suffix.isNotEmpty() && showFields and SHOW_SUFFIX_FIELD != 0)
- contact_suffix.copyOnLongClick(suffix)
-
- contact_nickname.text = nickname
- contact_nickname.beVisibleIf(nickname.isNotEmpty() && showFields and SHOW_NICKNAME_FIELD != 0)
- contact_nickname.copyOnLongClick(nickname)
-
- if (contact_prefix.isGone() && contact_first_name.isGone() && contact_middle_name.isGone() && contact_surname.isGone() && contact_suffix.isGone()
- && contact_nickname.isGone()) {
- contact_name_image.beInvisible()
- }
- }
+ val displayName = contact!!.getNameToDisplay()
+ contact_name.text = displayName
+ contact_name.copyOnLongClick(displayName)
+ contact_name.beVisibleIf(displayName.isNotEmpty() && !contact!!.isABusinessContact())
+ contact_name_image.beInvisibleIf(contact_name.isGone())
}
private fun setupPhoneNumbers() {
@@ -564,6 +539,14 @@ class ViewContactActivity : ContactActivity() {
showSocialActions(key.id)
}
}
+
+ if (value.toLowerCase() == THREEMA) {
+ contact_source_image.setImageDrawable(getPackageDrawable(THREEMA_PACKAGE))
+ contact_source_image.beVisible()
+ contact_source_image.setOnClickListener {
+ showSocialActions(key.id)
+ }
+ }
}
}
@@ -588,6 +571,43 @@ class ViewContactActivity : ContactActivity() {
}
}
+ private fun setupRingtone() {
+ if (showFields and SHOW_RINGTONE_FIELD != 0) {
+ contact_ringtone_image.beVisible()
+ contact_ringtone.beVisible()
+
+ val ringtone = contact!!.ringtone
+ if (ringtone != null && ringtone.isNotEmpty()) {
+ if (ringtone == SILENT) {
+ contact_ringtone.text = getString(R.string.no_sound)
+ } else {
+ val contactRingtone = RingtoneManager.getRingtone(this, Uri.parse(ringtone))
+ val ringtoneTitle = contactRingtone.getTitle(this)
+ contact_ringtone.text = ringtoneTitle
+ }
+ } else {
+ contact_ringtone_image.beGone()
+ contact_ringtone.beGone()
+ return
+ }
+
+ contact_ringtone.copyOnLongClick(contact_ringtone.text.toString())
+
+ contact_ringtone.setOnClickListener {
+ val currentRingtone = contact!!.ringtone ?: getDefaultAlarmSound(RingtoneManager.TYPE_RINGTONE).uri
+ SelectAlarmSoundDialog(this, currentRingtone, AudioManager.STREAM_RING, PICK_RINGTONE_INTENT_ID, RingtoneManager.TYPE_RINGTONE, true,
+ onAlarmPicked = {
+ contact_ringtone.text = it?.title
+ ringtoneUpdated(it?.uri)
+ }, onAlarmSoundDeleted = {}
+ )
+ }
+ } else {
+ contact_ringtone_image.beGone()
+ contact_ringtone.beGone()
+ }
+ }
+
private fun setupOrganization() {
val organization = contact!!.organization
if (organization.isNotEmpty() && showFields and SHOW_ORGANIZATION_FIELD != 0) {
@@ -625,6 +645,23 @@ class ViewContactActivity : ContactActivity() {
}
}
+ override fun customRingtoneSelected(ringtonePath: String) {
+ contact_ringtone.text = ringtonePath.getFilenameFromPath()
+ ringtoneUpdated(ringtonePath)
+ }
+
+ private fun ringtoneUpdated(path: String?) {
+ contact!!.ringtone = path
+
+ ensureBackgroundThread {
+ if (contact!!.isPrivate()) {
+ LocalContactsHelper(this).updateRingtone(contact!!.contactId, path ?: "")
+ } else {
+ ContactsHelper(this).updateRingtone(contact!!.contactId.toString(), path ?: "")
+ }
+ }
+ }
+
private fun getDuplicateContacts(callback: () -> Unit) {
ContactsHelper(this).getDuplicatesOfContact(contact!!, false) { contacts ->
ensureBackgroundThread {
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ContactsAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ContactsAdapter.kt
index dae16557..fd01c50d 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ContactsAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ContactsAdapter.kt
@@ -15,7 +15,10 @@ import com.bumptech.glide.signature.ObjectKey
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
-import com.simplemobiletools.commons.extensions.*
+import com.simplemobiletools.commons.extensions.beVisibleIf
+import com.simplemobiletools.commons.extensions.getTextSize
+import com.simplemobiletools.commons.extensions.highlightTextFromNumbers
+import com.simplemobiletools.commons.extensions.highlightTextPart
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.RadioItem
import com.simplemobiletools.commons.views.FastScroller
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ViewPagerAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ViewPagerAdapter.kt
index e4cb8d3e..f88c1566 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ViewPagerAdapter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/ViewPagerAdapter.kt
@@ -3,11 +3,13 @@ package com.simplemobiletools.contacts.pro.adapters
import android.view.View
import android.view.ViewGroup
import androidx.viewpager.widget.PagerAdapter
+import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.helpers.TAB_CONTACTS
import com.simplemobiletools.commons.helpers.TAB_FAVORITES
import com.simplemobiletools.commons.helpers.TAB_GROUPS
import com.simplemobiletools.contacts.pro.R
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
+import com.simplemobiletools.contacts.pro.extensions.config
import com.simplemobiletools.contacts.pro.fragments.MyViewPagerFragment
class ViewPagerAdapter(val activity: SimpleActivity, val currTabsList: ArrayList, val showTabs: Int) : PagerAdapter() {
@@ -19,6 +21,7 @@ class ViewPagerAdapter(val activity: SimpleActivity, val currTabsList: ArrayList
(view as MyViewPagerFragment).apply {
setupFragment(activity)
+ setupColors(activity.config.textColor, activity.getAdjustedPrimaryColor())
}
return view
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
index 042ab5c0..b078c7e5 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/databases/ContactsDatabase.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/databases/ContactsDatabase.kt
@@ -17,7 +17,7 @@ import com.simplemobiletools.contacts.pro.models.Group
import com.simplemobiletools.contacts.pro.models.LocalContact
import java.util.concurrent.Executors
-@Database(entities = [LocalContact::class, Group::class], version = 2)
+@Database(entities = [LocalContact::class, Group::class], version = 3)
@TypeConverters(Converters::class)
abstract class ContactsDatabase : RoomDatabase() {
@@ -40,6 +40,7 @@ abstract class ContactsDatabase : RoomDatabase() {
}
})
.addMigrations(MIGRATION_1_2)
+ .addMigrations(MIGRATION_2_3)
.build()
}
}
@@ -77,5 +78,13 @@ abstract class ContactsDatabase : RoomDatabase() {
}
}
}
+
+ private val MIGRATION_2_3 = object : Migration(2, 3) {
+ override fun migrate(database: SupportSQLiteDatabase) {
+ database.apply {
+ execSQL("ALTER TABLE contacts ADD COLUMN ringtone TEXT DEFAULT ''")
+ }
+ }
+ }
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt
index d6444e1f..3bcb36e1 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageVisibleFieldsDialog.kt
@@ -30,6 +30,7 @@ class ManageVisibleFieldsDialog(val activity: BaseSimpleActivity) {
put(SHOW_WEBSITES_FIELD, R.id.manage_visible_fields_websites)
put(SHOW_GROUPS_FIELD, R.id.manage_visible_fields_groups)
put(SHOW_CONTACT_SOURCE_FIELD, R.id.manage_visible_fields_contact_source)
+ put(SHOW_RINGTONE_FIELD, R.id.manage_ringtone)
}
val showContactFields = activity.config.showContactFields
@@ -38,11 +39,11 @@ class ManageVisibleFieldsDialog(val activity: BaseSimpleActivity) {
}
AlertDialog.Builder(activity)
- .setPositiveButton(R.string.ok) { dialog, which -> dialogConfirmed() }
- .setNegativeButton(R.string.cancel, null)
- .create().apply {
- activity.setupDialogStuff(view, this)
- }
+ .setPositiveButton(R.string.ok) { dialog, which -> dialogConfirmed() }
+ .setNegativeButton(R.string.cancel, null)
+ .create().apply {
+ activity.setupDialogStuff(view, this)
+ }
}
private fun dialogConfirmed() {
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectGroupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectGroupsDialog.kt
index 25e97f5b..0367c611 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectGroupsDialog.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectGroupsDialog.kt
@@ -2,6 +2,7 @@ package com.simplemobiletools.contacts.pro.dialogs
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
+import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
import com.simplemobiletools.commons.extensions.setupDialogStuff
import com.simplemobiletools.commons.views.MyAppCompatCheckbox
import com.simplemobiletools.contacts.pro.R
@@ -51,11 +52,12 @@ class SelectGroupsDialog(val activity: SimpleActivity, val selectedGroups: Array
item_checkbox_holder.setOnClickListener {
item_checkbox.toggle()
}
+
item_checkbox.apply {
isChecked = selectedGroups.contains(group)
text = group.title
tag = group.id
- setColors(config.textColor, config.primaryColor, config.backgroundColor)
+ setColors(config.textColor, activity.getAdjustedPrimaryColor(), config.backgroundColor)
}
view.dialog_groups_holder.addView(this)
}
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 9ad033d4..91cef212 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
@@ -36,7 +36,7 @@ fun Context.getEmptyContact(): Contact {
val originalContactSource = if (hasContactPermissions()) config.lastUsedContactSource else SMT_PRIVATE
val organization = Organization("", "")
return Contact(0, "", "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), originalContactSource, 0, 0, "",
- null, "", ArrayList(), organization, ArrayList(), ArrayList())
+ null, "", ArrayList(), organization, ArrayList(), ArrayList(), DEFAULT_MIMETYPE, null)
}
fun Context.viewContact(contact: Contact) {
@@ -66,17 +66,6 @@ fun Context.sendEmailIntent(recipient: String) {
}
}
-fun Context.sendSMSIntent(recipient: String) {
- Intent(Intent.ACTION_SENDTO).apply {
- data = Uri.fromParts("smsto", recipient, null)
- if (resolveActivity(packageManager) != null) {
- startActivity(this)
- } else {
- toast(R.string.no_app_found)
- }
- }
-}
-
fun Context.sendAddressIntent(address: String) {
val location = Uri.encode(address)
val uri = Uri.parse("geo:0,0?q=$location")
@@ -91,8 +80,14 @@ fun Context.sendAddressIntent(address: String) {
}
fun Context.openWebsiteIntent(url: String) {
+ val website = if (url.startsWith("http")) {
+ url
+ } else {
+ "https://$url"
+ }
+
Intent(Intent.ACTION_VIEW).apply {
- data = Uri.parse(url)
+ data = Uri.parse(website)
if (resolveActivity(packageManager) != null) {
startActivity(this)
} else {
@@ -364,6 +359,10 @@ fun Context.getSocialActions(id: Int): ArrayList {
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.call" -> SOCIAL_VOICE_CALL
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.call.video" -> SOCIAL_VIDEO_CALL
"vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile" -> SOCIAL_MESSAGE
+
+ // Threema
+ "vnd.android.cursor.item/vnd.ch.threema.app.profile" -> SOCIAL_MESSAGE
+ "vnd.android.cursor.item/vnd.ch.threema.app.call" -> SOCIAL_VOICE_CALL
else -> return@queryCursor
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/fragments/MyViewPagerFragment.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/fragments/MyViewPagerFragment.kt
index e526708b..ea1eb5a7 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/fragments/MyViewPagerFragment.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/fragments/MyViewPagerFragment.kt
@@ -61,7 +61,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
}
fragment_placeholder_2?.underlineText()
- updateViewStuff()
when {
this is FavoritesFragment -> {
@@ -76,22 +75,24 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
}
}
- fun textColorChanged(color: Int) {
+ fun setupColors(textColor: Int, adjustedPrimaryColor: Int) {
when {
- this is GroupsFragment -> (fragment_list.adapter as GroupsAdapter).updateTextColor(color)
+ this is GroupsFragment -> (fragment_list.adapter as? GroupsAdapter)?.updateTextColor(textColor)
else -> (fragment_list.adapter as? ContactsAdapter)?.apply {
- updateTextColor(color)
+ updateTextColor(textColor)
}
}
- letter_fastscroller?.textColor = color.getColorStateList()
- }
-
- fun primaryColorChanged() {
+ context.updateTextColors(fragment_wrapper.parent as ViewGroup)
fragment_fastscroller?.updatePrimaryColor()
fragment_fastscroller?.updateBubblePrimaryColor()
- letter_fastscroller_thumb?.thumbColor = config.primaryColor.getColorStateList()
- letter_fastscroller_thumb?.textColor = config.primaryColor.getContrastColor()
+ fragment_placeholder_2?.setTextColor(adjustedPrimaryColor)
+
+ letter_fastscroller?.textColor = textColor.getColorStateList()
+ letter_fastscroller?.pressedTextColor = adjustedPrimaryColor
+ letter_fastscroller_thumb?.fontSize = context.getTextSize()
+ letter_fastscroller_thumb?.textColor = adjustedPrimaryColor.getContrastColor()
+ letter_fastscroller_thumb?.thumbColor = adjustedPrimaryColor.getColorStateList()
}
fun startNameWithSurnameChanged(startNameWithSurname: Boolean) {
@@ -143,11 +144,8 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
} else {
setupContactsFavoritesAdapter(contacts)
contactsIgnoringSearch = (fragment_list?.adapter as? ContactsAdapter)?.contactItems ?: ArrayList()
-
- letter_fastscroller.textColor = config.textColor.getColorStateList()
setupLetterFastscroller(contacts)
letter_fastscroller_thumb.setupWithFastScroller(letter_fastscroller)
- letter_fastscroller_thumb.textColor = config.primaryColor.getContrastColor()
}
}
@@ -274,10 +272,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
}
}
- fun onActivityResume() {
- updateViewStuff()
- }
-
fun finishActMode() {
(fragment_list.adapter as? MyRecyclerViewAdapter)?.finishActMode()
}
@@ -288,18 +282,18 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
val shouldNormalize = text.normalizeString() == text
val filtered = contactsIgnoringSearch.filter {
getProperText(it.getNameToDisplay(), shouldNormalize).contains(text, true) ||
- getProperText(it.nickname, shouldNormalize).contains(text, true) ||
- it.phoneNumbers.any {
- text.normalizePhoneNumber().isNotEmpty() && (it.normalizedNumber
- ?: it.value).contains(text.normalizePhoneNumber(), true)
- } ||
- it.emails.any { it.value.contains(text, true) } ||
- it.addresses.any { getProperText(it.value, shouldNormalize).contains(text, true) } ||
- it.IMs.any { it.value.contains(text, true) } ||
- getProperText(it.notes, shouldNormalize).contains(text, true) ||
- getProperText(it.organization.company, shouldNormalize).contains(text, true) ||
- getProperText(it.organization.jobPosition, shouldNormalize).contains(text, true) ||
- it.websites.any { it.contains(text, true) }
+ getProperText(it.nickname, shouldNormalize).contains(text, true) ||
+ it.phoneNumbers.any {
+ text.normalizePhoneNumber().isNotEmpty() && (it.normalizedNumber
+ ?: it.value).contains(text.normalizePhoneNumber(), true)
+ } ||
+ it.emails.any { it.value.contains(text, true) } ||
+ it.addresses.any { getProperText(it.value, shouldNormalize).contains(text, true) } ||
+ it.IMs.any { it.value.contains(text, true) } ||
+ getProperText(it.notes, shouldNormalize).contains(text, true) ||
+ getProperText(it.organization.company, shouldNormalize).contains(text, true) ||
+ getProperText(it.organization.jobPosition, shouldNormalize).contains(text, true) ||
+ it.websites.any { it.contains(text, true) }
} as ArrayList
filtered.sortBy {
@@ -348,13 +342,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
}
}
- private fun updateViewStuff() {
- context.updateTextColors(fragment_wrapper.parent as ViewGroup)
- fragment_fastscroller?.updateBubbleColors()
- fragment_placeholder_2?.setTextColor(context.getAdjustedPrimaryColor())
- letter_fastscroller_thumb?.fontSize = context.getTextSize()
- }
-
private fun setupViewVisibility(hasItemsToShow: Boolean) {
fragment_placeholder_2?.beVisibleIf(!hasItemsToShow)
fragment_placeholder?.beVisibleIf(!hasItemsToShow)
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 ca6720f4..a52405fa 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
@@ -93,6 +93,7 @@ const val SHOW_CONTACT_SOURCE_FIELD = 4096
const val SHOW_WEBSITES_FIELD = 8192
const val SHOW_NICKNAME_FIELD = 16384
const val SHOW_IMS_FIELD = 32768
+const val SHOW_RINGTONE_FIELD = 65536
const val DEFAULT_EMAIL_TYPE = CommonDataKinds.Email.TYPE_HOME
const val DEFAULT_PHONE_NUMBER_TYPE = CommonDataKinds.Phone.TYPE_MOBILE
@@ -101,22 +102,25 @@ const val DEFAULT_EVENT_TYPE = CommonDataKinds.Event.TYPE_BIRTHDAY
const val DEFAULT_ORGANIZATION_TYPE = CommonDataKinds.Organization.TYPE_WORK
const val DEFAULT_WEBSITE_TYPE = CommonDataKinds.Website.TYPE_HOMEPAGE
const val DEFAULT_IM_TYPE = CommonDataKinds.Im.PROTOCOL_SKYPE
+const val DEFAULT_MIMETYPE = CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
// apps with special handling
const val TELEGRAM_PACKAGE = "org.telegram.messenger"
const val SIGNAL_PACKAGE = "org.thoughtcrime.securesms"
const val WHATSAPP_PACKAGE = "com.whatsapp"
const val VIBER_PACKAGE = "com.viber.voip"
+const val THREEMA_PACKAGE = "ch.threema.app"
const val WHATSAPP = "whatsapp"
const val SIGNAL = "signal"
const val VIBER = "viber"
const val TELEGRAM = "telegram"
+const val THREEMA = "threema"
const val SOCIAL_VOICE_CALL = 0
const val SOCIAL_VIDEO_CALL = 1
const val SOCIAL_MESSAGE = 2
-fun getEmptyLocalContact() = LocalContact(0, "", "", "", "", "", "", null, "", ArrayList(), ArrayList(), ArrayList(), 0, ArrayList(), "", ArrayList(), "", "", ArrayList(), ArrayList())
+fun getEmptyLocalContact() = LocalContact(0, "", "", "", "", "", "", null, "", ArrayList(), ArrayList(), ArrayList(), 0, ArrayList(), "", ArrayList(), "", "", ArrayList(), ArrayList(), null)
fun getProperText(text: String, shouldNormalize: Boolean) = if (shouldNormalize) text.normalizeString() else text
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/ContactsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/ContactsHelper.kt
index b771c496..66482c12 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/ContactsHelper.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/ContactsHelper.kt
@@ -28,7 +28,7 @@ class ContactsHelper(val context: Context) {
private val BATCH_SIZE = 50
private var displayContactSources = ArrayList()
- fun getContacts(getAll: Boolean = false, ignoredContactSources: HashSet = HashSet(), callback: (ArrayList) -> Unit) {
+ fun getContacts(getAll: Boolean = false, gettingDuplicates: Boolean = false, ignoredContactSources: HashSet = HashSet(), callback: (ArrayList) -> Unit) {
ensureBackgroundThread {
val contacts = SparseArray()
displayContactSources = context.getVisibleContactSources()
@@ -43,7 +43,7 @@ class ContactsHelper(val context: Context) {
}
}
- getDeviceContacts(contacts, ignoredContactSources)
+ getDeviceContacts(contacts, ignoredContactSources, gettingDuplicates)
if (displayContactSources.contains(SMT_PRIVATE)) {
LocalContactsHelper(context).getAllContacts().forEach {
@@ -125,7 +125,7 @@ class ContactsHelper(val context: Context) {
}
}
- private fun getDeviceContacts(contacts: SparseArray, ignoredContactSources: HashSet?) {
+ private fun getDeviceContacts(contacts: SparseArray, ignoredContactSources: HashSet?, gettingDuplicates: Boolean) {
if (!context.hasContactPermissions()) {
return
}
@@ -134,55 +134,87 @@ class ContactsHelper(val context: Context) {
val uri = Data.CONTENT_URI
val projection = getContactProjection()
- val selection = "${Data.MIMETYPE} = ? OR ${Data.MIMETYPE} = ?"
- val selectionArgs = arrayOf(StructuredName.CONTENT_ITEM_TYPE, CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
- val sortOrder = getSortString()
+ arrayOf(CommonDataKinds.Organization.CONTENT_ITEM_TYPE, StructuredName.CONTENT_ITEM_TYPE).forEach { mimetype ->
+ val selection = "${Data.MIMETYPE} = ?"
+ val selectionArgs = arrayOf(mimetype)
+ val sortOrder = getSortString()
- context.queryCursor(uri, projection, selection, selectionArgs, sortOrder, true) { cursor ->
- val accountName = cursor.getStringValue(RawContacts.ACCOUNT_NAME) ?: ""
- val accountType = cursor.getStringValue(RawContacts.ACCOUNT_TYPE) ?: ""
- if (ignoredSources.contains("$accountName:$accountType")) {
- return@queryCursor
+ context.queryCursor(uri, projection, selection, selectionArgs, sortOrder, true) { cursor ->
+ val accountName = cursor.getStringValue(RawContacts.ACCOUNT_NAME) ?: ""
+ val accountType = cursor.getStringValue(RawContacts.ACCOUNT_TYPE) ?: ""
+
+ if (ignoredSources.contains("$accountName:$accountType")) {
+ return@queryCursor
+ }
+
+ val id = cursor.getIntValue(Data.RAW_CONTACT_ID)
+ var prefix = ""
+ var firstName = ""
+ var middleName = ""
+ var surname = ""
+ var suffix = ""
+
+ // ignore names at Organization type contacts
+ if (mimetype == StructuredName.CONTENT_ITEM_TYPE) {
+ prefix = cursor.getStringValue(StructuredName.PREFIX) ?: ""
+ firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: ""
+ middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: ""
+ surname = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: ""
+ suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: ""
+ }
+
+ var photoUri = ""
+ var starred = 0
+ var contactId = 0
+ var thumbnailUri = ""
+ var ringtone: String? = null
+
+ if (!gettingDuplicates) {
+ photoUri = cursor.getStringValue(StructuredName.PHOTO_URI) ?: ""
+ starred = cursor.getIntValue(StructuredName.STARRED)
+ contactId = cursor.getIntValue(Data.CONTACT_ID)
+ thumbnailUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
+ ringtone = cursor.getStringValue(StructuredName.CUSTOM_RINGTONE)
+ }
+
+ val nickname = ""
+ val numbers = ArrayList() // proper value is obtained below
+ val emails = ArrayList()
+ val addresses = ArrayList()
+ val events = ArrayList()
+ val notes = ""
+ val groups = ArrayList()
+ val organization = Organization("", "")
+ val websites = ArrayList()
+ val ims = ArrayList()
+ val contact = Contact(id, prefix, firstName, middleName, surname, suffix, nickname, photoUri, numbers, emails, addresses,
+ events, accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims, mimetype, ringtone)
+
+ contacts.put(id, contact)
}
+ }
- val id = cursor.getIntValue(Data.RAW_CONTACT_ID)
- var prefix = ""
- var firstName = ""
- var middleName = ""
- var surname = ""
- var suffix = ""
+ val emails = getEmails()
+ var size = emails.size()
+ for (i in 0 until size) {
+ val key = emails.keyAt(i)
+ contacts[key]?.emails = emails.valueAt(i)
+ }
- // ignore names at Organization type contacts
- if (cursor.getStringValue(Data.MIMETYPE) == StructuredName.CONTENT_ITEM_TYPE) {
- prefix = cursor.getStringValue(StructuredName.PREFIX) ?: ""
- firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: ""
- middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: ""
- surname = cursor.getStringValue(StructuredName.FAMILY_NAME) ?: ""
- suffix = cursor.getStringValue(StructuredName.SUFFIX) ?: ""
- }
+ val organizations = getOrganizations()
+ size = organizations.size()
+ for (i in 0 until size) {
+ val key = organizations.keyAt(i)
+ contacts[key]?.organization = organizations.valueAt(i)
+ }
- val nickname = ""
- val photoUri = cursor.getStringValue(StructuredName.PHOTO_URI) ?: ""
- val numbers = ArrayList() // proper value is obtained below
- val emails = ArrayList()
- val addresses = ArrayList()
- val events = ArrayList()
- val starred = cursor.getIntValue(StructuredName.STARRED)
- val contactId = cursor.getIntValue(Data.CONTACT_ID)
- val thumbnailUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
- val notes = ""
- val groups = ArrayList()
- val organization = Organization("", "")
- val websites = ArrayList()
- val ims = ArrayList()
- val contact = Contact(id, prefix, firstName, middleName, surname, suffix, nickname, photoUri, numbers, emails, addresses,
- events, accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims)
-
- contacts.put(id, contact)
+ // no need to fetch some fields if we are only getting duplicates of the current contact
+ if (gettingDuplicates) {
+ return
}
val phoneNumbers = getPhoneNumbers(null)
- var size = phoneNumbers.size()
+ size = phoneNumbers.size()
for (i in 0 until size) {
val key = phoneNumbers.keyAt(i)
if (contacts[key] != null) {
@@ -191,20 +223,6 @@ class ContactsHelper(val context: Context) {
}
}
- val nicknames = getNicknames()
- size = nicknames.size()
- for (i in 0 until size) {
- val key = nicknames.keyAt(i)
- contacts[key]?.nickname = nicknames.valueAt(i)
- }
-
- val emails = getEmails()
- size = emails.size()
- for (i in 0 until size) {
- val key = emails.keyAt(i)
- contacts[key]?.emails = emails.valueAt(i)
- }
-
val addresses = getAddresses()
size = addresses.size()
for (i in 0 until size) {
@@ -233,13 +251,6 @@ class ContactsHelper(val context: Context) {
contacts[key]?.notes = notes.valueAt(i)
}
- val organizations = getOrganizations()
- size = organizations.size()
- for (i in 0 until size) {
- val key = organizations.keyAt(i)
- contacts[key]?.organization = organizations.valueAt(i)
- }
-
val websites = getWebsites()
size = websites.size()
for (i in 0 until size) {
@@ -695,9 +706,10 @@ class ContactsHelper(val context: Context) {
var middleName = ""
var surname = ""
var suffix = ""
+ val mimetype = cursor.getStringValue(Data.MIMETYPE)
// ignore names at Organization type contacts
- if (cursor.getStringValue(Data.MIMETYPE) == StructuredName.CONTENT_ITEM_TYPE) {
+ if (mimetype == StructuredName.CONTENT_ITEM_TYPE) {
prefix = cursor.getStringValue(StructuredName.PREFIX) ?: ""
firstName = cursor.getStringValue(StructuredName.GIVEN_NAME) ?: ""
middleName = cursor.getStringValue(StructuredName.MIDDLE_NAME) ?: ""
@@ -714,6 +726,7 @@ class ContactsHelper(val context: Context) {
val notes = getNotes(id)[id] ?: ""
val accountName = cursor.getStringValue(RawContacts.ACCOUNT_NAME) ?: ""
val starred = cursor.getIntValue(StructuredName.STARRED)
+ val ringtone = cursor.getStringValue(StructuredName.CUSTOM_RINGTONE)
val contactId = cursor.getIntValue(Data.CONTACT_ID)
val groups = getContactGroups(storedGroups, contactId)[contactId] ?: ArrayList()
val thumbnailUri = cursor.getStringValue(StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
@@ -721,7 +734,7 @@ class ContactsHelper(val context: Context) {
val websites = getWebsites(id)[id] ?: ArrayList()
val ims = getIMs(id)[id] ?: ArrayList()
return Contact(id, prefix, firstName, middleName, surname, suffix, nickname, photoUri, number, emails, addresses, events,
- accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims)
+ accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims, mimetype, ringtone)
}
}
@@ -745,7 +758,8 @@ class ContactsHelper(val context: Context) {
val ignoredTypes = arrayListOf(
SIGNAL_PACKAGE,
TELEGRAM_PACKAGE,
- WHATSAPP_PACKAGE
+ WHATSAPP_PACKAGE,
+ THREEMA_PACKAGE
)
val contactSources = getContactSourcesSync()
@@ -819,6 +833,7 @@ class ContactsHelper(val context: Context) {
StructuredName.PHOTO_URI,
StructuredName.PHOTO_THUMBNAIL_URI,
StructuredName.STARRED,
+ StructuredName.CUSTOM_RINGTONE,
RawContacts.ACCOUNT_NAME,
RawContacts.ACCOUNT_TYPE
)
@@ -858,8 +873,8 @@ class ContactsHelper(val context: Context) {
try {
val operations = ArrayList()
ContentProviderOperation.newUpdate(Data.CONTENT_URI).apply {
- val selection = "${Data.RAW_CONTACT_ID} = ? AND (${Data.MIMETYPE} = ? OR ${Data.MIMETYPE} = ?)"
- val selectionArgs = arrayOf(contact.id.toString(), StructuredName.CONTENT_ITEM_TYPE, CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
+ val selection = "${Data.RAW_CONTACT_ID} = ? AND ${Data.MIMETYPE} = ?"
+ val selectionArgs = arrayOf(contact.id.toString(), contact.mimetype)
withSelection(selection, selectionArgs)
withValue(StructuredName.PREFIX, contact.prefix)
withValue(StructuredName.GIVEN_NAME, contact.firstName)
@@ -1010,14 +1025,16 @@ class ContactsHelper(val context: Context) {
}
// add organization
- ContentProviderOperation.newInsert(Data.CONTENT_URI).apply {
- withValue(Data.RAW_CONTACT_ID, contact.id)
- withValue(Data.MIMETYPE, CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
- withValue(CommonDataKinds.Organization.COMPANY, contact.organization.company)
- withValue(CommonDataKinds.Organization.TYPE, DEFAULT_ORGANIZATION_TYPE)
- withValue(CommonDataKinds.Organization.TITLE, contact.organization.jobPosition)
- withValue(CommonDataKinds.Organization.TYPE, DEFAULT_ORGANIZATION_TYPE)
- operations.add(build())
+ if (contact.organization.isNotEmpty()) {
+ ContentProviderOperation.newInsert(Data.CONTENT_URI).apply {
+ withValue(Data.RAW_CONTACT_ID, contact.id)
+ withValue(Data.MIMETYPE, CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
+ withValue(CommonDataKinds.Organization.COMPANY, contact.organization.company)
+ withValue(CommonDataKinds.Organization.TYPE, DEFAULT_ORGANIZATION_TYPE)
+ withValue(CommonDataKinds.Organization.TITLE, contact.organization.jobPosition)
+ withValue(CommonDataKinds.Organization.TYPE, DEFAULT_ORGANIZATION_TYPE)
+ operations.add(build())
+ }
}
// delete websites
@@ -1061,11 +1078,12 @@ class ContactsHelper(val context: Context) {
}
}
- // favorite
+ // favorite, ringtone
try {
val uri = Uri.withAppendedPath(Contacts.CONTENT_URI, contact.contactId.toString())
- val contentValues = ContentValues(1)
+ val contentValues = ContentValues(2)
contentValues.put(Contacts.STARRED, contact.starred)
+ contentValues.put(Contacts.CUSTOM_RINGTONE, contact.ringtone)
context.contentResolver.update(uri, contentValues, null, null)
} catch (e: Exception) {
context.showErrorToast(e)
@@ -1327,12 +1345,13 @@ class ContactsHelper(val context: Context) {
addFullSizePhoto(rawId, fullSizePhotoData)
}
- // favorite
+ // favorite, ringtone
val userId = getRealContactId(rawId)
- if (userId != 0 && contact.starred == 1) {
+ if (userId != 0) {
val uri = Uri.withAppendedPath(Contacts.CONTENT_URI, userId.toString())
- val contentValues = ContentValues(1)
+ val contentValues = ContentValues(2)
contentValues.put(Contacts.STARRED, contact.starred)
+ contentValues.put(Contacts.CUSTOM_RINGTONE, contact.ringtone)
context.contentResolver.update(uri, contentValues, null, null)
}
@@ -1413,6 +1432,21 @@ class ContactsHelper(val context: Context) {
LocalContactsHelper(context).toggleFavorites(localContacts, addToFavorites)
}
+ fun updateRingtone(contactId: String, newUri: String) {
+ try {
+ val operations = ArrayList()
+ val uri = Uri.withAppendedPath(Contacts.CONTENT_URI, contactId)
+ ContentProviderOperation.newUpdate(uri).apply {
+ withValue(Contacts.CUSTOM_RINGTONE, newUri)
+ operations.add(build())
+ }
+
+ context.contentResolver.applyBatch(AUTHORITY, operations)
+ } catch (e: Exception) {
+ context.showErrorToast(e)
+ }
+ }
+
fun deleteContact(originalContact: Contact, deleteClones: Boolean = false, callback: (success: Boolean) -> Unit) {
ensureBackgroundThread {
if (deleteClones) {
@@ -1463,7 +1497,7 @@ class ContactsHelper(val context: Context) {
fun getDuplicatesOfContact(contact: Contact, addOriginal: Boolean, callback: (ArrayList) -> Unit) {
ensureBackgroundThread {
- getContacts(true) { contacts ->
+ getContacts(true, true) { contacts ->
val duplicates = contacts.filter { it.id != contact.id && it.getHashToCompare() == contact.getHashToCompare() }.toMutableList() as ArrayList
if (addOriginal) {
duplicates.add(contact)
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/LocalContactsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/LocalContactsHelper.kt
index cb415e7a..b3fbeb61 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/LocalContactsHelper.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/LocalContactsHelper.kt
@@ -6,7 +6,6 @@ import android.graphics.BitmapFactory
import android.net.Uri
import android.provider.ContactsContract.CommonDataKinds.Event
import android.provider.MediaStore
-import com.simplemobiletools.commons.extensions.getChoppedList
import com.simplemobiletools.commons.models.SimpleContact
import com.simplemobiletools.contacts.pro.extensions.contactsDB
import com.simplemobiletools.contacts.pro.extensions.getByteArray
@@ -56,7 +55,7 @@ class LocalContactsHelper(val context: Context) {
}
fun deleteContactIds(ids: MutableList) {
- ids.getChoppedList().forEach {
+ ids.chunked(30).forEach {
context.contactsDB.deleteContactIds(it)
}
}
@@ -68,6 +67,10 @@ class LocalContactsHelper(val context: Context) {
}
}
+ fun updateRingtone(id: Int, ringtone: String) {
+ context.contactsDB.updateRingtone(ringtone, id)
+ }
+
private fun getPhotoByteArray(uri: String): ByteArray {
if (uri.isEmpty()) {
return ByteArray(0)
@@ -83,7 +86,7 @@ class LocalContactsHelper(val context: Context) {
return scaledSizePhotoData
}
- fun convertLocalContactToContact(localContact: LocalContact?, storedGroups: ArrayList): Contact? {
+ private fun convertLocalContactToContact(localContact: LocalContact?, storedGroups: ArrayList): Contact? {
if (localContact == null) {
return null
}
@@ -121,6 +124,7 @@ class LocalContactsHelper(val context: Context) {
organization = Organization(localContact.company, localContact.jobPosition)
websites = localContact.websites
IMs = localContact.IMs
+ ringtone = localContact.ringtone
}
}
@@ -151,6 +155,7 @@ class LocalContactsHelper(val context: Context) {
jobPosition = contact.organization.jobPosition
websites = contact.websites
IMs = contact.IMs
+ ringtone = contact.ringtone
}
}
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt
index db2ce7a4..f7b7bab6 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/VcfImporter.kt
@@ -115,6 +115,7 @@ class VcfImporter(val activity: SimpleActivity) {
val photoData = ezContact.photos.firstOrNull()?.data
val photo = null
val thumbnailUri = savePhoto(photoData)
+ val ringtone = null
val IMs = ArrayList()
ezContact.impps.forEach {
@@ -138,11 +139,16 @@ class VcfImporter(val activity: SimpleActivity) {
}
val contact = Contact(0, prefix, firstName, middleName, surname, suffix, nickname, photoUri, phoneNumbers, emails, addresses, events,
- targetContactSource, starred, contactId, thumbnailUri, photo, notes, groups, organization, websites, IMs)
+ targetContactSource, starred, contactId, thumbnailUri, photo, notes, groups, organization, websites, IMs, DEFAULT_MIMETYPE, ringtone)
// if there is no N and ORG fields at the given contact, only FN, treat it as an organization
if (contact.getNameToDisplay().isEmpty() && contact.organization.isEmpty() && ezContact.formattedName?.value?.isNotEmpty() == true) {
contact.organization.company = ezContact.formattedName.value
+ contact.mimetype = CommonDataKinds.Organization.CONTENT_ITEM_TYPE
+ }
+
+ if (contact.isABusinessContact()) {
+ contact.mimetype = CommonDataKinds.Organization.CONTENT_ITEM_TYPE
}
if (ContactsHelper(activity).insertContact(contact)) {
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
index e419e78b..b4a7bda9 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/interfaces/ContactsDao.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/interfaces/ContactsDao.kt
@@ -23,6 +23,9 @@ interface ContactsDao {
@Query("UPDATE contacts SET starred = :isStarred WHERE id = :id")
fun updateStarred(isStarred: Int, id: Int)
+ @Query("UPDATE contacts SET ringtone = :ringtone WHERE id = :id")
+ fun updateRingtone(ringtone: String, id: Int)
+
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertOrUpdate(contact: LocalContact): Long
diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/Contact.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/Contact.kt
index 83e0ff17..2a20f174 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/Contact.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/Contact.kt
@@ -13,8 +13,9 @@ import com.simplemobiletools.contacts.pro.helpers.SMT_PRIVATE
data class Contact(var id: Int, var prefix: String, var firstName: String, var middleName: String, var surname: String, var suffix: String, var nickname: String,
var photoUri: String, var phoneNumbers: ArrayList, var emails: ArrayList, var addresses: ArrayList,
var events: ArrayList, var source: String, var starred: Int, var contactId: Int, var thumbnailUri: String, var photo: Bitmap?, var notes: String,
- var groups: ArrayList, var organization: Organization, var websites: ArrayList, var IMs: ArrayList) :
- Comparable {
+ var groups: ArrayList, var organization: Organization, var websites: ArrayList, var IMs: ArrayList, var mimetype: String,
+ var ringtone: String?) :
+ Comparable {
companion object {
var sorting = 0
var startWithSurname = false
@@ -71,7 +72,7 @@ data class Contact(var id: Int, var prefix: String, var firstName: String, var m
} else if (firstString.isNotEmpty() && secondString.isEmpty()) {
-1
} else {
- if (firstString.toLowerCase() == secondString.toLowerCase()) {
+ if (firstString.equals(secondString, ignoreCase = true)) {
getNameToDisplay().compareTo(other.getNameToDisplay(), true)
} else {
firstString.compareTo(secondString, true)
@@ -112,7 +113,7 @@ data class Contact(var id: Int, var prefix: String, var firstName: String, var m
fun getStringToCompare(): String {
return copy(id = 0, prefix = "", firstName = getNameToDisplay().toLowerCase(), middleName = "", surname = "", suffix = "", nickname = "", photoUri = "",
phoneNumbers = ArrayList(), emails = ArrayList(), events = ArrayList(), source = "", addresses = ArrayList(), starred = 0, contactId = 0,
- thumbnailUri = "", notes = "", groups = ArrayList(), websites = ArrayList(), organization = Organization("", ""), IMs = ArrayList()).toString()
+ thumbnailUri = "", notes = "", groups = ArrayList(), websites = ArrayList(), organization = Organization("", ""), IMs = ArrayList(), ringtone = "").toString()
}
fun getHashToCompare() = getStringToCompare().hashCode()
@@ -130,9 +131,9 @@ data class Contact(var id: Int, var prefix: String, var firstName: String, var m
val normalizedText = if (convertLetters) text.normalizePhoneNumber() else text
phoneNumbers.any {
PhoneNumberUtils.compare(it.normalizedNumber, normalizedText) ||
- it.value.contains(text) ||
- it.normalizedNumber?.contains(normalizedText) == true ||
- it.value.normalizePhoneNumber().contains(normalizedText)
+ it.value.contains(text) ||
+ it.normalizedNumber?.contains(normalizedText) == true ||
+ it.value.normalizePhoneNumber().contains(normalizedText)
}
} else {
false
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
index 53f96fcd..b34f9b86 100644
--- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/LocalContact.kt
+++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/models/LocalContact.kt
@@ -7,26 +7,27 @@ import androidx.room.PrimaryKey
@Entity(tableName = "contacts", indices = [(Index(value = ["id"], unique = true))])
data class LocalContact(
- @PrimaryKey(autoGenerate = true) var id: Int?,
- @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 = "photo_uri") var photoUri: String,
- @ColumnInfo(name = "phone_numbers") var phoneNumbers: ArrayList,
- @ColumnInfo(name = "emails") var emails: ArrayList,
- @ColumnInfo(name = "events") var events: ArrayList,
- @ColumnInfo(name = "starred") var starred: Int,
- @ColumnInfo(name = "addresses") var addresses: ArrayList,
- @ColumnInfo(name = "notes") var notes: String,
- @ColumnInfo(name = "groups") var groups: ArrayList,
- @ColumnInfo(name = "company") var company: String,
- @ColumnInfo(name = "job_position") var jobPosition: String,
- @ColumnInfo(name = "websites") var websites: ArrayList,
- @ColumnInfo(name = "ims") var IMs: ArrayList) {
+ @PrimaryKey(autoGenerate = true) var id: Int?,
+ @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 = "photo_uri") var photoUri: String,
+ @ColumnInfo(name = "phone_numbers") var phoneNumbers: ArrayList,
+ @ColumnInfo(name = "emails") var emails: ArrayList,
+ @ColumnInfo(name = "events") var events: ArrayList,
+ @ColumnInfo(name = "starred") var starred: Int,
+ @ColumnInfo(name = "addresses") var addresses: ArrayList,
+ @ColumnInfo(name = "notes") var notes: String,
+ @ColumnInfo(name = "groups") var groups: ArrayList,
+ @ColumnInfo(name = "company") var company: String,
+ @ColumnInfo(name = "job_position") var jobPosition: String,
+ @ColumnInfo(name = "websites") var websites: ArrayList,
+ @ColumnInfo(name = "ims") var IMs: ArrayList,
+ @ColumnInfo(name = "ringtone") var ringtone: String?) {
override fun equals(other: Any?) = id == (other as? LocalContact?)?.id
diff --git a/app/src/main/res/layout/activity_edit_contact.xml b/app/src/main/res/layout/activity_edit_contact.xml
index eabe713f..e67be2cd 100644
--- a/app/src/main/res/layout/activity_edit_contact.xml
+++ b/app/src/main/res/layout/activity_edit_contact.xml
@@ -384,6 +384,31 @@
android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size" />
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_view_contact.xml b/app/src/main/res/layout/activity_view_contact.xml
index b7a3e0fd..f6ca310f 100644
--- a/app/src/main/res/layout/activity_view_contact.xml
+++ b/app/src/main/res/layout/activity_view_contact.xml
@@ -104,7 +104,7 @@
android:src="@drawable/ic_person_vector" />
-
-
-
-
-
-
-
-
-
-
+ android:textSize="@dimen/bigger_text_size"
+ android:tooltipText="John Doe" />
+
+
@@ -413,11 +341,26 @@
android:visibility="gone" />
+
+
-
@@ -11,8 +10,8 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/activity_margin"
- android:paddingEnd="@dimen/activity_margin"
- android:paddingTop="@dimen/activity_margin">
+ android:paddingTop="@dimen/activity_margin"
+ android:paddingEnd="@dimen/activity_margin">
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/first_name" />
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/middle_name" />
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/surname" />
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/full_name" />
-
+
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/ascending" />
+ android:paddingBottom="@dimen/medium_margin"
+ android:text="@string/descending" />
diff --git a/app/src/main/res/layout/dialog_manage_visible_fields.xml b/app/src/main/res/layout/dialog_manage_visible_fields.xml
index acf214b2..4998e348 100644
--- a/app/src/main/res/layout/dialog_manage_visible_fields.xml
+++ b/app/src/main/res/layout/dialog_manage_visible_fields.xml
@@ -1,6 +1,5 @@
-
@@ -11,136 +10,144 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/activity_margin"
- android:paddingEnd="@dimen/activity_margin"
- android:paddingTop="@dimen/activity_margin">
+ android:paddingTop="@dimen/activity_margin"
+ android:paddingEnd="@dimen/activity_margin">
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/prefix" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/first_name" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/middle_name" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/surname" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/suffix" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/nickname" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/phone_numbers" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/emails" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/addresses" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/instant_messaging" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/events" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/notes" />
+
+
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/organization" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/websites" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/groups" />
+ android:paddingBottom="@dimen/activity_margin"
+ android:text="@string/contact_source" />
diff --git a/app/src/main/res/layout/item_view_contact_source.xml b/app/src/main/res/layout/item_view_contact_source.xml
index f32cc87b..53eed9be 100644
--- a/app/src/main/res/layout/item_view_contact_source.xml
+++ b/app/src/main/res/layout/item_view_contact_source.xml
@@ -32,6 +32,7 @@
android:layout_marginEnd="@dimen/normal_margin"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="@dimen/small_margin"
+ android:visibility="gone"
tools:src="@drawable/ic_phone_vector" />
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 86048aec..e79a2bd3 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -105,6 +105,7 @@
مجموعات
مصدر الاتصال
المراسلة الفورية (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml
index 329b2c51..f37ceb11 100644
--- a/app/src/main/res/values-az/strings.xml
+++ b/app/src/main/res/values-az/strings.xml
@@ -105,6 +105,7 @@
Qruplar
Kontakt kökü
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 88c7b64c..a141450b 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -105,6 +105,7 @@
Skupiny
Zdroje kontaktů
Rychlé zprávy (IM)
+ Ringtone
Kontakt bude vymazán ze všech zdrojů kontaktů.
diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml
index 7c5cce09..402964ee 100644
--- a/app/src/main/res/values-cy/strings.xml
+++ b/app/src/main/res/values-cy/strings.xml
@@ -105,6 +105,7 @@
Grwpiau
Ffynhonnell gyswllt
Negesu ar unwaith (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index 19785552..2c307eb6 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -105,6 +105,7 @@
Groupper
Kontaktkilde
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index e7d10151..9dcaf9f6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -105,6 +105,7 @@
Gruppen
Kontaktquelle
Instant messaging (IM)
+ Ringtone
Der Kontakt wird von allen Kontaktquellen entfernt.
@@ -124,38 +125,38 @@
Verwalten Sie Ihre Kontakte professionell, schnell und sicher mit dieser App
- A lightweight app for managing your contacts loved by millions of people. The contacts can be stored on your device only, but also synchronized via Google, or other accounts.
+ Eine simple App um deine Kontakte zu verwalten, die von Millionen Menschen geliebt wird. Die Kontakte können entweder lokal auf dem Gerät gespeichert oder via Google und anderen Accounts synchronisiert werden.
- You can use it for managing user emails and events too. It has the ability to sort/filter by multiple parameters, optionally display surname as the first name.
+ Sie können die App auch nutzen, um Emails und Events der Kontakte zu speichern. Die App hat die Fähigkeit, mit verschiedenen Parametern zu suchen und zu sortieren und kann wahlweise den Vornamen an erster Stelle anzeigen.
- You can display your favorite contacts or groups on a separate list. Groups can be used for sending out batch emails or SMS, to save you some time, you can rename them easily.
+ Ihre Lieblingskontakte oder -gruppen können in einer seperaten Liste angezeigt werden. Gruppen können dafür genutzt werden, um einen Stapel an Emails oder SMS zu versenden, was Ihnen Zeit erspart. Zudem können Sie diese einfach umbennen.
- It contains handy buttons for calling, or texting your contacts. All visible fields can be customized as you wish, you can easily hide the unused ones. The search function will search the given string at every visible contact field, to make you find your desired contact easily.
+ Es sind nützliche Buttons verfügbar, um Ihre Kontakte anzurufen oder ihnen zu schreiben. Alle angezeigten Felder können nach Ihren Wünschen angepasst werden, alle ungenutzen Felder können ausgeblendet werden. Die Suchfunktion wird den angegebenen String in jedem sichtbaren Kontaktfeld suchen, sodass Sie Ihren gewüschten Kontakt einfach finden können.
- There is a lightweight dialpad at your service too, with smart contact suggestions.
+ Es gibt ein einfaches Wählfeld, mit intelligenten Kontaktvervollständigungen.
- It supports exporting/importing contacts in vCard format to .vcf files, for easy migrations or backing up your data.
+ Kontakte können im vCard-Format als .vcf Dateien exportiert und importiert werden, um einfach zu migrieren oder ein Backup zu erstellen.
- With this modern and stable contacts manager you can protect your contacts by not sharing them with other apps, so you can keep your contacts private.
+ Mit diesem modernen und stabilen Kontakte Manager können Sie Ihre Kontakte schützen, indem diese nicht mit andern Apps geteilt werden, sodass Ihre Kontakte privat bleiben.
- Like the contact source, you can also easily change the contact name, email, phone number, address, organization, groups and many other customizable fields. You can use it for storing contact events too, like birthdays, anniversaries, or any other custom ones.
+ Genauso wie die Kontaktquelle, können Sie ebnso einfach den Kontaktnamen, dessen Email, Telefonnummer, Addresse, Organisation, Gruppe und viele andere Felder anpassen. Sie können auch Events wie Geburtstage, Feiern oder benutzerdefinierte Events angeben.
- This simple contact editor has many handy settings like showing phone numbers on the main screen, toggle contact thumbnail visibility, showing only contacts with phone numbers, showing a call confirmation dialog before initiating a call. It comes with a quick dialer that also makes use of letters.
+ Dieser einfache Kontakte-Editor hat viele nützliche Einstellungen - zum Beispiel kann es die Telefonnummer im Hauptbildschirm anzeigen, das Kontake-Vorschaubild ein- und ausblenden, nur Kontakte mit Telefonnummern anzeigen und eine Anrufsbestätigung anzeigen, bevor der Anruf gestartet wird. Das schnelle Wahlfeld unterstützt auch Buchstaben.
- To further improve the user experience, you can customize what happens at clicking on a contact. You can either initiate a call, go to the View Details screen, or edit the selected contact.
+ Um die Nutzererfahrung noch mehr zu verbessern, können Sie anpassen, was passiert, wenn Sie auf den Kontakt drücken. Entweder kann ein Anruf gestartet, der Kontakt angepasst (editiert) oder Details angeigt werden.
- You can easily block phone numbers to avoid unwanted incoming calls.
+ Um ungewollte Anrufe zu vermeiden, können Anrufe einfach blockiert werden.
+
+ Um zu verhindern, dass potentiell ungewollte Kontakte angezeigt werden, führt die App Duplikate automatisch zusammen.
- To avoid showing potentially unwanted contacts, it has a powerful built in duplicate contact merger.
-
- It comes with material design and dark theme by default, provides great user experience for easy usage. The lack of internet access gives you more privacy, security and stability than other apps.
+ Die App beinhaltet standardmäßig material design und Dunkelmodus, um großartige Nutzererfahrungen und einfache Nutzung zu ermöglichen. Da die App keine Internetverbindung besitzt, bietet die App Ihnen mehr Datenschutz, Sicherheit und Stabilität als andere Apps.
Enthält keine Werbung oder unnötige Berechtigungen. Vollständig quelloffen. Die Farben sind anpassbar.
- Check out the full suite of Simple Tools here:
+ Entdecke die gesamte Serie an schlichten Apps hier:
https://www.simplemobiletools.com
- Standalone website of Simple Contacts Pro:
+ Standalone Webseite von Simple Contacts Pro:
https://www.simplemobiletools.com/contacts
Facebook:
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 5e770876..a442d1ed 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -87,11 +87,11 @@
Εξαγωγή επαφών σε .vcf αρχείο
Προορισμός πηγής επαφής
Συμπερίληψη πηγών επαφών
- Όνομα αρχείου (χωρίς .vcf)
+ Όνομα αρχείου (εκτός .vcf)
Πληκτρολόγιο
- Προσθήκη επαφής σε αριθμό
+ Προσθήκη αριθμού σε επαφή
Πρόθεμα
@@ -105,6 +105,7 @@
Ομάδες
Προέλευση επαφής
Αμεσο μήνυμα (IM)
+ Ήχος κλήσης
Η επαφή θα καταργηθεί από όλες τις πηγές επαφών.
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index be2e1d2b..867df01c 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -53,7 +53,7 @@
Contactos
Mostrar un cuadro de confirmación antes de iniciar una llamada
Solo mostrar contactos con números telefónicos
- Show private contacts to Simple Dialer, Simple SMS Messenger and Simple Calendar Pro
+ Mostrar contactos privados a Marcador Simple, Mensajería SMS Simple y Calendario Simple Pro
Casa
@@ -105,6 +105,7 @@
Grupos
Orígenes de contacto
Mensaje instantáneo (IM)
+ Ringtone
El contacto será eliminado de todos los orígenes de contactos.
@@ -115,7 +116,7 @@
- Quiero cambiar qué acmpos son visibles en loos contactos. ¿Puedo hacerlo?
+ Quiero cambiar qué campos son visibles en los contactos. ¿Puedo hacerlo?
Sí, todo lo que tienes que hacer es ir a Ajustes -> Administrar campos del contacto mostrados. Ahí puedes seleccionar que campos deberían ser visibles. Algunos de ellos están desactivados por defecto, así que podrías encontrar algunos nuevos ahí.
@@ -124,35 +125,35 @@
La mejor app de gestión de contactos con soporte de la función de grupos
- A lightweight app for managing your contacts loved by millions of people. The contacts can be stored on your device only, but also synchronized via Google, or other accounts.
+ Una ligera aplicación para administrar tus contactos amada por millones. Los contactos pueden ser almacenados únicamente en tu dispositivo, per otambién sincronizarlos vía Google u otras cuentas.
- You can use it for managing user emails and events too. It has the ability to sort/filter by multiple parameters, optionally display surname as the first name.
+ Puedes usarla para administrar correos electrónicos de usuarios y eventos también. Tiene la habilidad de ordenar/filtrar por múltiples parámetros y, opcionalmente, mostrar el apellido como el nombre.
- You can display your favorite contacts or groups on a separate list. Groups can be used for sending out batch emails or SMS, to save you some time, you can rename them easily.
+ Puedes mostrar tus contáctos favoritos o grupos en listas separadas. Los grupos pueden ser usados para enviar correos electrónicos o SMS por lotes, para ahorrate algo de tiempo, y puedes renombrarlos fácilmente.
- It contains handy buttons for calling, or texting your contacts. All visible fields can be customized as you wish, you can easily hide the unused ones. The search function will search the given string at every visible contact field, to make you find your desired contact easily.
+ Contiene prácticos botones para llamar o mensajear a tus contactos. Todos los campos visibles pueden ser personalizados a tu gusto, y fácilmente puedes ocultar los que no uses. La función de búsqueda buscará el texto dado en cada campo de contacto visible, para hacer más fácil encontrar el contacto deseado.
- There is a lightweight dialpad at your service too, with smart contact suggestions.
+ También tiene un ligero teclado de marcado a tu servicio, con sugerencias de contactos inteligentes.
- It supports exporting/importing contacts in vCard format to .vcf files, for easy migrations or backing up your data.
+ Soporta exportar/importar contactos en formato vCard a archivos .vcf, para fácil migración o respaldo de tu información.
- With this modern and stable contacts manager you can protect your contacts by not sharing them with other apps, so you can keep your contacts private.
+ Con este moderno y estable gestor de contactos puedes proteger tus contactos no compartiéndolos con otras aplicaciones, así puedes mantener tus contactos privados.
- Like the contact source, you can also easily change the contact name, email, phone number, address, organization, groups and many other customizable fields. You can use it for storing contact events too, like birthdays, anniversaries, or any other custom ones.
+ Como el origen del contacto, fácilmente también puedes cambiar el nombre del contacto, correo electrónico, número de teléfono, dirección, organización, grupos y muchos otros campos personalizables. Puedes usarlo para almacenar eventos de contactos también, como cumpleaños, aniversarios, o cualqueir otro personalizado.
- This simple contact editor has many handy settings like showing phone numbers on the main screen, toggle contact thumbnail visibility, showing only contacts with phone numbers, showing a call confirmation dialog before initiating a call. It comes with a quick dialer that also makes use of letters.
+ Este simple editor de contactos tiene varios ajustes prácticos como mostrar números de teléfono en la pantalla principal, alternar entre mostrar la miniatura del contacto, mostrar sólamente contactos con números de teléfono, mostrar un diálogo de confirmar llamada antes de iniciarla. Incluye un marcador rápido que también hace uso de las letras.
- To further improve the user experience, you can customize what happens at clicking on a contact. You can either initiate a call, go to the View Details screen, or edit the selected contact.
+ Para mejorar la experiencia de usuario aún más, puedes personalizar lo que pasa al tocar un contacto. Puedes iniciar una llamada, ir a la Vista de detalles o editar el contacto seleccionado.
- You can easily block phone numbers to avoid unwanted incoming calls.
+ Puedes bloquear números de teléfono fácilmente para evitar llamadas indeseadas.
- To avoid showing potentially unwanted contacts, it has a powerful built in duplicate contact merger.
+ Para evitar mosrar contactos potencialmente indeseados, tiene un poderoso fusionador de contactos duplicados.
- It comes with material design and dark theme by default, provides great user experience for easy usage. The lack of internet access gives you more privacy, security and stability than other apps.
+ Incluye diseño material y tema obscuro por defecto, provee una gran experiencia de usuario para uso sencillo. La falta del acceso a internet te da más privacidad, seguridad y estabilidad que otras aplicaciones.
- No contiene anuncios o permisos innecesarios. Es complétamente de código abierto, provee colores personalziables.
+ No contiene anuncios o permisos innecesarios. Es completamente de código abierto, provee colores personalizables.
- Check out the full suite of Simple Tools here:
+ Mira la suite completa de herramientas Simples aquí:
https://www.simplemobiletools.com
Standalone website of Simple Contacts Pro:
diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml
index 35204c41..3489b55a 100644
--- a/app/src/main/res/values-eu/strings.xml
+++ b/app/src/main/res/values-eu/strings.xml
@@ -105,6 +105,7 @@
Taldeak
Kontaktu jatorria
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 5ffa76e3..05df6c49 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -2,17 +2,17 @@
Simple Contacts
Yhteystiedot
Osoite
- Sijoitetaan
- Päivitetään
- Puhelimen muisti piilotettu
+ Sijoitetaan...
+ Päivitetään...
+ Puhelimen muisti (piilotettu muilta sovelluksilta)
Yritys
Ammatti
- Internet-sivu
+ Verkkosivu
Lähetä tekstiviesti yhteystiedoille
Lähetä sähköposti yhteystiedoille
Lähetä tekstiviesti ryhmälle
Lähetä sähköposti ryhmälle
- Soita
+ Soita %s
Luo uusi yhteystieto
Lisää olemassa olevaan yhteystietoon
@@ -30,8 +30,8 @@
Luo uusi ryhmä
Poista ryhmästä
Ryhmä on tyhjä
- Lisää yhteystietoja
- Ryhmää ei luotu
+ Lisää yhteystietoihin
+ Laitteessa ei ole yhteistietoryhmiä
Luo ryhmä
Lisää ryhmään
Luo ryhmä tilille
@@ -42,16 +42,16 @@
Poista kuva
- Näytä puhelinnumerot
+ Näytä puhelinnumerot päänäytöllä
Näytä yhteystietojen kuvakkeet
- Näytä soittimen painike
- Yhteystietoa painaessa…
+ Näytä numeronvalitsin-painike päänäytöllä
+ Yhteystietoa painaessa
Soita
Näytä yhteystieto
Valitse, mitkä yhteystietojen kentät näytetään
Valitse sovelluksen välilehdet
Yhteystiedot
- Näytä puhelun vahvistusruutu
+ Näytä soiton vahvistusruutu ennen soittoa
Näytä ainoastaan numerolliset yhteystiedot
Näytä yksityiset yhteystiedot sovelluksissa Simple Dialer, Simple SMS Messenger ja Simple Calendar Pro
@@ -62,9 +62,9 @@
Matkapuhelin
- Päänumero
- Työfaxi
- Kotifaxi
+ Oletus
+ Faksi (työ)
+ Faksi (koti)
Hakulaite
Puhelinnumeroa ei löytynyt
@@ -73,7 +73,7 @@
Vuosipäivä
- Ei suosikkeja
+ Näyttää siltä, että et ole vielä lisännyt suosikkiyhteystietoja.
Etsi yhteystietoja
@@ -83,46 +83,47 @@
Tuo yhteystietoja
Vie yhteystietoja
- Tuo .vcf yhteystietoja
- Vie .vcf yhteystietoja
- Kohdenna yhteystiedon lähde
+ Tuo yhteystietoja .vcf-tiedostosta
+ Vie yhteystietoja .vcf-tiedostoon
+ Yhteystietojen lähde
Sisällytä yhteystiedon lähteet
- Tiedostonimi ilman .vcf-päätettä
+ Tiedostonimi (ilman .vcf-päätettä)
- Näppäimistö
+ Numeronvalitsin
Lisää numero yhteystietoihin
- Alku
- Pääte
- Puhelinnumero
+ Etuliite
+ Jälkiliite
+ Puhelinnumerot
Sähköpostit
Osoitteet
- Tapahtumat
- Organisaatio
- Internetsivut
+ Tapahtumat (syntymäpäivät, vuosipäivät)
+ Yritys
+ Verkkosivut
Ryhmät
Yhteystiedon lähde
Pikaviestin
+ Soittoääni
Yhteystieto poistetaan kaikista lähteistä.
- - %d ryhmä
+ - %d ryhmän
- %d ryhmää
- Voinko valita, mitkä täytettävät kentät näytetään yhteystiedon ominaisuuksissa?
- Kyllä. Mene asetuksiin -> Valitse täytettävät kentät. Voit valita, mitkä kentät näytetään. Osa kentistä on oletuksena piilotettuna, , joten saatat löytää joitain uusia.
+ Voinko valita, mitkä täytettävät kentät näytetään yhteystiedon ominaisuuksissa?
+ Kyllä. Mene asetuksiin -> Valitse täytettävät kentät. Voit valita, mitkä kentät näytetään. Osa kentistä on oletuksena piilotettuna, joten saatat löytää joitain uusia.
- Simple Contacts Pro - Manage your contacts easily
+ Simple Contacts Pro - Yhteystietojen hallinta
- Easy and quick contact management with no ads, handles groups and favorites too.
+ Helppo ja nopea yhteystietojen hallinta ilman mainoksia. Hallitsee myös ryhmät ja suosikit.
A lightweight app for managing your contacts loved by millions of people. The contacts can be stored on your device only, but also synchronized via Google, or other accounts.
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index 081fe49f..c09bbb23 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -103,6 +103,7 @@
Groupe
Source du contact
Messagerie instantanée (MI)
+ Ringtone
Le contact sera supprimé de toutes les sources de contacts.
diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml
index 472de9c3..4f813d53 100644
--- a/app/src/main/res/values-hr/strings.xml
+++ b/app/src/main/res/values-hr/strings.xml
@@ -105,6 +105,7 @@
Grupe
Izvori kontakata
Brzo slanje poruka (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 208eb685..ad093db1 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -105,6 +105,7 @@
Csoportok
Névjegy account
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml
index b83035cb..bebecc6a 100644
--- a/app/src/main/res/values-id/strings.xml
+++ b/app/src/main/res/values-id/strings.xml
@@ -105,6 +105,7 @@
Grup
Sumber kontak
Pesan singkat (IM)
+ Ringtone
Kontak akan dihapus dari semua sumber kontak.
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index b83035cb..bebecc6a 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -105,6 +105,7 @@
Grup
Sumber kontak
Pesan singkat (IM)
+ Ringtone
Kontak akan dihapus dari semua sumber kontak.
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 23518958..4f63a7a3 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -105,6 +105,7 @@
Gruppi
Provenienza del contatto
Messaggistica istantanea (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 19240a9b..894e501c 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -1,5 +1,5 @@
- Simple Contacts
+ Simpleコンタクト
連絡先
住所
挿入中…
@@ -12,7 +12,7 @@
連絡先にメールを送信
グループにSMSを送信
グループにメールを送信
- Call %s
+ %sに発信
新しい連絡先を作成
既存の連絡先に追加
@@ -53,7 +53,7 @@
連絡先
発信する前に確認ダイアログを表示する
電話番号が登録された連絡先のみ表示する
- Show private contacts to Simple Dialer, Simple SMS Messenger and Simple Calendar Pro
+ Simpleダイヤラー、Simpleショートメール、SimpleカレンダーProに個人の連絡先を表示
自宅
@@ -62,7 +62,7 @@
携帯
- Main
+ メイン
職場FAX
自宅FAX
ポケベル
@@ -78,15 +78,15 @@
連絡先を検索
お気に入りを検索
- Search groups
+ グループを検索
連絡先をインポート
連絡先をエクスポート
.vcfファイルから連絡先をインポート
連絡先を.vcfファイルにエクスポート
- Target contact source
- Include contact sources
+ 対象となる連絡先のソース
+ 連絡先のソースを含める
ファイル名 (.vcfを含めない)
@@ -104,14 +104,15 @@
ウェブサイト
グループ
インポート元
- Instant messaging (IM)
+ インスタントメッセージ(IM)
+ Ringtone
- The contact will be removed from all contact sources.
+ 全ての連絡先ソースから連絡先を消去します
- - %d group
- - %d groups
+ - %d件のグループ
+ - %d件のグループ
diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml
index ddbe3720..4f73d699 100644
--- a/app/src/main/res/values-ko-rKR/strings.xml
+++ b/app/src/main/res/values-ko-rKR/strings.xml
@@ -105,6 +105,7 @@
Groups
Contact source
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-lt/strings.xml b/app/src/main/res/values-lt/strings.xml
index 082f2ee6..e005659b 100644
--- a/app/src/main/res/values-lt/strings.xml
+++ b/app/src/main/res/values-lt/strings.xml
@@ -105,6 +105,7 @@
Grupės
Kontakto šaltinis
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml
index b4a7910a..d8b9fb1d 100644
--- a/app/src/main/res/values-ml/strings.xml
+++ b/app/src/main/res/values-ml/strings.xml
@@ -105,6 +105,7 @@
ഗ്രൂപ്പുകൾ
കോൺടാക്റ്റ് ഉറവിടം
തത്സമയ സന്ദേശം അയക്കൽ
+ Ringtone
എല്ലാ കോൺടാക്റ്റ് ഉറവിടങ്ങളിൽ നിന്നും ഈ കോൺടാക്റ്റ് നീക്കംചെയ്യും.
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 5015502f..3e1cf44c 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -65,7 +65,7 @@
Standaard
Fax Werk
Fax Thuis
- Pager
+ Pieper
Geen telefoonnummers gevonden
@@ -105,6 +105,7 @@
Groepen
Account
Instant messaging (IM)
+ Ringtone
De contactpersoon zal worden verwijderd uit alle accounts.
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index fc65632b..08882179 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -105,6 +105,7 @@
Grupy
Miejsce przechowywania kontaktu
Komunikator
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index e0385213..a77eb898 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -105,6 +105,7 @@
Grupos
Origem do contato
Mensageiro instantâneo (MI)
+ Ringtone
O contato será removido de todas removido de todas as fontes de contato.
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index a309c527..fe1bbc63 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -105,6 +105,7 @@
Grupos
Origem do contacto
Mensagem instantânea (IM)
+ Ringtone
O contacto será apagado de todas as origens.
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index d9460fd7..730a71c1 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -105,6 +105,7 @@
Группы
Источник контакта
Мессенджеры
+ Ringtone
Контакт будет удалён из всех источников контактов.
diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml
index 7768b1ab..98a31b04 100644
--- a/app/src/main/res/values-sk/strings.xml
+++ b/app/src/main/res/values-sk/strings.xml
@@ -105,6 +105,7 @@
Skupiny
Zdroje kontaktov
Rýchle správy (IM)
+ Zvonenie
Kontakt bude vymazaný zo všetkých zdrojov kontaktov.
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index e95df35f..858798db 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -105,6 +105,7 @@
Grupper
Kontaktkälla
Snabbmeddelanden (IM)
+ Ringtone
Kontakten kommer att tas bort från alla kontaktkällor.
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 86616fc0..5d1b453b 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -105,6 +105,7 @@
Gruplar
Kişi kaynağı
Anlık mesajlaşma (IM)
+ Zil sesi
Kişi tüm kişi kaynaklarından kaldırılacak.
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 62f701c0..a31d5ab6 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -105,6 +105,7 @@
Групи
Походження контакту
Мессенджери
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index c2f885da..995fbd6a 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -105,6 +105,7 @@
群组
联系人来源
即时通讯 (IM)
+ Ringtone
该联系人将会被从所有联系人来源移除。
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index e739f373..08cf9aa9 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -105,6 +105,7 @@
群組
聯絡人來源
即時通訊 (IM)
+ Ringtone
這聯絡人將從全部通訊錄來源移除。
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 209bf69c..9f72e262 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -105,6 +105,7 @@
Groups
Contact source
Instant messaging (IM)
+ Ringtone
The contact will be removed from all contact sources.
diff --git a/build.gradle b/build.gradle
index 9e841957..d4107b09 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = '1.4.10'
+ ext.kotlin_version = '1.4.30'
repositories {
google()
@@ -9,7 +9,7 @@ buildscript {
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.2'
+ classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
diff --git a/fastlane/metadata/android/en-US/changelogs/78.txt b/fastlane/metadata/android/en-US/changelogs/78.txt
new file mode 100644
index 00000000..4beec155
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/78.txt
@@ -0,0 +1 @@
+ * Added some translation, stability and UX improvements
diff --git a/fastlane/metadata/android/en-US/changelogs/79.txt b/fastlane/metadata/android/en-US/changelogs/79.txt
new file mode 100644
index 00000000..1be5a1ae
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/79.txt
@@ -0,0 +1,4 @@
+ * Always fetch the same contacts, no matter what sorting is set
+ * Fix an organization updating related issue
+ * Merge names into 1 line at the View Details screen
+ * Improve Threema contact handling
diff --git a/fastlane/metadata/android/en-US/changelogs/80.txt b/fastlane/metadata/android/en-US/changelogs/80.txt
new file mode 100644
index 00000000..45d85bfc
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/80.txt
@@ -0,0 +1,4 @@
+ * Allow customizing the ringtone per contact (Ringtone has to be enabled as a customizable field in the app settings)
+ * Added a White theme with special handling
+ * Added some letter fastscroller related improvements
+ * Some performance, stability and translation related improvements
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_1.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/app_1.jpg
deleted file mode 100644
index eddad087..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_1.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_2.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/app_2.jpg
deleted file mode 100644
index e9602d8b..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_2.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_3.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/app_3.jpg
deleted file mode 100644
index a3a5fdc6..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_3.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_4.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/app_4.jpg
deleted file mode 100644
index 109fbcea..00000000
Binary files a/fastlane/metadata/android/en-US/images/phoneScreenshots/app_4.jpg and /dev/null differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/english/1.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/1.jpg
new file mode 100644
index 00000000..526832ef
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/1.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/english/2.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/2.jpg
new file mode 100644
index 00000000..5f3510a2
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/2.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/english/3.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/3.jpg
new file mode 100644
index 00000000..64ef52f6
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/3.jpg differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/english/4.jpg b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/4.jpg
new file mode 100644
index 00000000..c9e39b50
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/english/4.jpg differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 272e8b44..dc129daa 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Jun 18 23:08:40 CEST 2020
+#Tue Nov 03 22:18:17 CET 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip