From f2a098c9c4d23983943295f7a3d4799b227cc780 Mon Sep 17 00:00:00 2001 From: merkost Date: Fri, 14 Jul 2023 13:27:38 +1000 Subject: [PATCH 01/18] Added backup setting in activity_settings.xml --- app/src/main/res/layout/activity_settings.xml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index c120cb1a..672ccc60 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -341,6 +341,51 @@ android:text="@string/start_name_with_surname" /> + + + + + + + + + + + + + + + + + + From cc332fb0a8e45167557635f108a858b9b7f4418e Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 13:45:11 +1000 Subject: [PATCH 02/18] Added receivers to manifest --- app/src/main/AndroidManifest.xml | 16 ++++++++++++++++ .../pro/receivers/AutomaticBackupReceiver.kt | 17 +++++++++++++++++ .../pro/receivers/BootCompletedReceiver.kt | 18 ++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/receivers/AutomaticBackupReceiver.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/receivers/BootCompletedReceiver.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5c4563d7..5fcbad4f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -206,6 +206,22 @@ android:label="@string/customize_colors" android:parentActivityName=".activities.SettingsActivity" /> + + + + + + + + + + + + Date: Sat, 15 Jul 2023 13:50:09 +1000 Subject: [PATCH 03/18] Added backup settings --- .../contacts/pro/helpers/Config.kt | 21 ++++++++++++++ .../contacts/pro/helpers/Constants.kt | 28 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt index 6fd98956..328ea41a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt @@ -1,6 +1,7 @@ package com.simplemobiletools.contacts.pro.helpers import android.content.Context +import android.os.Environment import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.SHOW_TABS @@ -12,4 +13,24 @@ class Config(context: Context) : BaseConfig(context) { var showTabs: Int get() = prefs.getInt(SHOW_TABS, ALL_TABS_MASK) set(showTabs) = prefs.edit().putInt(SHOW_TABS, showTabs).apply() + + var autoBackup: Boolean + get() = prefs.getBoolean(AUTO_BACKUP, false) + set(enableAutomaticBackups) = prefs.edit().putBoolean(AUTO_BACKUP, enableAutomaticBackups).apply() + + var autoBackupFolder: String + get() = prefs.getString(AUTO_BACKUP_FOLDER, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath)!! + set(autoBackupPath) = prefs.edit().putString(AUTO_BACKUP_FOLDER, autoBackupPath).apply() + + var autoBackupFilename: String + get() = prefs.getString(AUTO_BACKUP_FILENAME, "")!! + set(autoBackupFilename) = prefs.edit().putString(AUTO_BACKUP_FILENAME, autoBackupFilename).apply() + + var autoBackupContactSources: Set + get() = prefs.getStringSet(AUTO_BACKUP_CONTACT_SOURCES, setOf())!! + set(autoBackupContactTypes) = prefs.edit().remove(AUTO_BACKUP_CONTACT_SOURCES).putStringSet(AUTO_BACKUP_CONTACT_SOURCES, autoBackupContactTypes).apply() + + var lastAutoBackupTime: Long + get() = prefs.getLong(LAST_AUTO_BACKUP_TIME, 0L) + set(lastAutoBackupTime) = prefs.edit().putLong(LAST_AUTO_BACKUP_TIME, lastAutoBackupTime).apply() } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt index 6ea62bfb..204a9e6a 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt @@ -3,6 +3,7 @@ package com.simplemobiletools.contacts.pro.helpers import com.simplemobiletools.commons.helpers.TAB_CONTACTS import com.simplemobiletools.commons.helpers.TAB_FAVORITES import com.simplemobiletools.commons.helpers.TAB_GROUPS +import org.joda.time.DateTime const val GROUP = "group" const val IS_FROM_SIMPLE_CONTACTS = "is_from_simple_contacts" @@ -13,6 +14,16 @@ const val DEFAULT_FILE_NAME = "contacts.vcf" const val AVOID_CHANGING_TEXT_TAG = "avoid_changing_text_tag" const val AVOID_CHANGING_VISIBILITY_TAG = "avoid_changing_visibility_tag" +const val AUTOMATIC_BACKUP_REQUEST_CODE = 10001 +const val AUTO_BACKUP_INTERVAL_IN_DAYS = 1 + +const val AUTO_BACKUP = "auto_backup" +const val AUTO_BACKUP_FOLDER = "auto_backup_folder" +const val AUTO_BACKUP_FILENAME = "auto_backup_filename" +const val LAST_AUTO_BACKUP_TIME = "last_auto_backup_time" + +const val AUTO_BACKUP_CONTACT_SOURCES = "auto_backup_contact_sources" + // extras used at third party intents const val KEY_NAME = "name" const val KEY_EMAIL = "email" @@ -53,3 +64,20 @@ const val SIGNAL = "signal" const val VIBER = "viber" const val TELEGRAM = "telegram" const val THREEMA = "threema" + + +// 6 am is the hardcoded automatic backup time, intervals shorter than 1 day are not yet supported. +fun getNextAutoBackupTime(): DateTime { + val now = DateTime.now() + val sixHour = now.withHourOfDay(6) + return if (now.millis < sixHour.millis) { + sixHour + } else { + sixHour.plusDays(AUTO_BACKUP_INTERVAL_IN_DAYS) + } +} + +fun getPreviousAutoBackupTime(): DateTime { + val nextBackupTime = getNextAutoBackupTime() + return nextBackupTime.minusDays(AUTO_BACKUP_INTERVAL_IN_DAYS) +} From 0e205e6cb37496709e83414930fae1b53c1d7e40 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 13:52:03 +1000 Subject: [PATCH 04/18] Added new backup dialogs --- .../adapters/FilterContactSourcesAdapter.kt | 2 +- .../pro/dialogs/DateTimePatternInfoDialog.kt | 18 +++ .../pro/dialogs/ManageAutoBackupsDialog.kt | 138 ++++++++++++++++++ .../pro/dialogs/SelectContactTypesDialog.kt | 82 +++++++++++ .../layout/datetime_pattern_info_layout.xml | 9 ++ .../dialog_manage_automatic_backups.xml | 84 +++++++++++ 6 files changed, 332 insertions(+), 1 deletion(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/DateTimePatternInfoDialog.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt create mode 100644 app/src/main/res/layout/datetime_pattern_info_layout.xml create mode 100644 app/src/main/res/layout/dialog_manage_automatic_backups.xml diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/FilterContactSourcesAdapter.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/FilterContactSourcesAdapter.kt index ceb5f091..3af91af1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/FilterContactSourcesAdapter.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/adapters/FilterContactSourcesAdapter.kt @@ -15,7 +15,7 @@ import kotlinx.android.synthetic.main.item_filter_contact_source.view.* class FilterContactSourcesAdapter( val activity: SimpleActivity, private val contactSources: List, - private val displayContactSources: ArrayList + private val displayContactSources: List ) : RecyclerView.Adapter() { private val selectedKeys = HashSet() diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/DateTimePatternInfoDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/DateTimePatternInfoDialog.kt new file mode 100644 index 00000000..ad5cd722 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/DateTimePatternInfoDialog.kt @@ -0,0 +1,18 @@ +package com.simplemobiletools.contacts.pro.dialogs + +import com.simplemobiletools.commons.activities.BaseSimpleActivity +import com.simplemobiletools.commons.extensions.getAlertDialogBuilder +import com.simplemobiletools.commons.extensions.setupDialogStuff +import com.simplemobiletools.contacts.pro.R + +class DateTimePatternInfoDialog(activity: BaseSimpleActivity) { + + init { + val view = activity.layoutInflater.inflate(R.layout.datetime_pattern_info_layout, null) + activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok) { _, _ -> { } } + .apply { + activity.setupDialogStuff(view, this) + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt new file mode 100644 index 00000000..555370b7 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt @@ -0,0 +1,138 @@ +package com.simplemobiletools.contacts.pro.dialogs + +import android.view.ViewGroup +import androidx.appcompat.app.AlertDialog +import com.simplemobiletools.commons.dialogs.FilePickerDialog +import com.simplemobiletools.commons.extensions.getAlertDialogBuilder +import com.simplemobiletools.commons.extensions.hideKeyboard +import com.simplemobiletools.commons.extensions.humanizePath +import com.simplemobiletools.commons.extensions.isAValidFilename +import com.simplemobiletools.commons.extensions.setupDialogStuff +import com.simplemobiletools.commons.extensions.toast +import com.simplemobiletools.commons.extensions.value +import com.simplemobiletools.commons.helpers.ContactsHelper +import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.commons.models.contacts.ContactSource +import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.activities.SimpleActivity +import com.simplemobiletools.contacts.pro.extensions.config +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_filename +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_filename_hint +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_folder +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.manage_event_types_holder +import java.io.File + +class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: () -> Unit) { + private val view = (activity.layoutInflater.inflate(R.layout.dialog_manage_automatic_backups, null) as ViewGroup) + private val config = activity.config + private var backupFolder = config.autoBackupFolder + private var selectedContactTypes = HashSet() + + private fun setContactTypes() { + ContactsHelper(activity).getContactSources { contactSources -> + val availableContactSources = contactSources.toSet() + if (config.autoBackupContactSources.isEmpty()) { + selectedContactTypes = contactSources.toHashSet() + } else { + selectedContactTypes = availableContactSources.filter { it.name in config.autoBackupContactSources }.toHashSet() + } + } + } + + init { + setContactTypes() + view.apply { + backup_events_folder.setText(activity.humanizePath(backupFolder)) + val filename = config.autoBackupFilename.ifEmpty { + "${activity.getString(R.string.contacts)}_%Y%M%D_%h%m%s" + } + + backup_events_filename.setText(filename) + backup_events_filename_hint.setEndIconOnClickListener { + DateTimePatternInfoDialog(activity) + } + + backup_events_filename_hint.setEndIconOnLongClickListener { + DateTimePatternInfoDialog(activity) + true + } + + backup_events_folder.setOnClickListener { + selectBackupFolder() + } + + manage_event_types_holder.setOnClickListener { + activity.runOnUiThread { + SelectContactTypesDialog(activity, selectedContactTypes.map { it.name }) { + selectedContactTypes = it + config.autoBackupContactSources = it.map { it.name }.toSet() + } + } + } + } + activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null) + .apply { + activity.setupDialogStuff(view, this, R.string.manage_automatic_backups) { dialog -> + dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { + val filename = view.backup_events_filename.value + when { + filename.isEmpty() -> activity.toast(R.string.empty_name) + filename.isAValidFilename() -> { + val file = File(backupFolder, "$filename.ics") + if (file.exists() && !file.canWrite()) { + activity.toast(R.string.name_taken) + return@setOnClickListener + } + + if (selectedContactTypes.isEmpty()) { + activity.toast(R.string.no_entries_for_exporting) + return@setOnClickListener + } + + ensureBackgroundThread { + config.apply { + autoBackupFolder = backupFolder + autoBackupFilename = filename + if (autoBackupContactSources != selectedContactTypes) { + autoBackupContactSources = selectedContactTypes.map { it.type }.toSet() + } + } + + activity.runOnUiThread { + onSuccess() + } + + dialog.dismiss() + } + } + + else -> activity.toast(R.string.invalid_name) + } + } + } + } + } + + private fun selectBackupFolder() { + activity.hideKeyboard(view.backup_events_filename) + FilePickerDialog(activity, backupFolder, false, showFAB = true) { path -> + activity.handleSAFDialog(path) { grantedSAF -> + if (!grantedSAF) { + return@handleSAFDialog + } + + activity.handleSAFDialogSdk30(path) { grantedSAF30 -> + if (!grantedSAF30) { + return@handleSAFDialogSdk30 + } + + backupFolder = path + view.backup_events_folder.setText(activity.humanizePath(path)) + } + } + } + } +} + diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt new file mode 100644 index 00000000..93d7d83d --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt @@ -0,0 +1,82 @@ +package com.simplemobiletools.contacts.pro.dialogs + +import androidx.appcompat.app.AlertDialog +import com.simplemobiletools.commons.extensions.getAlertDialogBuilder +import com.simplemobiletools.commons.extensions.setupDialogStuff +import com.simplemobiletools.commons.helpers.ContactsHelper +import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.commons.models.contacts.ContactSource +import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.activities.SimpleActivity +import com.simplemobiletools.contacts.pro.adapters.FilterContactSourcesAdapter +import kotlinx.android.synthetic.main.dialog_filter_contact_sources.view.filter_contact_sources_list + +class SelectContactTypesDialog( + val activity: SimpleActivity, + private val selectedContactTypes: List, + val callback: (HashSet) -> Unit +) { + private var dialog: AlertDialog? = null + private val view = activity.layoutInflater.inflate(R.layout.dialog_filter_contact_sources, null) + + private var contactSources = mutableListOf() + private var contacts = listOf() + private var isContactSourcesReady = false + private var isContactsReady = false + + init { + ContactsHelper(activity).getContactSources { sources -> + contactSources = sources + isContactSourcesReady = true + processDataIfReady() + } + + ContactsHelper(activity).getContacts(getAll = true) { receivedContacts -> + contacts = receivedContacts + isContactsReady = true + processDataIfReady() + } + } + + private fun processDataIfReady() { + if (!isContactSourcesReady) { + return + } + + val contactSourcesWithCount = mutableListOf() + for (contactSource in contactSources) { + val count = if (isContactsReady) { + contacts.count { it.source == contactSource.name } + } else { + -1 + } + contactSourcesWithCount.add(contactSource.copy(count = count)) + } + + contactSources.clear() + contactSources.addAll(contactSourcesWithCount) + + activity.runOnUiThread { + view.filter_contact_sources_list.adapter = FilterContactSourcesAdapter(activity, contactSourcesWithCount, selectedContactTypes.toList()) + if (dialog == null) { + activity.runOnUiThread { + activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok) { _, _ -> confirmContactTypes() } + .setNegativeButton(R.string.cancel, null) + .apply { + activity.setupDialogStuff(view, this) { alertDialog -> + dialog = alertDialog + } + } + } + } + } + } + + private fun confirmContactTypes() { + val adapter = view.filter_contact_sources_list.adapter as FilterContactSourcesAdapter + val selectedItems = adapter.getSelectedContactSources() + callback(selectedItems.toHashSet()) + dialog?.dismiss() + } +} diff --git a/app/src/main/res/layout/datetime_pattern_info_layout.xml b/app/src/main/res/layout/datetime_pattern_info_layout.xml new file mode 100644 index 00000000..36ee34d1 --- /dev/null +++ b/app/src/main/res/layout/datetime_pattern_info_layout.xml @@ -0,0 +1,9 @@ + + diff --git a/app/src/main/res/layout/dialog_manage_automatic_backups.xml b/app/src/main/res/layout/dialog_manage_automatic_backups.xml new file mode 100644 index 00000000..64e59a6b --- /dev/null +++ b/app/src/main/res/layout/dialog_manage_automatic_backups.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From a3338b994c3088bc3a8cb911cfc0f2bd2c34f629 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 13:52:26 +1000 Subject: [PATCH 05/18] New backup settings in SettingsActivity --- .../pro/activities/SettingsActivity.kt | 47 ++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt index e45db403..e65d385f 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt @@ -6,11 +6,15 @@ import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.dialogs.ManageAutoBackupsDialog import com.simplemobiletools.contacts.pro.dialogs.ManageVisibleFieldsDialog import com.simplemobiletools.contacts.pro.dialogs.ManageVisibleTabsDialog +import com.simplemobiletools.contacts.pro.extensions.cancelScheduledAutomaticBackup import com.simplemobiletools.contacts.pro.extensions.config +import com.simplemobiletools.contacts.pro.extensions.scheduleNextAutomaticBackup import kotlinx.android.synthetic.main.activity_settings.* import java.util.* +import kotlin.system.exitProcess class SettingsActivity : SimpleActivity() { @@ -42,6 +46,8 @@ class SettingsActivity : SimpleActivity() { setupShowPrivateContacts() setupOnContactClick() setupDefaultTab() + setupEnableAutomaticBackups() + setupManageAutomaticBackups() updateTextColors(settings_holder) arrayOf(settings_color_customization_section_label, settings_general_settings_label, settings_main_screen_label, settings_list_view_label).forEach { @@ -116,7 +122,7 @@ class SettingsActivity : SimpleActivity() { settings_use_english_holder.setOnClickListener { settings_use_english.toggle() config.useEnglish = settings_use_english.isChecked - System.exit(0) + exitProcess(0) } } @@ -215,4 +221,43 @@ class SettingsActivity : SimpleActivity() { config.mergeDuplicateContacts = settings_merge_duplicate_contacts.isChecked } } + + private fun setupEnableAutomaticBackups() { + settings_backups_label.beVisibleIf(isRPlus()) + settings_enable_automatic_backups_holder.beVisibleIf(isRPlus()) + settings_enable_automatic_backups.isChecked = config.autoBackup + settings_enable_automatic_backups_holder.setOnClickListener { + val wasBackupDisabled = !config.autoBackup + if (wasBackupDisabled) { + ManageAutoBackupsDialog( + activity = this, + onSuccess = { + enableOrDisableAutomaticBackups(true) + scheduleNextAutomaticBackup() + } + ) + } else { + cancelScheduledAutomaticBackup() + enableOrDisableAutomaticBackups(false) + } + } + } + + private fun setupManageAutomaticBackups() { + settings_manage_automatic_backups_holder.beVisibleIf(isRPlus() && config.autoBackup) + settings_manage_automatic_backups_holder.setOnClickListener { + ManageAutoBackupsDialog( + activity = this, + onSuccess = { + scheduleNextAutomaticBackup() + } + ) + } + } + + private fun enableOrDisableAutomaticBackups(enable: Boolean) { + config.autoBackup = enable + settings_enable_automatic_backups.isChecked = enable + settings_manage_automatic_backups_holder.beVisibleIf(enable) + } } From 1df5f66c8b75bdb7f28e78c8e792df8b8d198fae Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 13:53:07 +1000 Subject: [PATCH 06/18] Context functions for backup added --- .../contacts/pro/extensions/Context.kt | 127 +++++++++++++++++- 1 file changed, 122 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt index b4f18f1a..009497c0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt @@ -1,18 +1,25 @@ package com.simplemobiletools.contacts.pro.extensions import android.annotation.SuppressLint +import android.app.AlarmManager +import android.app.PendingIntent import android.content.Context +import android.content.Intent import android.graphics.drawable.Drawable +import androidx.core.app.AlarmManagerCompat import androidx.core.content.FileProvider -import com.simplemobiletools.commons.extensions.getCachePhoto -import com.simplemobiletools.commons.helpers.SIGNAL_PACKAGE -import com.simplemobiletools.commons.helpers.TELEGRAM_PACKAGE -import com.simplemobiletools.commons.helpers.VIBER_PACKAGE -import com.simplemobiletools.commons.helpers.WHATSAPP_PACKAGE +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.contacts.pro.BuildConfig import com.simplemobiletools.contacts.pro.R +import com.simplemobiletools.contacts.pro.helpers.AUTOMATIC_BACKUP_REQUEST_CODE import com.simplemobiletools.contacts.pro.helpers.Config +import com.simplemobiletools.contacts.pro.helpers.getNextAutoBackupTime +import com.simplemobiletools.contacts.pro.helpers.getPreviousAutoBackupTime +import com.simplemobiletools.contacts.pro.receivers.AutomaticBackupReceiver +import org.joda.time.DateTime import java.io.File +import java.io.FileOutputStream val Context.config: Config get() = Config.newInstance(applicationContext) fun Context.getCachePhotoUri(file: File = getCachePhoto()) = FileProvider.getUriForFile(this, "${BuildConfig.APPLICATION_ID}.provider", file) @@ -29,3 +36,113 @@ fun Context.getPackageDrawable(packageName: String): Drawable { }, theme ) } + +fun Context.getAutomaticBackupIntent(): PendingIntent { + val intent = Intent(this, AutomaticBackupReceiver::class.java) + return PendingIntent.getBroadcast(this, AUTOMATIC_BACKUP_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) +} + +fun Context.scheduleNextAutomaticBackup() { + if (config.autoBackup) { + val backupAtMillis = getNextAutoBackupTime().millis + val pendingIntent = getAutomaticBackupIntent() + val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager + try { + AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, backupAtMillis, pendingIntent) + } catch (e: Exception) { + showErrorToast(e) + } + } +} + +fun Context.cancelScheduledAutomaticBackup() { + val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager + alarmManager.cancel(getAutomaticBackupIntent()) +} + +fun Context.checkAndBackupContactsOnBoot() { + if (config.autoBackup) { + val previousRealBackupTime = config.lastAutoBackupTime + val previousScheduledBackupTime = getPreviousAutoBackupTime().millis + val missedPreviousBackup = previousRealBackupTime < previousScheduledBackupTime + if (missedPreviousBackup) { + // device was probably off at the scheduled time so backup now + backupContacts() + } + } +} + +fun Context.backupContacts() { + require(isRPlus()) + ensureBackgroundThread { + val config = config + ContactsHelper(this).getContactsToExport(selectedContactSources = config.autoBackupContactSources) { contactsToBackup -> + if (contactsToBackup.isEmpty()) { + toast(R.string.no_entries_for_exporting) + config.lastAutoBackupTime = DateTime.now().millis + scheduleNextAutomaticBackup() + return@getContactsToExport + } + + + val now = DateTime.now() + val year = now.year.toString() + val month = now.monthOfYear.ensureTwoDigits() + val day = now.dayOfMonth.ensureTwoDigits() + val hours = now.hourOfDay.ensureTwoDigits() + val minutes = now.minuteOfHour.ensureTwoDigits() + val seconds = now.secondOfMinute.ensureTwoDigits() + + val filename = config.autoBackupFilename + .replace("%Y", year, false) + .replace("%M", month, false) + .replace("%D", day, false) + .replace("%h", hours, false) + .replace("%m", minutes, false) + .replace("%s", seconds, false) + + val outputFolder = File(config.autoBackupFolder).apply { + mkdirs() + } + + var exportFile = File(outputFolder, "$filename.ics") + var exportFilePath = exportFile.absolutePath + val outputStream = try { + if (hasProperStoredFirstParentUri(exportFilePath)) { + val exportFileUri = createDocumentUriUsingFirstParentTreeUri(exportFilePath) + if (!getDoesFilePathExist(exportFilePath)) { + createSAFFileSdk30(exportFilePath) + } + applicationContext.contentResolver.openOutputStream(exportFileUri, "wt") ?: FileOutputStream(exportFile) + } else { + var num = 0 + while (getDoesFilePathExist(exportFilePath) && !exportFile.canWrite()) { + num++ + exportFile = File(outputFolder, "${filename}_${num}.json") + exportFilePath = exportFile.absolutePath + } + FileOutputStream(exportFile) + } + } catch (e: Exception) { + showErrorToast(e) + scheduleNextAutomaticBackup() + return@getContactsToExport + } + + val exportResult = try { + ContactsHelper(this).exportContacts(contactsToBackup, outputStream) + } catch (e: Exception) { + showErrorToast(e) + } + + when (exportResult) { + ExportResult.EXPORT_OK -> toast(R.string.exporting_successful) + else -> toast(R.string.exporting_failed) + } + + config.lastAutoBackupTime = DateTime.now().millis + scheduleNextAutomaticBackup() + } + } +} + From 13a66d9c8d8569972409b9ba2fa20d889468014d Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 13:53:35 +1000 Subject: [PATCH 07/18] Deleted settings divider at the end --- app/src/main/res/layout/activity_settings.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml index 672ccc60..d225ec4e 100644 --- a/app/src/main/res/layout/activity_settings.xml +++ b/app/src/main/res/layout/activity_settings.xml @@ -383,9 +383,6 @@ - From 6d67aa4ae7f4dcd8a4f33c9a7cf6287dfa444094 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 14:00:47 +1000 Subject: [PATCH 08/18] Dialog bug fixed --- .../pro/dialogs/ManageAutoBackupsDialog.kt | 24 ++++--------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt index 555370b7..cbddeff0 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt @@ -12,7 +12,6 @@ import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.value import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.ensureBackgroundThread -import com.simplemobiletools.commons.models.contacts.ContactSource import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.activities.SimpleActivity import com.simplemobiletools.contacts.pro.extensions.config @@ -26,21 +25,9 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( private val view = (activity.layoutInflater.inflate(R.layout.dialog_manage_automatic_backups, null) as ViewGroup) private val config = activity.config private var backupFolder = config.autoBackupFolder - private var selectedContactTypes = HashSet() - - private fun setContactTypes() { - ContactsHelper(activity).getContactSources { contactSources -> - val availableContactSources = contactSources.toSet() - if (config.autoBackupContactSources.isEmpty()) { - selectedContactTypes = contactSources.toHashSet() - } else { - selectedContactTypes = availableContactSources.filter { it.name in config.autoBackupContactSources }.toHashSet() - } - } - } + private var selectedContactSources = config.autoBackupContactSources init { - setContactTypes() view.apply { backup_events_folder.setText(activity.humanizePath(backupFolder)) val filename = config.autoBackupFilename.ifEmpty { @@ -63,8 +50,8 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( manage_event_types_holder.setOnClickListener { activity.runOnUiThread { - SelectContactTypesDialog(activity, selectedContactTypes.map { it.name }) { - selectedContactTypes = it + SelectContactTypesDialog(activity, selectedContactSources.toList()) { + selectedContactSources = it.map { it.name }.toSet() config.autoBackupContactSources = it.map { it.name }.toSet() } } @@ -86,7 +73,7 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( return@setOnClickListener } - if (selectedContactTypes.isEmpty()) { + if (selectedContactSources.isEmpty()) { activity.toast(R.string.no_entries_for_exporting) return@setOnClickListener } @@ -95,9 +82,6 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( config.apply { autoBackupFolder = backupFolder autoBackupFilename = filename - if (autoBackupContactSources != selectedContactTypes) { - autoBackupContactSources = selectedContactTypes.map { it.type }.toSet() - } } activity.runOnUiThread { From 88e4ae97f7c4892523fbaafaa266fecf53bd5f94 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 14:01:58 +1000 Subject: [PATCH 09/18] Added permissions --- app/src/main/AndroidManifest.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5fcbad4f..c7d5386f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,11 +4,14 @@ package="com.simplemobiletools.contacts.pro" android:installLocation="auto"> + + + Date: Sat, 15 Jul 2023 14:01:58 +1000 Subject: [PATCH 10/18] Added permissions --- app/src/main/AndroidManifest.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5fcbad4f..6bfa8854 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,11 +4,15 @@ package="com.simplemobiletools.contacts.pro" android:installLocation="auto"> + + + + Date: Sat, 15 Jul 2023 22:12:52 +1000 Subject: [PATCH 11/18] Dialog refactoring --- .../pro/dialogs/ManageAutoBackupsDialog.kt | 85 +++++++++++++------ .../pro/dialogs/SelectContactTypesDialog.kt | 82 ------------------ .../dialog_manage_automatic_backups.xml | 53 ++++++------ 3 files changed, 84 insertions(+), 136 deletions(-) delete mode 100644 app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt index cbddeff0..b5677528 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt @@ -1,69 +1,78 @@ package com.simplemobiletools.contacts.pro.dialogs +import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AlertDialog import com.simplemobiletools.commons.dialogs.FilePickerDialog -import com.simplemobiletools.commons.extensions.getAlertDialogBuilder -import com.simplemobiletools.commons.extensions.hideKeyboard -import com.simplemobiletools.commons.extensions.humanizePath -import com.simplemobiletools.commons.extensions.isAValidFilename -import com.simplemobiletools.commons.extensions.setupDialogStuff -import com.simplemobiletools.commons.extensions.toast -import com.simplemobiletools.commons.extensions.value +import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.ContactsHelper import com.simplemobiletools.commons.helpers.ensureBackgroundThread +import com.simplemobiletools.commons.models.contacts.Contact +import com.simplemobiletools.commons.models.contacts.ContactSource import com.simplemobiletools.contacts.pro.R import com.simplemobiletools.contacts.pro.activities.SimpleActivity +import com.simplemobiletools.contacts.pro.adapters.FilterContactSourcesAdapter import com.simplemobiletools.contacts.pro.extensions.config -import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_filename -import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_filename_hint -import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_events_folder -import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.manage_event_types_holder +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_contact_sources_list +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_contacts_filename +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_contacts_filename_hint +import kotlinx.android.synthetic.main.dialog_manage_automatic_backups.view.backup_contacts_folder import java.io.File class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: () -> Unit) { private val view = (activity.layoutInflater.inflate(R.layout.dialog_manage_automatic_backups, null) as ViewGroup) private val config = activity.config private var backupFolder = config.autoBackupFolder + private var contactSources = mutableListOf() private var selectedContactSources = config.autoBackupContactSources + private var contacts = ArrayList() + private var isContactSourcesReady = false + private var isContactsReady = false init { view.apply { - backup_events_folder.setText(activity.humanizePath(backupFolder)) + backup_contacts_folder.setText(activity.humanizePath(backupFolder)) val filename = config.autoBackupFilename.ifEmpty { "${activity.getString(R.string.contacts)}_%Y%M%D_%h%m%s" } - backup_events_filename.setText(filename) - backup_events_filename_hint.setEndIconOnClickListener { + backup_contacts_filename.setText(filename) + backup_contacts_filename_hint.setEndIconOnClickListener { DateTimePatternInfoDialog(activity) } - backup_events_filename_hint.setEndIconOnLongClickListener { + backup_contacts_filename_hint.setEndIconOnLongClickListener { DateTimePatternInfoDialog(activity) true } - backup_events_folder.setOnClickListener { + backup_contacts_folder.setOnClickListener { selectBackupFolder() } - manage_event_types_holder.setOnClickListener { - activity.runOnUiThread { - SelectContactTypesDialog(activity, selectedContactSources.toList()) { - selectedContactSources = it.map { it.name }.toSet() - config.autoBackupContactSources = it.map { it.name }.toSet() - } - } + ContactsHelper(activity).getContactSources { sources -> + contactSources = sources + isContactSourcesReady = true + processDataIfReady(this) + } + + ContactsHelper(activity).getContacts(getAll = true) { receivedContacts -> + contacts = receivedContacts + isContactsReady = true + processDataIfReady(this) } } + activity.getAlertDialogBuilder() .setPositiveButton(R.string.ok, null) .setNegativeButton(R.string.cancel, null) .apply { activity.setupDialogStuff(view, this, R.string.manage_automatic_backups) { dialog -> dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { - val filename = view.backup_events_filename.value + if (view.backup_contact_sources_list.adapter == null) { + return@setOnClickListener + } + val filename = view.backup_contacts_filename.value when { filename.isEmpty() -> activity.toast(R.string.empty_name) filename.isAValidFilename() -> { @@ -73,11 +82,14 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( return@setOnClickListener } - if (selectedContactSources.isEmpty()) { + val selectedSources = (view.backup_contact_sources_list.adapter as FilterContactSourcesAdapter).getSelectedContactSources() + if (selectedSources.isEmpty()) { activity.toast(R.string.no_entries_for_exporting) return@setOnClickListener } + config.autoBackupContactSources = selectedSources.map { it.name }.toSet() + ensureBackgroundThread { config.apply { autoBackupFolder = backupFolder @@ -99,8 +111,27 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( } } + private fun processDataIfReady(view: View) { + if (!isContactSourcesReady || !isContactsReady) { + return + } + + val contactSourcesWithCount = mutableListOf() + for (source in contactSources) { + val count = contacts.filter { it.source == source.name }.count() + contactSourcesWithCount.add(source.copy(count = count)) + } + + contactSources.clear() + contactSources.addAll(contactSourcesWithCount) + + activity.runOnUiThread { + view.backup_contact_sources_list.adapter = FilterContactSourcesAdapter(activity, contactSourcesWithCount, selectedContactSources.toList()) + } + } + private fun selectBackupFolder() { - activity.hideKeyboard(view.backup_events_filename) + activity.hideKeyboard(view.backup_contacts_filename) FilePickerDialog(activity, backupFolder, false, showFAB = true) { path -> activity.handleSAFDialog(path) { grantedSAF -> if (!grantedSAF) { @@ -113,7 +144,7 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( } backupFolder = path - view.backup_events_folder.setText(activity.humanizePath(path)) + view.backup_contacts_folder.setText(activity.humanizePath(path)) } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt deleted file mode 100644 index 93d7d83d..00000000 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/SelectContactTypesDialog.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.simplemobiletools.contacts.pro.dialogs - -import androidx.appcompat.app.AlertDialog -import com.simplemobiletools.commons.extensions.getAlertDialogBuilder -import com.simplemobiletools.commons.extensions.setupDialogStuff -import com.simplemobiletools.commons.helpers.ContactsHelper -import com.simplemobiletools.commons.models.contacts.Contact -import com.simplemobiletools.commons.models.contacts.ContactSource -import com.simplemobiletools.contacts.pro.R -import com.simplemobiletools.contacts.pro.activities.SimpleActivity -import com.simplemobiletools.contacts.pro.adapters.FilterContactSourcesAdapter -import kotlinx.android.synthetic.main.dialog_filter_contact_sources.view.filter_contact_sources_list - -class SelectContactTypesDialog( - val activity: SimpleActivity, - private val selectedContactTypes: List, - val callback: (HashSet) -> Unit -) { - private var dialog: AlertDialog? = null - private val view = activity.layoutInflater.inflate(R.layout.dialog_filter_contact_sources, null) - - private var contactSources = mutableListOf() - private var contacts = listOf() - private var isContactSourcesReady = false - private var isContactsReady = false - - init { - ContactsHelper(activity).getContactSources { sources -> - contactSources = sources - isContactSourcesReady = true - processDataIfReady() - } - - ContactsHelper(activity).getContacts(getAll = true) { receivedContacts -> - contacts = receivedContacts - isContactsReady = true - processDataIfReady() - } - } - - private fun processDataIfReady() { - if (!isContactSourcesReady) { - return - } - - val contactSourcesWithCount = mutableListOf() - for (contactSource in contactSources) { - val count = if (isContactsReady) { - contacts.count { it.source == contactSource.name } - } else { - -1 - } - contactSourcesWithCount.add(contactSource.copy(count = count)) - } - - contactSources.clear() - contactSources.addAll(contactSourcesWithCount) - - activity.runOnUiThread { - view.filter_contact_sources_list.adapter = FilterContactSourcesAdapter(activity, contactSourcesWithCount, selectedContactTypes.toList()) - if (dialog == null) { - activity.runOnUiThread { - activity.getAlertDialogBuilder() - .setPositiveButton(R.string.ok) { _, _ -> confirmContactTypes() } - .setNegativeButton(R.string.cancel, null) - .apply { - activity.setupDialogStuff(view, this) { alertDialog -> - dialog = alertDialog - } - } - } - } - } - } - - private fun confirmContactTypes() { - val adapter = view.filter_contact_sources_list.adapter as FilterContactSourcesAdapter - val selectedItems = adapter.getSelectedContactSources() - callback(selectedItems.toHashSet()) - dialog?.dismiss() - } -} diff --git a/app/src/main/res/layout/dialog_manage_automatic_backups.xml b/app/src/main/res/layout/dialog_manage_automatic_backups.xml index 64e59a6b..6816bd4a 100644 --- a/app/src/main/res/layout/dialog_manage_automatic_backups.xml +++ b/app/src/main/res/layout/dialog_manage_automatic_backups.xml @@ -1,19 +1,19 @@ @@ -30,7 +30,7 @@ - + + - - - - + android:clipToPadding="false" + android:overScrollMode="never" + android:paddingTop="@dimen/medium_margin" + app:layoutManager="com.simplemobiletools.commons.views.MyLinearLayoutManager" /> From 7c142490edfaa2368980306ebbf7146c142de8ee Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 22:13:01 +1000 Subject: [PATCH 12/18] Filename fix --- .../com/simplemobiletools/contacts/pro/extensions/Context.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt index 009497c0..acfa96ce 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt @@ -105,7 +105,7 @@ fun Context.backupContacts() { mkdirs() } - var exportFile = File(outputFolder, "$filename.ics") + var exportFile = File(outputFolder, "$filename.json") var exportFilePath = exportFile.absolutePath val outputStream = try { if (hasProperStoredFirstParentUri(exportFilePath)) { From 141ab9f70c01bb340aefaf977b3a8d69305b7ba7 Mon Sep 17 00:00:00 2001 From: merkost Date: Sat, 15 Jul 2023 22:14:24 +1000 Subject: [PATCH 13/18] Backup file extension fix --- .../com/simplemobiletools/contacts/pro/extensions/Context.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt index acfa96ce..1ed82973 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/extensions/Context.kt @@ -105,7 +105,7 @@ fun Context.backupContacts() { mkdirs() } - var exportFile = File(outputFolder, "$filename.json") + var exportFile = File(outputFolder, "$filename.vcf") var exportFilePath = exportFile.absolutePath val outputStream = try { if (hasProperStoredFirstParentUri(exportFilePath)) { @@ -118,7 +118,7 @@ fun Context.backupContacts() { var num = 0 while (getDoesFilePathExist(exportFilePath) && !exportFile.canWrite()) { num++ - exportFile = File(outputFolder, "${filename}_${num}.json") + exportFile = File(outputFolder, "${filename}_${num}.vcf") exportFilePath = exportFile.absolutePath } FileOutputStream(exportFile) From 8b815df88465a22675b01616034418d1f64ab521 Mon Sep 17 00:00:00 2001 From: merkost Date: Sun, 16 Jul 2023 09:51:11 +1000 Subject: [PATCH 14/18] Moved shared config to commons lib --- .../contacts/pro/helpers/Config.kt | 18 +----------------- .../contacts/pro/helpers/Constants.kt | 5 ----- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt index 328ea41a..21822187 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Config.kt @@ -1,7 +1,6 @@ package com.simplemobiletools.contacts.pro.helpers import android.content.Context -import android.os.Environment import com.simplemobiletools.commons.helpers.BaseConfig import com.simplemobiletools.commons.helpers.SHOW_TABS @@ -14,23 +13,8 @@ class Config(context: Context) : BaseConfig(context) { get() = prefs.getInt(SHOW_TABS, ALL_TABS_MASK) set(showTabs) = prefs.edit().putInt(SHOW_TABS, showTabs).apply() - var autoBackup: Boolean - get() = prefs.getBoolean(AUTO_BACKUP, false) - set(enableAutomaticBackups) = prefs.edit().putBoolean(AUTO_BACKUP, enableAutomaticBackups).apply() - - var autoBackupFolder: String - get() = prefs.getString(AUTO_BACKUP_FOLDER, Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath)!! - set(autoBackupPath) = prefs.edit().putString(AUTO_BACKUP_FOLDER, autoBackupPath).apply() - - var autoBackupFilename: String - get() = prefs.getString(AUTO_BACKUP_FILENAME, "")!! - set(autoBackupFilename) = prefs.edit().putString(AUTO_BACKUP_FILENAME, autoBackupFilename).apply() - var autoBackupContactSources: Set get() = prefs.getStringSet(AUTO_BACKUP_CONTACT_SOURCES, setOf())!! - set(autoBackupContactTypes) = prefs.edit().remove(AUTO_BACKUP_CONTACT_SOURCES).putStringSet(AUTO_BACKUP_CONTACT_SOURCES, autoBackupContactTypes).apply() + set(autoBackupContactSources) = prefs.edit().remove(AUTO_BACKUP_CONTACT_SOURCES).putStringSet(AUTO_BACKUP_CONTACT_SOURCES, autoBackupContactSources).apply() - var lastAutoBackupTime: Long - get() = prefs.getLong(LAST_AUTO_BACKUP_TIME, 0L) - set(lastAutoBackupTime) = prefs.edit().putLong(LAST_AUTO_BACKUP_TIME, lastAutoBackupTime).apply() } diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt index 204a9e6a..a51d3504 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt @@ -17,11 +17,6 @@ const val AVOID_CHANGING_VISIBILITY_TAG = "avoid_changing_visibility_tag" const val AUTOMATIC_BACKUP_REQUEST_CODE = 10001 const val AUTO_BACKUP_INTERVAL_IN_DAYS = 1 -const val AUTO_BACKUP = "auto_backup" -const val AUTO_BACKUP_FOLDER = "auto_backup_folder" -const val AUTO_BACKUP_FILENAME = "auto_backup_filename" -const val LAST_AUTO_BACKUP_TIME = "last_auto_backup_time" - const val AUTO_BACKUP_CONTACT_SOURCES = "auto_backup_contact_sources" // extras used at third party intents From 03d6662e5b117a7f6baa2f6a496b0b81066133e6 Mon Sep 17 00:00:00 2001 From: merkost Date: Thu, 20 Jul 2023 12:34:18 +1000 Subject: [PATCH 15/18] Fixed file extension to .vcf --- .../contacts/pro/dialogs/ManageAutoBackupsDialog.kt | 2 +- app/src/main/res/layout/dialog_manage_automatic_backups.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt index b5677528..8aedcd8e 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt @@ -76,7 +76,7 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( when { filename.isEmpty() -> activity.toast(R.string.empty_name) filename.isAValidFilename() -> { - val file = File(backupFolder, "$filename.ics") + val file = File(backupFolder, "$filename.vcf") if (file.exists() && !file.canWrite()) { activity.toast(R.string.name_taken) return@setOnClickListener diff --git a/app/src/main/res/layout/dialog_manage_automatic_backups.xml b/app/src/main/res/layout/dialog_manage_automatic_backups.xml index 6816bd4a..21690ff2 100644 --- a/app/src/main/res/layout/dialog_manage_automatic_backups.xml +++ b/app/src/main/res/layout/dialog_manage_automatic_backups.xml @@ -35,7 +35,7 @@ android:layout_height="wrap_content" android:layout_marginStart="@dimen/activity_margin" android:layout_marginEnd="@dimen/activity_margin" - android:hint="@string/filename_without_json" + android:hint="@string/filename_without_vcf" app:endIconDrawable="@drawable/ic_info_vector" app:endIconMode="custom"> From 5c8f39c6262f3da857ef005b0d6b3e4e2c92feee Mon Sep 17 00:00:00 2001 From: merkost Date: Thu, 20 Jul 2023 12:47:12 +1000 Subject: [PATCH 16/18] Added initial all sources selection if none selected previously --- .../contacts/pro/dialogs/ManageAutoBackupsDialog.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt index 8aedcd8e..9e999647 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/dialogs/ManageAutoBackupsDialog.kt @@ -116,9 +116,13 @@ class ManageAutoBackupsDialog(private val activity: SimpleActivity, onSuccess: ( return } + if (selectedContactSources.isEmpty()) { + selectedContactSources = contactSources.map { it.name }.toSet() + } + val contactSourcesWithCount = mutableListOf() for (source in contactSources) { - val count = contacts.filter { it.source == source.name }.count() + val count = contacts.count { it.source == source.name } contactSourcesWithCount.add(source.copy(count = count)) } From 3c3e2b8b1787a23449e649208fb8addb43b39ff5 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Thu, 20 Jul 2023 09:08:16 +0200 Subject: [PATCH 17/18] apply proper color at Backups settings label --- .../contacts/pro/activities/SettingsActivity.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt index e65d385f..5b4d9011 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/activities/SettingsActivity.kt @@ -13,7 +13,7 @@ import com.simplemobiletools.contacts.pro.extensions.cancelScheduledAutomaticBac import com.simplemobiletools.contacts.pro.extensions.config import com.simplemobiletools.contacts.pro.extensions.scheduleNextAutomaticBackup import kotlinx.android.synthetic.main.activity_settings.* -import java.util.* +import java.util.Locale import kotlin.system.exitProcess class SettingsActivity : SimpleActivity() { @@ -50,7 +50,13 @@ class SettingsActivity : SimpleActivity() { setupManageAutomaticBackups() updateTextColors(settings_holder) - arrayOf(settings_color_customization_section_label, settings_general_settings_label, settings_main_screen_label, settings_list_view_label).forEach { + arrayOf( + settings_color_customization_section_label, + settings_general_settings_label, + settings_main_screen_label, + settings_list_view_label, + settings_backups_label + ).forEach { it.setTextColor(getProperPrimaryColor()) } } From d7077c73fa97958b41acedfe0d2e9906921fbb71 Mon Sep 17 00:00:00 2001 From: Tibor Kaputa Date: Thu, 20 Jul 2023 09:14:24 +0200 Subject: [PATCH 18/18] removing some unused constants --- .../com/simplemobiletools/contacts/pro/helpers/Constants.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt index a51d3504..665ff482 100644 --- a/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/contacts/pro/helpers/Constants.kt @@ -8,8 +8,6 @@ import org.joda.time.DateTime const val GROUP = "group" 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 DEFAULT_FILE_NAME = "contacts.vcf" const val AVOID_CHANGING_TEXT_TAG = "avoid_changing_text_tag" const val AVOID_CHANGING_VISIBILITY_TAG = "avoid_changing_visibility_tag"