diff --git a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt index d53df9a75..e4320386c 100644 --- a/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt +++ b/app/src/main/java/com/todoroo/astrid/service/Upgrader.kt @@ -197,7 +197,7 @@ class Upgrader @Inject constructor( if (isNullOrEmpty(defaultGoogleTaskList)) { // TODO: look up default list } else { - val googleTaskList = googleTaskListDao.getByRemoteId(defaultGoogleTaskList) + val googleTaskList = googleTaskListDao.getByRemoteId(defaultGoogleTaskList!!) if (googleTaskList != null) { defaultFilterProvider.defaultRemoteList = GtasksFilter(googleTaskList) } diff --git a/app/src/main/java/org/tasks/preferences/Preferences.java b/app/src/main/java/org/tasks/preferences/Preferences.java deleted file mode 100644 index 4ad23604d..000000000 --- a/app/src/main/java/org/tasks/preferences/Preferences.java +++ /dev/null @@ -1,552 +0,0 @@ -package org.tasks.preferences; - -import static android.content.SharedPreferences.Editor; -import static androidx.preference.PreferenceManager.setDefaultValues; -import static com.google.common.collect.Iterables.filter; -import static com.google.common.collect.Iterables.transform; -import static com.google.common.collect.Sets.newHashSet; -import static java.util.Collections.emptySet; -import static org.tasks.Strings.isNullOrEmpty; - -import android.annotation.SuppressLint; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.media.RingtoneManager; -import android.net.Uri; -import android.os.Binder; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.documentfile.provider.DocumentFile; -import com.todoroo.astrid.activity.BeastModePreferences; -import com.todoroo.astrid.api.AstridApiConstants; -import com.todoroo.astrid.core.SortHelper; -import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.data.Task.Priority; -import java.io.File; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.TimeUnit; -import org.tasks.BuildConfig; -import org.tasks.R; -import org.tasks.billing.Purchase; -import org.tasks.data.TaskAttachment; -import org.tasks.themes.ColorProvider; -import org.tasks.themes.ThemeBase; -import org.tasks.time.DateTime; -import timber.log.Timber; - -public class Preferences { - - public static final String P_CURRENT_VERSION = "cv"; // $NON-NLS-1$ - - private static final String PREF_SORT_SORT = "sort_sort"; // $NON-NLS-1$ - - private final Context context; - private final SharedPreferences prefs; - private final SharedPreferences publicPrefs; - - public Preferences(Context context) { - this(context, getSharedPreferencesName(context)); - } - - public Preferences(Context context, String name) { - this.context = context; - prefs = context.getSharedPreferences(name, Context.MODE_PRIVATE); - publicPrefs = - context.getSharedPreferences(AstridApiConstants.PUBLIC_PREFS, Context.MODE_PRIVATE); - } - - private static String getSharedPreferencesName(Context context) { - return context.getPackageName() + "_preferences"; - } - - public boolean addTasksToTop() { - return getBoolean(R.string.p_add_to_top, true); - } - - public boolean backButtonSavesTask() { - return getBoolean(R.string.p_back_button_saves_task, false); - } - - public boolean isCurrentlyQuietHours() { - if (quietHoursEnabled()) { - DateTime dateTime = new DateTime(); - DateTime start = dateTime.withMillisOfDay(getQuietHoursStart()); - DateTime end = dateTime.withMillisOfDay(getQuietHoursEnd()); - if (start.isAfter(end)) { - return dateTime.isBefore(end) || dateTime.isAfter(start); - } else { - return dateTime.isAfter(start) && dateTime.isBefore(end); - } - } - return false; - } - - public long adjustForQuietHours(long time) { - if (quietHoursEnabled()) { - DateTime dateTime = new DateTime(time); - DateTime start = dateTime.withMillisOfDay(getQuietHoursStart()); - DateTime end = dateTime.withMillisOfDay(getQuietHoursEnd()); - if (start.isAfter(end)) { - if (dateTime.isBefore(end)) { - return end.getMillis(); - } else if (dateTime.isAfter(start)) { - return end.plusDays(1).getMillis(); - } - } else { - if (dateTime.isAfter(start) && dateTime.isBefore(end)) { - return end.getMillis(); - } - } - } - return time; - } - - private boolean quietHoursEnabled() { - return getBoolean(R.string.p_rmd_enable_quiet, false); - } - - public int getDefaultDueTime() { - return getInt(R.string.p_rmd_time, (int) TimeUnit.HOURS.toMillis(18)); - } - - private int getQuietHoursStart() { - return getMillisPerDayPref(R.string.p_rmd_quietStart, R.integer.default_quiet_hours_start); - } - - private int getQuietHoursEnd() { - return getMillisPerDayPref(R.string.p_rmd_quietEnd, R.integer.default_quiet_hours_end); - } - - public int getDateShortcutMorning() { - return getMillisPerDayPref(R.string.p_date_shortcut_morning, R.integer.default_morning); - } - - public int getDateShortcutAfternoon() { - return getMillisPerDayPref(R.string.p_date_shortcut_afternoon, R.integer.default_afternoon); - } - - public int getDateShortcutEvening() { - return getMillisPerDayPref(R.string.p_date_shortcut_evening, R.integer.default_evening); - } - - public Iterable getPurchases() { - try { - return transform( - prefs.getStringSet(context.getString(R.string.p_purchases), emptySet()), Purchase::new); - } catch (Exception e) { - Timber.e(e); - return emptySet(); - } - } - - public void setPurchases(Collection purchases) { - try { - Editor editor = prefs.edit(); - editor.putStringSet( - context.getString(R.string.p_purchases), - newHashSet(transform(purchases, Purchase::toJson))); - editor.apply(); - } catch (Exception e) { - Timber.e(e); - } - } - - public int getDateShortcutNight() { - return getMillisPerDayPref(R.string.p_date_shortcut_night, R.integer.default_night); - } - - private int getMillisPerDayPref(int resId, int defResId) { - int setting = getInt(resId, -1); - if (setting < 0 || setting > DateTime.MAX_MILLIS_PER_DAY) { - return context.getResources().getInteger(defResId); - } - return setting; - } - - public boolean isDefaultCalendarSet() { - String defaultCalendar = getDefaultCalendar(); - return defaultCalendar != null && !defaultCalendar.equals("-1") && !defaultCalendar.equals("0"); - } - - public Uri getRingtone() { - String ringtone = getStringValue(R.string.p_rmd_ringtone); - if (ringtone == null) { - return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - } - if ("".equals(ringtone)) { - return null; - } - return Uri.parse(ringtone); - } - - public boolean isTrackingEnabled() { - return getBoolean(R.string.p_collect_statistics, true); - } - - public String getDefaultCalendar() { - return getStringValue(R.string.gcal_p_default); - } - - public int getFirstDayOfWeek() { - int firstDayOfWeek = getIntegerFromString(R.string.p_start_of_week, 0); - return firstDayOfWeek < 1 || firstDayOfWeek > 7 ? 0 : firstDayOfWeek; - } - - @SuppressLint("ApplySharedPref") - public void clear() { - prefs.edit().clear().commit(); - } - - public void setDefaults() { - setDefaultValues(context, R.xml.preferences, true); - setDefaultValues(context, R.xml.preferences_look_and_feel, true); - setDefaultValues(context, R.xml.preferences_notifications, true); - setDefaultValues(context, R.xml.preferences_synchronization, true); - setDefaultValues(context, R.xml.preferences_task_defaults, true); - setDefaultValues(context, R.xml.preferences_date_and_time, true); - setDefaultValues(context, R.xml.preferences_navigation_drawer, true); - setDefaultValues(context, R.xml.preferences_backups, true); - setDefaultValues(context, R.xml.preferences_advanced, true); - setDefaultValues(context, R.xml.help_and_feedback, true); - - BeastModePreferences.setDefaultOrder(this, context); - } - - public void reset() { - clear(); - setDefaults(); - } - - public String getStringValue(String key) { - return prefs.getString(key, null); - } - - public @Nullable String getStringValue(int keyResource) { - return prefs.getString(context.getString(keyResource), null); - } - - public int getDefaultReminders() { - return getIntegerFromString( - R.string.p_default_reminders_key, Task.NOTIFY_AT_DEADLINE | Task.NOTIFY_AFTER_DEADLINE); - } - - public int getDefaultRingMode() { - return getIntegerFromString(R.string.p_default_reminders_mode_key, 0); - } - - public int getFontSize() { - return getInt(R.string.p_fontSize, 16); - } - - public int getIntegerFromString(int keyResource, int defaultValue) { - return getIntegerFromString(context.getString(keyResource), defaultValue); - } - - public int getIntegerFromString(String keyResource, int defaultValue) { - String value = prefs.getString(keyResource, null); - if (value == null) { - return defaultValue; - } - - try { - return Integer.parseInt(value); - } catch (Exception e) { - Timber.e(e); - return defaultValue; - } - } - - private Uri getUri(int key) { - String uri = getStringValue(key); - return isNullOrEmpty(uri) ? null : Uri.parse(uri); - } - - public void setUri(int key, java.net.URI uri) { - setString(key, uri.toString()); - } - - public void setUri(int key, Uri uri) { - setString(key, uri.toString()); - } - - public void setString(int key, String newValue) { - setString(context.getString(key), newValue); - } - - public void setString(String key, String newValue) { - Editor editor = prefs.edit(); - editor.putString(key, newValue); - editor.apply(); - } - - public void setStringFromInteger(int keyResource, int newValue) { - Editor editor = prefs.edit(); - editor.putString(context.getString(keyResource), Integer.toString(newValue)); - editor.apply(); - } - - public boolean getBoolean(String key, boolean defValue) { - try { - return prefs.getBoolean(key, defValue); - } catch (ClassCastException e) { - Timber.e(e); - return defValue; - } - } - - public boolean getBoolean(int keyResources, boolean defValue) { - return getBoolean(context.getString(keyResources), defValue); - } - - public void setBoolean(int keyResource, boolean value) { - setBoolean(context.getString(keyResource), value); - } - - public void setBoolean(String key, boolean value) { - Editor editor = prefs.edit(); - editor.putBoolean(key, value); - editor.apply(); - } - - public int getInt(int resourceId, int defValue) { - return getInt(context.getString(resourceId), defValue); - } - - public int getInt(String key, int defValue) { - return prefs.getInt(key, defValue); - } - - public void setInt(int resourceId, int value) { - setInt(context.getString(resourceId), value); - } - - public void setInt(String key, int value) { - Editor editor = prefs.edit(); - editor.putInt(key, value); - editor.apply(); - } - - public long getLong(int resourceId, long defValue) { - return getLong(context.getString(resourceId), defValue); - } - - public long getLong(String key, long defValue) { - return prefs.getLong(key, defValue); - } - - public void setLong(int resourceId, long value) { - setLong(context.getString(resourceId), value); - } - - public void setLong(String key, long value) { - Editor editor = prefs.edit(); - editor.putLong(key, value); - editor.apply(); - } - - public void clear(String key) { - Editor editor = prefs.edit(); - editor.remove(key); - editor.apply(); - } - - public int getLastSetVersion() { - return getInt(P_CURRENT_VERSION, 0); - } - - public void setCurrentVersion(int version) { - setInt(P_CURRENT_VERSION, version); - } - - public int getSortMode() { - return publicPrefs.getInt(PREF_SORT_SORT, SortHelper.SORT_AUTO); - } - - public void setSortMode(int value) { - setPublicPref(PREF_SORT_SORT, value); - } - - private void setPublicPref(String key, int value) { - if (publicPrefs != null) { - Editor edit = publicPrefs.edit(); - if (edit != null) { - edit.putInt(key, value).apply(); - } - } - } - - public @Nullable Uri getBackupDirectory() { - return getDirectory(R.string.p_backup_dir, "backups"); - } - - public @Nullable Uri getAttachmentsDirectory() { - return getDirectory(R.string.p_attachment_dir, TaskAttachment.FILES_DIRECTORY_DEFAULT); - } - - private @Nullable Uri getDirectory(int pref, String name) { - Uri uri = getUri(pref); - if (uri != null) { - switch (uri.getScheme()) { - case ContentResolver.SCHEME_FILE: - File file = new File(uri.getPath()); - try { - if (file.canWrite()) { - return uri; - } - } catch (SecurityException ignored) { - } - break; - case ContentResolver.SCHEME_CONTENT: - if (hasWritePermission(context, uri)) { - return uri; - } - break; - } - } - - DocumentFile documentFile = - DocumentFile.fromFile(context.getExternalFilesDir(null)).createDirectory(name); - if (documentFile != null) { - return documentFile.getUri(); - } - - File file = getDefaultFileLocation(name); - if (file != null) { - return Uri.fromFile(file); - } - return null; - } - - private @Nullable File getDefaultFileLocation(String type) { - File externalFilesDir = context.getExternalFilesDir(null); - if (externalFilesDir == null) { - return null; - } - String path = String.format("%s/%s", externalFilesDir.getAbsolutePath(), type); - File file = new File(path); - return file.isDirectory() || file.mkdirs() ? file : null; - } - - public Uri getCacheDirectory() { - File cacheDir = context.getExternalCacheDir(); - if (cacheDir == null) { - cacheDir = context.getCacheDir(); - } - - return DocumentFile.fromFile(cacheDir).getUri(); - } - - private boolean hasWritePermission(Context context, Uri uri) { - return PackageManager.PERMISSION_GRANTED - == context.checkUriPermission( - uri, - Binder.getCallingPid(), - Binder.getCallingUid(), - Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); - } - - public int getNotificationDefaults() { - int result = 0; - if (getBoolean(R.string.p_rmd_vibrate, true)) { - result |= NotificationCompat.DEFAULT_VIBRATE; - } - if (getBoolean(R.string.p_led_notification, true)) { - result |= NotificationCompat.DEFAULT_LIGHTS; - } - return result; - } - - public void remove(int resId) { - Editor editor = prefs.edit(); - editor.remove(context.getString(resId)); - editor.apply(); - } - - public boolean bundleNotifications() { - return getBoolean(R.string.p_bundle_notifications, true); - } - - public boolean usePersistentReminders() { - return getBoolean(R.string.p_rmd_persistent, true); - } - - public boolean isSyncOngoing() { - return getBoolean(R.string.p_sync_ongoing, false); - } - - public void setSyncOngoing(boolean value) { - setBoolean(R.string.p_sync_ongoing, value); - } - - public boolean useGoogleMaps() { - return getInt(R.string.p_map_provider, 0) == 1; - } - - public boolean useGooglePlaces() { - return getInt(R.string.p_place_provider, 0) == 1; - } - - public Map getPrefs(Class c) { - Map result = new HashMap<>(); - Iterable> entries = - filter(prefs.getAll().entrySet(), e -> c.isInstance(e.getValue())); - for (Entry entry : entries) { - result.put(entry.getKey(), (T) entry.getValue()); - } - return result; - } - - public boolean isFlipperEnabled() { - return BuildConfig.DEBUG && getBoolean(R.string.p_flipper, false); - } - - public boolean isPositionHackEnabled() { - return getLong(R.string.p_google_tasks_position_hack, 0) > 0; - } - - public boolean isManualSort() { - return getBoolean(R.string.p_manual_sort, false); - } - - public boolean isAstridSort() { - return getBoolean(R.string.p_astrid_sort_enabled, false) && getBoolean(R.string.p_astrid_sort, false); - } - - public boolean isReverseSort() { - return getBoolean(R.string.p_reverse_sort, false); - } - - public int getDefaultPriority() { - return getIntegerFromString(R.string.p_default_importance_key, Priority.LOW); - } - - public int getThemeBase() { - return getInt(R.string.p_theme, ThemeBase.DEFAULT_BASE_THEME); - } - - public boolean alreadyNotified(String account, String scope) { - return getBoolean(context.getString(R.string.p_notified_oauth_error, account, scope), false); - } - - public void setAlreadyNotified(String account, String scope, boolean value) { - setBoolean(context.getString(R.string.p_notified_oauth_error, account, scope), value); - } - - public int getDefaultThemeColor() { - return getInt(R.string.p_theme_color, ColorProvider.BLUE_500); - } - - public boolean usePagedQueries() { - return getBoolean(R.string.p_use_paged_queries, false); - } - - public boolean showGroupHeaders() { - return !usePagedQueries() && !getBoolean(R.string.p_disable_sort_groups, false); - } -} diff --git a/app/src/main/java/org/tasks/preferences/Preferences.kt b/app/src/main/java/org/tasks/preferences/Preferences.kt new file mode 100644 index 000000000..b4d1b9a14 --- /dev/null +++ b/app/src/main/java/org/tasks/preferences/Preferences.kt @@ -0,0 +1,482 @@ +package org.tasks.preferences + +import android.annotation.SuppressLint +import android.content.ContentResolver +import android.content.Context +import android.content.Intent +import android.content.SharedPreferences +import android.content.pm.PackageManager +import android.media.RingtoneManager +import android.net.Uri +import android.os.Binder +import androidx.core.app.NotificationCompat +import androidx.documentfile.provider.DocumentFile +import androidx.preference.PreferenceManager +import com.todoroo.astrid.activity.BeastModePreferences +import com.todoroo.astrid.api.AstridApiConstants +import com.todoroo.astrid.core.SortHelper +import com.todoroo.astrid.data.Task +import org.tasks.BuildConfig +import org.tasks.R +import org.tasks.Strings.isNullOrEmpty +import org.tasks.billing.Purchase +import org.tasks.data.TaskAttachment +import org.tasks.themes.ColorProvider +import org.tasks.themes.ThemeBase +import org.tasks.time.DateTime +import timber.log.Timber +import java.io.File +import java.net.URI +import java.util.* +import java.util.concurrent.TimeUnit + +class Preferences @JvmOverloads constructor(private val context: Context, name: String? = getSharedPreferencesName(context)) { + private val prefs: SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE) + private val publicPrefs: SharedPreferences = context.getSharedPreferences(AstridApiConstants.PUBLIC_PREFS, Context.MODE_PRIVATE) + + fun addTasksToTop(): Boolean { + return getBoolean(R.string.p_add_to_top, true) + } + + fun backButtonSavesTask(): Boolean { + return getBoolean(R.string.p_back_button_saves_task, false) + } + + val isCurrentlyQuietHours: Boolean + get() { + if (quietHoursEnabled()) { + val dateTime = DateTime() + val start = dateTime.withMillisOfDay(quietHoursStart) + val end = dateTime.withMillisOfDay(quietHoursEnd) + return if (start.isAfter(end)) { + dateTime.isBefore(end) || dateTime.isAfter(start) + } else { + dateTime.isAfter(start) && dateTime.isBefore(end) + } + } + return false + } + + fun adjustForQuietHours(time: Long): Long { + if (quietHoursEnabled()) { + val dateTime = DateTime(time) + val start = dateTime.withMillisOfDay(quietHoursStart) + val end = dateTime.withMillisOfDay(quietHoursEnd) + if (start.isAfter(end)) { + if (dateTime.isBefore(end)) { + return end.millis + } else if (dateTime.isAfter(start)) { + return end.plusDays(1).millis + } + } else { + if (dateTime.isAfter(start) && dateTime.isBefore(end)) { + return end.millis + } + } + } + return time + } + + private fun quietHoursEnabled(): Boolean { + return getBoolean(R.string.p_rmd_enable_quiet, false) + } + + val defaultDueTime: Int + get() = getInt(R.string.p_rmd_time, TimeUnit.HOURS.toMillis(18).toInt()) + + private val quietHoursStart: Int + get() = getMillisPerDayPref(R.string.p_rmd_quietStart, R.integer.default_quiet_hours_start) + + private val quietHoursEnd: Int + get() = getMillisPerDayPref(R.string.p_rmd_quietEnd, R.integer.default_quiet_hours_end) + + val dateShortcutMorning: Int + get() = getMillisPerDayPref(R.string.p_date_shortcut_morning, R.integer.default_morning) + + val dateShortcutAfternoon: Int + get() = getMillisPerDayPref(R.string.p_date_shortcut_afternoon, R.integer.default_afternoon) + + val dateShortcutEvening: Int + get() = getMillisPerDayPref(R.string.p_date_shortcut_evening, R.integer.default_evening) + + val purchases: List + get() = try { + prefs.getStringSet(context.getString(R.string.p_purchases), emptySet())!!.map(::Purchase) + } catch (e: Exception) { + Timber.e(e) + emptyList() + } + + fun setPurchases(purchases: Collection) { + try { + val editor = prefs.edit() + editor.putStringSet( + context.getString(R.string.p_purchases), + purchases.map(Purchase::toJson).toHashSet()) + editor.apply() + } catch (e: Exception) { + Timber.e(e) + } + } + + val dateShortcutNight: Int + get() = getMillisPerDayPref(R.string.p_date_shortcut_night, R.integer.default_night) + + private fun getMillisPerDayPref(resId: Int, defResId: Int): Int { + val setting = getInt(resId, -1) + return if (setting < 0 || setting > DateTime.MAX_MILLIS_PER_DAY) { + context.resources.getInteger(defResId) + } else setting + } + + val isDefaultCalendarSet: Boolean + get() { + val defaultCalendar = defaultCalendar + return defaultCalendar != null && defaultCalendar != "-1" && defaultCalendar != "0" + } + + val ringtone: Uri? + get() { + val ringtone = getStringValue(R.string.p_rmd_ringtone) + ?: return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION) + return if ("" == ringtone) { + null + } else Uri.parse(ringtone) + } + + val isTrackingEnabled: Boolean + get() = getBoolean(R.string.p_collect_statistics, true) + + val defaultCalendar: String? + get() = getStringValue(R.string.gcal_p_default) + + val firstDayOfWeek: Int + get() { + val firstDayOfWeek = getIntegerFromString(R.string.p_start_of_week, 0) + return if (firstDayOfWeek < 1 || firstDayOfWeek > 7) 0 else firstDayOfWeek + } + + @SuppressLint("ApplySharedPref") + fun clear() { + prefs.edit().clear().commit() + } + + fun setDefaults() { + PreferenceManager.setDefaultValues(context, R.xml.preferences, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_look_and_feel, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_notifications, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_synchronization, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_task_defaults, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_date_and_time, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_navigation_drawer, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_backups, true) + PreferenceManager.setDefaultValues(context, R.xml.preferences_advanced, true) + PreferenceManager.setDefaultValues(context, R.xml.help_and_feedback, true) + BeastModePreferences.setDefaultOrder(this, context) + } + + fun reset() { + clear() + setDefaults() + } + + fun getStringValue(key: String?): String? { + return prefs.getString(key, null) + } + + fun getStringValue(keyResource: Int): String? { + return prefs.getString(context.getString(keyResource), null) + } + + val defaultReminders: Int + get() = getIntegerFromString( + R.string.p_default_reminders_key, Task.NOTIFY_AT_DEADLINE or Task.NOTIFY_AFTER_DEADLINE) + + val defaultRingMode: Int + get() = getIntegerFromString(R.string.p_default_reminders_mode_key, 0) + + val fontSize: Int + get() = getInt(R.string.p_fontSize, 16) + + fun getIntegerFromString(keyResource: Int, defaultValue: Int): Int { + return getIntegerFromString(context.getString(keyResource), defaultValue) + } + + fun getIntegerFromString(keyResource: String?, defaultValue: Int): Int { + val value = prefs.getString(keyResource, null) ?: return defaultValue + return try { + value.toInt() + } catch (e: Exception) { + Timber.e(e) + defaultValue + } + } + + private fun getUri(key: Int): Uri? { + val uri = getStringValue(key) + return if (isNullOrEmpty(uri)) null else Uri.parse(uri) + } + + fun setUri(key: Int, uri: URI) { + setString(key, uri.toString()) + } + + fun setUri(key: Int, uri: Uri) { + setString(key, uri.toString()) + } + + fun setString(key: Int, newValue: String?) { + setString(context.getString(key), newValue) + } + + fun setString(key: String?, newValue: String?) { + val editor = prefs.edit() + editor.putString(key, newValue) + editor.apply() + } + + fun setStringFromInteger(keyResource: Int, newValue: Int) { + val editor = prefs.edit() + editor.putString(context.getString(keyResource), newValue.toString()) + editor.apply() + } + + fun getBoolean(key: String?, defValue: Boolean): Boolean { + return try { + prefs.getBoolean(key, defValue) + } catch (e: ClassCastException) { + Timber.e(e) + defValue + } + } + + fun getBoolean(keyResources: Int, defValue: Boolean): Boolean { + return getBoolean(context.getString(keyResources), defValue) + } + + fun setBoolean(keyResource: Int, value: Boolean) { + setBoolean(context.getString(keyResource), value) + } + + fun setBoolean(key: String?, value: Boolean) { + val editor = prefs.edit() + editor.putBoolean(key, value) + editor.apply() + } + + fun getInt(resourceId: Int, defValue: Int): Int { + return getInt(context.getString(resourceId), defValue) + } + + fun getInt(key: String?, defValue: Int): Int { + return prefs.getInt(key, defValue) + } + + fun setInt(resourceId: Int, value: Int) { + setInt(context.getString(resourceId), value) + } + + fun setInt(key: String?, value: Int) { + val editor = prefs.edit() + editor.putInt(key, value) + editor.apply() + } + + fun getLong(resourceId: Int, defValue: Long): Long { + return getLong(context.getString(resourceId), defValue) + } + + fun getLong(key: String?, defValue: Long): Long { + return prefs.getLong(key, defValue) + } + + fun setLong(resourceId: Int, value: Long) { + setLong(context.getString(resourceId), value) + } + + fun setLong(key: String?, value: Long) { + val editor = prefs.edit() + editor.putLong(key, value) + editor.apply() + } + + fun clear(key: String?) { + val editor = prefs.edit() + editor.remove(key) + editor.apply() + } + + val lastSetVersion: Int + get() = getInt(P_CURRENT_VERSION, 0) + + fun setCurrentVersion(version: Int) { + setInt(P_CURRENT_VERSION, version) + } + + var sortMode: Int + get() = publicPrefs.getInt(PREF_SORT_SORT, SortHelper.SORT_AUTO) + set(value) { + setPublicPref(PREF_SORT_SORT, value) + } + + private fun setPublicPref(key: String, value: Int) { + val edit = publicPrefs.edit() + edit?.putInt(key, value)?.apply() + } + + val backupDirectory: Uri? + get() = getDirectory(R.string.p_backup_dir, "backups") + + val attachmentsDirectory: Uri? + get() = getDirectory(R.string.p_attachment_dir, TaskAttachment.FILES_DIRECTORY_DEFAULT) + + private fun getDirectory(pref: Int, name: String): Uri? { + val uri = getUri(pref) + if (uri != null) { + when (uri.scheme) { + ContentResolver.SCHEME_FILE -> { + val file = File(uri.path) + try { + if (file.canWrite()) { + return uri + } + } catch (ignored: SecurityException) { + } + } + ContentResolver.SCHEME_CONTENT -> if (hasWritePermission(context, uri)) { + return uri + } + } + } + val documentFile = DocumentFile.fromFile(context.getExternalFilesDir(null)!!).createDirectory(name) + if (documentFile != null) { + return documentFile.uri + } + val file = getDefaultFileLocation(name) + return if (file != null) { + Uri.fromFile(file) + } else null + } + + private fun getDefaultFileLocation(type: String): File? { + val externalFilesDir = context.getExternalFilesDir(null) ?: return null + val path = String.format("%s/%s", externalFilesDir.absolutePath, type) + val file = File(path) + return if (file.isDirectory || file.mkdirs()) file else null + } + + val cacheDirectory: Uri + get() { + var cacheDir = context.externalCacheDir + if (cacheDir == null) { + cacheDir = context.cacheDir + } + return DocumentFile.fromFile(cacheDir!!).uri + } + + private fun hasWritePermission(context: Context, uri: Uri): Boolean { + return (PackageManager.PERMISSION_GRANTED + == context.checkUriPermission( + uri, + Binder.getCallingPid(), + Binder.getCallingUid(), + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) + } + + val notificationDefaults: Int + get() { + var result = 0 + if (getBoolean(R.string.p_rmd_vibrate, true)) { + result = result or NotificationCompat.DEFAULT_VIBRATE + } + if (getBoolean(R.string.p_led_notification, true)) { + result = result or NotificationCompat.DEFAULT_LIGHTS + } + return result + } + + fun remove(resId: Int) { + val editor = prefs.edit() + editor.remove(context.getString(resId)) + editor.apply() + } + + fun bundleNotifications(): Boolean { + return getBoolean(R.string.p_bundle_notifications, true) + } + + fun usePersistentReminders(): Boolean { + return getBoolean(R.string.p_rmd_persistent, true) + } + + var isSyncOngoing: Boolean + get() = getBoolean(R.string.p_sync_ongoing, false) + set(value) { + setBoolean(R.string.p_sync_ongoing, value) + } + + fun useGoogleMaps(): Boolean { + return getInt(R.string.p_map_provider, 0) == 1 + } + + fun useGooglePlaces(): Boolean { + return getInt(R.string.p_place_provider, 0) == 1 + } + + fun getPrefs(c: Class): Map { + val result: MutableMap = HashMap() + val entries: Iterable> = prefs.all.entries.filter { e: Map.Entry -> c.isInstance(e.value) } + for ((key, value) in entries) { + result[key] = value as T + } + return result + } + + val isFlipperEnabled: Boolean + get() = BuildConfig.DEBUG && getBoolean(R.string.p_flipper, false) + + val isPositionHackEnabled: Boolean + get() = getLong(R.string.p_google_tasks_position_hack, 0) > 0 + + val isManualSort: Boolean + get() = getBoolean(R.string.p_manual_sort, false) + + val isAstridSort: Boolean + get() = getBoolean(R.string.p_astrid_sort_enabled, false) && getBoolean(R.string.p_astrid_sort, false) + + val isReverseSort: Boolean + get() = getBoolean(R.string.p_reverse_sort, false) + + val defaultPriority: Int + get() = getIntegerFromString(R.string.p_default_importance_key, Task.Priority.LOW) + + val themeBase: Int + get() = getInt(R.string.p_theme, ThemeBase.DEFAULT_BASE_THEME) + + fun alreadyNotified(account: String?, scope: String?): Boolean { + return getBoolean(context.getString(R.string.p_notified_oauth_error, account, scope), false) + } + + fun setAlreadyNotified(account: String?, scope: String?, value: Boolean) { + setBoolean(context.getString(R.string.p_notified_oauth_error, account, scope), value) + } + + val defaultThemeColor: Int + get() = getInt(R.string.p_theme_color, ColorProvider.BLUE_500) + + fun usePagedQueries(): Boolean { + return getBoolean(R.string.p_use_paged_queries, false) + } + + fun showGroupHeaders(): Boolean { + return !usePagedQueries() && !getBoolean(R.string.p_disable_sort_groups, false) + } + + companion object { + const val P_CURRENT_VERSION = "cv" // $NON-NLS-1$ + private const val PREF_SORT_SORT = "sort_sort" // $NON-NLS-1$ + private fun getSharedPreferencesName(context: Context): String { + return context.packageName + "_preferences" + } + } +} \ No newline at end of file