mirror of
https://github.com/SimpleMobileTools/Simple-Contacts.git
synced 2025-02-17 03:51:03 +01:00
commit
bba01c770a
7
.gitignore
vendored
7
.gitignore
vendored
@ -1,10 +1,11 @@
|
||||
*.iml
|
||||
*.aab
|
||||
.gradle
|
||||
/local.properties
|
||||
/gradle.properties
|
||||
/.idea/
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
release.keystore
|
||||
signing.properties
|
||||
/library/build
|
||||
keystore.jks
|
||||
keystore.properties
|
||||
|
25
CHANGELOG.md
25
CHANGELOG.md
@ -1,10 +1,33 @@
|
||||
Changelog
|
||||
==========
|
||||
|
||||
Version 6.1.0 *(2018-11-30)*
|
||||
----------------------------
|
||||
|
||||
* Allow setting the app as the default for handling calls
|
||||
* Allow blocking numbers on Android 7+
|
||||
* Improved contact recognition at Recents
|
||||
* Fixed some handling related to creating new contact with a number, or adding a number to an existing contact
|
||||
* Add handling for secret codes like *#*#4636#*#*
|
||||
* Allow copying all contact fields from the view screen by long pressing them
|
||||
* Added an option for hiding the dialpad button on the main screen
|
||||
* Fixed some issues related to importing contacts with birthdays
|
||||
|
||||
Version 6.0.0 *(2018-11-06)*
|
||||
----------------------------
|
||||
|
||||
* Initial Pro version
|
||||
|
||||
Version 5.1.2 *(2018-11-28)*
|
||||
----------------------------
|
||||
|
||||
* Had to remove the Recents tab due to the latest Googles' permissions policy. The Pro app will be updated with a Recents tab and a mandatory Dialer soon.
|
||||
* This version of the app is no longer maintained, please upgrade to the Pro version. You can find the Upgrade button at the top of the app Settings.
|
||||
|
||||
Version 5.1.1 *(2018-11-05)*
|
||||
----------------------------
|
||||
|
||||
* This version of the app is no longer maintained. Please upgrade to the Pro version. It is free till Nov 13 2018. You can find the Upgrade button at the top of the app Settings.
|
||||
* Added some stability and translation improvements
|
||||
|
||||
Version 5.1.0 *(2018-10-28)*
|
||||
----------------------------
|
||||
|
@ -9,8 +9,8 @@ Contains no ads or unnecessary permissions. It is fully opensource, provides cus
|
||||
|
||||
This app is just one piece of a bigger series of apps. You can find the rest of them at http://www.simplemobiletools.com
|
||||
|
||||
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.contacts'><img src='http://simplemobiletools.github.io/assets/public/google-play.png' alt='Get it on Google Play' height='45' /></a>
|
||||
<a href='https://f-droid.org/packages/com.simplemobiletools.contacts'><img src='http://simplemobiletools.github.io/assets/public/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
|
||||
<a href='https://play.google.com/store/apps/details?id=com.simplemobiletools.contacts.pro'><img src='http://simplemobiletools.github.io/assets/public/google-play.png' alt='Get it on Google Play' height='45' /></a>
|
||||
<a href='https://f-droid.org/packages/com.simplemobiletools.contacts.pro'><img src='http://simplemobiletools.github.io/assets/public/f-droid.png' alt='Get it on F-Droid' height='45' /></a>
|
||||
|
||||
<div style="display:flex;">
|
||||
<img alt="App image" src="fastlane/metadata/android/en-US/images/phoneScreenshots/app.png" width="30%">
|
||||
|
@ -1,6 +1,11 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||
def keystoreProperties = new Properties()
|
||||
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
@ -10,13 +15,18 @@ android {
|
||||
applicationId "com.simplemobiletools.contacts.pro"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 35
|
||||
versionName "5.1.1"
|
||||
versionCode 37
|
||||
versionName "6.1.0"
|
||||
setProperty("archivesBaseName", "contacts")
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
release
|
||||
release {
|
||||
keyAlias keystoreProperties['keyAlias']
|
||||
keyPassword keystoreProperties['keyPassword']
|
||||
storeFile file(keystoreProperties['storeFile'])
|
||||
storePassword keystoreProperties['storePassword']
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@ -41,28 +51,12 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.simplemobiletools:commons:5.3.11'
|
||||
implementation 'joda-time:joda-time:2.9.9'
|
||||
implementation 'com.facebook.stetho:stetho:1.5.0'
|
||||
implementation 'com.simplemobiletools:commons:5.5.1'
|
||||
implementation 'joda-time:joda-time:2.10.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
|
||||
implementation 'com.googlecode.ez-vcard:ez-vcard:0.10.4'
|
||||
}
|
||||
|
||||
Properties props = new Properties()
|
||||
def propFile = new File('signing.properties')
|
||||
if (propFile.canRead()) {
|
||||
props.load(new FileInputStream(propFile))
|
||||
|
||||
if (props != null && props.containsKey('STORE_FILE') && props.containsKey('KEY_ALIAS') && props.containsKey('PASSWORD')) {
|
||||
android.signingConfigs.release.storeFile = file(props['STORE_FILE'])
|
||||
android.signingConfigs.release.storePassword = props['PASSWORD']
|
||||
android.signingConfigs.release.keyAlias = props['KEY_ALIAS']
|
||||
android.signingConfigs.release.keyPassword = props['PASSWORD']
|
||||
} else {
|
||||
println 'signing.properties found but some entries are missing'
|
||||
android.buildTypes.release.signingConfig = null
|
||||
}
|
||||
} else {
|
||||
println 'signing.properties not found'
|
||||
android.buildTypes.release.signingConfig = null
|
||||
kapt "androidx.room:room-compiler:2.0.0"
|
||||
implementation "androidx.room:room-runtime:2.0.0"
|
||||
annotationProcessor "androidx.room:room-compiler:2.0.0"
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
android:installLocation="auto">
|
||||
|
||||
<uses-permission android:name="android.permission.CALL_PHONE"/>
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
@ -13,6 +14,11 @@
|
||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
|
||||
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
|
||||
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.telephony"
|
||||
@ -53,6 +59,15 @@
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
|
||||
<data android:mimeType="vnd.android.cursor.dir/calls"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
@ -188,10 +203,42 @@
|
||||
android:label="@string/frequently_asked_questions"
|
||||
android:parentActivityName="com.simplemobiletools.commons.activities.AboutActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".activities.ManageBlockedNumbersActivity"
|
||||
android:label="@string/blocked_numbers"
|
||||
android:parentActivityName=".activities.SettingsActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".activities.DialpadActivity"
|
||||
android:label="@string/dialpad"
|
||||
android:parentActivityName=".activities.MainActivity"/>
|
||||
android:parentActivityName=".activities.MainActivity">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DIAL"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<data android:scheme="tel"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DIAL"/>
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".activities.DialerActivity"
|
||||
android:label="@string/dialer"
|
||||
android:theme="@style/Theme.Transparent">
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.CALL"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
<data android:scheme="tel"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
@ -1,16 +1,11 @@
|
||||
package com.simplemobiletools.contacts.pro
|
||||
|
||||
import android.app.Application
|
||||
import com.facebook.stetho.Stetho
|
||||
import com.simplemobiletools.commons.extensions.checkUseEnglish
|
||||
|
||||
class App : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (BuildConfig.DEBUG) {
|
||||
Stetho.initializeWithDefaults(this)
|
||||
}
|
||||
|
||||
checkUseEnglish()
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,10 @@ abstract class ContactActivity : SimpleActivity() {
|
||||
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
|
||||
.centerCrop()
|
||||
|
||||
if (isDestroyed) {
|
||||
return
|
||||
}
|
||||
|
||||
Glide.with(this)
|
||||
.load(bitmap ?: path)
|
||||
.transition(DrawableTransitionOptions.withCrossFade())
|
||||
|
@ -0,0 +1,66 @@
|
||||
package com.simplemobiletools.contacts.pro.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.telecom.PhoneAccount
|
||||
import android.telecom.TelecomManager
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.extensions.isDefaultDialer
|
||||
import com.simplemobiletools.contacts.pro.extensions.telecomManager
|
||||
import com.simplemobiletools.contacts.pro.helpers.REQUEST_CODE_SET_DEFAULT_DIALER
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
class DialerActivity : SimpleActivity() {
|
||||
private var callNumber: Uri? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
if (intent.action == Intent.ACTION_CALL && intent.data != null) {
|
||||
callNumber = intent.data
|
||||
|
||||
// make sure Simple Contacts is the default Phone app before initiating an outgoing call
|
||||
if (!isDefaultDialer()) {
|
||||
launchSetDefaultDialerIntent()
|
||||
} else {
|
||||
initOutgoingCall()
|
||||
}
|
||||
} else {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
private fun initOutgoingCall() {
|
||||
try {
|
||||
Bundle().apply {
|
||||
putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, telecomManager.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL))
|
||||
putBoolean(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, false)
|
||||
putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false)
|
||||
telecomManager.placeCall(callNumber, this)
|
||||
finish()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
showErrorToast(e)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
if (requestCode == REQUEST_CODE_SET_DEFAULT_DIALER) {
|
||||
if (!isDefaultDialer()) {
|
||||
finish()
|
||||
} else {
|
||||
initOutgoingCall()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,27 +1,36 @@
|
||||
package com.simplemobiletools.contacts.pro.activities
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Telephony.Sms.Intents.SECRET_CODE_ACTION
|
||||
import android.telephony.TelephonyManager
|
||||
import android.view.KeyEvent
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.isOreoPlus
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
|
||||
import com.simplemobiletools.contacts.pro.dialogs.CallConfirmationDialog
|
||||
import com.simplemobiletools.contacts.pro.extensions.callContact
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.isDefaultDialer
|
||||
import com.simplemobiletools.contacts.pro.extensions.startCallIntent
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.helpers.KEY_PHONE
|
||||
import com.simplemobiletools.contacts.pro.helpers.LOCATION_DIALPAD
|
||||
import com.simplemobiletools.contacts.pro.helpers.REQUEST_CODE_SET_DEFAULT_DIALER
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import kotlinx.android.synthetic.main.activity_dialpad.*
|
||||
|
||||
class DialpadActivity : SimpleActivity() {
|
||||
var contacts = ArrayList<Contact>()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_dialpad)
|
||||
@ -70,6 +79,14 @@ class DialpadActivity : SimpleActivity() {
|
||||
return true
|
||||
}
|
||||
|
||||
private fun checkDialIntent() {
|
||||
if (intent.action == Intent.ACTION_DIAL && intent.data != null && intent.dataString?.contains("tel:") == true) {
|
||||
val number = Uri.decode(intent.dataString).substringAfter("tel:")
|
||||
dialpad_input.setText(number)
|
||||
dialpad_input.setSelection(number.length)
|
||||
}
|
||||
}
|
||||
|
||||
private fun addNumberToContact() {
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_INSERT_OR_EDIT
|
||||
@ -121,12 +138,27 @@ class DialpadActivity : SimpleActivity() {
|
||||
|
||||
private fun gotContacts(newContacts: ArrayList<Contact>) {
|
||||
contacts = newContacts
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
contacts.sort()
|
||||
checkDialIntent()
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private fun dialpadValueChanged(text: String) {
|
||||
val len = text.length
|
||||
if (len > 8 && text.startsWith("*#*#") && text.endsWith("#*#*")) {
|
||||
val secretCode = text.substring(4, text.length - 4)
|
||||
if (isOreoPlus()) {
|
||||
if (isDefaultDialer()) {
|
||||
getSystemService(TelephonyManager::class.java).sendDialerSpecialCode(secretCode)
|
||||
} else {
|
||||
launchSetDefaultDialerIntent()
|
||||
}
|
||||
} else {
|
||||
val intent = Intent(SECRET_CODE_ACTION, Uri.parse("android_secret_code://$secretCode"))
|
||||
sendBroadcast(intent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
(dialpad_list.adapter as? ContactsAdapter)?.finishActMode()
|
||||
val filtered = contacts.filter { it.doesContainPhoneNumber(text) } as ArrayList<Contact>
|
||||
|
||||
@ -144,6 +176,13 @@ class DialpadActivity : SimpleActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
if (requestCode == REQUEST_CODE_SET_DEFAULT_DIALER && isDefaultDialer()) {
|
||||
dialpadValueChanged(dialpad_input.value)
|
||||
}
|
||||
}
|
||||
|
||||
private fun initCall() {
|
||||
val number = dialpad_input.value
|
||||
if (number.isNotEmpty()) {
|
||||
|
@ -91,7 +91,7 @@ class EditContactActivity : ContactActivity() {
|
||||
if (wasActivityInitialized) {
|
||||
menu.findItem(R.id.delete).isVisible = contact?.id != 0
|
||||
menu.findItem(R.id.share).isVisible = contact?.id != 0
|
||||
menu.findItem(R.id.open_with).isVisible = contact?.id != 0 && contact?.source != SMT_PRIVATE
|
||||
menu.findItem(R.id.open_with).isVisible = contact?.id != 0 && contact?.isPrivate() == false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -128,7 +128,11 @@ class EditContactActivity : ContactActivity() {
|
||||
val data = intent.data
|
||||
if (data != null) {
|
||||
val rawId = if (data.path.contains("lookup")) {
|
||||
getLookupUriRawId(data)
|
||||
if (data.pathSegments.last().startsWith("local_")) {
|
||||
data.path.substringAfter("local_").toInt()
|
||||
} else {
|
||||
getLookupUriRawId(data)
|
||||
}
|
||||
} else {
|
||||
getContactUriRawId(data)
|
||||
}
|
||||
@ -140,36 +144,46 @@ class EditContactActivity : ContactActivity() {
|
||||
}
|
||||
|
||||
if (contactId != 0) {
|
||||
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||
if (contact == null) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
finish()
|
||||
return
|
||||
}
|
||||
Thread {
|
||||
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||
if (contact == null) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
finish()
|
||||
} else {
|
||||
runOnUiThread {
|
||||
gotContact()
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
} else {
|
||||
gotContact()
|
||||
}
|
||||
}
|
||||
|
||||
private fun gotContact() {
|
||||
contact_scrollview.beVisible()
|
||||
if (contact == null) {
|
||||
setupNewContact()
|
||||
} else {
|
||||
setupEditContact()
|
||||
}
|
||||
|
||||
if ((contact!!.id == 0 && intent.extras != null && intent.extras.containsKey(KEY_PHONE) && action == Intent.ACTION_INSERT) || action == ADD_NEW_CONTACT_NUMBER) {
|
||||
val phone = intent.extras.get(KEY_PHONE)
|
||||
if (phone != null) {
|
||||
val phoneNumber = phone.toString()
|
||||
contact!!.phoneNumbers.add(PhoneNumber(phoneNumber, DEFAULT_PHONE_NUMBER_TYPE, ""))
|
||||
val action = intent.action
|
||||
if (((contact!!.id == 0 && action == Intent.ACTION_INSERT) || action == ADD_NEW_CONTACT_NUMBER) && intent.extras != null) {
|
||||
val phoneNumber = getPhoneNumberFromIntent(intent)
|
||||
if (phoneNumber != null) {
|
||||
contact!!.phoneNumbers.add(PhoneNumber(phoneNumber, DEFAULT_PHONE_NUMBER_TYPE, "", phoneNumber.normalizeNumber()))
|
||||
if (phoneNumber.isNotEmpty() && action == ADD_NEW_CONTACT_NUMBER) {
|
||||
highlightLastPhoneNumber = true
|
||||
}
|
||||
}
|
||||
|
||||
val firstName = intent.extras.get(KEY_NAME)
|
||||
val firstName = intent.extras!!.get(KEY_NAME)
|
||||
if (firstName != null) {
|
||||
contact!!.firstName = firstName.toString()
|
||||
}
|
||||
|
||||
val data = intent.extras.getParcelableArrayList<ContentValues>("data")
|
||||
val data = intent.extras!!.getParcelableArrayList<ContentValues>("data")
|
||||
if (data != null) {
|
||||
parseIntentData(data)
|
||||
}
|
||||
@ -530,7 +544,7 @@ class EditContactActivity : ContactActivity() {
|
||||
applyColorFilter(getAdjustedPrimaryColor())
|
||||
background.applyColorFilter(config.textColor)
|
||||
setOnClickListener {
|
||||
removeGroup(group.id)
|
||||
removeGroup(group.id!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -561,9 +575,7 @@ class EditContactActivity : ContactActivity() {
|
||||
private fun setupNewContact() {
|
||||
supportActionBar?.title = resources.getString(R.string.new_contact)
|
||||
originalContactSource = if (hasContactPermissions()) config.lastUsedContactSource else SMT_PRIVATE
|
||||
val organization = Organization("", "")
|
||||
contact = Contact(0, "", "", "", "", "", "", "", ArrayList(), ArrayList(), ArrayList(), ArrayList(), originalContactSource, 0, 0, "",
|
||||
null, "", ArrayList(), organization, ArrayList(), ArrayList(), ArrayList())
|
||||
contact = getEmptyContact()
|
||||
contact_source.text = getPublicContactSource(contact!!.source)
|
||||
}
|
||||
|
||||
@ -875,7 +887,7 @@ class EditContactActivity : ContactActivity() {
|
||||
val numberLabel = if (numberType == CommonDataKinds.Phone.TYPE_CUSTOM) numberHolder.contact_number_type.value else ""
|
||||
|
||||
if (number.isNotEmpty()) {
|
||||
phoneNumbers.add(PhoneNumber(number, numberType, numberLabel))
|
||||
phoneNumbers.add(PhoneNumber(number, numberType, numberLabel, number.normalizeNumber()))
|
||||
}
|
||||
}
|
||||
return phoneNumbers
|
||||
|
@ -70,8 +70,8 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
|
||||
private fun fabClicked() {
|
||||
SelectContactsDialog(this, allContacts, groupContacts) { addedContacts, removedContacts ->
|
||||
Thread {
|
||||
addContactsToGroup(addedContacts, group.id)
|
||||
removeContactsFromGroup(removedContacts, group.id)
|
||||
addContactsToGroup(addedContacts, group.id!!)
|
||||
removeContactsFromGroup(removedContacts, group.id!!)
|
||||
refreshContacts()
|
||||
}.start()
|
||||
}
|
||||
@ -86,11 +86,6 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
|
||||
group_contacts_placeholder_2.beVisibleIf(groupContacts.isEmpty())
|
||||
group_contacts_placeholder.beVisibleIf(groupContacts.isEmpty())
|
||||
group_contacts_list.beVisibleIf(groupContacts.isNotEmpty())
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
groupContacts.sort()
|
||||
|
||||
updateContacts(groupContacts)
|
||||
}
|
||||
}
|
||||
@ -129,8 +124,8 @@ class GroupContactsActivity : SimpleActivity(), RemoveFromGroupListener, Refresh
|
||||
|
||||
override fun removeFromGroup(contacts: ArrayList<Contact>) {
|
||||
Thread {
|
||||
removeContactsFromGroup(contacts, group.id)
|
||||
if (groupContacts.size == 0) {
|
||||
removeContactsFromGroup(contacts, group.id!!)
|
||||
if (groupContacts.size == contacts.size) {
|
||||
refreshContacts()
|
||||
}
|
||||
}.start()
|
||||
|
@ -13,10 +13,7 @@ import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.adapters.ContactsAdapter
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.getContactPublicUri
|
||||
import com.simplemobiletools.contacts.pro.helpers.ADD_NEW_CONTACT_NUMBER
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.helpers.KEY_PHONE
|
||||
import com.simplemobiletools.contacts.pro.helpers.LOCATION_INSERT_OR_EDIT
|
||||
import com.simplemobiletools.contacts.pro.helpers.*
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import kotlinx.android.synthetic.main.activity_insert_edit_contact.*
|
||||
|
||||
@ -45,7 +42,7 @@ class InsertOrEditContactActivity : SimpleActivity() {
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_INSERT
|
||||
data = ContactsContract.Contacts.CONTENT_URI
|
||||
putExtra(KEY_PHONE, intent.getStringExtra(KEY_PHONE))
|
||||
putExtra(KEY_PHONE, getPhoneNumberFromIntent(intent))
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
startActivityForResult(this, START_INSERT_ACTIVITY)
|
||||
} else {
|
||||
@ -58,15 +55,13 @@ class InsertOrEditContactActivity : SimpleActivity() {
|
||||
}
|
||||
|
||||
private fun gotContacts(contacts: ArrayList<Contact>) {
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
contacts.sort()
|
||||
|
||||
ContactsAdapter(this, contacts, null, LOCATION_INSERT_OR_EDIT, null, existing_contact_list, existing_contact_fastscroller) {
|
||||
val contact = it as Contact
|
||||
Intent(applicationContext, EditContactActivity::class.java).apply {
|
||||
data = getContactPublicUri(it as Contact)
|
||||
data = getContactPublicUri(contact)
|
||||
action = ADD_NEW_CONTACT_NUMBER
|
||||
putExtra(KEY_PHONE, intent.getStringExtra(KEY_PHONE))
|
||||
putExtra(KEY_PHONE, getPhoneNumberFromIntent(intent))
|
||||
putExtra(IS_PRIVATE, contact.isPrivate())
|
||||
startActivityForResult(this, START_EDIT_ACTIVITY)
|
||||
}
|
||||
}.apply {
|
||||
|
@ -22,6 +22,7 @@ import com.simplemobiletools.commons.models.Release
|
||||
import com.simplemobiletools.contacts.pro.BuildConfig
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.adapters.ViewPagerAdapter
|
||||
import com.simplemobiletools.contacts.pro.databases.ContactsDatabase
|
||||
import com.simplemobiletools.contacts.pro.dialogs.ChangeSortingDialog
|
||||
import com.simplemobiletools.contacts.pro.dialogs.ExportContactsDialog
|
||||
import com.simplemobiletools.contacts.pro.dialogs.FilterContactSourcesDialog
|
||||
@ -39,6 +40,7 @@ import kotlinx.android.synthetic.main.fragment_groups.*
|
||||
import kotlinx.android.synthetic.main.fragment_recents.*
|
||||
import java.io.FileOutputStream
|
||||
|
||||
|
||||
class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
private var isSearchOpen = false
|
||||
private var searchMenuItem: MenuItem? = null
|
||||
@ -158,11 +160,15 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
isFirstResume = false
|
||||
|
||||
val dialpadIcon = resources.getColoredDrawableWithColor(R.drawable.ic_dialpad, if (isBlackAndWhiteTheme()) Color.BLACK else Color.WHITE)
|
||||
main_dialpad_button.setImageDrawable(dialpadIcon)
|
||||
main_dialpad_button.background.applyColorFilter(getAdjustedPrimaryColor())
|
||||
main_dialpad_button.apply {
|
||||
setImageDrawable(dialpadIcon)
|
||||
background.applyColorFilter(getAdjustedPrimaryColor())
|
||||
beVisibleIf(config.showDialpadButton)
|
||||
}
|
||||
|
||||
isFirstResume = false
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
@ -173,6 +179,9 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
config.lastUsedViewPagerPage = viewpager.currentItem
|
||||
if (!isChangingConfigurations) {
|
||||
ContactsDatabase.destroyInstance()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
@ -362,7 +371,11 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
// selecting the proper tab sometimes glitches, add an extra selector to make sure we have it right
|
||||
main_tabs_holder.onGlobalLayout {
|
||||
Handler().postDelayed({
|
||||
main_tabs_holder.getTabAt(config.lastUsedViewPagerPage)?.select()
|
||||
if (intent?.action == Intent.ACTION_VIEW && intent.type == "vnd.android.cursor.dir/calls") {
|
||||
main_tabs_holder.getTabAt(getRecentsTabIndex())?.select()
|
||||
} else {
|
||||
main_tabs_holder.getTabAt(config.lastUsedViewPagerPage)?.select()
|
||||
}
|
||||
invalidateOptionsMenu()
|
||||
}, 100L)
|
||||
}
|
||||
@ -478,7 +491,7 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
}
|
||||
|
||||
private fun launchAbout() {
|
||||
val licenses = LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON or LICENSE_STETHO
|
||||
val licenses = LICENSE_JODA or LICENSE_GLIDE or LICENSE_GSON
|
||||
|
||||
val faqItems = arrayListOf(
|
||||
FAQItem(R.string.faq_1_title, R.string.faq_1_text),
|
||||
@ -506,30 +519,39 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
return@getContacts
|
||||
}
|
||||
|
||||
val contacts = it
|
||||
if (refreshTabsMask and CONTACTS_TAB_MASK != 0) {
|
||||
contacts_fragment?.refreshContacts(it)
|
||||
contacts_fragment?.refreshContacts(contacts)
|
||||
}
|
||||
|
||||
if (refreshTabsMask and FAVORITES_TAB_MASK != 0) {
|
||||
favorites_fragment?.refreshContacts(it)
|
||||
favorites_fragment?.refreshContacts(contacts)
|
||||
}
|
||||
|
||||
if (refreshTabsMask and RECENTS_TAB_MASK != 0) {
|
||||
recents_fragment?.refreshContacts(it)
|
||||
recents_fragment?.refreshContacts(contacts)
|
||||
}
|
||||
|
||||
if (refreshTabsMask and GROUPS_TAB_MASK != 0) {
|
||||
if (refreshTabsMask == GROUPS_TAB_MASK) {
|
||||
groups_fragment.skipHashComparing = true
|
||||
}
|
||||
groups_fragment?.refreshContacts(it)
|
||||
groups_fragment?.refreshContacts(contacts)
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshTabsMask and RECENTS_TAB_MASK != 0) {
|
||||
ContactsHelper(this).getRecents {
|
||||
runOnUiThread {
|
||||
recents_fragment?.updateRecentCalls(it)
|
||||
if (refreshTabsMask and RECENTS_TAB_MASK != 0) {
|
||||
ContactsHelper(this).getRecents {
|
||||
it.filter { it.name == null }.forEach {
|
||||
val namelessCall = it
|
||||
val contact = contacts.firstOrNull { it.doesContainPhoneNumber(namelessCall.number) }
|
||||
if (contact != null) {
|
||||
it.name = contact.getNameToDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
recents_fragment?.updateRecentCalls(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -537,6 +559,22 @@ class MainActivity : SimpleActivity(), RefreshContactsListener {
|
||||
|
||||
private fun getAllFragments() = arrayListOf(contacts_fragment, favorites_fragment, recents_fragment, groups_fragment)
|
||||
|
||||
private fun getRecentsTabIndex(): Int {
|
||||
var index = 0
|
||||
if (config.showTabs and RECENTS_TAB_MASK == 0) {
|
||||
return index
|
||||
}
|
||||
|
||||
if (config.showTabs and CONTACTS_TAB_MASK != 0) {
|
||||
index++
|
||||
}
|
||||
|
||||
if (config.showTabs and FAVORITES_TAB_MASK != 0) {
|
||||
index++
|
||||
}
|
||||
return index
|
||||
}
|
||||
|
||||
private fun checkWhatsNewDialog() {
|
||||
arrayListOf<Release>().apply {
|
||||
add(Release(10, R.string.release_10))
|
||||
|
@ -0,0 +1,93 @@
|
||||
package com.simplemobiletools.contacts.pro.activities
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.extensions.getAdjustedPrimaryColor
|
||||
import com.simplemobiletools.commons.extensions.underlineText
|
||||
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.adapters.ManageBlockedNumbersAdapter
|
||||
import com.simplemobiletools.contacts.pro.dialogs.AddBlockedNumberDialog
|
||||
import com.simplemobiletools.contacts.pro.extensions.getBlockedNumbers
|
||||
import com.simplemobiletools.contacts.pro.extensions.isDefaultDialer
|
||||
import com.simplemobiletools.contacts.pro.helpers.REQUEST_CODE_SET_DEFAULT_DIALER
|
||||
import com.simplemobiletools.contacts.pro.models.BlockedNumber
|
||||
import kotlinx.android.synthetic.main.activity_manage_blocked_numbers.*
|
||||
|
||||
class ManageBlockedNumbersActivity : SimpleActivity(), RefreshRecyclerViewListener {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_manage_blocked_numbers)
|
||||
updateBlockedNumbers()
|
||||
updateTextColors(manage_blocked_numbers_wrapper)
|
||||
updatePlaceholderTexts()
|
||||
|
||||
manage_blocked_numbers_placeholder_2.apply {
|
||||
underlineText()
|
||||
setTextColor(getAdjustedPrimaryColor())
|
||||
setOnClickListener {
|
||||
if (isDefaultDialer()) {
|
||||
addOrEditBlockedNumber()
|
||||
} else {
|
||||
launchSetDefaultDialerIntent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_add_blocked_number, menu)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.add_blocked_number -> addOrEditBlockedNumber()
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun refreshItems() {
|
||||
updateBlockedNumbers()
|
||||
}
|
||||
|
||||
private fun updatePlaceholderTexts() {
|
||||
manage_blocked_numbers_placeholder.text = getString(if (isDefaultDialer()) R.string.not_blocking_anyone else R.string.must_make_default_dialer)
|
||||
manage_blocked_numbers_placeholder_2.text = getString(if (isDefaultDialer()) R.string.add_a_blocked_number else R.string.set_to_default)
|
||||
}
|
||||
|
||||
private fun updateBlockedNumbers() {
|
||||
Thread {
|
||||
val blockedNumbers = getBlockedNumbers()
|
||||
runOnUiThread {
|
||||
ManageBlockedNumbersAdapter(this, blockedNumbers, this, manage_blocked_numbers_list) {
|
||||
addOrEditBlockedNumber(it as BlockedNumber)
|
||||
}.apply {
|
||||
manage_blocked_numbers_list.adapter = this
|
||||
}
|
||||
|
||||
manage_blocked_numbers_placeholder.beVisibleIf(blockedNumbers.isEmpty())
|
||||
manage_blocked_numbers_placeholder_2.beVisibleIf(blockedNumbers.isEmpty())
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun addOrEditBlockedNumber(currentNumber: BlockedNumber? = null) {
|
||||
AddBlockedNumberDialog(this, currentNumber) {
|
||||
updateBlockedNumbers()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, resultData)
|
||||
if (requestCode == REQUEST_CODE_SET_DEFAULT_DIALER && isDefaultDialer()) {
|
||||
updatePlaceholderTexts()
|
||||
updateBlockedNumbers()
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,6 @@ import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.getContactPublicUri
|
||||
import com.simplemobiletools.contacts.pro.extensions.getVisibleContactSources
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.helpers.SMT_PRIVATE
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import kotlinx.android.synthetic.main.activity_select_contact.*
|
||||
|
||||
@ -90,7 +89,7 @@ class SelectContactActivity : SimpleActivity() {
|
||||
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE -> it.phoneNumbers.isNotEmpty()
|
||||
else -> true
|
||||
}
|
||||
it.source != SMT_PRIVATE && hasRequiredValues
|
||||
!it.isPrivate() && hasRequiredValues
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -99,10 +98,6 @@ class SelectContactActivity : SimpleActivity() {
|
||||
val contactSources = getVisibleContactSources()
|
||||
contacts = contacts.filter { contactSources.contains(it.source) } as ArrayList<Contact>
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
contacts.sort()
|
||||
|
||||
runOnUiThread {
|
||||
updatePlaceholderVisibility(contacts)
|
||||
SelectContactsAdapter(this, contacts, ArrayList(), false, select_contact_list) {
|
||||
|
@ -1,8 +1,13 @@
|
||||
package com.simplemobiletools.contacts.pro.activities
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.extensions.updateTextColors
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.commons.models.RadioItem
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.dialogs.ManageVisibleFieldsDialog
|
||||
@ -26,6 +31,7 @@ class SettingsActivity : SimpleActivity() {
|
||||
setupCustomizeColors()
|
||||
setupManageShownContactFields()
|
||||
setupManageShownTabs()
|
||||
setupManageBlockedNumbers()
|
||||
setupUseEnglish()
|
||||
setupShowInfoBubble()
|
||||
setupShowContactThumbnails()
|
||||
@ -35,6 +41,7 @@ class SettingsActivity : SimpleActivity() {
|
||||
setupUse24HourTimeFormat()
|
||||
setupFilterDuplicates()
|
||||
setupShowCallConfirmation()
|
||||
setupShowDialpadButton()
|
||||
setupOnContactClick()
|
||||
updateTextColors(settings_holder)
|
||||
}
|
||||
@ -57,6 +64,15 @@ class SettingsActivity : SimpleActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
// support for device-wise blocking came on Android 7, rely only on that
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
private fun setupManageBlockedNumbers() {
|
||||
settings_manage_blocked_numbers_holder.beVisibleIf(isNougatPlus())
|
||||
settings_manage_blocked_numbers_holder.setOnClickListener {
|
||||
startActivity(Intent(this, ManageBlockedNumbersActivity::class.java))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupUseEnglish() {
|
||||
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
|
||||
settings_use_english.isChecked = config.useEnglish
|
||||
@ -123,6 +139,14 @@ class SettingsActivity : SimpleActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupShowDialpadButton() {
|
||||
settings_show_dialpad_button.isChecked = config.showDialpadButton
|
||||
settings_show_dialpad_button_holder.setOnClickListener {
|
||||
settings_show_dialpad_button.toggle()
|
||||
config.showDialpadButton = settings_show_dialpad_button.isChecked
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupOnContactClick() {
|
||||
settings_on_contact_click.text = getOnContactClickText()
|
||||
settings_on_contact_click_holder.setOnClickListener {
|
||||
|
@ -1,7 +1,14 @@
|
||||
package com.simplemobiletools.contacts.pro.activities
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.ContentValues
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.telecom.TelecomManager
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.helpers.KEY_PHONE
|
||||
import com.simplemobiletools.contacts.pro.helpers.REQUEST_CODE_SET_DEFAULT_DIALER
|
||||
|
||||
open class SimpleActivity : BaseSimpleActivity() {
|
||||
override fun getAppIconIDs() = arrayListOf(
|
||||
@ -27,4 +34,27 @@ open class SimpleActivity : BaseSimpleActivity() {
|
||||
)
|
||||
|
||||
override fun getAppLauncherName() = getString(R.string.app_launcher_name)
|
||||
|
||||
protected fun getPhoneNumberFromIntent(intent: Intent): String? {
|
||||
if (intent.extras?.containsKey(KEY_PHONE) == true) {
|
||||
return intent.getStringExtra(KEY_PHONE)
|
||||
} else if (intent.extras?.containsKey("data") == true) {
|
||||
// sample contact number from Google Contacts:
|
||||
// data: [data1=+123 456 789 mimetype=vnd.android.cursor.item/phone_v2 _id=-1 data2=0]
|
||||
val data = intent.extras!!.get("data")
|
||||
if (data != null) {
|
||||
val contentValues = (data as? ArrayList<Any>)?.firstOrNull() as? ContentValues
|
||||
if (contentValues != null && contentValues.containsKey("data1")) {
|
||||
return contentValues.getAsString("data1")
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
protected fun launchSetDefaultDialerIntent() {
|
||||
val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, packageName)
|
||||
startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER)
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.os.Bundle
|
||||
import android.provider.ContactsContract
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
import android.widget.RelativeLayout
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
@ -25,6 +26,7 @@ import kotlinx.android.synthetic.main.item_website.view.*
|
||||
|
||||
class ViewContactActivity : ContactActivity() {
|
||||
private var isViewIntent = false
|
||||
private var wasEditLaunched = false
|
||||
private var showFields = 0
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -39,21 +41,25 @@ class ViewContactActivity : ContactActivity() {
|
||||
if (isViewIntent) {
|
||||
handlePermission(PERMISSION_READ_CONTACTS) {
|
||||
if (it) {
|
||||
initContact()
|
||||
Thread {
|
||||
initContact()
|
||||
}.start()
|
||||
} else {
|
||||
toast(R.string.no_contacts_permission)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initContact()
|
||||
Thread {
|
||||
initContact()
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.menu_view_contact, menu)
|
||||
menu.apply {
|
||||
findItem(R.id.open_with).isVisible = contact?.source != SMT_PRIVATE
|
||||
findItem(R.id.open_with).isVisible = contact?.isPrivate() == false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -64,7 +70,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
}
|
||||
|
||||
when (item.itemId) {
|
||||
R.id.edit -> editContact(contact!!)
|
||||
R.id.edit -> editContact()
|
||||
R.id.share -> shareContact()
|
||||
R.id.open_with -> openWith()
|
||||
R.id.delete -> deleteContact()
|
||||
@ -100,19 +106,29 @@ class ViewContactActivity : ContactActivity() {
|
||||
if (contactId != 0 && !wasLookupKeyUsed) {
|
||||
contact = ContactsHelper(this).getContactWithId(contactId, intent.getBooleanExtra(IS_PRIVATE, false))
|
||||
if (contact == null) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
if (!wasEditLaunched) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
}
|
||||
finish()
|
||||
return
|
||||
} else {
|
||||
runOnUiThread {
|
||||
gotContact()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (contact == null) {
|
||||
finish()
|
||||
} else {
|
||||
runOnUiThread {
|
||||
gotContact()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (contact == null) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
private fun gotContact() {
|
||||
contact_scrollview.beVisible()
|
||||
setupViewContact()
|
||||
|
||||
contact_send_sms.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
||||
contact_start_call.beVisibleIf(contact!!.phoneNumbers.isNotEmpty())
|
||||
contact_send_email.beVisibleIf(contact!!.emails.isNotEmpty())
|
||||
@ -163,6 +179,11 @@ class ViewContactActivity : ContactActivity() {
|
||||
setupContactSource()
|
||||
}
|
||||
|
||||
private fun editContact() {
|
||||
wasEditLaunched = true
|
||||
editContact(contact!!)
|
||||
}
|
||||
|
||||
private fun openWith() {
|
||||
Intent().apply {
|
||||
action = ContactsContract.QuickContact.ACTION_QUICK_CONTACT
|
||||
@ -191,21 +212,27 @@ class ViewContactActivity : ContactActivity() {
|
||||
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()) {
|
||||
@ -225,6 +252,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_numbers_holder.addView(this)
|
||||
contact_number.text = phoneNumber.value
|
||||
contact_number_type.text = getPhoneNumberTypeText(phoneNumber.type, phoneNumber.label)
|
||||
copyOnLongClick(phoneNumber.value)
|
||||
|
||||
setOnClickListener {
|
||||
if (config.showCallConfirmation) {
|
||||
@ -235,12 +263,6 @@ class ViewContactActivity : ContactActivity() {
|
||||
startCallIntent(phoneNumber.value)
|
||||
}
|
||||
}
|
||||
|
||||
setOnLongClickListener {
|
||||
copyToClipboard(phoneNumber.value)
|
||||
toast(R.string.value_copied_to_clipboard)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
contact_numbers_image.beVisible()
|
||||
@ -261,6 +283,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_emails_holder.addView(this)
|
||||
contact_email.text = email.value
|
||||
contact_email_type.text = getEmailTypeText(email.type, email.label)
|
||||
copyOnLongClick(email.value)
|
||||
|
||||
setOnClickListener {
|
||||
sendEmailIntent(email.value)
|
||||
@ -285,6 +308,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_addresses_holder.addView(this)
|
||||
contact_address.text = address.value
|
||||
contact_address_type.text = getAddressTypeText(address.type, address.label)
|
||||
copyOnLongClick(address.value)
|
||||
|
||||
setOnClickListener {
|
||||
sendAddressIntent(address.value)
|
||||
@ -309,6 +333,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_ims_holder.addView(this)
|
||||
contact_im.text = IM.value
|
||||
contact_im_type.text = getIMTypeText(IM.type, IM.label)
|
||||
copyOnLongClick(IM.value)
|
||||
}
|
||||
}
|
||||
contact_ims_image.beVisible()
|
||||
@ -330,6 +355,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
it.value.getDateTimeFromDateString(contact_event)
|
||||
contact_event_type.setText(getEventTextId(it.type))
|
||||
contact_event_remove.beGone()
|
||||
copyOnLongClick(it.value)
|
||||
}
|
||||
}
|
||||
contact_events_image.beVisible()
|
||||
@ -346,6 +372,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_notes.text = notes
|
||||
contact_notes_image.beVisible()
|
||||
contact_notes.beVisible()
|
||||
contact_notes.copyOnLongClick(notes)
|
||||
} else {
|
||||
contact_notes_image.beGone()
|
||||
contact_notes.beGone()
|
||||
@ -360,6 +387,8 @@ class ViewContactActivity : ContactActivity() {
|
||||
contact_organization_image.beGoneIf(organization.isEmpty())
|
||||
contact_organization_company.beGoneIf(organization.company.isEmpty())
|
||||
contact_organization_job_position.beGoneIf(organization.jobPosition.isEmpty())
|
||||
contact_organization_company.copyOnLongClick(contact_organization_company.value)
|
||||
contact_organization_job_position.copyOnLongClick(contact_organization_job_position.value)
|
||||
|
||||
if (organization.company.isEmpty() && organization.jobPosition.isNotEmpty()) {
|
||||
(contact_organization_image.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.ALIGN_TOP, contact_organization_job_position.id)
|
||||
@ -380,6 +409,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
layoutInflater.inflate(R.layout.item_website, contact_websites_holder, false).apply {
|
||||
contact_websites_holder.addView(this)
|
||||
contact_website.text = url
|
||||
copyOnLongClick(url)
|
||||
|
||||
setOnClickListener {
|
||||
openWebsiteIntent(url)
|
||||
@ -403,6 +433,7 @@ class ViewContactActivity : ContactActivity() {
|
||||
val group = it
|
||||
contact_groups_holder.addView(this)
|
||||
contact_group.text = group.title
|
||||
copyOnLongClick(group.title)
|
||||
}
|
||||
}
|
||||
contact_groups_image.beVisible()
|
||||
@ -415,9 +446,11 @@ class ViewContactActivity : ContactActivity() {
|
||||
|
||||
private fun setupContactSource() {
|
||||
if (showFields and SHOW_CONTACT_SOURCE_FIELD != 0) {
|
||||
contact_source.text = getPublicContactSource(contact!!.source)
|
||||
val contactSourceValue = getPublicContactSource(contact!!.source)
|
||||
contact_source.text = contactSourceValue
|
||||
contact_source_image.beVisible()
|
||||
contact_source.beVisible()
|
||||
contact_source.copyOnLongClick(contactSourceValue)
|
||||
} else {
|
||||
contact_source_image.beGone()
|
||||
contact_source.beGone()
|
||||
@ -425,4 +458,12 @@ class ViewContactActivity : ContactActivity() {
|
||||
}
|
||||
|
||||
private fun getStarDrawable(on: Boolean) = resources.getDrawable(if (on) R.drawable.ic_star_on_big else R.drawable.ic_star_off_big)
|
||||
|
||||
private fun View.copyOnLongClick(value: String) {
|
||||
setOnLongClickListener {
|
||||
copyToClipboard(value)
|
||||
toast(R.string.value_copied_to_clipboard)
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
private val location: Int, private val removeListener: RemoveFromGroupListener?, recyclerView: MyRecyclerView,
|
||||
fastScroller: FastScroller, highlightText: String = "", itemClick: (Any) -> Unit) :
|
||||
MyRecyclerViewAdapter(activity, recyclerView, fastScroller, itemClick) {
|
||||
private val NEW_GROUP_ID = -1
|
||||
|
||||
private lateinit var contactDrawable: Drawable
|
||||
private lateinit var businessContactDrawable: Drawable
|
||||
@ -158,7 +159,10 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
val positions = getSelectedItemPositions()
|
||||
contactItems.removeAll(contactsToRemove)
|
||||
|
||||
ContactsHelper(activity).deleteContacts(contactsToRemove)
|
||||
Thread {
|
||||
ContactsHelper(activity).deleteContacts(contactsToRemove)
|
||||
}.start()
|
||||
|
||||
if (contactItems.isEmpty()) {
|
||||
refreshListener?.refreshContacts(ALL_TABS_MASK)
|
||||
finishActMode()
|
||||
@ -195,19 +199,23 @@ class ContactsAdapter(activity: SimpleActivity, var contactItems: ArrayList<Cont
|
||||
}
|
||||
|
||||
private fun addToGroup() {
|
||||
val selectedContacts = getSelectedItems()
|
||||
val NEW_GROUP_ID = -1
|
||||
val items = ArrayList<RadioItem>()
|
||||
ContactsHelper(activity).getStoredGroups().forEach {
|
||||
items.add(RadioItem(it.id.toInt(), it.title))
|
||||
ContactsHelper(activity).getStoredGroups {
|
||||
it.forEach {
|
||||
items.add(RadioItem(it.id!!.toInt(), it.title))
|
||||
}
|
||||
items.add(RadioItem(NEW_GROUP_ID, activity.getString(R.string.create_new_group)))
|
||||
showGroupsPicker(items)
|
||||
}
|
||||
items.add(RadioItem(NEW_GROUP_ID, activity.getString(R.string.create_new_group)))
|
||||
}
|
||||
|
||||
RadioGroupDialog(activity, items, 0) {
|
||||
private fun showGroupsPicker(radioItems: ArrayList<RadioItem>) {
|
||||
val selectedContacts = getSelectedItems()
|
||||
RadioGroupDialog(activity, radioItems, 0) {
|
||||
if (it as Int == NEW_GROUP_ID) {
|
||||
CreateNewGroupDialog(activity) {
|
||||
Thread {
|
||||
activity.addContactsToGroup(selectedContacts, it.id)
|
||||
activity.addContactsToGroup(selectedContacts, it.id!!.toLong())
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
}.start()
|
||||
finishActMode()
|
||||
|
@ -13,7 +13,7 @@ import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.dialogs.RenameGroupDialog
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.pro.extensions.groupsDB
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.helpers.GROUPS_TAB_MASK
|
||||
import com.simplemobiletools.contacts.pro.interfaces.RefreshContactsListener
|
||||
@ -59,7 +59,7 @@ class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val
|
||||
|
||||
override fun getItemSelectionKey(position: Int) = groups.getOrNull(position)?.id?.toInt()
|
||||
|
||||
override fun getItemKeyPosition(key: Int) = groups.indexOfFirst { it.id.toInt() == key }
|
||||
override fun getItemKeyPosition(key: Int) = groups.indexOfFirst { it.id!!.toInt() == key }
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_group, parent)
|
||||
|
||||
@ -73,7 +73,7 @@ class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val
|
||||
|
||||
override fun getItemCount() = groups.size
|
||||
|
||||
private fun getItemWithKey(key: Int): Group? = groups.firstOrNull { it.id.toInt() == key }
|
||||
private fun getItemWithKey(key: Int): Group? = groups.firstOrNull { it.id!!.toInt() == key }
|
||||
|
||||
fun updateItems(newItems: ArrayList<Group>) {
|
||||
groups = newItems
|
||||
@ -92,7 +92,9 @@ class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val
|
||||
|
||||
private fun askConfirmDelete() {
|
||||
ConfirmationDialog(activity) {
|
||||
deleteGroups()
|
||||
Thread {
|
||||
deleteGroups()
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,28 +103,30 @@ class GroupsAdapter(activity: SimpleActivity, var groups: ArrayList<Group>, val
|
||||
return
|
||||
}
|
||||
|
||||
val groupsToRemove = groups.filter { selectedKeys.contains(it.id.toInt()) } as ArrayList<Group>
|
||||
val groupsToRemove = groups.filter { selectedKeys.contains(it.id!!.toInt()) } as ArrayList<Group>
|
||||
val positions = getSelectedItemPositions()
|
||||
groupsToRemove.forEach {
|
||||
if (it.isPrivateSecretGroup()) {
|
||||
activity.dbHelper.deleteGroup(it.id)
|
||||
activity.groupsDB.deleteGroupId(it.id!!)
|
||||
} else {
|
||||
ContactsHelper(activity).deleteGroup(it.id)
|
||||
ContactsHelper(activity).deleteGroup(it.id!!)
|
||||
}
|
||||
}
|
||||
groups.removeAll(groupsToRemove)
|
||||
|
||||
if (groups.isEmpty()) {
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
finishActMode()
|
||||
} else {
|
||||
removeSelectedItems(positions)
|
||||
activity.runOnUiThread {
|
||||
if (groups.isEmpty()) {
|
||||
refreshListener?.refreshContacts(GROUPS_TAB_MASK)
|
||||
finishActMode()
|
||||
} else {
|
||||
removeSelectedItems(positions)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupView(view: View, group: Group) {
|
||||
view.apply {
|
||||
group_frame?.isSelected = selectedKeys.contains(group.id.toInt())
|
||||
group_frame?.isSelected = selectedKeys.contains(group.id!!.toInt())
|
||||
group_name.apply {
|
||||
setTextColor(textColor)
|
||||
text = String.format(activity.getString(R.string.groups_placeholder), group.title, group.contactsCount.toString())
|
||||
|
@ -0,0 +1,83 @@
|
||||
package com.simplemobiletools.contacts.pro.adapters
|
||||
|
||||
import android.view.Menu
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.interfaces.RefreshRecyclerViewListener
|
||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.deleteBlockedNumber
|
||||
import com.simplemobiletools.contacts.pro.models.BlockedNumber
|
||||
import kotlinx.android.synthetic.main.item_manage_blocked_number.view.*
|
||||
import java.util.*
|
||||
|
||||
class ManageBlockedNumbersAdapter(activity: BaseSimpleActivity, var blockedNumbers: ArrayList<BlockedNumber>, val listener: RefreshRecyclerViewListener?,
|
||||
recyclerView: MyRecyclerView, itemClick: (Any) -> Unit) : MyRecyclerViewAdapter(activity, recyclerView, null, itemClick) {
|
||||
|
||||
private val config = activity.config
|
||||
|
||||
init {
|
||||
setupDragListener(true)
|
||||
}
|
||||
|
||||
override fun getActionMenuId() = R.menu.cab_remove_only
|
||||
|
||||
override fun prepareActionMode(menu: Menu) {}
|
||||
|
||||
override fun actionItemPressed(id: Int) {
|
||||
when (id) {
|
||||
R.id.cab_remove -> removeSelection()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSelectableItemCount() = blockedNumbers.size
|
||||
|
||||
override fun getIsItemSelectable(position: Int) = true
|
||||
|
||||
override fun getItemSelectionKey(position: Int) = blockedNumbers.getOrNull(position)?.id?.toInt()
|
||||
|
||||
override fun getItemKeyPosition(key: Int) = blockedNumbers.indexOfFirst { it.id.toInt() == key }
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = createViewHolder(R.layout.item_manage_blocked_number, parent)
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val blockedNumber = blockedNumbers[position]
|
||||
holder.bindView(blockedNumber, true, true) { itemView, adapterPosition ->
|
||||
setupView(itemView, blockedNumber)
|
||||
}
|
||||
bindViewHolder(holder)
|
||||
}
|
||||
|
||||
override fun getItemCount() = blockedNumbers.size
|
||||
|
||||
private fun getSelectedItems() = blockedNumbers.filter { selectedKeys.contains(it.id.toInt()) } as ArrayList<BlockedNumber>
|
||||
|
||||
private fun setupView(view: View, blockedNumber: BlockedNumber) {
|
||||
view.apply {
|
||||
manage_blocked_number_holder?.isSelected = selectedKeys.contains(blockedNumber.id.toInt())
|
||||
manage_blocked_number_title.apply {
|
||||
text = blockedNumber.number
|
||||
setTextColor(config.textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeSelection() {
|
||||
val removeBlockedNumbers = ArrayList<BlockedNumber>(selectedKeys.size)
|
||||
val positions = getSelectedItemPositions()
|
||||
|
||||
getSelectedItems().forEach {
|
||||
removeBlockedNumbers.add(it)
|
||||
activity.deleteBlockedNumber(it.number)
|
||||
}
|
||||
|
||||
blockedNumbers.removeAll(removeBlockedNumbers)
|
||||
removeSelectedItems(positions)
|
||||
if (blockedNumbers.isEmpty()) {
|
||||
listener?.refreshItems()
|
||||
}
|
||||
}
|
||||
}
|
@ -6,10 +6,12 @@ import android.view.ViewGroup
|
||||
import com.simplemobiletools.commons.adapters.MyRecyclerViewAdapter
|
||||
import com.simplemobiletools.commons.dialogs.ConfirmationDialog
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.commons.views.FastScroller
|
||||
import com.simplemobiletools.commons.views.MyRecyclerView
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.extensions.addBlockedNumber
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.helpers.RECENTS_TAB_MASK
|
||||
@ -28,7 +30,12 @@ class RecentCallsAdapter(activity: SimpleActivity, var recentCalls: ArrayList<Re
|
||||
|
||||
override fun getActionMenuId() = R.menu.cab_recent_calls
|
||||
|
||||
override fun prepareActionMode(menu: Menu) {}
|
||||
override fun prepareActionMode(menu: Menu) {
|
||||
menu.apply {
|
||||
findItem(R.id.cab_block_number).isVisible = isNougatPlus()
|
||||
findItem(R.id.cab_block_number).title = activity.getString(if (isOneItemSelected()) R.string.block_number else R.string.block_numbers)
|
||||
}
|
||||
}
|
||||
|
||||
override fun actionItemPressed(id: Int) {
|
||||
if (selectedKeys.isEmpty()) {
|
||||
@ -38,6 +45,7 @@ class RecentCallsAdapter(activity: SimpleActivity, var recentCalls: ArrayList<Re
|
||||
when (id) {
|
||||
R.id.cab_select_all -> selectAll()
|
||||
R.id.cab_delete -> askConfirmDelete()
|
||||
R.id.cab_block_number -> blockNumber()
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +100,19 @@ class RecentCallsAdapter(activity: SimpleActivity, var recentCalls: ArrayList<Re
|
||||
}
|
||||
}
|
||||
|
||||
private fun blockNumber() {
|
||||
Thread {
|
||||
getSelectedItems().forEach {
|
||||
activity.addBlockedNumber(it.number)
|
||||
}
|
||||
|
||||
refreshListener?.refreshContacts(RECENTS_TAB_MASK)
|
||||
activity.runOnUiThread {
|
||||
finishActMode()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun getSelectedItems() = recentCalls.filter { selectedKeys.contains(it.id) } as ArrayList<RecentCall>
|
||||
|
||||
private fun setupView(view: View, recentCall: RecentCall) {
|
||||
|
@ -0,0 +1,71 @@
|
||||
package com.simplemobiletools.contacts.pro.databases
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import com.simplemobiletools.contacts.pro.helpers.Converters
|
||||
import com.simplemobiletools.contacts.pro.helpers.FIRST_CONTACT_ID
|
||||
import com.simplemobiletools.contacts.pro.helpers.FIRST_GROUP_ID
|
||||
import com.simplemobiletools.contacts.pro.helpers.getEmptyLocalContact
|
||||
import com.simplemobiletools.contacts.pro.interfaces.ContactsDao
|
||||
import com.simplemobiletools.contacts.pro.interfaces.GroupsDao
|
||||
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 = 1)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class ContactsDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun ContactsDao(): ContactsDao
|
||||
|
||||
abstract fun GroupsDao(): GroupsDao
|
||||
|
||||
companion object {
|
||||
private var db: ContactsDatabase? = null
|
||||
|
||||
fun getInstance(context: Context): ContactsDatabase {
|
||||
if (db == null) {
|
||||
synchronized(ContactsDatabase::class) {
|
||||
if (db == null) {
|
||||
db = Room.databaseBuilder(context.applicationContext, ContactsDatabase::class.java, "local_contacts.db")
|
||||
.addCallback(object : Callback() {
|
||||
override fun onCreate(db: SupportSQLiteDatabase) {
|
||||
super.onCreate(db)
|
||||
increaseAutoIncrementIds()
|
||||
}
|
||||
})
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
return db!!
|
||||
}
|
||||
|
||||
fun destroyInstance() {
|
||||
db = null
|
||||
}
|
||||
|
||||
// start autoincrement ID from FIRST_CONTACT_ID/FIRST_GROUP_ID to avoid conflicts
|
||||
// Room doesn't seem to have a built in way for it, so just create a contact/group and delete it
|
||||
private fun increaseAutoIncrementIds() {
|
||||
Executors.newSingleThreadExecutor().execute {
|
||||
val emptyContact = getEmptyLocalContact()
|
||||
emptyContact.id = FIRST_CONTACT_ID
|
||||
db!!.ContactsDao().apply {
|
||||
insertOrUpdate(emptyContact)
|
||||
deleteContactId(FIRST_CONTACT_ID)
|
||||
}
|
||||
|
||||
val emptyGroup = Group(FIRST_GROUP_ID, "")
|
||||
db!!.GroupsDao().apply {
|
||||
insertOrUpdate(emptyGroup)
|
||||
deleteGroupId(FIRST_GROUP_ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.simplemobiletools.contacts.pro.dialogs
|
||||
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||
import com.simplemobiletools.commons.extensions.showKeyboard
|
||||
import com.simplemobiletools.commons.extensions.value
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.extensions.addBlockedNumber
|
||||
import com.simplemobiletools.contacts.pro.extensions.deleteBlockedNumber
|
||||
import com.simplemobiletools.contacts.pro.models.BlockedNumber
|
||||
import kotlinx.android.synthetic.main.dialog_add_blocked_number.view.*
|
||||
|
||||
class AddBlockedNumberDialog(val activity: BaseSimpleActivity, val originalNumber: BlockedNumber? = null, val callback: () -> Unit) {
|
||||
init {
|
||||
val view = activity.layoutInflater.inflate(R.layout.dialog_add_blocked_number, null).apply {
|
||||
if (originalNumber != null) {
|
||||
add_blocked_number_edittext.setText(originalNumber.number)
|
||||
}
|
||||
}
|
||||
|
||||
AlertDialog.Builder(activity)
|
||||
.setPositiveButton(R.string.ok, null)
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.create().apply {
|
||||
activity.setupDialogStuff(view, this) {
|
||||
showKeyboard(view.add_blocked_number_edittext)
|
||||
getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
val newBlockedNumber = view.add_blocked_number_edittext.value
|
||||
if (originalNumber != null && newBlockedNumber != originalNumber.number) {
|
||||
activity.deleteBlockedNumber(originalNumber.number)
|
||||
}
|
||||
|
||||
if (newBlockedNumber.isNotEmpty()) {
|
||||
activity.addBlockedNumber(newBlockedNumber)
|
||||
}
|
||||
|
||||
callback()
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -65,10 +65,14 @@ class CreateNewGroupDialog(val activity: BaseSimpleActivity, val callback: (newG
|
||||
}
|
||||
|
||||
private fun createGroupUnder(name: String, contactSource: ContactSource, dialog: AlertDialog) {
|
||||
val newGroup = ContactsHelper(activity).createNewGroup(name, contactSource.name, contactSource.type)
|
||||
if (newGroup != null) {
|
||||
callback(newGroup)
|
||||
}
|
||||
dialog.dismiss()
|
||||
Thread {
|
||||
val newGroup = ContactsHelper(activity).createNewGroup(name, contactSource.name, contactSource.type)
|
||||
activity.runOnUiThread {
|
||||
if (newGroup != null) {
|
||||
callback(newGroup)
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.pro.extensions.groupsDB
|
||||
import com.simplemobiletools.contacts.pro.helpers.ContactsHelper
|
||||
import com.simplemobiletools.contacts.pro.models.Group
|
||||
import kotlinx.android.synthetic.main.dialog_rename_group.view.*
|
||||
@ -35,13 +35,17 @@ class RenameGroupDialog(val activity: BaseSimpleActivity, val group: Group, val
|
||||
}
|
||||
|
||||
group.title = newTitle
|
||||
if (group.isPrivateSecretGroup()) {
|
||||
activity.dbHelper.renameGroup(group)
|
||||
} else {
|
||||
ContactsHelper(activity).renameGroup(group)
|
||||
}
|
||||
callback()
|
||||
dismiss()
|
||||
Thread {
|
||||
if (group.isPrivateSecretGroup()) {
|
||||
activity.groupsDB.insertOrUpdate(group)
|
||||
} else {
|
||||
ContactsHelper(activity).renameGroup(group)
|
||||
}
|
||||
activity.runOnUiThread {
|
||||
callback()
|
||||
dismiss()
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,12 +6,11 @@ import com.simplemobiletools.commons.extensions.setupDialogStuff
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.adapters.SelectContactsAdapter
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.getVisibleContactSources
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import kotlinx.android.synthetic.main.layout_select_contact.view.*
|
||||
|
||||
class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayList<Contact>, val selectContacts: ArrayList<Contact>? = null,
|
||||
class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayList<Contact>, selectContacts: ArrayList<Contact>? = null,
|
||||
val callback: (addedContacts: ArrayList<Contact>, removedContacts: ArrayList<Contact>) -> Unit) {
|
||||
private var view = activity.layoutInflater.inflate(R.layout.layout_select_contact, null)
|
||||
private var initiallySelectedContacts = ArrayList<Contact>()
|
||||
@ -27,10 +26,6 @@ class SelectContactsDialog(val activity: SimpleActivity, initialContacts: ArrayL
|
||||
initiallySelectedContacts = selectContacts
|
||||
}
|
||||
|
||||
Contact.sorting = activity.config.sorting
|
||||
Contact.startWithSurname = activity.config.startNameWithSurname
|
||||
allContacts.sort()
|
||||
|
||||
activity.runOnUiThread {
|
||||
view.apply {
|
||||
select_contact_list.adapter = SelectContactsAdapter(activity, allContacts, initiallySelectedContacts, true, select_contact_list)
|
||||
|
@ -17,11 +17,20 @@ import java.util.*
|
||||
class SelectGroupsDialog(val activity: SimpleActivity, val selectedGroups: ArrayList<Group>, val callback: (newGroups: ArrayList<Group>) -> Unit) {
|
||||
private val view = activity.layoutInflater.inflate(R.layout.dialog_select_groups, null) as ViewGroup
|
||||
private val checkboxes = ArrayList<MyAppCompatCheckbox>()
|
||||
private val groups = ContactsHelper(activity).getStoredGroups()
|
||||
private var groups = ArrayList<Group>()
|
||||
private val config = activity.config
|
||||
private val dialog: AlertDialog?
|
||||
private var dialog: AlertDialog? = null
|
||||
|
||||
init {
|
||||
ContactsHelper(activity).getStoredGroups {
|
||||
groups = it
|
||||
activity.runOnUiThread {
|
||||
initDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun initDialog() {
|
||||
groups.sortedBy { it.title }.forEach {
|
||||
addGroupCheckbox(it)
|
||||
}
|
||||
|
@ -1,9 +1,7 @@
|
||||
package com.simplemobiletools.contacts.pro.extensions
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.provider.ContactsContract
|
||||
import com.simplemobiletools.commons.activities.BaseSimpleActivity
|
||||
import com.simplemobiletools.commons.dialogs.RadioGroupDialog
|
||||
import com.simplemobiletools.commons.extensions.sharePathIntent
|
||||
@ -17,8 +15,6 @@ import com.simplemobiletools.contacts.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.dialogs.CallConfirmationDialog
|
||||
import com.simplemobiletools.contacts.pro.helpers.*
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import com.simplemobiletools.contacts.pro.models.ContactSource
|
||||
import java.io.File
|
||||
|
||||
fun SimpleActivity.startCallIntent(recipient: String) {
|
||||
handlePermission(PERMISSION_CALL_PHONE) {
|
||||
@ -93,13 +89,6 @@ fun SimpleActivity.showContactSourcePicker(currentSource: String, callback: (new
|
||||
}
|
||||
}
|
||||
|
||||
fun SimpleActivity.getPublicContactSource(source: String): String {
|
||||
return when (source) {
|
||||
config.localAccountName -> getString(R.string.phone_storage)
|
||||
SMT_PRIVATE -> getString(R.string.phone_storage_hidden)
|
||||
else -> source
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.shareContacts(contacts: ArrayList<Contact>) {
|
||||
val file = getTempFile()
|
||||
@ -117,96 +106,6 @@ fun BaseSimpleActivity.shareContacts(contacts: ArrayList<Contact>) {
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.sendSMSToContacts(contacts: ArrayList<Contact>) {
|
||||
val numbers = StringBuilder()
|
||||
contacts.forEach {
|
||||
val number = it.phoneNumbers.firstOrNull { it.type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE }
|
||||
?: it.phoneNumbers.firstOrNull()
|
||||
if (number != null) {
|
||||
numbers.append("${number.value};")
|
||||
}
|
||||
|
||||
val uriString = "smsto:${numbers.toString().trimEnd(';')}"
|
||||
Intent(Intent.ACTION_SENDTO, Uri.parse(uriString)).apply {
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
startActivity(this)
|
||||
} else {
|
||||
toast(R.string.no_app_found)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.sendEmailToContacts(contacts: ArrayList<Contact>) {
|
||||
val emails = ArrayList<String>()
|
||||
contacts.forEach {
|
||||
it.emails.forEach {
|
||||
if (it.value.isNotEmpty()) {
|
||||
emails.add(it.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
type = "message/rfc822"
|
||||
putExtra(Intent.EXTRA_EMAIL, emails.toTypedArray())
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
startActivity(this)
|
||||
} else {
|
||||
toast(R.string.no_app_found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.getTempFile(): File? {
|
||||
val folder = File(cacheDir, "contacts")
|
||||
if (!folder.exists()) {
|
||||
if (!folder.mkdir()) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return File(folder, "contacts.vcf")
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val publicContacts = contacts.filter { it.source != SMT_PRIVATE }
|
||||
val privateContacts = contacts.filter { it.source == SMT_PRIVATE }
|
||||
if (publicContacts.isNotEmpty()) {
|
||||
ContactsHelper(this).addContactsToGroup(contacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
dbHelper.addContactsToGroup(contacts, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val publicContacts = contacts.filter { it.source != SMT_PRIVATE }
|
||||
val privateContacts = contacts.filter { it.source == SMT_PRIVATE }
|
||||
if (publicContacts.isNotEmpty() && hasContactPermissions()) {
|
||||
ContactsHelper(this).removeContactsFromGroup(contacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
dbHelper.removeContactsFromGroup(contacts, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
fun BaseSimpleActivity.getContactPublicUri(contact: Contact): Uri {
|
||||
val lookupKey = ContactsHelper(this).getContactLookupKey(contact.id.toString())
|
||||
return Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||
}
|
||||
|
||||
fun Activity.getVisibleContactSources(): ArrayList<String> {
|
||||
val sources = ContactsHelper(this).getDeviceContactSources()
|
||||
sources.add(ContactSource(getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
val sourceNames = ArrayList(sources).map { if (it.type == SMT_PRIVATE) SMT_PRIVATE else it.name }.toMutableList() as ArrayList<String>
|
||||
sourceNames.removeAll(config.ignoredContactSources)
|
||||
return sourceNames
|
||||
}
|
||||
|
||||
fun SimpleActivity.contactClicked(contact: Contact) {
|
||||
when (config.onContactClick) {
|
||||
ON_CLICK_CALL_CONTACT -> callContact(contact)
|
||||
|
@ -1,32 +1,55 @@
|
||||
package com.simplemobiletools.contacts.pro.extensions
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.Cursor
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.BlockedNumberContract
|
||||
import android.provider.BlockedNumberContract.BlockedNumbers
|
||||
import android.provider.ContactsContract
|
||||
import android.telecom.TelecomManager
|
||||
import androidx.core.content.FileProvider
|
||||
import com.simplemobiletools.commons.extensions.getIntValue
|
||||
import com.simplemobiletools.commons.extensions.hasPermission
|
||||
import com.simplemobiletools.commons.extensions.toast
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CONTACTS
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CONTACTS
|
||||
import com.simplemobiletools.commons.helpers.isNougatPlus
|
||||
import com.simplemobiletools.contacts.pro.BuildConfig
|
||||
import com.simplemobiletools.contacts.pro.R
|
||||
import com.simplemobiletools.contacts.pro.activities.EditContactActivity
|
||||
import com.simplemobiletools.contacts.pro.activities.ViewContactActivity
|
||||
import com.simplemobiletools.contacts.pro.databases.ContactsDatabase
|
||||
import com.simplemobiletools.contacts.pro.helpers.*
|
||||
import com.simplemobiletools.contacts.pro.interfaces.ContactsDao
|
||||
import com.simplemobiletools.contacts.pro.interfaces.GroupsDao
|
||||
import com.simplemobiletools.contacts.pro.models.BlockedNumber
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import com.simplemobiletools.contacts.pro.models.ContactSource
|
||||
import com.simplemobiletools.contacts.pro.models.Organization
|
||||
import java.io.File
|
||||
|
||||
|
||||
val Context.config: Config get() = Config.newInstance(applicationContext)
|
||||
|
||||
val Context.dbHelper: DBHelper get() = DBHelper.newInstance(applicationContext)
|
||||
val Context.contactsDB: ContactsDao get() = ContactsDatabase.getInstance(applicationContext).ContactsDao()
|
||||
|
||||
val Context.groupsDB: GroupsDao get() = ContactsDatabase.getInstance(applicationContext).GroupsDao()
|
||||
|
||||
val Context.telecomManager: TelecomManager get() = getSystemService(Context.TELECOM_SERVICE) as TelecomManager
|
||||
|
||||
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())
|
||||
}
|
||||
|
||||
fun Context.viewContact(contact: Contact) {
|
||||
Intent(applicationContext, ViewContactActivity::class.java).apply {
|
||||
putExtra(CONTACT_ID, contact.id)
|
||||
putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE)
|
||||
putExtra(IS_PRIVATE, contact.isPrivate())
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
@ -34,7 +57,7 @@ fun Context.viewContact(contact: Contact) {
|
||||
fun Context.editContact(contact: Contact) {
|
||||
Intent(applicationContext, EditContactActivity::class.java).apply {
|
||||
putExtra(CONTACT_ID, contact.id)
|
||||
putExtra(IS_PRIVATE, contact.source == SMT_PRIVATE)
|
||||
putExtra(IS_PRIVATE, contact.isPrivate())
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
@ -168,3 +191,157 @@ fun Context.getPhotoThumbnailSize(): Int {
|
||||
}
|
||||
|
||||
fun Context.hasContactPermissions() = hasPermission(PERMISSION_READ_CONTACTS) && hasPermission(PERMISSION_WRITE_CONTACTS)
|
||||
|
||||
fun Context.getPublicContactSource(source: String): String {
|
||||
return when (source) {
|
||||
config.localAccountName -> getString(R.string.phone_storage)
|
||||
SMT_PRIVATE -> getString(R.string.phone_storage_hidden)
|
||||
else -> source
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.sendSMSToContacts(contacts: ArrayList<Contact>) {
|
||||
val numbers = StringBuilder()
|
||||
contacts.forEach {
|
||||
val number = it.phoneNumbers.firstOrNull { it.type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE }
|
||||
?: it.phoneNumbers.firstOrNull()
|
||||
if (number != null) {
|
||||
numbers.append("${number.value};")
|
||||
}
|
||||
|
||||
val uriString = "smsto:${numbers.toString().trimEnd(';')}"
|
||||
Intent(Intent.ACTION_SENDTO, Uri.parse(uriString)).apply {
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
startActivity(this)
|
||||
} else {
|
||||
toast(R.string.no_app_found)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.sendEmailToContacts(contacts: ArrayList<Contact>) {
|
||||
val emails = ArrayList<String>()
|
||||
contacts.forEach {
|
||||
it.emails.forEach {
|
||||
if (it.value.isNotEmpty()) {
|
||||
emails.add(it.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Intent(Intent.ACTION_SEND_MULTIPLE).apply {
|
||||
type = "message/rfc822"
|
||||
putExtra(Intent.EXTRA_EMAIL, emails.toTypedArray())
|
||||
if (resolveActivity(packageManager) != null) {
|
||||
startActivity(this)
|
||||
} else {
|
||||
toast(R.string.no_app_found)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getTempFile(): File? {
|
||||
val folder = File(cacheDir, "contacts")
|
||||
if (!folder.exists()) {
|
||||
if (!folder.mkdir()) {
|
||||
toast(R.string.unknown_error_occurred)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
return File(folder, "contacts.vcf")
|
||||
}
|
||||
|
||||
fun Context.addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val publicContacts = contacts.filter { !it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||
val privateContacts = contacts.filter { it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||
if (publicContacts.isNotEmpty()) {
|
||||
ContactsHelper(this).addContactsToGroup(publicContacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
LocalContactsHelper(this).addContactsToGroup(privateContacts, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
val publicContacts = contacts.filter { !it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||
val privateContacts = contacts.filter { it.isPrivate() }.toMutableList() as ArrayList<Contact>
|
||||
if (publicContacts.isNotEmpty() && hasContactPermissions()) {
|
||||
ContactsHelper(this).removeContactsFromGroup(publicContacts, groupId)
|
||||
}
|
||||
|
||||
if (privateContacts.isNotEmpty()) {
|
||||
LocalContactsHelper(this).removeContactsFromGroup(privateContacts, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.getContactPublicUri(contact: Contact): Uri {
|
||||
val lookupKey = if (contact.isPrivate()) {
|
||||
"local_${contact.id}"
|
||||
} else {
|
||||
ContactsHelper(this).getContactLookupKey(contact.id.toString())
|
||||
}
|
||||
return Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey)
|
||||
}
|
||||
|
||||
fun Context.getVisibleContactSources(): ArrayList<String> {
|
||||
val sources = ContactsHelper(this).getDeviceContactSources()
|
||||
sources.add(ContactSource(getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
val sourceNames = ArrayList(sources).map { if (it.type == SMT_PRIVATE) SMT_PRIVATE else it.name }.toMutableList() as ArrayList<String>
|
||||
sourceNames.removeAll(config.ignoredContactSources)
|
||||
return sourceNames
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
fun Context.getBlockedNumbers(): ArrayList<BlockedNumber> {
|
||||
val blockedNumbers = ArrayList<BlockedNumber>()
|
||||
if (!isNougatPlus() || !isDefaultDialer()) {
|
||||
return blockedNumbers
|
||||
}
|
||||
|
||||
val uri = BlockedNumberContract.BlockedNumbers.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
BlockedNumberContract.BlockedNumbers.COLUMN_ID,
|
||||
BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
|
||||
BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER
|
||||
)
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = contentResolver.query(uri, projection, null, null, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getLongValue(BlockedNumberContract.BlockedNumbers.COLUMN_ID)
|
||||
val number = cursor.getStringValue(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER) ?: ""
|
||||
val normalizedNumber = cursor.getStringValue(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER) ?: ""
|
||||
val blockedNumber = BlockedNumber(id, number, normalizedNumber)
|
||||
blockedNumbers.add(blockedNumber)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
return blockedNumbers
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
fun Context.addBlockedNumber(number: String) {
|
||||
ContentValues().apply {
|
||||
put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number)
|
||||
contentResolver.insert(BlockedNumbers.CONTENT_URI, this)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.N)
|
||||
fun Context.deleteBlockedNumber(number: String) {
|
||||
val values = ContentValues()
|
||||
values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, number)
|
||||
val uri = contentResolver.insert(BlockedNumbers.CONTENT_URI, values)
|
||||
contentResolver.delete(uri, null, null)
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
fun Context.isDefaultDialer() = telecomManager.defaultDialerPackage == packageName
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.simplemobiletools.contacts.pro.extensions
|
||||
|
||||
import android.telephony.PhoneNumberUtils
|
||||
import android.widget.TextView
|
||||
import com.simplemobiletools.commons.helpers.getDateFormats
|
||||
import com.simplemobiletools.contacts.pro.helpers.PHONE_NUMBER_PATTERN
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import java.text.DateFormat
|
||||
@ -34,4 +34,4 @@ fun String.getDateTimeFromDateString(viewToUpdate: TextView? = null): DateTime {
|
||||
return date
|
||||
}
|
||||
|
||||
fun String.applyRegexFiltering() = replace(PHONE_NUMBER_PATTERN.toRegex(), "")
|
||||
fun String.normalizeNumber() = PhoneNumberUtils.normalizeNumber(this)
|
||||
|
@ -61,6 +61,7 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
this is RecentsFragment -> {
|
||||
fragment_fab.beGone()
|
||||
fragment_placeholder.text = activity.getString(R.string.no_recent_calls_found)
|
||||
fragment_placeholder_2.text = activity.getString(R.string.request_the_required_permissions)
|
||||
}
|
||||
}
|
||||
@ -108,9 +109,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
config.lastUsedContactSource = grouped?.key ?: ""
|
||||
}
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
contacts.sort()
|
||||
allContacts = contacts
|
||||
|
||||
val filtered = when {
|
||||
@ -145,42 +143,44 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
}
|
||||
|
||||
private fun setupGroupsAdapter(contacts: ArrayList<Contact>) {
|
||||
var storedGroups = ContactsHelper(activity!!).getStoredGroups()
|
||||
contacts.forEach {
|
||||
it.groups.forEach {
|
||||
val group = it
|
||||
val storedGroup = storedGroups.firstOrNull { it.id == group.id }
|
||||
storedGroup?.addContact()
|
||||
}
|
||||
}
|
||||
|
||||
storedGroups = storedGroups.asSequence().sortedWith(compareBy { it.title.normalizeString() }).toMutableList() as ArrayList<Group>
|
||||
|
||||
fragment_placeholder_2.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_placeholder.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_list.beVisibleIf(storedGroups.isNotEmpty())
|
||||
|
||||
val currAdapter = fragment_list.adapter
|
||||
if (currAdapter == null) {
|
||||
GroupsAdapter(activity as SimpleActivity, storedGroups, activity, fragment_list, fragment_fastscroller) {
|
||||
Intent(activity, GroupContactsActivity::class.java).apply {
|
||||
putExtra(GROUP, it as Group)
|
||||
activity!!.startActivity(this)
|
||||
ContactsHelper(activity!!).getStoredGroups {
|
||||
var storedGroups = it
|
||||
contacts.forEach {
|
||||
it.groups.forEach {
|
||||
val group = it
|
||||
val storedGroup = storedGroups.firstOrNull { it.id == group.id }
|
||||
storedGroup?.addContact()
|
||||
}
|
||||
}.apply {
|
||||
addVerticalDividers(true)
|
||||
fragment_list.adapter = this
|
||||
}
|
||||
|
||||
fragment_fastscroller.setScrollToY(0)
|
||||
fragment_fastscroller.setViews(fragment_list) {
|
||||
val item = (fragment_list.adapter as GroupsAdapter).groups.getOrNull(it)
|
||||
fragment_fastscroller.updateBubbleText(item?.getBubbleText() ?: "")
|
||||
}
|
||||
} else {
|
||||
(currAdapter as GroupsAdapter).apply {
|
||||
showContactThumbnails = activity.config.showContactThumbnails
|
||||
updateItems(storedGroups)
|
||||
storedGroups = storedGroups.asSequence().sortedWith(compareBy { it.title.normalizeString() }).toMutableList() as ArrayList<Group>
|
||||
|
||||
fragment_placeholder_2.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_placeholder.beVisibleIf(storedGroups.isEmpty())
|
||||
fragment_list.beVisibleIf(storedGroups.isNotEmpty())
|
||||
|
||||
val currAdapter = fragment_list.adapter
|
||||
if (currAdapter == null) {
|
||||
GroupsAdapter(activity as SimpleActivity, storedGroups, activity, fragment_list, fragment_fastscroller) {
|
||||
Intent(activity, GroupContactsActivity::class.java).apply {
|
||||
putExtra(GROUP, it as Group)
|
||||
activity!!.startActivity(this)
|
||||
}
|
||||
}.apply {
|
||||
addVerticalDividers(true)
|
||||
fragment_list.adapter = this
|
||||
}
|
||||
|
||||
fragment_fastscroller.setScrollToY(0)
|
||||
fragment_fastscroller.setViews(fragment_list) {
|
||||
val item = (fragment_list.adapter as GroupsAdapter).groups.getOrNull(it)
|
||||
fragment_fastscroller.updateBubbleText(item?.getBubbleText() ?: "")
|
||||
}
|
||||
} else {
|
||||
(currAdapter as GroupsAdapter).apply {
|
||||
showContactThumbnails = activity.config.showContactThumbnails
|
||||
updateItems(storedGroups)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -251,9 +251,6 @@ abstract class MyViewPagerFragment(context: Context, attributeSet: AttributeSet)
|
||||
it.websites.any { it.contains(text, true) }
|
||||
} as ArrayList
|
||||
|
||||
Contact.sorting = config.sorting
|
||||
Contact.startWithSurname = config.startNameWithSurname
|
||||
filtered.sort()
|
||||
filtered.sortBy { !getProperText(it.getNameToDisplay(), shouldNormalize).startsWith(text, true) }
|
||||
|
||||
if (filtered.isEmpty() && this@MyViewPagerFragment is FavoritesFragment) {
|
||||
|
@ -1,16 +1,21 @@
|
||||
package com.simplemobiletools.contacts.pro.fragments
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.telecom.TelecomManager
|
||||
import android.util.AttributeSet
|
||||
import com.simplemobiletools.commons.extensions.beVisibleIf
|
||||
import com.simplemobiletools.commons.extensions.hasPermission
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_READ_CALL_LOG
|
||||
import com.simplemobiletools.commons.helpers.PERMISSION_WRITE_CALL_LOG
|
||||
import com.simplemobiletools.contacts.pro.activities.EditContactActivity
|
||||
import com.simplemobiletools.commons.helpers.isMarshmallowPlus
|
||||
import com.simplemobiletools.contacts.pro.activities.InsertOrEditContactActivity
|
||||
import com.simplemobiletools.contacts.pro.adapters.RecentCallsAdapter
|
||||
import com.simplemobiletools.contacts.pro.extensions.applyRegexFiltering
|
||||
import com.simplemobiletools.contacts.pro.extensions.contactClicked
|
||||
import com.simplemobiletools.contacts.pro.extensions.isDefaultDialer
|
||||
import com.simplemobiletools.contacts.pro.extensions.normalizeNumber
|
||||
import com.simplemobiletools.contacts.pro.helpers.IS_FROM_SIMPLE_CONTACTS
|
||||
import com.simplemobiletools.contacts.pro.helpers.KEY_PHONE
|
||||
import com.simplemobiletools.contacts.pro.helpers.RECENTS_TAB_MASK
|
||||
@ -21,13 +26,19 @@ import kotlinx.android.synthetic.main.fragment_layout.view.*
|
||||
class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPagerFragment(context, attributeSet) {
|
||||
override fun fabClicked() {}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
override fun placeholderClicked() {
|
||||
activity!!.handlePermission(PERMISSION_WRITE_CALL_LOG) {
|
||||
if (it) {
|
||||
activity!!.handlePermission(PERMISSION_READ_CALL_LOG) {
|
||||
activity?.refreshContacts(RECENTS_TAB_MASK)
|
||||
if (!isMarshmallowPlus() || (isMarshmallowPlus() && context.isDefaultDialer())) {
|
||||
activity!!.handlePermission(PERMISSION_WRITE_CALL_LOG) {
|
||||
if (it) {
|
||||
activity!!.handlePermission(PERMISSION_READ_CALL_LOG) {
|
||||
activity?.refreshContacts(RECENTS_TAB_MASK)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val intent = Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER).putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, context.packageName)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,10 +54,10 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage
|
||||
val currAdapter = fragment_list.adapter
|
||||
if (currAdapter == null) {
|
||||
RecentCallsAdapter(activity!!, recentCalls, activity, fragment_list, fragment_fastscroller) {
|
||||
val recentCall = (it as RecentCall).number.applyRegexFiltering()
|
||||
val recentCall = (it as RecentCall).number.normalizeNumber()
|
||||
var selectedContact: Contact? = null
|
||||
for (contact in allContacts) {
|
||||
if (contact.phoneNumbers.any { it.value.applyRegexFiltering() == recentCall }) {
|
||||
if (contact.doesContainPhoneNumber(recentCall)) {
|
||||
selectedContact = contact
|
||||
break
|
||||
}
|
||||
@ -55,8 +66,8 @@ class RecentsFragment(context: Context, attributeSet: AttributeSet) : MyViewPage
|
||||
if (selectedContact != null) {
|
||||
activity?.contactClicked(selectedContact)
|
||||
} else {
|
||||
Intent(context, EditContactActivity::class.java).apply {
|
||||
action = Intent.ACTION_INSERT
|
||||
Intent(context, InsertOrEditContactActivity::class.java).apply {
|
||||
action = Intent.ACTION_INSERT_OR_EDIT
|
||||
putExtra(KEY_PHONE, recentCall)
|
||||
putExtra(IS_FROM_SIMPLE_CONTACTS, true)
|
||||
context.startActivity(this)
|
||||
|
@ -60,4 +60,8 @@ class Config(context: Context) : BaseConfig(context) {
|
||||
var showCallConfirmation: Boolean
|
||||
get() = prefs.getBoolean(SHOW_CALL_CONFIRMATION, false)
|
||||
set(showCallConfirmation) = prefs.edit().putBoolean(SHOW_CALL_CONFIRMATION, showCallConfirmation).apply()
|
||||
|
||||
var showDialpadButton: Boolean
|
||||
get() = prefs.getBoolean(SHOW_DIALPAD_BUTTON, true)
|
||||
set(showDialpadButton) = prefs.edit().putBoolean(SHOW_DIALPAD_BUTTON, showDialpadButton).apply()
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package com.simplemobiletools.contacts.pro.helpers
|
||||
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
import com.simplemobiletools.contacts.pro.models.LocalContact
|
||||
|
||||
// shared prefs
|
||||
const val SHOW_CONTACT_THUMBNAILS = "show_contact_thumbnails"
|
||||
@ -16,15 +17,17 @@ const val SHOW_CONTACT_FIELDS = "show_contact_fields"
|
||||
const val SHOW_TABS = "show_tabs"
|
||||
const val FILTER_DUPLICATES = "filter_duplicates"
|
||||
const val SHOW_CALL_CONFIRMATION = "show_call_confirmation"
|
||||
const val SHOW_DIALPAD_BUTTON = "show_dialpad_button"
|
||||
|
||||
const val CONTACT_ID = "contact_id"
|
||||
const val SMT_PRIVATE = "smt_private" // used at the contact source of local contacts hidden from other apps
|
||||
const val IS_PRIVATE = "is_private"
|
||||
const val GROUP = "group"
|
||||
const val FIRST_GROUP_ID = 10000
|
||||
const val PHONE_NUMBER_PATTERN = "[^0-9#*+]"
|
||||
const val IS_FROM_SIMPLE_CONTACTS = "is_from_simple_contacts"
|
||||
const val ADD_NEW_CONTACT_NUMBER = "add_new_contact_number"
|
||||
const val FIRST_CONTACT_ID = 1000000
|
||||
const val FIRST_GROUP_ID = 10000L
|
||||
const val REQUEST_CODE_SET_DEFAULT_DIALER = 1
|
||||
|
||||
// extras used at third party intents
|
||||
const val KEY_PHONE = "phone"
|
||||
@ -119,3 +122,5 @@ val localAccountTypes = arrayListOf("vnd.sec.contact.phone",
|
||||
const val TELEGRAM_PACKAGE = "org.telegram.messenger"
|
||||
const val SIGNAL_PACKAGE = "org.thoughtcrime.securesms"
|
||||
const val WHATSAPP_PACKAGE = "com.whatsapp"
|
||||
|
||||
fun getEmptyLocalContact() = LocalContact(0, "", "", "", "", "", "", null, ArrayList(), ArrayList(), ArrayList(), 0, ArrayList(), "", ArrayList(), "", "", ArrayList(), ArrayList())
|
||||
|
@ -3,11 +3,12 @@ package com.simplemobiletools.contacts.pro.helpers
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountManager
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.*
|
||||
import android.database.Cursor
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.provider.CallLog
|
||||
import android.provider.ContactsContract
|
||||
import android.provider.ContactsContract.CommonDataKinds
|
||||
@ -26,24 +27,24 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
class ContactsHelper(val activity: Activity) {
|
||||
class ContactsHelper(val context: Context) {
|
||||
private val BATCH_SIZE = 100
|
||||
private var displayContactSources = ArrayList<String>()
|
||||
|
||||
fun getContacts(callback: (ArrayList<Contact>) -> Unit) {
|
||||
Thread {
|
||||
val contacts = SparseArray<Contact>()
|
||||
displayContactSources = activity.getVisibleContactSources()
|
||||
displayContactSources = context.getVisibleContactSources()
|
||||
getDeviceContacts(contacts)
|
||||
|
||||
if (displayContactSources.contains(SMT_PRIVATE)) {
|
||||
activity.dbHelper.getContacts(activity).forEach {
|
||||
LocalContactsHelper(context).getAllContacts().forEach {
|
||||
contacts.put(it.id, it)
|
||||
}
|
||||
}
|
||||
|
||||
val contactsSize = contacts.size()
|
||||
val showOnlyContactsWithNumbers = activity.config.showOnlyContactsWithNumbers
|
||||
val showOnlyContactsWithNumbers = context.config.showOnlyContactsWithNumbers
|
||||
var tempContacts = ArrayList<Contact>(contactsSize)
|
||||
val resultContacts = ArrayList<Contact>(contactsSize)
|
||||
|
||||
@ -57,7 +58,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
contacts.valueAt(it)
|
||||
}
|
||||
|
||||
if (activity.config.filterDuplicates) {
|
||||
if (context.config.filterDuplicates) {
|
||||
tempContacts = tempContacts.distinctBy {
|
||||
it.getHashToCompare()
|
||||
} as ArrayList<Contact>
|
||||
@ -75,14 +76,18 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
// groups are obtained with contactID, not rawID, so assign them to proper contacts like this
|
||||
val groups = getContactGroups(getStoredGroups())
|
||||
val groups = getContactGroups(getStoredGroupsSync())
|
||||
val size = groups.size()
|
||||
for (i in 0 until size) {
|
||||
val key = groups.keyAt(i)
|
||||
resultContacts.firstOrNull { it.contactId == key }?.groups = groups.valueAt(i)
|
||||
}
|
||||
|
||||
activity.runOnUiThread {
|
||||
Contact.sorting = context.config.sorting
|
||||
Contact.startWithSurname = context.config.startNameWithSurname
|
||||
resultContacts.sort()
|
||||
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
callback(resultContacts)
|
||||
}
|
||||
}.start()
|
||||
@ -98,7 +103,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
val sources = HashSet<ContactSource>()
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, null, null, null)
|
||||
cursor = context.contentResolver.query(uri, projection, null, null, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val name = cursor.getStringValue(ContactsContract.RawContacts.ACCOUNT_NAME) ?: ""
|
||||
@ -116,7 +121,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
private fun getDeviceContacts(contacts: SparseArray<Contact>) {
|
||||
if (!activity.hasContactPermissions()) {
|
||||
if (!context.hasContactPermissions()) {
|
||||
return
|
||||
}
|
||||
|
||||
@ -128,7 +133,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, sortOrder)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -151,21 +156,19 @@ class ContactsHelper(val activity: Activity) {
|
||||
val groups = ArrayList<Group>()
|
||||
val organization = Organization("", "")
|
||||
val websites = ArrayList<String>()
|
||||
val cleanNumbers = ArrayList<PhoneNumber>()
|
||||
val ims = ArrayList<IM>()
|
||||
val contact = Contact(id, prefix, firstName, middleName, surname, suffix, nickname, photoUri, numbers, emails, addresses,
|
||||
events, accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, cleanNumbers, ims)
|
||||
events, accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims)
|
||||
|
||||
contacts.put(id, contact)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
|
||||
val filterDuplicates = activity.config.filterDuplicates
|
||||
val phoneNumbers = getPhoneNumbers(null)
|
||||
var size = phoneNumbers.size()
|
||||
for (i in 0 until size) {
|
||||
@ -173,13 +176,6 @@ class ContactsHelper(val activity: Activity) {
|
||||
if (contacts[key] != null) {
|
||||
val numbers = phoneNumbers.valueAt(i)
|
||||
contacts[key].phoneNumbers = numbers
|
||||
|
||||
if (filterDuplicates) {
|
||||
// remove all spaces, dashes etc from numbers for easier comparing, used only at list views
|
||||
numbers.forEach {
|
||||
numbers.mapTo(contacts[key].cleanPhoneNumbers) { PhoneNumber(it.value.applyRegexFiltering(), 0, "") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -246,6 +242,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
val projection = arrayOf(
|
||||
ContactsContract.Data.RAW_CONTACT_ID,
|
||||
CommonDataKinds.Phone.NUMBER,
|
||||
CommonDataKinds.Phone.NORMALIZED_NUMBER,
|
||||
CommonDataKinds.Phone.TYPE,
|
||||
CommonDataKinds.Phone.LABEL
|
||||
)
|
||||
@ -255,11 +252,12 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
val number = cursor.getStringValue(CommonDataKinds.Phone.NUMBER) ?: continue
|
||||
val normalizedNumber = cursor.getStringValue(CommonDataKinds.Phone.NORMALIZED_NUMBER) ?: number.normalizeNumber()
|
||||
val type = cursor.getIntValue(CommonDataKinds.Phone.TYPE)
|
||||
val label = cursor.getStringValue(CommonDataKinds.Phone.LABEL) ?: ""
|
||||
|
||||
@ -267,12 +265,12 @@ class ContactsHelper(val activity: Activity) {
|
||||
phoneNumbers.put(id, ArrayList())
|
||||
}
|
||||
|
||||
val phoneNumber = PhoneNumber(number, type, label)
|
||||
val phoneNumber = PhoneNumber(number, type, label, normalizedNumber)
|
||||
phoneNumbers[id].add(phoneNumber)
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -293,7 +291,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -302,7 +300,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -325,7 +323,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -341,7 +339,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -364,7 +362,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -380,7 +378,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -403,7 +401,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -419,7 +417,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -441,7 +439,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -456,7 +454,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -477,7 +475,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -486,7 +484,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -508,7 +506,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -523,7 +521,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -544,7 +542,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
@ -558,7 +556,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -568,7 +566,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
private fun getContactGroups(storedGroups: ArrayList<Group>, contactId: Int? = null): SparseArray<ArrayList<Group>> {
|
||||
val groups = SparseArray<ArrayList<Group>>()
|
||||
if (!activity.hasContactPermissions()) {
|
||||
if (!context.hasContactPermissions()) {
|
||||
return groups
|
||||
}
|
||||
|
||||
@ -583,7 +581,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
@ -598,7 +596,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -648,15 +646,24 @@ class ContactsHelper(val activity: Activity) {
|
||||
return args.toTypedArray()
|
||||
}
|
||||
|
||||
fun getStoredGroups(): ArrayList<Group> {
|
||||
fun getStoredGroups(callback: (ArrayList<Group>) -> Unit) {
|
||||
Thread {
|
||||
val groups = getStoredGroupsSync()
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
callback(groups)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun getStoredGroupsSync(): ArrayList<Group> {
|
||||
val groups = getDeviceStoredGroups()
|
||||
groups.addAll(activity.dbHelper.getGroups())
|
||||
groups.addAll(context.groupsDB.getGroups())
|
||||
return groups
|
||||
}
|
||||
|
||||
fun getDeviceStoredGroups(): ArrayList<Group> {
|
||||
val groups = ArrayList<Group>()
|
||||
if (!activity.hasContactPermissions()) {
|
||||
if (!context.hasContactPermissions()) {
|
||||
return groups
|
||||
}
|
||||
|
||||
@ -672,7 +679,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getLongValue(ContactsContract.Groups._ID)
|
||||
@ -687,7 +694,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
} finally {
|
||||
cursor?.close()
|
||||
}
|
||||
@ -696,7 +703,10 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
fun createNewGroup(title: String, accountName: String, accountType: String): Group? {
|
||||
if (accountType == SMT_PRIVATE) {
|
||||
return activity.dbHelper.insertGroup(Group(0, title))
|
||||
val newGroup = Group(null, title)
|
||||
val id = context.groupsDB.insertOrUpdate(newGroup)
|
||||
newGroup.id = id
|
||||
return newGroup
|
||||
}
|
||||
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
@ -709,11 +719,11 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
try {
|
||||
val results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
val results = context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
val rawId = ContentUris.parseId(results[0].uri)
|
||||
return Group(rawId, title)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -729,9 +739,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
try {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -744,9 +754,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
operations.add(ContentProviderOperation.newDelete(uri).build())
|
||||
|
||||
try {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,7 +764,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
if (id == 0) {
|
||||
return null
|
||||
} else if (isLocalPrivate) {
|
||||
return activity.dbHelper.getContactWithId(activity, id)
|
||||
return LocalContactsHelper(context).getContactWithId(id)
|
||||
}
|
||||
|
||||
val selection = "${ContactsContract.Data.MIMETYPE} = ? AND ${ContactsContract.Data.RAW_CONTACT_ID} = ?"
|
||||
@ -769,12 +779,12 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
private fun parseContactCursor(selection: String, selectionArgs: Array<String>): Contact? {
|
||||
val storedGroups = getStoredGroups()
|
||||
val storedGroups = getStoredGroupsSync()
|
||||
val uri = ContactsContract.Data.CONTENT_URI
|
||||
val projection = getContactProjection()
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.RAW_CONTACT_ID)
|
||||
val prefix = cursor.getStringValue(CommonDataKinds.StructuredName.PREFIX) ?: ""
|
||||
@ -796,10 +806,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
val thumbnailUri = cursor.getStringValue(CommonDataKinds.StructuredName.PHOTO_THUMBNAIL_URI) ?: ""
|
||||
val organization = getOrganizations(id)[id] ?: Organization("", "")
|
||||
val websites = getWebsites(id)[id] ?: ArrayList()
|
||||
val cleanNumbers = ArrayList<PhoneNumber>()
|
||||
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, cleanNumbers, ims)
|
||||
accountName, starred, contactId, thumbnailUri, null, notes, groups, organization, websites, ims)
|
||||
}
|
||||
} finally {
|
||||
cursor?.close()
|
||||
@ -816,22 +825,22 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
private fun getContactSourcesSync(): ArrayList<ContactSource> {
|
||||
val sources = getDeviceContactSources()
|
||||
sources.add(ContactSource(activity.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
sources.add(ContactSource(context.getString(R.string.phone_storage_hidden), SMT_PRIVATE))
|
||||
return ArrayList(sources)
|
||||
}
|
||||
|
||||
fun getDeviceContactSources(): LinkedHashSet<ContactSource> {
|
||||
val sources = LinkedHashSet<ContactSource>()
|
||||
if (!activity.hasContactPermissions()) {
|
||||
if (!context.hasContactPermissions()) {
|
||||
return sources
|
||||
}
|
||||
|
||||
val accounts = AccountManager.get(activity).accounts
|
||||
val accounts = AccountManager.get(context).accounts
|
||||
accounts.forEach {
|
||||
if (ContentResolver.getIsSyncable(it, ContactsContract.AUTHORITY) == 1) {
|
||||
val contactSource = ContactSource(it.name, it.type)
|
||||
if (it.type == TELEGRAM_PACKAGE) {
|
||||
contactSource.name += " (${activity.getString(R.string.telegram)})"
|
||||
contactSource.name += " (${context.getString(R.string.telegram)})"
|
||||
}
|
||||
sources.add(contactSource)
|
||||
}
|
||||
@ -842,7 +851,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
sources.addAll(contentResolverAccounts)
|
||||
|
||||
if (sources.isEmpty() && activity.config.localAccountName.isEmpty() && activity.config.localAccountType.isEmpty()) {
|
||||
if (sources.isEmpty() && context.config.localAccountName.isEmpty() && context.config.localAccountType.isEmpty()) {
|
||||
sources.add(ContactSource("", ""))
|
||||
}
|
||||
|
||||
@ -866,7 +875,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
)
|
||||
|
||||
private fun getSortString(): String {
|
||||
val sorting = activity.config.sorting
|
||||
val sorting = context.config.sorting
|
||||
var sort = when {
|
||||
sorting and SORT_BY_FIRST_NAME != 0 -> "${CommonDataKinds.StructuredName.GIVEN_NAME} COLLATE NOCASE"
|
||||
sorting and SORT_BY_MIDDLE_NAME != 0 -> "${CommonDataKinds.StructuredName.MIDDLE_NAME} COLLATE NOCASE"
|
||||
@ -888,7 +897,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id.toString())
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
}
|
||||
@ -900,9 +909,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
fun updateContact(contact: Contact, photoUpdateStatus: Int): Boolean {
|
||||
activity.toast(R.string.updating)
|
||||
if (contact.source == SMT_PRIVATE) {
|
||||
return activity.dbHelper.updateContact(contact)
|
||||
context.toast(R.string.updating)
|
||||
if (contact.isPrivate()) {
|
||||
return LocalContactsHelper(context).insertOrUpdateContact(contact)
|
||||
}
|
||||
|
||||
try {
|
||||
@ -949,6 +958,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
withValue(ContactsContract.Data.RAW_CONTACT_ID, contact.id)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Phone.NUMBER, it.value)
|
||||
withValue(CommonDataKinds.Phone.NORMALIZED_NUMBER, it.normalizedNumber)
|
||||
withValue(CommonDataKinds.Phone.TYPE, it.type)
|
||||
withValue(CommonDataKinds.Phone.LABEL, it.label)
|
||||
operations.add(build())
|
||||
@ -1089,7 +1099,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
// delete groups
|
||||
val relevantGroupIDs = getStoredGroups().map { it.id }
|
||||
val relevantGroupIDs = getStoredGroupsSync().map { it.id }
|
||||
if (relevantGroupIDs.isNotEmpty()) {
|
||||
val IDsString = TextUtils.join(",", relevantGroupIDs)
|
||||
ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI).apply {
|
||||
@ -1115,9 +1125,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, contact.contactId.toString())
|
||||
val contentValues = ContentValues(1)
|
||||
contentValues.put(ContactsContract.Contacts.STARRED, contact.starred)
|
||||
activity.contentResolver.update(uri, contentValues, null, null)
|
||||
context.contentResolver.update(uri, contentValues, null, null)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
|
||||
// photo
|
||||
@ -1126,10 +1136,10 @@ class ContactsHelper(val activity: Activity) {
|
||||
PHOTO_REMOVED -> removePhoto(contact, operations)
|
||||
}
|
||||
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -1137,9 +1147,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
private fun addPhoto(contact: Contact, operations: ArrayList<ContentProviderOperation>): ArrayList<ContentProviderOperation> {
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
val photoUri = Uri.parse(contact.photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = activity.getPhotoThumbnailSize()
|
||||
val thumbnailSize = context.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||
val scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
scaledPhoto.recycle()
|
||||
@ -1181,15 +1191,15 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1204,16 +1214,16 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
}
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
}
|
||||
|
||||
fun insertContact(contact: Contact): Boolean {
|
||||
if (contact.source == SMT_PRIVATE) {
|
||||
return insertLocalContact(contact)
|
||||
if (contact.isPrivate()) {
|
||||
return LocalContactsHelper(context).insertOrUpdateContact(contact)
|
||||
}
|
||||
|
||||
try {
|
||||
@ -1251,6 +1261,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
|
||||
withValue(ContactsContract.Data.MIMETYPE, CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
|
||||
withValue(CommonDataKinds.Phone.NUMBER, it.value)
|
||||
withValue(CommonDataKinds.Phone.NORMALIZED_NUMBER, it.normalizedNumber)
|
||||
withValue(CommonDataKinds.Phone.TYPE, it.type)
|
||||
withValue(CommonDataKinds.Phone.LABEL, it.label)
|
||||
operations.add(build())
|
||||
@ -1351,9 +1362,9 @@ class ContactsHelper(val activity: Activity) {
|
||||
var scaledSizePhotoData: ByteArray?
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
val photoUri = Uri.parse(contact.photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(activity.contentResolver, photoUri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = activity.getPhotoThumbnailSize()
|
||||
val thumbnailSize = context.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize, thumbnailSize, false)
|
||||
scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
|
||||
@ -1371,7 +1382,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
val results: Array<ContentProviderResult>
|
||||
try {
|
||||
results = activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
results = context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} finally {
|
||||
scaledSizePhotoData = null
|
||||
}
|
||||
@ -1388,22 +1399,20 @@ class ContactsHelper(val activity: Activity) {
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, userId.toString())
|
||||
val contentValues = ContentValues(1)
|
||||
contentValues.put(ContactsContract.Contacts.STARRED, contact.starred)
|
||||
activity.contentResolver.update(uri, contentValues, null, null)
|
||||
context.contentResolver.update(uri, contentValues, null, null)
|
||||
}
|
||||
|
||||
return true
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun insertLocalContact(contact: Contact) = activity.dbHelper.insertContact(contact)
|
||||
|
||||
private fun addFullSizePhoto(contactId: Long, fullSizePhotoData: ByteArray) {
|
||||
val baseUri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, contactId)
|
||||
val displayPhotoUri = Uri.withAppendedPath(baseUri, ContactsContract.RawContacts.DisplayPhoto.CONTENT_DIRECTORY)
|
||||
val fileDescriptor = activity.contentResolver.openAssetFileDescriptor(displayPhotoUri, "rw")
|
||||
val fileDescriptor = context.contentResolver.openAssetFileDescriptor(displayPhotoUri, "rw")
|
||||
val photoStream = fileDescriptor.createOutputStream()
|
||||
photoStream.write(fullSizePhotoData)
|
||||
photoStream.close()
|
||||
@ -1417,7 +1426,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
val selectionArgs = arrayOf(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, contactId)
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
val id = cursor.getIntValue(ContactsContract.Data.CONTACT_ID)
|
||||
val lookupKey = cursor.getStringValue(ContactsContract.Data.LOOKUP_KEY)
|
||||
@ -1437,7 +1446,7 @@ class ContactsHelper(val activity: Activity) {
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
cursor = context.contentResolver.query(uri, projection, selection, selectionArgs, null)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
return cursor.getStringValue(ContactsContract.Data._ID)
|
||||
}
|
||||
@ -1448,23 +1457,27 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
fun addFavorites(contacts: ArrayList<Contact>) {
|
||||
toggleLocalFavorites(contacts, true)
|
||||
if (activity.hasContactPermissions()) {
|
||||
toggleFavorites(contacts, true)
|
||||
}
|
||||
Thread {
|
||||
toggleLocalFavorites(contacts, true)
|
||||
if (context.hasContactPermissions()) {
|
||||
toggleFavorites(contacts, true)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun removeFavorites(contacts: ArrayList<Contact>) {
|
||||
toggleLocalFavorites(contacts, false)
|
||||
if (activity.hasContactPermissions()) {
|
||||
toggleFavorites(contacts, false)
|
||||
}
|
||||
Thread {
|
||||
toggleLocalFavorites(contacts, false)
|
||||
if (context.hasContactPermissions()) {
|
||||
toggleFavorites(contacts, false)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
private fun toggleFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) {
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
contacts.filter { it.source != SMT_PRIVATE }.map { it.contactId.toString() }.forEach {
|
||||
contacts.filter { !it.isPrivate() }.map { it.contactId.toString() }.forEach {
|
||||
val uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_URI, it)
|
||||
ContentProviderOperation.newUpdate(uri).apply {
|
||||
withValue(ContactsContract.Contacts.STARRED, if (addToFavorites) 1 else 0)
|
||||
@ -1472,68 +1485,69 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
}
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun toggleLocalFavorites(contacts: ArrayList<Contact>, addToFavorites: Boolean) {
|
||||
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray()
|
||||
activity.dbHelper.toggleFavorites(localContacts, addToFavorites)
|
||||
val localContacts = contacts.filter { it.isPrivate() }.map { it.id }.toTypedArray()
|
||||
LocalContactsHelper(context).toggleFavorites(localContacts, addToFavorites)
|
||||
}
|
||||
|
||||
fun deleteContact(contact: Contact) {
|
||||
if (contact.source == SMT_PRIVATE) {
|
||||
activity.dbHelper.deleteContact(contact.id)
|
||||
} else {
|
||||
deleteContacts(arrayListOf(contact))
|
||||
}
|
||||
Thread {
|
||||
if (contact.isPrivate()) {
|
||||
context.contactsDB.deleteContactId(contact.id)
|
||||
} else {
|
||||
deleteContacts(arrayListOf(contact))
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun deleteContacts(contacts: ArrayList<Contact>) {
|
||||
Thread {
|
||||
val localContacts = contacts.filter { it.source == SMT_PRIVATE }.map { it.id.toString() }.toTypedArray()
|
||||
activity.dbHelper.deleteContacts(localContacts)
|
||||
val localContacts = contacts.filter { it.isPrivate() }.map { it.id }.toTypedArray()
|
||||
LocalContactsHelper(context).deleteContactIds(localContacts)
|
||||
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
val selection = "${ContactsContract.RawContacts._ID} = ?"
|
||||
contacts.filter { it.source != SMT_PRIVATE }.forEach {
|
||||
ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI).apply {
|
||||
val selectionArgs = arrayOf(it.id.toString())
|
||||
withSelection(selection, selectionArgs)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
try {
|
||||
val operations = ArrayList<ContentProviderOperation>()
|
||||
val selection = "${ContactsContract.RawContacts._ID} = ?"
|
||||
contacts.filter { !it.isPrivate() }.forEach {
|
||||
ContentProviderOperation.newDelete(ContactsContract.RawContacts.CONTENT_URI).apply {
|
||||
val selectionArgs = arrayOf(it.id.toString())
|
||||
withSelection(selection, selectionArgs)
|
||||
operations.add(build())
|
||||
}
|
||||
|
||||
if (activity.hasPermission(PERMISSION_WRITE_CONTACTS)) {
|
||||
activity.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
}
|
||||
}.start()
|
||||
|
||||
if (context.hasPermission(PERMISSION_WRITE_CONTACTS)) {
|
||||
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, operations)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun getRecents(callback: (ArrayList<RecentCall>) -> Unit) {
|
||||
Thread {
|
||||
val calls = ArrayList<RecentCall>()
|
||||
if (!activity.hasPermission(PERMISSION_WRITE_CALL_LOG) || !activity.hasPermission(PERMISSION_READ_CALL_LOG)) {
|
||||
if (!context.hasPermission(PERMISSION_WRITE_CALL_LOG) || !context.hasPermission(PERMISSION_READ_CALL_LOG)) {
|
||||
callback(calls)
|
||||
return@Thread
|
||||
}
|
||||
|
||||
val blockedNumbers = context.getBlockedNumbers()
|
||||
val uri = CallLog.Calls.CONTENT_URI
|
||||
val projection = arrayOf(
|
||||
CallLog.Calls._ID,
|
||||
@ -1547,13 +1561,13 @@ class ContactsHelper(val activity: Activity) {
|
||||
val currentYear = SimpleDateFormat("yyyy", Locale.getDefault()).format(currentDate)
|
||||
val todayDate = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(currentDate)
|
||||
val yesterdayDate = SimpleDateFormat("dd MMM yyyy", Locale.getDefault()).format(Date(System.currentTimeMillis() - DAY_SECONDS * 1000))
|
||||
val yesterday = activity.getString(R.string.yesterday)
|
||||
val timeFormat = if (activity.config.use24HourFormat) "HH:mm" else "h:mm a"
|
||||
val yesterday = context.getString(R.string.yesterday)
|
||||
val timeFormat = if (context.config.use24HourFormat) "HH:mm" else "h:mm a"
|
||||
var prevNumber = ""
|
||||
|
||||
var cursor: Cursor? = null
|
||||
try {
|
||||
cursor = activity.contentResolver.query(uri, projection, null, null, sorting)
|
||||
cursor = context.contentResolver.query(uri, projection, null, null, sorting)
|
||||
if (cursor?.moveToFirst() == true) {
|
||||
do {
|
||||
val id = cursor.getIntValue(CallLog.Calls._ID)
|
||||
@ -1564,6 +1578,10 @@ class ContactsHelper(val activity: Activity) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (blockedNumbers.any { it.number == number || it.normalizedNumber == number }) {
|
||||
continue
|
||||
}
|
||||
|
||||
var formattedDate = SimpleDateFormat("dd MMM yyyy, $timeFormat", Locale.getDefault()).format(Date(date))
|
||||
val datePart = formattedDate.substring(0, 11)
|
||||
when {
|
||||
@ -1597,14 +1615,14 @@ class ContactsHelper(val activity: Activity) {
|
||||
}
|
||||
|
||||
if (operations.size % BATCH_SIZE == 0) {
|
||||
activity.contentResolver.applyBatch(CallLog.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(CallLog.AUTHORITY, operations)
|
||||
operations.clear()
|
||||
}
|
||||
}
|
||||
|
||||
activity.contentResolver.applyBatch(CallLog.AUTHORITY, operations)
|
||||
context.contentResolver.applyBatch(CallLog.AUTHORITY, operations)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
context.showErrorToast(e)
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
package com.simplemobiletools.contacts.pro.helpers
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.simplemobiletools.contacts.pro.models.*
|
||||
|
||||
class Converters {
|
||||
private val gson = Gson()
|
||||
private val longType = object : TypeToken<List<Long>>() {}.type
|
||||
private val stringType = object : TypeToken<List<String>>() {}.type
|
||||
private val numberType = object : TypeToken<List<PhoneNumber>>() {}.type
|
||||
private val emailType = object : TypeToken<List<Email>>() {}.type
|
||||
private val addressType = object : TypeToken<List<Address>>() {}.type
|
||||
private val eventType = object : TypeToken<List<Event>>() {}.type
|
||||
private val imType = object : TypeToken<List<IM>>() {}.type
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToStringList(value: String) = gson.fromJson<ArrayList<String>>(value, stringType)
|
||||
|
||||
@TypeConverter
|
||||
fun stringListToJson(list: ArrayList<String>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToLongList(value: String) = gson.fromJson<ArrayList<Long>>(value, longType)
|
||||
|
||||
@TypeConverter
|
||||
fun longListToJson(list: ArrayList<Long>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToPhoneNumberList(value: String) = gson.fromJson<ArrayList<PhoneNumber>>(value, numberType)
|
||||
|
||||
@TypeConverter
|
||||
fun phoneNumberListToJson(list: ArrayList<PhoneNumber>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToEmailList(value: String) = gson.fromJson<ArrayList<Email>>(value, emailType)
|
||||
|
||||
@TypeConverter
|
||||
fun emailListToJson(list: ArrayList<Email>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToAddressList(value: String) = gson.fromJson<ArrayList<Address>>(value, addressType)
|
||||
|
||||
@TypeConverter
|
||||
fun addressListToJson(list: ArrayList<Address>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToEventList(value: String) = gson.fromJson<ArrayList<Event>>(value, eventType)
|
||||
|
||||
@TypeConverter
|
||||
fun eventListToJson(list: ArrayList<Event>) = gson.toJson(list)
|
||||
|
||||
@TypeConverter
|
||||
fun jsonToIMsList(value: String) = gson.fromJson<ArrayList<IM>>(value, imType)
|
||||
|
||||
@TypeConverter
|
||||
fun IMsListToJson(list: ArrayList<IM>) = gson.toJson(list)
|
||||
}
|
@ -1,369 +0,0 @@
|
||||
package com.simplemobiletools.contacts.pro.helpers
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.simplemobiletools.commons.extensions.getBlobValue
|
||||
import com.simplemobiletools.commons.extensions.getIntValue
|
||||
import com.simplemobiletools.commons.extensions.getLongValue
|
||||
import com.simplemobiletools.commons.extensions.getStringValue
|
||||
import com.simplemobiletools.contacts.pro.extensions.applyRegexFiltering
|
||||
import com.simplemobiletools.contacts.pro.extensions.config
|
||||
import com.simplemobiletools.contacts.pro.extensions.getByteArray
|
||||
import com.simplemobiletools.contacts.pro.extensions.getPhotoThumbnailSize
|
||||
import com.simplemobiletools.contacts.pro.models.*
|
||||
|
||||
class DBHelper private constructor(val context: Context) : SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) {
|
||||
private val CONTACTS_TABLE_NAME = "contacts"
|
||||
private val COL_ID = "id"
|
||||
private val COL_PREFIX = "prefix"
|
||||
private val COL_FIRST_NAME = "first_name"
|
||||
private val COL_MIDDLE_NAME = "middle_name"
|
||||
private val COL_SURNAME = "surname"
|
||||
private val COL_SUFFIX = "suffix"
|
||||
private val COL_NICKNAME = "nickname"
|
||||
private val COL_PHOTO = "photo"
|
||||
private val COL_PHONE_NUMBERS = "phone_numbers"
|
||||
private val COL_EMAILS = "emails"
|
||||
private val COL_EVENTS = "events"
|
||||
private val COL_STARRED = "starred"
|
||||
private val COL_ADDRESSES = "addresses"
|
||||
private val COL_IMS = "ims"
|
||||
private val COL_NOTES = "notes"
|
||||
private val COL_COMPANY = "company"
|
||||
private val COL_JOB_POSITION = "job_position"
|
||||
private val COL_GROUPS = "groups"
|
||||
private val COL_WEBSITES = "websites"
|
||||
|
||||
private val GROUPS_TABLE_NAME = "groups"
|
||||
private val COL_TITLE = "title"
|
||||
|
||||
private val FIRST_CONTACT_ID = 1000000
|
||||
|
||||
private val mDb = writableDatabase
|
||||
|
||||
companion object {
|
||||
const val DB_NAME = "contacts.db"
|
||||
private const val DB_VERSION = 7
|
||||
private var dbInstance: DBHelper? = null
|
||||
var gson = Gson()
|
||||
|
||||
fun newInstance(context: Context): DBHelper {
|
||||
if (dbInstance == null)
|
||||
dbInstance = DBHelper(context)
|
||||
|
||||
return dbInstance!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(db: SQLiteDatabase) {
|
||||
db.execSQL("CREATE TABLE $CONTACTS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_FIRST_NAME TEXT, $COL_MIDDLE_NAME TEXT, " +
|
||||
"$COL_SURNAME TEXT, $COL_PHOTO BLOB, $COL_PHONE_NUMBERS TEXT, $COL_EMAILS TEXT, $COL_EVENTS TEXT, $COL_STARRED INTEGER, " +
|
||||
"$COL_ADDRESSES TEXT, $COL_NOTES TEXT, $COL_GROUPS TEXT, $COL_PREFIX TEXT, $COL_SUFFIX TEXT, $COL_COMPANY TEXT, $COL_JOB_POSITION TEXT," +
|
||||
"$COL_WEBSITES TEXT, $COL_NICKNAME TEXT, $COL_IMS TEXT)")
|
||||
|
||||
// start autoincrement ID from FIRST_CONTACT_ID to avoid conflicts
|
||||
db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$CONTACTS_TABLE_NAME', $FIRST_CONTACT_ID)")
|
||||
|
||||
createGroupsTable(db)
|
||||
}
|
||||
|
||||
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
if (oldVersion == 1) {
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_ADDRESSES TEXT DEFAULT ''")
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_NOTES TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 3) {
|
||||
createGroupsTable(db)
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_GROUPS TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 4) {
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_PREFIX TEXT DEFAULT ''")
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_SUFFIX TEXT DEFAULT ''")
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_COMPANY TEXT DEFAULT ''")
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_JOB_POSITION TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 5) {
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_WEBSITES TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 6) {
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_NICKNAME TEXT DEFAULT ''")
|
||||
}
|
||||
|
||||
if (oldVersion < 7) {
|
||||
db.execSQL("ALTER TABLE $CONTACTS_TABLE_NAME ADD COLUMN $COL_IMS TEXT DEFAULT ''")
|
||||
}
|
||||
}
|
||||
|
||||
private fun createGroupsTable(db: SQLiteDatabase) {
|
||||
db.execSQL("CREATE TABLE $GROUPS_TABLE_NAME ($COL_ID INTEGER PRIMARY KEY AUTOINCREMENT, $COL_TITLE TEXT)")
|
||||
|
||||
// start autoincrement ID from FIRST_GROUP_ID to avoid conflicts
|
||||
db.execSQL("REPLACE INTO sqlite_sequence (name, seq) VALUES ('$GROUPS_TABLE_NAME', $FIRST_GROUP_ID)")
|
||||
}
|
||||
|
||||
fun insertContact(contact: Contact): Boolean {
|
||||
val contactValues = fillContactValues(contact)
|
||||
val id = mDb.insert(CONTACTS_TABLE_NAME, null, contactValues).toInt()
|
||||
return id != -1
|
||||
}
|
||||
|
||||
fun updateContact(contact: Contact): Boolean {
|
||||
val contactValues = fillContactValues(contact)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(contact.id.toString())
|
||||
return mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, selectionArgs) == 1
|
||||
}
|
||||
|
||||
fun deleteContact(id: Int) = deleteContacts(arrayOf(id.toString()))
|
||||
|
||||
fun deleteContacts(ids: Array<String>) {
|
||||
if (ids.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val args = TextUtils.join(", ", ids)
|
||||
val selection = "$CONTACTS_TABLE_NAME.$COL_ID IN ($args)"
|
||||
mDb.delete(CONTACTS_TABLE_NAME, selection, null)
|
||||
}
|
||||
|
||||
private fun fillContactValues(contact: Contact): ContentValues {
|
||||
return ContentValues().apply {
|
||||
put(COL_PREFIX, contact.prefix)
|
||||
put(COL_FIRST_NAME, contact.firstName)
|
||||
put(COL_MIDDLE_NAME, contact.middleName)
|
||||
put(COL_SURNAME, contact.surname)
|
||||
put(COL_SUFFIX, contact.suffix)
|
||||
put(COL_NICKNAME, contact.nickname)
|
||||
put(COL_PHONE_NUMBERS, gson.toJson(contact.phoneNumbers))
|
||||
put(COL_EMAILS, gson.toJson(contact.emails))
|
||||
put(COL_ADDRESSES, gson.toJson(contact.addresses))
|
||||
put(COL_IMS, gson.toJson(contact.IMs))
|
||||
put(COL_EVENTS, gson.toJson(contact.events))
|
||||
put(COL_STARRED, contact.starred)
|
||||
put(COL_NOTES, contact.notes)
|
||||
put(COL_GROUPS, gson.toJson(contact.groups.map { it.id }))
|
||||
put(COL_COMPANY, contact.organization.company)
|
||||
put(COL_JOB_POSITION, contact.organization.jobPosition)
|
||||
put(COL_WEBSITES, gson.toJson(contact.websites))
|
||||
|
||||
if (contact.photoUri.isNotEmpty()) {
|
||||
put(COL_PHOTO, getPhotoByteArray(contact.photoUri))
|
||||
} else if (contact.photo == null) {
|
||||
putNull(COL_PHOTO)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPhotoByteArray(uri: String): ByteArray {
|
||||
val photoUri = Uri.parse(uri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = context.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize * 2, thumbnailSize * 2, false)
|
||||
val scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
scaledPhoto.recycle()
|
||||
return scaledSizePhotoData
|
||||
}
|
||||
|
||||
fun toggleFavorites(ids: Array<String>, addToFavorites: Boolean) {
|
||||
val contactValues = ContentValues()
|
||||
contactValues.put(COL_STARRED, if (addToFavorites) 1 else 0)
|
||||
|
||||
val args = TextUtils.join(", ", ids)
|
||||
val selection = "$COL_ID IN ($args)"
|
||||
mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, null)
|
||||
}
|
||||
|
||||
fun insertGroup(group: Group): Group? {
|
||||
val contactValues = fillGroupValues(group)
|
||||
val id = mDb.insert(GROUPS_TABLE_NAME, null, contactValues)
|
||||
return if (id == -1L) {
|
||||
null
|
||||
} else {
|
||||
Group(id, group.title)
|
||||
}
|
||||
}
|
||||
|
||||
fun renameGroup(group: Group): Boolean {
|
||||
val contactValues = fillGroupValues(group)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(group.id.toString())
|
||||
return mDb.update(GROUPS_TABLE_NAME, contactValues, selection, selectionArgs) == 1
|
||||
}
|
||||
|
||||
fun deleteGroup(id: Long) = deleteGroups(arrayOf(id.toString()))
|
||||
|
||||
private fun deleteGroups(ids: Array<String>) {
|
||||
val args = TextUtils.join(", ", ids)
|
||||
val selection = "$GROUPS_TABLE_NAME.$COL_ID IN ($args)"
|
||||
mDb.delete(GROUPS_TABLE_NAME, selection, null)
|
||||
}
|
||||
|
||||
fun getGroups(): ArrayList<Group> {
|
||||
val groups = ArrayList<Group>()
|
||||
val projection = arrayOf(COL_ID, COL_TITLE)
|
||||
val cursor = mDb.query(GROUPS_TABLE_NAME, projection, null, null, null, null, null)
|
||||
cursor.use {
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getLongValue(COL_ID)
|
||||
val title = cursor.getStringValue(COL_TITLE)
|
||||
val group = Group(id, title)
|
||||
groups.add(group)
|
||||
}
|
||||
}
|
||||
return groups
|
||||
}
|
||||
|
||||
private fun fillGroupValues(group: Group): ContentValues {
|
||||
return ContentValues().apply {
|
||||
put(COL_TITLE, group.title)
|
||||
}
|
||||
}
|
||||
|
||||
fun addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val currentGroupIds = it.groups.map { it.id } as ArrayList<Long>
|
||||
currentGroupIds.add(groupId)
|
||||
updateContactGroups(it, currentGroupIds)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val currentGroupIds = it.groups.map { it.id } as ArrayList<Long>
|
||||
currentGroupIds.remove(groupId)
|
||||
updateContactGroups(it, currentGroupIds)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateContactGroups(contact: Contact, groupIds: ArrayList<Long>) {
|
||||
val contactValues = fillContactGroupValues(groupIds)
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(contact.id.toString())
|
||||
mDb.update(CONTACTS_TABLE_NAME, contactValues, selection, selectionArgs)
|
||||
}
|
||||
|
||||
private fun fillContactGroupValues(groupIds: ArrayList<Long>): ContentValues {
|
||||
return ContentValues().apply {
|
||||
put(COL_GROUPS, gson.toJson(groupIds))
|
||||
}
|
||||
}
|
||||
|
||||
fun getContacts(activity: Activity, selection: String? = null, selectionArgs: Array<String>? = null): ArrayList<Contact> {
|
||||
val storedGroups = ContactsHelper(activity).getStoredGroups()
|
||||
val filterDuplicates = activity.config.filterDuplicates
|
||||
val contacts = ArrayList<Contact>()
|
||||
val projection = arrayOf(COL_ID, COL_PREFIX, COL_FIRST_NAME, COL_MIDDLE_NAME, COL_SURNAME, COL_SUFFIX, COL_NICKNAME, COL_PHONE_NUMBERS,
|
||||
COL_EMAILS, COL_EVENTS, COL_STARRED, COL_PHOTO, COL_ADDRESSES, COL_IMS, COL_NOTES, COL_GROUPS, COL_COMPANY, COL_JOB_POSITION, COL_WEBSITES)
|
||||
|
||||
val phoneNumbersToken = object : TypeToken<List<PhoneNumber>>() {}.type
|
||||
val emailsToken = object : TypeToken<List<Email>>() {}.type
|
||||
val addressesToken = object : TypeToken<List<Address>>() {}.type
|
||||
val IMsToken = object : TypeToken<List<IM>>() {}.type
|
||||
val eventsToken = object : TypeToken<List<Event>>() {}.type
|
||||
val groupIdsToken = object : TypeToken<List<Long>>() {}.type
|
||||
val websitesToken = object : TypeToken<List<String>>() {}.type
|
||||
|
||||
val cursor = mDb.query(CONTACTS_TABLE_NAME, projection, selection, selectionArgs, null, null, null)
|
||||
cursor.use {
|
||||
while (cursor.moveToNext()) {
|
||||
val id = cursor.getIntValue(COL_ID)
|
||||
val prefix = cursor.getStringValue(COL_PREFIX)
|
||||
val firstName = cursor.getStringValue(COL_FIRST_NAME)
|
||||
val middleName = cursor.getStringValue(COL_MIDDLE_NAME)
|
||||
val surname = cursor.getStringValue(COL_SURNAME)
|
||||
val suffix = cursor.getStringValue(COL_SUFFIX)
|
||||
val nickname = cursor.getStringValue(COL_NICKNAME)
|
||||
|
||||
val phoneNumbersJson = cursor.getStringValue(COL_PHONE_NUMBERS)
|
||||
val phoneNumbers = if (phoneNumbersJson == "[]") ArrayList() else gson.fromJson<ArrayList<PhoneNumber>>(phoneNumbersJson, phoneNumbersToken)
|
||||
?: ArrayList(1)
|
||||
|
||||
// labels can be null at upgrading from older app versions, when the label wasn't available at all yet
|
||||
phoneNumbers.filter { it.label == null }.forEach {
|
||||
it.label = ""
|
||||
}
|
||||
|
||||
val emailsJson = cursor.getStringValue(COL_EMAILS)
|
||||
val emails = if (emailsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Email>>(emailsJson, emailsToken)
|
||||
?: ArrayList(1)
|
||||
|
||||
emails.filter { it.label == null }.forEach {
|
||||
it.label = ""
|
||||
}
|
||||
|
||||
val addressesJson = cursor.getStringValue(COL_ADDRESSES)
|
||||
val addresses = if (addressesJson == "[]") ArrayList() else gson.fromJson<ArrayList<Address>>(addressesJson, addressesToken)
|
||||
?: ArrayList(1)
|
||||
|
||||
addresses.filter { it.label == null }.forEach {
|
||||
it.label = ""
|
||||
}
|
||||
|
||||
val IMsJson = cursor.getStringValue(COL_IMS)
|
||||
val IMs = if (IMsJson == "[]") ArrayList() else gson.fromJson<ArrayList<IM>>(IMsJson, IMsToken) ?: ArrayList(1)
|
||||
|
||||
val eventsJson = cursor.getStringValue(COL_EVENTS)
|
||||
val events = if (eventsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Event>>(eventsJson, eventsToken)
|
||||
?: ArrayList(1)
|
||||
|
||||
val photoByteArray = cursor.getBlobValue(COL_PHOTO) ?: null
|
||||
val photo = if (photoByteArray?.isNotEmpty() == true) {
|
||||
try {
|
||||
BitmapFactory.decodeByteArray(photoByteArray, 0, photoByteArray.size)
|
||||
} catch (e: OutOfMemoryError) {
|
||||
null
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
val notes = cursor.getStringValue(COL_NOTES)
|
||||
val starred = cursor.getIntValue(COL_STARRED)
|
||||
|
||||
val groupIdsJson = cursor.getStringValue(COL_GROUPS)
|
||||
val groupIds = if (groupIdsJson == "[]") ArrayList() else gson.fromJson<ArrayList<Long>>(groupIdsJson, groupIdsToken)
|
||||
?: ArrayList(1)
|
||||
val groups = storedGroups.filter { groupIds.contains(it.id) } as ArrayList<Group>
|
||||
|
||||
val company = cursor.getStringValue(COL_COMPANY)
|
||||
val jobPosition = cursor.getStringValue(COL_JOB_POSITION)
|
||||
val organization = Organization(company, jobPosition)
|
||||
|
||||
val websitesJson = cursor.getStringValue(COL_WEBSITES)
|
||||
val websites = if (websitesJson == "[]") ArrayList() else gson.fromJson<ArrayList<String>>(websitesJson, websitesToken)
|
||||
?: ArrayList(1)
|
||||
|
||||
val cleanPhoneNumbers = ArrayList<PhoneNumber>()
|
||||
if (filterDuplicates) {
|
||||
phoneNumbers.mapTo(cleanPhoneNumbers) { PhoneNumber(it.value.applyRegexFiltering(), 0, "") }
|
||||
}
|
||||
|
||||
val contact = Contact(id, prefix, firstName, middleName, surname, suffix, nickname, "", phoneNumbers, emails, addresses,
|
||||
events, SMT_PRIVATE, starred, id, "", photo, notes, groups, organization, websites, cleanPhoneNumbers, IMs)
|
||||
contacts.add(contact)
|
||||
}
|
||||
}
|
||||
return contacts
|
||||
}
|
||||
|
||||
fun getContactWithId(activity: Activity, id: Int): Contact? {
|
||||
val selection = "$COL_ID = ?"
|
||||
val selectionArgs = arrayOf(id.toString())
|
||||
return getContacts(activity, selection, selectionArgs).firstOrNull()
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
package com.simplemobiletools.contacts.pro.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import com.simplemobiletools.contacts.pro.extensions.contactsDB
|
||||
import com.simplemobiletools.contacts.pro.extensions.getByteArray
|
||||
import com.simplemobiletools.contacts.pro.extensions.getEmptyContact
|
||||
import com.simplemobiletools.contacts.pro.extensions.getPhotoThumbnailSize
|
||||
import com.simplemobiletools.contacts.pro.models.Contact
|
||||
import com.simplemobiletools.contacts.pro.models.Group
|
||||
import com.simplemobiletools.contacts.pro.models.LocalContact
|
||||
import com.simplemobiletools.contacts.pro.models.Organization
|
||||
|
||||
class LocalContactsHelper(val context: Context) {
|
||||
fun getAllContacts() = context.contactsDB.getContacts().map { convertLocalContactToContact(it) }.toMutableList() as ArrayList<Contact>
|
||||
|
||||
fun getContactWithId(id: Int) = convertLocalContactToContact(context.contactsDB.getContactWithId(id))
|
||||
|
||||
fun insertOrUpdateContact(contact: Contact): Boolean {
|
||||
val localContact = convertContactToLocalContact(contact)
|
||||
return context.contactsDB.insertOrUpdate(localContact) > 0
|
||||
}
|
||||
|
||||
fun addContactsToGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val localContact = convertContactToLocalContact(it)
|
||||
val newGroups = localContact.groups
|
||||
newGroups.add(groupId)
|
||||
newGroups.distinct()
|
||||
localContact.groups = newGroups
|
||||
context.contactsDB.insertOrUpdate(localContact)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeContactsFromGroup(contacts: ArrayList<Contact>, groupId: Long) {
|
||||
contacts.forEach {
|
||||
val localContact = convertContactToLocalContact(it)
|
||||
val newGroups = localContact.groups
|
||||
newGroups.remove(groupId)
|
||||
localContact.groups = newGroups
|
||||
context.contactsDB.insertOrUpdate(localContact)
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteContactIds(ids: Array<Int>) {
|
||||
ids.forEach {
|
||||
context.contactsDB.deleteContactId(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun toggleFavorites(ids: Array<Int>, addToFavorites: Boolean) {
|
||||
val isStarred = if (addToFavorites) 1 else 0
|
||||
ids.forEach {
|
||||
context.contactsDB.updateStarred(isStarred, it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPhotoByteArray(uri: String): ByteArray {
|
||||
if (uri.isEmpty()) {
|
||||
return ByteArray(0)
|
||||
}
|
||||
|
||||
val photoUri = Uri.parse(uri)
|
||||
val bitmap = MediaStore.Images.Media.getBitmap(context.contentResolver, photoUri)
|
||||
|
||||
val thumbnailSize = context.getPhotoThumbnailSize()
|
||||
val scaledPhoto = Bitmap.createScaledBitmap(bitmap, thumbnailSize * 2, thumbnailSize * 2, false)
|
||||
val scaledSizePhotoData = scaledPhoto.getByteArray()
|
||||
scaledPhoto.recycle()
|
||||
return scaledSizePhotoData
|
||||
}
|
||||
|
||||
private fun convertLocalContactToContact(localContact: LocalContact?): Contact? {
|
||||
if (localContact == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
val contactPhoto = if (localContact.photo == null) {
|
||||
null
|
||||
} else {
|
||||
try {
|
||||
BitmapFactory.decodeByteArray(localContact.photo, 0, localContact.photo!!.size)
|
||||
} catch (e: OutOfMemoryError) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val storedGroups = ContactsHelper(context).getStoredGroupsSync()
|
||||
|
||||
return context.getEmptyContact().apply {
|
||||
id = localContact.id!!
|
||||
prefix = localContact.prefix
|
||||
firstName = localContact.firstName
|
||||
middleName = localContact.middleName
|
||||
surname = localContact.surname
|
||||
suffix = localContact.suffix
|
||||
nickname = localContact.nickname
|
||||
photoUri = ""
|
||||
phoneNumbers = localContact.phoneNumbers
|
||||
emails = localContact.emails
|
||||
addresses = localContact.addresses
|
||||
events = localContact.events
|
||||
source = SMT_PRIVATE
|
||||
starred = localContact.starred
|
||||
contactId = localContact.id!!
|
||||
thumbnailUri = ""
|
||||
photo = contactPhoto
|
||||
notes = localContact.notes
|
||||
groups = storedGroups.filter { localContact.groups.contains(it.id) } as ArrayList<Group>
|
||||
organization = Organization(localContact.company, localContact.jobPosition)
|
||||
websites = localContact.websites
|
||||
IMs = localContact.IMs
|
||||
}
|
||||
}
|
||||
|
||||
private fun convertContactToLocalContact(contact: Contact): LocalContact {
|
||||
return getEmptyLocalContact().apply {
|
||||
id = if (contact.id == 0) null else contact.id
|
||||
prefix = contact.prefix
|
||||
firstName = contact.firstName
|
||||
middleName = contact.middleName
|
||||
surname = contact.surname
|
||||
suffix = contact.suffix
|
||||
nickname = contact.nickname
|
||||
photo = getPhotoByteArray(contact.photoUri)
|
||||
phoneNumbers = contact.phoneNumbers
|
||||
emails = contact.emails
|
||||
events = contact.events
|
||||
starred = contact.starred
|
||||
addresses = contact.addresses
|
||||
notes = contact.notes
|
||||
groups = contact.groups.map { it.id }.toMutableList() as ArrayList<Long>
|
||||
company = contact.organization.company
|
||||
jobPosition = contact.organization.jobPosition
|
||||
websites = contact.websites
|
||||
IMs = contact.IMs
|
||||
}
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
package com.simplemobiletools.contacts.pro.helpers
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.net.URLEncoder
|
||||
|
||||
// https://alvinalexander.com/java/jwarehouse/android/core/java/com/google/android/mms/pdu/QuotedPrintable.java.shtml
|
||||
object QuotedPrintable {
|
||||
private const val ESCAPE_CHAR: Byte = '='.toByte()
|
||||
fun decode(value: String?): String {
|
||||
val bytes = value?.toByteArray()
|
||||
if (bytes == null || bytes.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
|
||||
val buffer = ByteArrayOutputStream()
|
||||
var i = 0
|
||||
while (i < bytes.size) {
|
||||
val b = bytes[i].toInt()
|
||||
if (b == ESCAPE_CHAR.toInt()) {
|
||||
try {
|
||||
if ('\r' == bytes[i + 1].toChar() && '\n' == bytes[i + 2].toChar()) {
|
||||
i += 3
|
||||
continue
|
||||
}
|
||||
|
||||
val u = Character.digit(bytes[++i].toChar(), 16)
|
||||
val l = Character.digit(bytes[++i].toChar(), 16)
|
||||
if (u == -1 || l == -1) {
|
||||
return ""
|
||||
}
|
||||
|
||||
buffer.write(((u shl 4) + l).toChar().toInt())
|
||||
} catch (e: ArrayIndexOutOfBoundsException) {
|
||||
return ""
|
||||
}
|
||||
|
||||
} else {
|
||||
buffer.write(b)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return String(buffer.toByteArray())
|
||||
}
|
||||
|
||||
fun encode(value: String): String {
|
||||
val result = StringBuilder()
|
||||
value.forEach {
|
||||
if (it == ' ') {
|
||||
result.append(' ')
|
||||
} else {
|
||||
val urlEncoded = urlEncode(it.toString())
|
||||
if (urlEncoded == it.toString()) {
|
||||
val hex = String.format("%04x", it.toInt()).trimStart('0').toUpperCase()
|
||||
result.append("=$hex")
|
||||
} else {
|
||||
result.append(urlEncoded)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun urlEncode(value: String) = URLEncoder.encode(value, "UTF-8").replace("+", " ").replace('%', '=')
|
||||
}
|
@ -152,7 +152,7 @@ class VcfExporter {
|
||||
contactsExported++
|
||||
}
|
||||
|
||||
Ezvcard.write(cards).go(file)
|
||||
Ezvcard.write(cards).go(it)
|
||||
} catch (e: Exception) {
|
||||
activity.showErrorToast(e)
|
||||
}
|
||||
|
@ -6,15 +6,14 @@ import android.provider.ContactsContract.CommonDataKinds
|
||||
import android.widget.Toast
|
||||
import com.simplemobiletools.commons.extensions.showErrorToast
|
||||
import com.simplemobiletools.contacts.pro.activities.SimpleActivity
|
||||
import com.simplemobiletools.contacts.pro.extensions.dbHelper
|
||||
import com.simplemobiletools.contacts.pro.extensions.getCachePhoto
|
||||
import com.simplemobiletools.contacts.pro.extensions.getCachePhotoUri
|
||||
import com.simplemobiletools.contacts.pro.extensions.groupsDB
|
||||
import com.simplemobiletools.contacts.pro.extensions.normalizeNumber
|
||||
import com.simplemobiletools.contacts.pro.helpers.VcfImporter.ImportResult.*
|
||||
import com.simplemobiletools.contacts.pro.models.*
|
||||
import ezvcard.Ezvcard
|
||||
import ezvcard.VCard
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.format.DateTimeFormat
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URLDecoder
|
||||
@ -25,8 +24,6 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
IMPORT_FAIL, IMPORT_OK, IMPORT_PARTIAL
|
||||
}
|
||||
|
||||
private val PATTERN = "EEE MMM dd HH:mm:ss 'GMT'ZZ YYYY"
|
||||
|
||||
private var contactsImported = 0
|
||||
private var contactsFailed = 0
|
||||
|
||||
@ -59,7 +56,7 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
""
|
||||
}
|
||||
|
||||
phoneNumbers.add(PhoneNumber(number, type, label))
|
||||
phoneNumbers.add(PhoneNumber(number, type, label, number.normalizeNumber()))
|
||||
}
|
||||
|
||||
val emails = ArrayList<Email>()
|
||||
@ -112,7 +109,6 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
val photoData = ezContact.photos.firstOrNull()?.data
|
||||
val photo = null
|
||||
val thumbnailUri = savePhoto(photoData)
|
||||
val cleanPhoneNumbers = ArrayList<PhoneNumber>()
|
||||
|
||||
val IMs = ArrayList<IM>()
|
||||
ezContact.impps.forEach {
|
||||
@ -136,7 +132,7 @@ 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, cleanPhoneNumbers, IMs)
|
||||
targetContactSource, starred, contactId, thumbnailUri, photo, notes, groups, organization, websites, IMs)
|
||||
|
||||
// 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()) {
|
||||
@ -160,8 +156,10 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
}
|
||||
|
||||
private fun formatDateToDayCode(date: Date): String {
|
||||
val dateTime = DateTime.parse(date.toString(), DateTimeFormat.forPattern(PATTERN))
|
||||
return dateTime.toString("yyyy-MM-dd")
|
||||
val year = 1900 + date.year
|
||||
val month = String.format("%02d", date.month + 1)
|
||||
val day = String.format("%02d", date.date)
|
||||
return "$year-$month-$day"
|
||||
}
|
||||
|
||||
private fun getContactGroups(ezContact: VCard): ArrayList<Group> {
|
||||
@ -170,7 +168,7 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
val groupNames = ezContact.categories.values
|
||||
|
||||
if (groupNames != null) {
|
||||
val storedGroups = ContactsHelper(activity).getStoredGroups()
|
||||
val storedGroups = ContactsHelper(activity).getStoredGroupsSync()
|
||||
|
||||
groupNames.forEach {
|
||||
val groupName = it
|
||||
@ -179,11 +177,10 @@ class VcfImporter(val activity: SimpleActivity) {
|
||||
if (storedGroup != null) {
|
||||
groups.add(storedGroup)
|
||||
} else {
|
||||
val newContactGroup = activity.dbHelper.insertGroup(Group(0, groupName))
|
||||
|
||||
if (newContactGroup != null) {
|
||||
groups.add(newContactGroup)
|
||||
}
|
||||
val newGroup = Group(null, groupName)
|
||||
val id = activity.groupsDB.insertOrUpdate(newGroup)
|
||||
newGroup.id = id
|
||||
groups.add(newGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.simplemobiletools.contacts.pro.interfaces
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.simplemobiletools.contacts.pro.models.LocalContact
|
||||
|
||||
@Dao
|
||||
interface ContactsDao {
|
||||
@Query("SELECT * FROM contacts")
|
||||
fun getContacts(): List<LocalContact>
|
||||
|
||||
@Query("SELECT * FROM contacts WHERE id = :id")
|
||||
fun getContactWithId(id: Int): LocalContact?
|
||||
|
||||
@Query("UPDATE contacts SET starred = :isStarred WHERE id = :id")
|
||||
fun updateStarred(isStarred: Int, id: Int)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertOrUpdate(contact: LocalContact): Long
|
||||
|
||||
@Query("DELETE FROM contacts WHERE id = :id")
|
||||
fun deleteContactId(id: Int)
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.simplemobiletools.contacts.pro.interfaces
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.simplemobiletools.contacts.pro.models.Group
|
||||
|
||||
@Dao
|
||||
interface GroupsDao {
|
||||
@Query("SELECT * FROM groups")
|
||||
fun getGroups(): List<Group>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertOrUpdate(group: Group): Long
|
||||
|
||||
@Query("DELETE FROM groups WHERE id = :id")
|
||||
fun deleteGroupId(id: Long)
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package com.simplemobiletools.contacts.pro.models
|
||||
|
||||
data class BlockedNumber(val id: Long, val number: String, val normalizedNumber: String)
|
@ -1,17 +1,18 @@
|
||||
package com.simplemobiletools.contacts.pro.models
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.telephony.PhoneNumberUtils
|
||||
import com.simplemobiletools.commons.extensions.normalizeString
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_FIRST_NAME
|
||||
import com.simplemobiletools.commons.helpers.SORT_BY_MIDDLE_NAME
|
||||
import com.simplemobiletools.commons.helpers.SORT_DESCENDING
|
||||
import com.simplemobiletools.contacts.pro.extensions.applyRegexFiltering
|
||||
import com.simplemobiletools.contacts.pro.extensions.normalizeNumber
|
||||
import com.simplemobiletools.contacts.pro.helpers.SMT_PRIVATE
|
||||
|
||||
data class Contact(val id: Int, var prefix: String, var firstName: String, var middleName: String, var surname: String, var suffix: String, var nickname: String,
|
||||
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<PhoneNumber>, var emails: ArrayList<Email>, var addresses: ArrayList<Address>,
|
||||
var events: ArrayList<Event>, var source: String, var starred: Int, val contactId: Int, val thumbnailUri: String, var photo: Bitmap?, var notes: String,
|
||||
var groups: ArrayList<Group>, var organization: Organization, var websites: ArrayList<String>, var cleanPhoneNumbers: ArrayList<PhoneNumber>,
|
||||
var IMs: ArrayList<IM>) :
|
||||
var events: ArrayList<Event>, var source: String, var starred: Int, var contactId: Int, var thumbnailUri: String, var photo: Bitmap?, var notes: String,
|
||||
var groups: ArrayList<Group>, var organization: Organization, var websites: ArrayList<String>, var IMs: ArrayList<IM>) :
|
||||
Comparable<Contact> {
|
||||
companion object {
|
||||
var sorting = 0
|
||||
@ -126,21 +127,19 @@ data class Contact(val id: Int, var prefix: String, var firstName: String, var m
|
||||
|
||||
fun isABusinessContact() = prefix.isEmpty() && firstName.isEmpty() && middleName.isEmpty() && surname.isEmpty() && suffix.isEmpty() && organization.isNotEmpty()
|
||||
|
||||
// do a more advanced phone number check here, compare numbers and and search query with dashes, spaces and everything but numbers removed
|
||||
fun doesContainPhoneNumber(text: String): Boolean {
|
||||
if (text.isNotEmpty()) {
|
||||
if (phoneNumbers.any { it.value.contains(text) } || cleanPhoneNumbers.any { it.value.contains(text) }) {
|
||||
return true
|
||||
return if (text.isNotEmpty()) {
|
||||
val normalizedText = text.normalizeNumber()
|
||||
phoneNumbers.any {
|
||||
PhoneNumberUtils.compare(it.normalizedNumber, normalizedText) ||
|
||||
it.value.contains(text) ||
|
||||
it.normalizedNumber?.contains(normalizedText) == true ||
|
||||
it.value.normalizeNumber().contains(normalizedText)
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
val filteredNumber = text.applyRegexFiltering()
|
||||
if (filteredNumber.isNotEmpty()) {
|
||||
if (phoneNumbers.any { it.value.contains(filteredNumber) } || cleanPhoneNumbers.any { it.value.contains(filteredNumber) }) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
fun isPrivate() = source == SMT_PRIVATE
|
||||
}
|
||||
|
@ -1,16 +1,21 @@
|
||||
package com.simplemobiletools.contacts.pro.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.simplemobiletools.contacts.pro.helpers.FIRST_GROUP_ID
|
||||
import java.io.Serializable
|
||||
|
||||
data class Group(var id: Long, var title: String, var contactsCount: Int = 0) : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID = -1384515348451345L
|
||||
}
|
||||
@Entity(tableName = "groups", indices = [(Index(value = ["id"], unique = true))])
|
||||
data class Group(
|
||||
@PrimaryKey(autoGenerate = true) var id: Long?,
|
||||
@ColumnInfo(name = "title") var title: String,
|
||||
@ColumnInfo(name = "contacts_count") var contactsCount: Int = 0) : Serializable {
|
||||
|
||||
fun addContact() = contactsCount++
|
||||
|
||||
fun getBubbleText() = title
|
||||
|
||||
fun isPrivateSecretGroup() = id >= FIRST_GROUP_ID
|
||||
fun isPrivateSecretGroup() = id ?: 0 >= FIRST_GROUP_ID
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
package com.simplemobiletools.contacts.pro.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "contacts", indices = [(Index(value = ["id"], unique = true))])
|
||||
data class LocalContact(
|
||||
@PrimaryKey(autoGenerate = true) var id: 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 = "phone_numbers") var phoneNumbers: ArrayList<PhoneNumber>,
|
||||
@ColumnInfo(name = "emails") var emails: ArrayList<Email>,
|
||||
@ColumnInfo(name = "events") var events: ArrayList<Event>,
|
||||
@ColumnInfo(name = "starred") var starred: Int,
|
||||
@ColumnInfo(name = "addresses") var addresses: ArrayList<Address>,
|
||||
@ColumnInfo(name = "notes") var notes: String,
|
||||
@ColumnInfo(name = "groups") var groups: ArrayList<Long>,
|
||||
@ColumnInfo(name = "company") var company: String,
|
||||
@ColumnInfo(name = "job_position") var jobPosition: String,
|
||||
@ColumnInfo(name = "websites") var websites: ArrayList<String>,
|
||||
@ColumnInfo(name = "ims") var IMs: ArrayList<IM>) {
|
||||
|
||||
override fun equals(other: Any?) = id == (other as? LocalContact?)?.id
|
||||
|
||||
override fun hashCode() = id ?: 0
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
package com.simplemobiletools.contacts.pro.models
|
||||
|
||||
data class PhoneNumber(var value: String, var type: Int, var label: String)
|
||||
data class PhoneNumber(var value: String, var type: Int, var label: String, var normalizedNumber: String?)
|
||||
|
BIN
app/src/main/res/drawable-hdpi/ic_block.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_block.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 495 B |
BIN
app/src/main/res/drawable-xhdpi/ic_block.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_block.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 624 B |
BIN
app/src/main/res/drawable-xxhdpi/ic_block.png
Normal file
BIN
app/src/main/res/drawable-xxhdpi/ic_block.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 928 B |
BIN
app/src/main/res/drawable-xxxhdpi/ic_block.png
Normal file
BIN
app/src/main/res/drawable-xxxhdpi/ic_block.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -4,7 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/contact_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/contact_holder"
|
||||
|
42
app/src/main/res/layout/activity_manage_blocked_numbers.xml
Normal file
42
app/src/main/res/layout/activity_manage_blocked_numbers.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/manage_blocked_numbers_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyRecyclerView
|
||||
android:id="@+id/manage_blocked_numbers_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager"/>
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/manage_blocked_numbers_placeholder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingLeft="@dimen/big_margin"
|
||||
android:paddingTop="@dimen/activity_margin"
|
||||
android:paddingRight="@dimen/big_margin"
|
||||
android:text="@string/not_blocking_anyone"
|
||||
android:textSize="@dimen/bigger_text_size"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/manage_blocked_numbers_placeholder_2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/manage_blocked_numbers_placeholder"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:gravity="center"
|
||||
android:padding="@dimen/activity_margin"
|
||||
android:text="@string/add_a_blocked_number"
|
||||
android:textSize="@dimen/bigger_text_size"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</RelativeLayout>
|
@ -78,6 +78,28 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_manage_blocked_numbers_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_margin"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="@dimen/normal_margin"
|
||||
android:paddingTop="@dimen/activity_margin"
|
||||
android:paddingRight="@dimen/normal_margin"
|
||||
android:paddingBottom="@dimen/activity_margin">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/settings_manage_blocked_numbers"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:paddingStart="@dimen/medium_margin"
|
||||
android:paddingLeft="@dimen/medium_margin"
|
||||
android:text="@string/manage_blocked_numbers"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_use_english_holder"
|
||||
android:layout_width="match_parent"
|
||||
@ -294,6 +316,30 @@
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_show_dialpad_button_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/medium_margin"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:paddingLeft="@dimen/normal_margin"
|
||||
android:paddingTop="@dimen/activity_margin"
|
||||
android:paddingRight="@dimen/normal_margin"
|
||||
android:paddingBottom="@dimen/activity_margin">
|
||||
|
||||
<com.simplemobiletools.commons.views.MySwitchCompat
|
||||
android:id="@+id/settings_show_dialpad_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:clickable="false"
|
||||
android:paddingStart="@dimen/medium_margin"
|
||||
android:paddingLeft="@dimen/medium_margin"
|
||||
android:text="@string/show_dialpad_button"
|
||||
app:switchPadding="@dimen/medium_margin"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/settings_on_contact_click_holder"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -4,7 +4,8 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/contact_scrollview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone">
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/contact_holder"
|
||||
@ -98,6 +99,7 @@
|
||||
android:layout_below="@+id/contact_photo"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -113,6 +115,7 @@
|
||||
android:layout_below="@+id/contact_prefix"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -128,6 +131,7 @@
|
||||
android:layout_below="@+id/contact_first_name"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -143,6 +147,7 @@
|
||||
android:layout_below="@+id/contact_middle_name"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -158,6 +163,7 @@
|
||||
android:layout_below="@+id/contact_surname"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -173,6 +179,7 @@
|
||||
android:layout_below="@+id/contact_suffix"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
@ -298,6 +305,7 @@
|
||||
android:layout_below="@+id/contact_events_holder"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_notes_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lineSpacingExtra="@dimen/medium_margin"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/normal_margin"
|
||||
@ -322,6 +330,7 @@
|
||||
android:layout_below="@+id/contact_notes"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_organization_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lineSpacingExtra="@dimen/medium_margin"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/normal_margin"
|
||||
@ -335,6 +344,7 @@
|
||||
android:layout_below="@+id/contact_organization_company"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_organization_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lineSpacingExtra="@dimen/medium_margin"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
android:paddingTop="@dimen/normal_margin"
|
||||
@ -398,6 +408,7 @@
|
||||
android:layout_below="@+id/contact_groups_holder"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/contact_name_image"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingLeft="@dimen/small_margin"
|
||||
|
20
app/src/main/res/layout/dialog_add_blocked_number.xml
Normal file
20
app/src/main/res/layout/dialog_add_blocked_number.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/dialog_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="@dimen/activity_margin">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyEditText
|
||||
android:id="@+id/add_blocked_number_edittext"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/activity_margin"
|
||||
android:layout_marginTop="@dimen/small_margin"
|
||||
android:layout_marginRight="@dimen/activity_margin"
|
||||
android:inputType="phone"
|
||||
android:textCursorDrawable="@null"
|
||||
android:textSize="@dimen/bigger_text_size"/>
|
||||
|
||||
</RelativeLayout>
|
20
app/src/main/res/layout/item_manage_blocked_number.xml
Normal file
20
app/src/main/res/layout/item_manage_blocked_number.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/manage_blocked_number_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="@drawable/selector"
|
||||
android:padding="@dimen/activity_margin">
|
||||
|
||||
<com.simplemobiletools.commons.views.MyTextView
|
||||
android:id="@+id/manage_blocked_number_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="@dimen/medium_margin"/>
|
||||
|
||||
</RelativeLayout>
|
@ -5,10 +5,11 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:ellipsize="end"
|
||||
android:lines="1"
|
||||
android:maxLines="1"
|
||||
android:paddingBottom="@dimen/normal_margin"
|
||||
android:paddingTop="@dimen/normal_margin"
|
||||
android:paddingBottom="@dimen/normal_margin"
|
||||
android:singleLine="true"
|
||||
android:textSize="@dimen/bigger_text_size"/>
|
||||
|
@ -11,4 +11,9 @@
|
||||
android:icon="@drawable/ic_select_all"
|
||||
android:title="@string/select_all"
|
||||
app:showAsAction="ifRoom"/>
|
||||
<item
|
||||
android:id="@+id/cab_block_number"
|
||||
android:icon="@drawable/ic_block"
|
||||
android:title="@string/block_number"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
||||
|
9
app/src/main/res/menu/menu_add_blocked_number.xml
Normal file
9
app/src/main/res/menu/menu_add_blocked_number.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/add_blocked_number"
|
||||
android:icon="@drawable/ic_plus"
|
||||
android:title="@string/add_a_blocked_number"
|
||||
app:showAsAction="ifRoom"/>
|
||||
</menu>
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Lazım olan icazələri istə</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Yeni kontakt</string>
|
||||
<string name="edit_contact">Redaktə et</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Ada soyaddan başla</string>
|
||||
<string name="show_phone_numbers">Telefon nömrələrini əsas ekranda göstər</string>
|
||||
<string name="show_contact_thumbnails">Kontakt görüntülərini göstər</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Kontakta toxunduqda</string>
|
||||
<string name="call_contact">Kontakta zəng et</string>
|
||||
<string name="view_contact">Kontakt detallarına bax</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Göstərmək üçün sahəni seç</string>
|
||||
<string name="prefix">Ön şəkilçi</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Kontakt kökü</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
|
||||
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Benötigte Berechtigungen anfordern</string>
|
||||
<string name="create_new_contact">Neuen Kontakt erstellen</string>
|
||||
<string name="add_to_existing_contact">Zu einem existierenden Kontakt hinzufügen</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_contacts_found">Keine Kontakte gefunden</string>
|
||||
<string name="no_contacts_with_emails">Keine Kontakte mit E-Mailadressen gefunden</string>
|
||||
<string name="no_contacts_with_phone_numbers">Keine Kontakte mit Telefonnummern gefunden</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Neuer Kontakt</string>
|
||||
<string name="edit_contact">Kontakt bearbeiten</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Namen mit Nachnamen beginnen</string>
|
||||
<string name="show_phone_numbers">Telefonnummern im Hauptmenü zeigen</string>
|
||||
<string name="show_contact_thumbnails">Vorschaubilder der Kontakte zeigen</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Beim Klicken auf den Kontakt</string>
|
||||
<string name="call_contact">Kontakt anrufen</string>
|
||||
<string name="view_contact">Kontaktdetails anzeigen</string>
|
||||
@ -62,7 +66,7 @@
|
||||
<string name="favorites">Favoriten</string>
|
||||
<string name="recent_calls">Anrufliste</string>
|
||||
<string name="show_call_confirmation_dialog">Bestätigungsdialog zeigen, bevor ein Anruf durchgeführt wird</string>
|
||||
<string name="show_only_contacts_with_numbers">Show only contacts with phone numbers</string>
|
||||
<string name="show_only_contacts_with_numbers">Nur Kontakte mit Telefonnummern anzeigen</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">E-Mail</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Wählfeld</string>
|
||||
<string name="add_number_to_contact">Nummer zu Kontakt hinzufügen</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Sichtbare Felder auswählen</string>
|
||||
<string name="prefix">Titel</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Kontaktquelle</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Ich möchte die sichtbaren Kontaktfelder ändern. Kann ich das machen?</string>
|
||||
<string name="faq_1_text">Ja, alles, was Sie tun müssen ist folgendes: Gehen Sie zu Einstellungen -> Bearbeite sichtbare Kontaktfelder. Hier können die sichtbaren Felder ausgewählt werden. Einige sind standardmäßig deaktiviert, weshalb hier neue gefunden werden können.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Ζητούνται τα απαιτούμενα δικαιώματα</string>
|
||||
<string name="create_new_contact">Δημιουργία νέας Επαφής</string>
|
||||
<string name="add_to_existing_contact">Προσθήκη σε μια υπάρχουσα Επαφή</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Νέα επαφή</string>
|
||||
<string name="edit_contact">Επεξεργασία επαφής</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Εμφάνιση πρώτα το επώνυμο</string>
|
||||
<string name="show_phone_numbers">Εμφάνιση τηλεφωνικών αριθμών στην κύρια οθόνη</string>
|
||||
<string name="show_contact_thumbnails">Εμφάνιση μικρογραφιών επαφής</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Στην επιλογή επαφής</string>
|
||||
<string name="call_contact">Κλήση επαφής</string>
|
||||
<string name="view_contact">Εμφάνιση λεπτομερειών επαφής</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Πληκτρολόγιο</string>
|
||||
<string name="add_number_to_contact">Προσθήκη αριθμού σε επαφή</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Επιλογή εμφάνισης πεδίων</string>
|
||||
<string name="prefix">Πρόθεμα</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Προέλευση επαφής</string>
|
||||
<string name="instant_messaging">Αμεσο μήνυμα (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Θέλω να αλλάξω τα πεδία που θα είναι ορατά στις επαφές. Μπορώ να το κάνω?</string>
|
||||
<string name="faq_1_text">Ναι, το μόνο που έχετε να κάνετε είναι να μεταβείτε στις Ρυθμίσεις -> Διαχείριση εμφανιζόμενων πεδίων επαφής. Εκεί μπορείτε να επιλέξετε ποια πεδία θα πρέπει να είναι ορατά. Κάποια από αυτά είναι ακόμη και απενεργοποιημένα από προεπιλογή, επομένως ίσως βρείτε κάποια νέα εκεί.</string>
|
||||
|
@ -2,8 +2,8 @@
|
||||
<string name="app_name">Kontaktu sinpleak</string>
|
||||
<string name="app_launcher_name">Kontaktuak</string>
|
||||
<string name="address">Helbidea</string>
|
||||
<string name="inserting">Txertatzen...</string>
|
||||
<string name="updating">Eguneratzen...</string>
|
||||
<string name="inserting">Txertatzen…</string>
|
||||
<string name="updating">Eguneratzen…</string>
|
||||
<string name="phone_storage">Telefono memoria</string>
|
||||
<string name="phone_storage_hidden">Telefono memoria (beste aplikazioentzat ikustezina)</string>
|
||||
<string name="company">Enpresa</string>
|
||||
@ -15,6 +15,16 @@
|
||||
<string name="send_email_to_group">Bidali emaila taldeari</string>
|
||||
<string name="call_person">%s deitu</string>
|
||||
<string name="request_the_required_permissions">Eskatu beharrezko baimenak</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Kontaktu berria</string>
|
||||
<string name="edit_contact">Editatu taldea</string>
|
||||
@ -23,6 +33,7 @@
|
||||
<string name="first_name">Izena</string>
|
||||
<string name="middle_name">Erdiko izena</string>
|
||||
<string name="surname">Abizena</string>
|
||||
<string name="nickname">Nickname</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Talderik ez</string>
|
||||
@ -43,6 +54,8 @@
|
||||
<!-- Settings -->
|
||||
<string name="start_name_with_surname">Abizenaren arabera sailkatu</string>
|
||||
<string name="show_phone_numbers">Erakutsi telefono zenbakiak pantaila nagusian</string>
|
||||
<string name="show_contact_thumbnails">Show contact thumbnails</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Kontaktu sakatzean</string>
|
||||
<string name="call_contact">Kontaktua deitu</string>
|
||||
<string name="view_contact">Ikusi kontaktu detaileak</string>
|
||||
@ -53,6 +66,7 @@
|
||||
<string name="favorites">Gogokoak</string>
|
||||
<string name="recent_calls">Azken deiak</string>
|
||||
<string name="show_call_confirmation_dialog">Erakutsi egiaztatze mezua dei bat hasi baino lehen</string>
|
||||
<string name="show_only_contacts_with_numbers">Show only contacts with phone numbers</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">Emaila</string>
|
||||
@ -66,6 +80,7 @@
|
||||
<string name="main_number">Nagusia</string>
|
||||
<string name="work_fax">Laneko faxa</string>
|
||||
<string name="home_fax">Etxeko faxa</string>
|
||||
<string name="pager">Pager</string>
|
||||
<string name="no_phone_number_found">Ez da telefono zenbakirik aurkitu</string>
|
||||
|
||||
<!-- Events -->
|
||||
@ -88,8 +103,24 @@
|
||||
<string name="export_contacts">Esportatu kontaktuak</string>
|
||||
<string name="import_contacts_from_vcf">Inportatu .vcf fitxategiko kontaktuak</string>
|
||||
<string name="export_contacts_to_vcf">Esportatu kontaktua .vcf fitxategi batera</string>
|
||||
<string name="target_contact_source">Target contact source</string>
|
||||
<string name="include_contact_sources">Include contact sources</string>
|
||||
<string name="filename_without_vcf">Fitxategi izena (.vcf gabe)</string>
|
||||
|
||||
<!-- Dialpad -->
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Hautatu erakusteko eremuak</string>
|
||||
<string name="prefix">Aurrizkia</string>
|
||||
@ -103,6 +134,15 @@
|
||||
<string name="websites">Webguneak</string>
|
||||
<string name="groups">Taldeak</string>
|
||||
<string name="contact_source">Kontaktu jatorria</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Aldatu ditzaket kontaktuetan ikusgarri dauden eremuak?</string>
|
||||
|
@ -2,26 +2,29 @@
|
||||
<string name="app_name">Simple Contacts</string>
|
||||
<string name="app_launcher_name">Contacts</string>
|
||||
<string name="address">Adresse</string>
|
||||
<string name="inserting">Ajout…</string>
|
||||
<string name="updating">Mise à jour…</string>
|
||||
<string name="inserting">Ajout en cours</string>
|
||||
<string name="updating">Actualisation en cours</string>
|
||||
<string name="phone_storage">Stockage du téléphone</string>
|
||||
<string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applis)</string>
|
||||
<string name="company">Société</string>
|
||||
<string name="phone_storage_hidden">Stockage du téléphone (non visible par d\'autres applications)</string>
|
||||
<string name="company">Entreprise</string>
|
||||
<string name="job_position">Poste</string>
|
||||
<string name="website">Site web</string>
|
||||
<string name="website">Site Internet</string>
|
||||
<string name="send_sms_to_contacts">Envoyer un SMS aux contacts</string>
|
||||
<string name="send_email_to_contacts">Envoyer un e-mail aux contacts</string>
|
||||
<string name="send_email_to_contacts">Envoyer un courriel aux contacts</string>
|
||||
<string name="send_sms_to_group">Envoyer un SMS au groupe</string>
|
||||
<string name="send_email_to_group">Envoyer un e-mail au groupe</string>
|
||||
<string name="call_person">Call %s</string>
|
||||
<string name="request_the_required_permissions">Demander les autorisations requises</string>
|
||||
<string name="send_email_to_group">Envoyer un courriel au groupe</string>
|
||||
<string name="call_person">Appeler %s</string>
|
||||
<string name="request_the_required_permissions">Demander les autorisations nécessaires</string>
|
||||
<string name="create_new_contact">Créer un nouveau contact</string>
|
||||
<string name="add_to_existing_contact">Ajouter à un contact existant</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_contacts_found">Aucun contact n\'a été trouvé</string>
|
||||
<string name="no_contacts_with_emails">Aucun contact avec une adresse de courriel n\'a été trouvé</string>
|
||||
<string name="no_contacts_with_phone_numbers">Aucun contact avec un numéro de téléphone n\'a été trouvé</string>
|
||||
<string name="no_recent_calls_found">Aucun appel récent n\'a été trouvé</string>
|
||||
|
||||
<string name="new_contact">Nouveau contact</string>
|
||||
<string name="edit_contact">Modifier contact</string>
|
||||
@ -33,15 +36,15 @@
|
||||
<string name="nickname">Surnom</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Pas de groupe</string>
|
||||
<string name="no_groups">Aucun groupe</string>
|
||||
<string name="create_new_group">Créer un nouveau groupe</string>
|
||||
<string name="remove_from_group">Enlever du groupe</string>
|
||||
<string name="remove_from_group">Supprimer du groupe</string>
|
||||
<string name="no_group_participants">Ce groupe est vide</string>
|
||||
<string name="add_contacts">Ajout contacts</string>
|
||||
<string name="no_group_created">Il n\'y a pas de groupes de contacts sur l\'appareil</string>
|
||||
<string name="add_contacts">Ajouter des contacts</string>
|
||||
<string name="no_group_created">Aucun groupe de contacts sur l\'appareil</string>
|
||||
<string name="create_group">Créer un groupe</string>
|
||||
<string name="add_to_group">Ajouter à un groupe</string>
|
||||
<string name="create_group_under_account">Créer un groupe pris en compte</string>
|
||||
<string name="create_group_under_account">Créer un groupe dans le compte</string>
|
||||
|
||||
<!-- Photo -->
|
||||
<string name="take_photo">Prendre une photo</string>
|
||||
@ -52,20 +55,21 @@
|
||||
<string name="start_name_with_surname">Trier les contacts par nom de famille</string>
|
||||
<string name="show_phone_numbers">Afficher les numéros de téléphone</string>
|
||||
<string name="show_contact_thumbnails">Afficher les vignettes des contacts</string>
|
||||
<string name="on_contact_click">Sur appui du contact</string>
|
||||
<string name="show_dialpad_button">Afficher un bouton \"Clavier téléphonique\" sur l\'écran principal</string>
|
||||
<string name="on_contact_click">Lors d\'un appui sur un contact</string>
|
||||
<string name="call_contact">Appeler le contact</string>
|
||||
<string name="view_contact">Voir les détails du contact</string>
|
||||
<string name="view_contact">Afficher les détails du contact</string>
|
||||
<string name="manage_shown_contact_fields">Configurer l\'affichage des champs des contacts</string>
|
||||
<string name="filter_duplicates">Essayez de filtrer les contacts en double</string>
|
||||
<string name="manage_shown_tabs">Gérer les onglets affichés</string>
|
||||
<string name="contacts">Contacts</string>
|
||||
<string name="favorites">Favorites</string>
|
||||
<string name="favorites">Favoris</string>
|
||||
<string name="recent_calls">Appels récents</string>
|
||||
<string name="show_call_confirmation_dialog">Afficher une boîte de dialogue de confirmation d\'appel avant de lancer un appel</string>
|
||||
<string name="show_only_contacts_with_numbers">Show only contacts with phone numbers</string>
|
||||
<string name="show_call_confirmation_dialog">Afficher une demande de confirmation avant de démarrer un appel</string>
|
||||
<string name="show_only_contacts_with_numbers">Afficher uniquement les contacts avec un numéro de téléphone</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">E-mail</string>
|
||||
<string name="email">Adresse de courriel</string>
|
||||
<string name="home">Maison</string>
|
||||
<string name="work">Travail</string>
|
||||
<string name="other">Autre</string>
|
||||
@ -84,11 +88,11 @@
|
||||
<string name="anniversary">Anniversaire</string>
|
||||
|
||||
<!-- Favorites -->
|
||||
<string name="no_favorites">Vous n\'ayez pas encore ajouté de contact favori.</string>
|
||||
<string name="no_favorites">Aucun contact favori n\'a été trouvé</string>
|
||||
<string name="add_favorites">Ajouter des favoris</string>
|
||||
<string name="add_to_favorites">Ajouter aux favoris</string>
|
||||
<string name="remove_from_favorites">Retirer des favoris</string>
|
||||
<string name="must_be_at_edit">Vous devez être sur l\'écran Modifier pour modifier un contact</string>
|
||||
<string name="remove_from_favorites">Supprimer des favoris</string>
|
||||
<string name="must_be_at_edit">Vous devez être sur l\'écran \"Modifier\" pour modifier un contact</string>
|
||||
|
||||
<!-- Search -->
|
||||
<string name="search_contacts">Rechercher des contacts</string>
|
||||
@ -99,44 +103,62 @@
|
||||
<string name="export_contacts">Exporter des contacts</string>
|
||||
<string name="import_contacts_from_vcf">Importer des contacts depuis un fichier .vcf</string>
|
||||
<string name="export_contacts_to_vcf">Exporter des contacts vers un fichier .vcf</string>
|
||||
<string name="target_contact_source">Source du contact cible</string>
|
||||
<string name="include_contact_sources">Inclure les sources du contact</string>
|
||||
<string name="target_contact_source">Compte pour le du contact destinataire</string>
|
||||
<string name="include_contact_sources">Ajouter le compte pour le contact</string>
|
||||
<string name="filename_without_vcf">Nom du fichier (sans .vcf)</string>
|
||||
|
||||
<!-- Dialpad -->
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="dialpad">Clavier téléphonique</string>
|
||||
<string name="add_number_to_contact">Ajouter un numéro au contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Numéroteur</string>
|
||||
<string name="calling">Appel en cours</string>
|
||||
<string name="incoming_call">Appel entrant</string>
|
||||
<string name="incoming_call_from">Appel entrant de…</string>
|
||||
<string name="ongoing_call">Appel en cours</string>
|
||||
<string name="disconnected">Interrompu</string>
|
||||
<string name="decline_call">Refuser</string>
|
||||
<string name="answer_call">Répondre</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Sélectionner les champs à afficher</string>
|
||||
<string name="prefix">Préfixe</string>
|
||||
<string name="suffix">Suffixe</string>
|
||||
<string name="phone_numbers">Numéros de téléphone</string>
|
||||
<string name="emails">E-mails</string>
|
||||
<string name="emails">Adresse de courriels</string>
|
||||
<string name="addresses">Adresses</string>
|
||||
<string name="events">Évènements (naissances, anniversaires)</string>
|
||||
<string name="notes">Notes</string>
|
||||
<string name="organization">Organisation</string>
|
||||
<string name="websites">Sites web</string>
|
||||
<string name="websites">Sites Internet</string>
|
||||
<string name="groups">Groupe</string>
|
||||
<string name="contact_source">Source du contact</string>
|
||||
<string name="contact_source">Compte pour le contact</string>
|
||||
<string name="instant_messaging">Messagerie instantanée (MI)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Je veux changer quelles champs sont visibles. Est-ce que je peux ?</string>
|
||||
<string name="faq_1_text">Oui, tout ce que vous avez à faire c\'est d\'aller dans Paramètres -> Configurer l\'affichage des champs de contact. Ici vous pouvez sélectionner quelles champs vous voulez afficher. Certains sont désactivés par défaut, ainsi vous pourrez y trouver des nouveaux champs.</string>
|
||||
<string name="faq_1_title">Je veux modifier les champs affichés sur les fiches de mes contacts. Puis-je le faire ?</string>
|
||||
<string name="faq_1_text">Oui, tout ce que vous avez à faire c\'est d\'aller dans \"Paramètres\" -> \"Configurer l\'affichage des champs de contact\". Sélectionnez les champs à afficher. Certains champs sont désactivés par défaut.</string>
|
||||
|
||||
<!-- Strings displayed only on Google Playstore. Optional, but good to have -->
|
||||
<!-- Short description has to have less than 80 chars -->
|
||||
<string name="app_short_description">Une appli de contacts pour gérer vos contacts sans pubs.</string>
|
||||
<string name="app_short_description">Une application répertoire pour gérer vos contacts sans publicité.</string>
|
||||
<string name="app_long_description">
|
||||
Une appli simple pour créer et gérer vos contacts depuis n\'importe quelle source. Les contacts peuvent être stockés sur votre appareil mais aussi synchronisés via Google ou d\'autres comptes. Vous pouvez afficher vos contacts favoris dans une liste séparée.
|
||||
Un outil simple pour créer et gérer vos contacts depuis n\'importe quelle source. Les contacts peuvent être stockés sur votre appareil mais aussi synchronisés via votre compte Google ou d\'autres comptes. Vous pouvez afficher vos contacts favoris dans une liste séparée.
|
||||
|
||||
Vous pouvez l\'utiliser pour gérer les e-mail et événements de vos contacts. Elle permet de trier/filter via de multiples paramètres, et même afficher le surnom en premier.
|
||||
Vous pouvez l\'utiliser pour gérer les adresses de courriels et les événements de vos contacts. Cet outil permet de trier/filtrer à l\'aide de multiples paramètres, par exemple : afficher le surnom en premier.
|
||||
|
||||
Aucune publicité ni de permission inutile. Elle est entièrement open source et vous permet de personnaliser les couleurs.
|
||||
L\'application ne contient ni publicité, ni autorisation inutile. Elle est totalement opensource et est également fournie avec des couleurs personnalisables.
|
||||
|
||||
Cette application fait parti d\'un groupe d\'applications. Vous pouvez trouver le reste des applis sur https://www.simplemobiletools.com
|
||||
Cette application fait partie d\'une plus grande suite. Vous pouvez trouver les autres applications sur https://www.simplemobiletools.com
|
||||
</string>
|
||||
|
||||
<!--
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Zatraži potrebna dopuštenja</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Novi kontakt</string>
|
||||
<string name="edit_contact">Uredi kontakt</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Započnite imena s prezimenima</string>
|
||||
<string name="show_phone_numbers">Prikaži telefonske brojeve na glavnom zaslonu</string>
|
||||
<string name="show_contact_thumbnails">Prikaži sličice kontakata</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Prilikom dodira kontakta</string>
|
||||
<string name="call_contact">Nazovi kontakt</string>
|
||||
<string name="view_contact">Prikaži pojedinosti o kontaktu</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Odaberi polja za prikaz</string>
|
||||
<string name="prefix">Prefiks</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Izvori kontakata</string>
|
||||
<string name="instant_messaging">Brzo slanje poruka (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Želim promijeniti polja koja su vidljiva na kontaktima. Mogu li to napraviti?</string>
|
||||
<string name="faq_1_text">Da, sve što morate učiniti je otići u Postavke -> Upravljanje poljima za prikaz. Tamo možete odabrati polja koja bi trebala biti vidljiva. Neka od njih su čak i onemogućena prema zadanim postavkama, tako da možete pronaći neke nove.</string>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<string name="inserting">Inserimento in corso…</string>
|
||||
<string name="updating">Aggiornamento in corso…</string>
|
||||
<string name="phone_storage">Memoria del telefono</string>
|
||||
<string name="phone_storage_hidden">Memoria del telfono (non visibile alle altre applicazioni)</string>
|
||||
<string name="phone_storage_hidden">Memoria del telefono (non visibile alle altre applicazioni)</string>
|
||||
<string name="company">Compagnia</string>
|
||||
<string name="job_position">Posizione lavorativa</string>
|
||||
<string name="website">Sito web</string>
|
||||
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Richiedi le permissioni necessarie</string>
|
||||
<string name="create_new_contact">Crea un nuovo contatto</string>
|
||||
<string name="add_to_existing_contact">Aggiungi ad un contatto esistente</string>
|
||||
<string name="must_make_default_dialer">È necessario impostare quest\'app come predefinita per utilizzare i numeri bloccati.</string>
|
||||
<string name="set_to_default">Imposta come predefinita</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">Nessun contatto trovato</string>
|
||||
<string name="no_contacts_with_emails">Nessun contatto trovato con un\'email</string>
|
||||
<string name="no_contacts_with_phone_numbers">Nessun contatto trovato con un numero di telefono</string>
|
||||
<string name="no_recent_calls_found">Nessuna chiamata recente trovata</string>
|
||||
|
||||
<string name="new_contact">Nuovo contatto</string>
|
||||
<string name="edit_contact">Modifica contatto</string>
|
||||
@ -52,11 +55,12 @@
|
||||
<string name="start_name_with_surname">Prima il nome poi il cognome</string>
|
||||
<string name="show_phone_numbers">Mostra i numeri di telefono nella schermata principale</string>
|
||||
<string name="show_contact_thumbnails">Mostra le anteprime dei contatti</string>
|
||||
<string name="show_dialpad_button">Mostra il pulante per la tastiera nello schermo principale</string>
|
||||
<string name="on_contact_click">Al click sul contatto</string>
|
||||
<string name="call_contact">Chiama contatto</string>
|
||||
<string name="view_contact">Visualizza i dettagli del contatto</string>
|
||||
<string name="manage_shown_contact_fields">Gestisci i campi mostrati</string>
|
||||
<string name="filter_duplicates">Prova a filetrare i contatti duplicati</string>
|
||||
<string name="filter_duplicates">Prova a filtrare i contatti duplicati</string>
|
||||
<string name="manage_shown_tabs">Gestisci le schede mostrate</string>
|
||||
<string name="contacts">Contatti</string>
|
||||
<string name="favorites">Preferiti</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Tastiera</string>
|
||||
<string name="add_number_to_contact">Aggiungi numero ai contatti</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Compositore</string>
|
||||
<string name="calling">Chiamata in corso</string>
|
||||
<string name="incoming_call">Chiamata in arrivo</string>
|
||||
<string name="incoming_call_from">Chiamata in arrivo da…</string>
|
||||
<string name="ongoing_call">Chiamata in corso</string>
|
||||
<string name="disconnected">Disconnesso</string>
|
||||
<string name="decline_call">Rifiuta</string>
|
||||
<string name="answer_call">Rispondi</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Seleziona i campi da mostrare</string>
|
||||
<string name="prefix">Prefisso</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Provenienza del contatto</string>
|
||||
<string name="instant_messaging">Messaggistica istantanea (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Gestisci i numeri bloccati</string>
|
||||
<string name="not_blocking_anyone">Non si sta blocccando alcun numero.</string>
|
||||
<string name="add_a_blocked_number">Aggiungi un numero da bloccare</string>
|
||||
<string name="block_number">Blocca numero</string>
|
||||
<string name="block_numbers">Blocca numeri</string>
|
||||
<string name="blocked_numbers">Numeri bloccati</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Voglio cambiare i campi visibili ai contatti. Come posso fare?</string>
|
||||
<string name="faq_1_text">Puoi farlo andando in Impostazioni -> Gestisci i campi mostrati. Qui puoi selezionare i campi che saranno visibili. Alcuni sono anche disabilitati in maniera predefinita, quindi potresti trovare qualche nuovo campo.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Request the required permissions</string>
|
||||
<string name="create_new_contact">新しい連絡先を作成</string>
|
||||
<string name="add_to_existing_contact">既存の連絡先に追加</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">連絡先が見つかりません</string>
|
||||
<string name="no_contacts_with_emails">メールアドレスが登録された連絡先が見つかりません</string>
|
||||
<string name="no_contacts_with_phone_numbers">電話番号が登録された連絡先が見つかりません</string>
|
||||
<string name="no_recent_calls_found">通話履歴はありません</string>
|
||||
|
||||
<string name="new_contact">新しい連絡先</string>
|
||||
<string name="edit_contact">連絡先を編集</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">姓を先に表示</string>
|
||||
<string name="show_phone_numbers">メイン画面に電話番号を表示</string>
|
||||
<string name="show_contact_thumbnails">連絡先のサムネイルを表示</string>
|
||||
<string name="show_dialpad_button">メイン画面にダイヤルパッドを表示</string>
|
||||
<string name="on_contact_click">連絡先をタップ</string>
|
||||
<string name="call_contact">連絡先に発信</string>
|
||||
<string name="view_contact">連絡先の詳細を表示</string>
|
||||
@ -60,7 +64,7 @@
|
||||
<string name="manage_shown_tabs">表示するタブを管理</string>
|
||||
<string name="contacts">連絡先</string>
|
||||
<string name="favorites">お気に入り</string>
|
||||
<string name="recent_calls">Recent calls</string>
|
||||
<string name="recent_calls">通話履歴</string>
|
||||
<string name="show_call_confirmation_dialog">発信する前に確認ダイアログを表示する</string>
|
||||
<string name="show_only_contacts_with_numbers">電話番号が登録された連絡先のみ表示する</string>
|
||||
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">ダイヤルパッド</string>
|
||||
<string name="add_number_to_contact">連絡先に番号を追加</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">電話</string>
|
||||
<string name="calling">発信中</string>
|
||||
<string name="incoming_call">着信中</string>
|
||||
<string name="incoming_call_from">着信中…</string>
|
||||
<string name="ongoing_call">通話中</string>
|
||||
<string name="disconnected">切断されました</string>
|
||||
<string name="decline_call">拒否</string>
|
||||
<string name="answer_call">応答</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">表示する項目を選択</string>
|
||||
<string name="prefix">敬称(名前の前)</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">インポート元</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">ブロックした番号を管理</string>
|
||||
<string name="not_blocking_anyone">まだ誰もブロックしていません.</string>
|
||||
<string name="add_a_blocked_number">ブロックする番号を追加</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">連絡先に表示される項目(フィールド)を変更することはできますか?</string>
|
||||
<string name="faq_1_text">可能です。[設定] -> [連絡先に表示するフィールドを管理] から、表示されるフィールドを選択することができます。これらの中にはデフォルトで無効になっているものもあるので、あなたは新しいものを見つけるかもしれません。</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Request the required permissions</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">새로운 연락처</string>
|
||||
<string name="edit_contact">연락처 수정</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">성을 먼저 표시</string>
|
||||
<string name="show_phone_numbers">메인 스크린에 전화번호 표시</string>
|
||||
<string name="show_contact_thumbnails">Show contact thumbnails</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">On contact click</string>
|
||||
<string name="call_contact">Call contact</string>
|
||||
<string name="view_contact">View contact details</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Select fields to show</string>
|
||||
<string name="prefix">Prefix</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Contact source</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
|
||||
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Request the required permissions</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Naujas kontaktas</string>
|
||||
<string name="edit_contact">Redaguoti kontaktą</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Pavardė rodoma pirma</string>
|
||||
<string name="show_phone_numbers">Rodyti telefono numerius pagrindiniame programos ekrane</string>
|
||||
<string name="show_contact_thumbnails">Rodyti kontaktų miniatiūras</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Ant kontakto paspaudimo</string>
|
||||
<string name="call_contact">Skambinti kontaktui</string>
|
||||
<string name="view_contact">Žiūrėti kontakto detales</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Pasirinkti rodomus laukelius</string>
|
||||
<string name="prefix">Priešdėlis</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Kontakto šaltinis</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Noriu pakeisti, kokie laukai yra matomi kontaktuose. Ar galiu tai padaryti?</string>
|
||||
<string name="faq_1_text">Taip, viskas, ką jums reikia padaryti, tai eiti į Nustatymai -> Tvarkyti rodomus kontaktų laukus. Čia galite pasirinkti, kurie laukai turėtų būti matomi. Kai kurie iš jų netgi yra išjungiami pagal numatytuosius nustatymus, todėl ten galite rasti naujų.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Pedir a permissão necessária</string>
|
||||
<string name="create_new_contact">Criar novo contacto</string>
|
||||
<string name="add_to_existing_contact">Adicionar a contacto existente</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_contacts_found">Não existem contactos</string>
|
||||
<string name="no_contacts_with_emails">Não existem contactos com endereço de e-mail</string>
|
||||
<string name="no_contacts_with_phone_numbers">Não existem contactos com número de telefone</string>
|
||||
<string name="no_recent_calls_found">Não existem chamadas recentes</string>
|
||||
|
||||
<string name="new_contact">Novo contacto</string>
|
||||
<string name="edit_contact">Editar contacto</string>
|
||||
@ -33,7 +36,7 @@
|
||||
<string name="nickname">Alcunha</string>
|
||||
|
||||
<!-- Groups -->
|
||||
<string name="no_groups">Não há grupos</string>
|
||||
<string name="no_groups">Não existem grupos</string>
|
||||
<string name="create_new_group">Criar um novo grupo</string>
|
||||
<string name="remove_from_group">Remover do grupo</string>
|
||||
<string name="no_group_participants">Este grupo está vazio</string>
|
||||
@ -52,17 +55,18 @@
|
||||
<string name="start_name_with_surname">Ordenar por apelido</string>
|
||||
<string name="show_phone_numbers">Mostrar número de telefone no ecrã principal</string>
|
||||
<string name="show_contact_thumbnails">Mostrar miniatura do contacto</string>
|
||||
<string name="show_dialpad_button">Mostrar botão Marcador no ecrã principal</string>
|
||||
<string name="on_contact_click">Ao tocar no contacto</string>
|
||||
<string name="call_contact">Ligar</string>
|
||||
<string name="view_contact">Ver detalhes</string>
|
||||
<string name="manage_shown_contact_fields">Gerir campos a exibir</string>
|
||||
<string name="manage_shown_contact_fields">Gerir campos a mostrar</string>
|
||||
<string name="filter_duplicates">Tentar filtrar contactos duplicados</string>
|
||||
<string name="manage_shown_tabs">Gerir separadores a exibir</string>
|
||||
<string name="contacts">Contactos</string>
|
||||
<string name="favorites">Favoritos</string>
|
||||
<string name="recent_calls">Chamadas recentes</string>
|
||||
<string name="show_call_confirmation_dialog">Mostrar diálogo para confirmar a chamada</string>
|
||||
<string name="show_only_contacts_with_numbers">Show only contacts with phone numbers</string>
|
||||
<string name="show_only_contacts_with_numbers">Mostrar apenas contactos com número de telefone</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">E-mail</string>
|
||||
@ -104,9 +108,19 @@
|
||||
<string name="filename_without_vcf">Nome do ficheiro (sem .vcf)</string>
|
||||
|
||||
<!-- Dialpad -->
|
||||
<string name="dialpad">Teclado</string>
|
||||
<string name="dialpad">Marcador</string>
|
||||
<string name="add_number_to_contact">Adicionar número a um contacto</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Marcador</string>
|
||||
<string name="calling">A chamar</string>
|
||||
<string name="incoming_call">Chamada recebida</string>
|
||||
<string name="incoming_call_from">Chamada recebida de…</string>
|
||||
<string name="ongoing_call">Chamada efetuada</string>
|
||||
<string name="disconnected">Desligada</string>
|
||||
<string name="decline_call">Recusar</string>
|
||||
<string name="answer_call">Atender</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Selecione os campos a mostrar</string>
|
||||
<string name="prefix">Prefixo</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Origem do contacto</string>
|
||||
<string name="instant_messaging">Mensagem instantânea (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
|
||||
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Запрос необходимых разрешений</string>
|
||||
<string name="create_new_contact">Создать новый контакт</string>
|
||||
<string name="add_to_existing_contact">Добавить к существующему контакту</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">Контакты не найдены</string>
|
||||
<string name="no_contacts_with_emails">Контакты с адресами электронной почты не найдены</string>
|
||||
<string name="no_contacts_with_phone_numbers">Контакты с номерами телефонов не найдены</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Новый контакт</string>
|
||||
<string name="edit_contact">Редактировать контакт</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Показывать сначала фамилию</string>
|
||||
<string name="show_phone_numbers">Показывать номера телефонов на главном экране</string>
|
||||
<string name="show_contact_thumbnails">Показывать фото контакта</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">При нажатии на контакт</string>
|
||||
<string name="call_contact">Позвонить контакту</string>
|
||||
<string name="view_contact">Просмотреть подробности о контакте</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Набор номера</string>
|
||||
<string name="add_number_to_contact">Добавить номер к контакту</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Выберите отображаемые поля</string>
|
||||
<string name="prefix">Префикс</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Источник контакта</string>
|
||||
<string name="instant_messaging">Мессенджеры (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Я хочу изменить поля, отображаемые у контактов. Могу ли я это сделать?</string>
|
||||
<string name="faq_1_text">Да, всё, что вам нужно сделать, это зайти в \"Настройки\" -> \"Управление отображаемыми полями контактов\". Там вы сможете выбрать, какие поля должны быть видимы. Некоторые из них даже отключены по умолчанию, так что вы можете найти некоторые новые.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Vyžiadať potrebné oprávnenia</string>
|
||||
<string name="create_new_contact">Vytvoriť nový kontakt</string>
|
||||
<string name="add_to_existing_contact">Pridať k existujúcemu kontaktu</string>
|
||||
<string name="must_make_default_dialer">Pre použitie blokovania čísel musíte nastaviť aplikáciu ako predvolenú pre správu hovorov.</string>
|
||||
<string name="set_to_default">Nastaviť ako predvolenú</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">Nenašli sa žiadne kontakty</string>
|
||||
<string name="no_contacts_with_emails">Nenašli sa žiadne kontakty s emailami</string>
|
||||
<string name="no_contacts_with_phone_numbers">Nenašli sa žiadne kontakty s telefónnymi číslami</string>
|
||||
<string name="no_recent_calls_found">Nenašli sa žiadne posledné hovory</string>
|
||||
|
||||
<string name="new_contact">Nový kontakt</string>
|
||||
<string name="edit_contact">Upraviť kontakt</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Začať meno priezviskom</string>
|
||||
<string name="show_phone_numbers">Zobraziť telefónne čísla na hlavnej obrazovke</string>
|
||||
<string name="show_contact_thumbnails">Zobraziť obrázky kontaktov</string>
|
||||
<string name="show_dialpad_button">Zobraziť tlačidlo pre číselník na hlavnej obrazovke</string>
|
||||
<string name="on_contact_click">Po kliknutí na kontakt</string>
|
||||
<string name="call_contact">Zavolať kontakt</string>
|
||||
<string name="view_contact">Zobraziť údaje kontaktu</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Číselník</string>
|
||||
<string name="add_number_to_contact">Pridať číslo kontaktu</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Telefón</string>
|
||||
<string name="calling">Vytáča sa</string>
|
||||
<string name="incoming_call">Prichádzajúci hovor</string>
|
||||
<string name="incoming_call_from">Prichádzajúci hovor od…</string>
|
||||
<string name="ongoing_call">Prebiehajúci hovor</string>
|
||||
<string name="disconnected">Ukončený hovor</string>
|
||||
<string name="decline_call">Odmietnuť</string>
|
||||
<string name="answer_call">Prijať</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Zvoľte polia na zobrazenie</string>
|
||||
<string name="prefix">Titul pred menom</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Zdroje kontaktov</string>
|
||||
<string name="instant_messaging">Rýchle správy (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Spravovať blokované čísla</string>
|
||||
<string name="not_blocking_anyone">Neblokujete nikoho.</string>
|
||||
<string name="add_a_blocked_number">Pridať blokované číslo</string>
|
||||
<string name="block_number">Blokovať číslo</string>
|
||||
<string name="block_numbers">Blokovať čísla</string>
|
||||
<string name="blocked_numbers">Blokované čísla</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Chcem upraviť viditeľné polia kontaktov. Dá sa to?</string>
|
||||
<string name="faq_1_text">Áno, stačí ísť do Nastavenia -> Spravovať zobrazené polia kontaktov. Tam si viete zvoliť, ktoré polia majú byť viditeľné. Niektoré sú v predvolenom stave vypnuté, čiže tam môžete objaviť aj nové.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Begär de behörigheter som krävs</string>
|
||||
<string name="create_new_contact">Skapa ny kontakt</string>
|
||||
<string name="add_to_existing_contact">Lägg till i en befintlig kontakt</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">Inga kontakter hittades</string>
|
||||
<string name="no_contacts_with_emails">Inga kontakter med e-postadresser hittades</string>
|
||||
<string name="no_contacts_with_phone_numbers">Inga kontakter med telefonnummer hittades</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Ny kontakt</string>
|
||||
<string name="edit_contact">Redigera kontakt</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Visa efternamn först</string>
|
||||
<string name="show_phone_numbers">Visa telefonnummer i huvudvyn</string>
|
||||
<string name="show_contact_thumbnails">Visa kontaktminiatyrer</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Vid kontakttryckning</string>
|
||||
<string name="call_contact">Ring kontakt</string>
|
||||
<string name="view_contact">Visa kontaktuppgifter</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Knappsats</string>
|
||||
<string name="add_number_to_contact">Lägg till nummer i kontakt</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Välj vilka fält som ska visas</string>
|
||||
<string name="prefix">Prefix</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Kontaktkälla</string>
|
||||
<string name="instant_messaging">Snabbmeddelanden (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
|
||||
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Gerekli izinleri iste</string>
|
||||
<string name="create_new_contact">Yeni kişi oluştur</string>
|
||||
<string name="add_to_existing_contact">Mevcut bir kişiye ekle</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">Kişi bulunamadı</string>
|
||||
<string name="no_contacts_with_emails">E-posta ile hiç bağlantı bulunamadı</string>
|
||||
<string name="no_contacts_with_phone_numbers">Telefon numaralarını içeren kişi bulunamadı</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">Yeni kişi</string>
|
||||
<string name="edit_contact">Kişiyi düzenle</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Soyadı ile başla</string>
|
||||
<string name="show_phone_numbers">Ana ekranda telefon numaralarını göster</string>
|
||||
<string name="show_contact_thumbnails">Kişi küçük resimlerini göster</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">Kişi tıklandığında</string>
|
||||
<string name="call_contact">Kişiyi ara</string>
|
||||
<string name="view_contact">Kişi bilgilerini göster</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Tuş takımı</string>
|
||||
<string name="add_number_to_contact">Kişiye numara ekle</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Görüntülenecek alanları seç</string>
|
||||
<string name="prefix">Önek</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Kişi kaynağı</string>
|
||||
<string name="instant_messaging">Anlık mesajlaşma (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">Rehberde görüntülenecek alanları değiştirmek istiyorum. Bunu yapabilir miyim?</string>
|
||||
<string name="faq_1_text">Evet, tek yapmanız gereken Ayarlar -> Görüntülenecek kişi alanlarını yönet\'e gitmek. Orada hangi alanların görüntüleneceğini seçebilirsiniz. Bazıları varsayılan olarak devre dışı bile olsa, orada bazı yenilerini bulabilirsiniz.</string>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">請求必要的權限</string>
|
||||
<string name="create_new_contact">建立新聯絡人</string>
|
||||
<string name="add_to_existing_contact">添加至已存在的聯絡人</string>
|
||||
<string name="must_make_default_dialer">你必須將這應用程式設為預設的撥號程式來使用黑名單。</string>
|
||||
<string name="set_to_default">設為預設</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_contacts_found">未發現聯絡人</string>
|
||||
<string name="no_contacts_with_emails">未發現含有電子信箱的聯絡人</string>
|
||||
<string name="no_contacts_with_phone_numbers">未發現含有電話號碼的聯絡人</string>
|
||||
<string name="no_recent_calls_found">未發現通話紀錄</string>
|
||||
|
||||
<string name="new_contact">新聯絡人</string>
|
||||
<string name="edit_contact">編輯聯絡人</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">姓氏在前</string>
|
||||
<string name="show_phone_numbers">主畫面顯示電話號碼</string>
|
||||
<string name="show_contact_thumbnails">顯示聯絡人縮圖</string>
|
||||
<string name="show_dialpad_button">在主畫面顯示撥號按鈕</string>
|
||||
<string name="on_contact_click">點擊聯絡人</string>
|
||||
<string name="call_contact">打電話給聯絡人</string>
|
||||
<string name="view_contact">顯示聯絡人資料</string>
|
||||
@ -62,7 +66,7 @@
|
||||
<string name="favorites">我的最愛</string>
|
||||
<string name="recent_calls">通話紀錄</string>
|
||||
<string name="show_call_confirmation_dialog">開始通話前顯示通話確認框</string>
|
||||
<string name="show_only_contacts_with_numbers">Show only contacts with phone numbers</string>
|
||||
<string name="show_only_contacts_with_numbers">只顯示含有電話話碼的聯絡人</string>
|
||||
|
||||
<!-- Emails -->
|
||||
<string name="email">電子信箱</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">撥號畫面</string>
|
||||
<string name="add_number_to_contact">添加號碼至通訊錄</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">撥號器</string>
|
||||
<string name="calling">撥號中</string>
|
||||
<string name="incoming_call">來電</string>
|
||||
<string name="incoming_call_from">通話來自於…</string>
|
||||
<string name="ongoing_call">持續通話</string>
|
||||
<string name="disconnected">未接電話</string>
|
||||
<string name="decline_call">掛斷電話</string>
|
||||
<string name="answer_call">回撥</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">選擇要顯示的欄位</string>
|
||||
<string name="prefix">前缀</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">聯絡人來源</string>
|
||||
<string name="instant_messaging">即時通訊 (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">管理黑名單</string>
|
||||
<string name="not_blocking_anyone">你沒有封鎖任何人</string>
|
||||
<string name="add_a_blocked_number">添加封鎖的號碼</string>
|
||||
<string name="block_number">封鎖號碼</string>
|
||||
<string name="block_numbers">封鎖號碼</string>
|
||||
<string name="blocked_numbers">黑名單</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">我想要更改在通訊錄會看到哪些欄位。我能這麼做嗎?</string>
|
||||
<string name="faq_1_text">可以,你要做的是到[設定] -> [管理顯示的聯絡人欄位]。在那裡,你可以選擇應該看到什麼欄位。其中有些甚至預設是關閉的,所以你可能會在那裡發現一些新的。</string>
|
||||
|
@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
</resources>
|
@ -7,5 +7,6 @@
|
||||
<dimen name="contact_item_with_number_height">56dp</dimen>
|
||||
<dimen name="create_new_contact_height">68dp</dimen>
|
||||
<dimen name="dialpad_button_size">60dp</dimen>
|
||||
|
||||
<dimen name="dialpad_text_size">34sp</dimen>
|
||||
</resources>
|
||||
|
@ -17,11 +17,14 @@
|
||||
<string name="request_the_required_permissions">Request the required permissions</string>
|
||||
<string name="create_new_contact">Create new contact</string>
|
||||
<string name="add_to_existing_contact">Add to an existing contact</string>
|
||||
<string name="must_make_default_dialer">You have to make this app the default dialer app to make use of blocked numbers.</string>
|
||||
<string name="set_to_default">Set to default</string>
|
||||
|
||||
<!-- Placeholders -->
|
||||
<string name="no_contacts_found">No contacts found</string>
|
||||
<string name="no_contacts_with_emails">No contacts with emails have been found</string>
|
||||
<string name="no_contacts_with_phone_numbers">No contacts with phone numbers have been found</string>
|
||||
<string name="no_recent_calls_found">No recent calls found</string>
|
||||
|
||||
<string name="new_contact">New contact</string>
|
||||
<string name="edit_contact">Edit contact</string>
|
||||
@ -52,6 +55,7 @@
|
||||
<string name="start_name_with_surname">Start name with surname</string>
|
||||
<string name="show_phone_numbers">Show phone numbers on the main screen</string>
|
||||
<string name="show_contact_thumbnails">Show contact thumbnails</string>
|
||||
<string name="show_dialpad_button">Show a dialpad button on the main screen</string>
|
||||
<string name="on_contact_click">On contact click</string>
|
||||
<string name="call_contact">Call contact</string>
|
||||
<string name="view_contact">View contact details</string>
|
||||
@ -107,6 +111,16 @@
|
||||
<string name="dialpad">Dialpad</string>
|
||||
<string name="add_number_to_contact">Add number to contact</string>
|
||||
|
||||
<!-- Dialer -->
|
||||
<string name="dialer">Dialer</string>
|
||||
<string name="calling">Calling</string>
|
||||
<string name="incoming_call">Incoming call</string>
|
||||
<string name="incoming_call_from">Incoming call from…</string>
|
||||
<string name="ongoing_call">Ongoing call</string>
|
||||
<string name="disconnected">Disconnected</string>
|
||||
<string name="decline_call">Decline</string>
|
||||
<string name="answer_call">Answer</string>
|
||||
|
||||
<!-- Visible fields -->
|
||||
<string name="select_fields_to_show">Select fields to show</string>
|
||||
<string name="prefix">Prefix</string>
|
||||
@ -122,6 +136,14 @@
|
||||
<string name="contact_source">Contact source</string>
|
||||
<string name="instant_messaging">Instant messaging (IM)</string>
|
||||
|
||||
<!-- Blocked numbers -->
|
||||
<string name="manage_blocked_numbers">Manage blocked numbers</string>
|
||||
<string name="not_blocking_anyone">You are not blocking anyone.</string>
|
||||
<string name="add_a_blocked_number">Add a blocked number</string>
|
||||
<string name="block_number">Block number</string>
|
||||
<string name="block_numbers">Block numbers</string>
|
||||
<string name="blocked_numbers">Blocked numbers</string>
|
||||
|
||||
<!-- FAQ -->
|
||||
<string name="faq_1_title">I want to change what fields are visible at contacts. Can I do it?</string>
|
||||
<string name="faq_1_text">Yes, all you have to do is go in Settings -> Manage shown contact fields. There you can select what fields should be visible. Some of them are even disabled by default, so you might find some new ones there.</string>
|
||||
|
@ -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.3.0'
|
||||
ext.kotlin_version = '1.3.10'
|
||||
|
||||
repositories {
|
||||
google()
|
||||
|
4
keystore.properties_sample
Normal file
4
keystore.properties_sample
Normal file
@ -0,0 +1,4 @@
|
||||
storePassword=123456
|
||||
keyPassword=abcdef
|
||||
keyAlias=myAlias
|
||||
storeFile=../keystore.jks
|
@ -1,3 +0,0 @@
|
||||
STORE_FILE=/path/to/your.keystore
|
||||
KEY_ALIAS=projectkeyalias
|
||||
PASSWORD=yourpass
|
Loading…
x
Reference in New Issue
Block a user