From 488fd6f044c6d43e3c67d38468b0eba366850d54 Mon Sep 17 00:00:00 2001 From: razeeman Date: Sun, 22 Sep 2024 10:53:34 +0300 Subject: [PATCH] add prefs to backup --- .../data_local/repo/PrefsRepoImpl.kt | 209 +++++++---------- .../data_local/resolver/BackupPrefsRepo.kt | 215 ++++++++++++++++++ .../data_local/resolver/BackupRepoImpl.kt | 9 + .../data_local/utils/PrefsUtils.kt | 3 + .../domain/interactor/PrefsInteractor.kt | 39 +++- .../domain/repo/PrefsRepo.kt | 18 +- .../viewModel/BackupViewModel.kt | 2 +- 7 files changed, 352 insertions(+), 143 deletions(-) create mode 100644 data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupPrefsRepo.kt diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/PrefsRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/PrefsRepoImpl.kt index 4f7ff1cad..3f135b7f3 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/PrefsRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/repo/PrefsRepoImpl.kt @@ -3,7 +3,6 @@ package com.example.util.simpletimetracker.data_local.repo import android.content.SharedPreferences import com.example.util.simpletimetracker.data_local.utils.delegate import com.example.util.simpletimetracker.data_local.utils.logPrefsDataAccess -import com.example.util.simpletimetracker.domain.extension.orZero import com.example.util.simpletimetracker.domain.model.ChartFilterType import com.example.util.simpletimetracker.domain.model.QuickSettingsWidgetType import com.example.util.simpletimetracker.domain.model.RangeLength @@ -57,6 +56,18 @@ class PrefsRepoImpl @Inject constructor( KEY_TAG_ORDER, 3, // Default to activity sort. ) + override var cardOrderManual: Set by prefs.delegate( + KEY_CARD_ORDER_MANUAL, emptySet(), + ) + + override var categoryOrderManual: Set by prefs.delegate( + KEY_CATEGORY_ORDER_MANUAL, emptySet(), + ) + + override var tagOrderManual: Set by prefs.delegate( + KEY_TAG_ORDER_MANUAL, emptySet(), + ) + override var statisticsRange: Int by prefs.delegate( KEY_STATISTICS_RANGE, 0, ) @@ -453,30 +464,6 @@ class PrefsRepoImpl @Inject constructor( prefs.edit().remove(key).apply() } - override fun setCardOrderManual(cardOrder: Map) { - setOrderManual(KEY_CARD_ORDER_MANUAL, cardOrder) - } - - override fun getCardOrderManual(): Map { - return getOrderManual(KEY_CARD_ORDER_MANUAL) - } - - override fun setCategoryOrderManual(cardOrder: Map) { - setOrderManual(KEY_CATEGORY_ORDER_MANUAL, cardOrder) - } - - override fun getCategoryOrderManual(): Map { - return getOrderManual(KEY_CATEGORY_ORDER_MANUAL) - } - - override fun setTagOrderManual(cardOrder: Map) { - setOrderManual(KEY_TAG_ORDER_MANUAL, cardOrder) - } - - override fun getTagOrderManual(): Map { - return getOrderManual(KEY_TAG_ORDER_MANUAL) - } - override fun clear() { prefs.edit().clear().apply() } @@ -492,120 +479,97 @@ class PrefsRepoImpl @Inject constructor( prefs.edit().remove(KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK).apply() } - private fun setOrderManual( - key: String, - cardOrder: Map, - ) { - logPrefsDataAccess("set $key") - val set = cardOrder.map { (typeId, order) -> - "$typeId$CARDS_ORDER_DELIMITER${order.toShort()}" - }.toSet() - - prefs.edit().putStringSet(key, set).apply() - } - - private fun getOrderManual( - key: String, - ): Map { - logPrefsDataAccess("get $key") - val set = prefs.getStringSet(key, emptySet()) - - return set - ?.map { string -> - string.split(CARDS_ORDER_DELIMITER).let { parts -> - parts.getOrNull(0).orEmpty() to parts.getOrNull(1).orEmpty() - } - } - ?.toMap() - ?.mapKeys { it.key.toLongOrNull().orZero() } - ?.mapValues { it.value.toLongOrNull().orZero() } - ?: emptyMap() + override fun hasValueSaved(key: String): Boolean { + return prefs.contains(key) } @Suppress("unused") companion object { private const val DO_NOT_DISTURB_PERIOD_START: Long = 0 // midnight private const val DO_NOT_DISTURB_PERIOD_END: Long = 1000 * 60 * 60 * 8 // 8 hours in the morning - private const val CARDS_ORDER_DELIMITER = "_" private const val POMODORO_DEFAULT_FOCUS_TIME_SEC: Long = 60 * 25 // 25 min private const val POMODORO_DEFAULT_BREAK_TIME_SEC: Long = 60 * 5 // 5 min private const val POMODORO_DEFAULT_LONG_BREAK_TIME_SEC: Long = 60 * 15 // 15 min private const val POMODORO_DEFAULT_UNTIL_LONG_BREAK: Long = 4 private const val RANGE_LAST_DAYS_DEFAULT: Int = 7 - private const val KEY_RECORD_TYPES_FILTERED_ON_LIST = "recordTypesFilteredOnList" - private const val KEY_RECORD_TYPES_FILTERED_ON_CHART = "recordTypesFilteredOnChart" - private const val KEY_CATEGORIES_TYPES_FILTERED_ON_CHART = "categoriesFilteredOnChart" - private const val KEY_TAGS_FILTERED_ON_CHART = "tagsFilteredOnChart" - private const val KEY_CHART_FILTER_TYPE = "chartFilterType" - private const val KEY_CARD_ORDER = "cardOrder" - private const val KEY_CATEGORY_ORDER = "categoryOrder" - private const val KEY_TAG_ORDER = "tagOrder" - private const val KEY_STATISTICS_RANGE = "statisticsRange" - private const val KEY_STATISTICS_RANGE_CUSTOM_START = "statisticsRangeCustomStart" - private const val KEY_STATISTICS_RANGE_CUSTOM_END = "statisticsRangeCustomEnd" - private const val KEY_STATISTICS_RANGE_LAST_DAYS = "statisticsRangeLastDays" - private const val KEY_STATISTICS_DETAIL_RANGE = "statisticsDetailRange" - private const val KEY_STATISTICS_DETAIL_RANGE_CUSTOM_START = "statisticsDetailRangeCustomStart" - private const val KEY_STATISTICS_DETAIL_RANGE_CUSTOM_END = "statisticsDetailRangeCustomEnd" - private const val KEY_STATISTICS_DETAIL_RANGE_LAST_DAYS = "statisticsDetailRangeLastDays" - private const val KEY_KEEP_STATISTICS_RANGE = "keepStatisticsRange" - private const val KEY_FIRST_DAY_OF_WEEK = "firstDayOfWeek" - private const val KEY_START_OF_DAY_SHIFT = "startOfDayShift" - private const val KEY_SHOW_UNTRACKED_IN_RECORDS = "showUntrackedInRecords" - private const val KEY_SHOW_UNTRACKED_IN_STATISTICS = "showUntrackedInStatistics" - private const val KEY_SHOW_RECORDS_CALENDAR = "showRecordsCalendar" - private const val KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB = "showCalendarButtonOnRecordsTab" - private const val KEY_REVERSE_ORDER_IN_CALENDAR = "reverseOrderInCalendar" - private const val KEY_DAYS_IN_CALENDAR = "daysInCalendar" - private const val KEY_SHOW_ACTIVITY_FILTERS = "showActivityFilters" - private const val KEY_ENABLE_REPEAT_BUTTON = "enableRepeatButton" - private const val KEY_ENABLE_POMODORO_MODE = "enablePomodoroMode" - private const val KEY_POMODORO_MODE_STARTED_TIMESTAMP = "pomodoroModeStartedTimestamp" - private const val KEY_POMODORO_FOCUS_TIME = "pomodoroFocusTime" - private const val KEY_POMODORO_BREAK_TIME = "pomodoroBreakTime" - private const val KEY_POMODORO_LONG_BREAK_TIME = "pomodoroLongBreakTime" - private const val KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK = "pomodoroPeriodsUntilLongBreak" - private const val KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS = "allowMultipleActivityFilters" - private const val KEY_SHOW_GOALS_SEPARATELY = "showGoalsSeparately" - private const val KEY_ALLOW_MULTITASKING = "allowMultitasking" - private const val KEY_SHOW_NOTIFICATIONS = "showNotifications" - private const val KEY_SHOW_NOTIFICATIONS_CONTROLS = "showNotificationsControls" - private const val KEY_INACTIVITY_REMINDER_DURATION = "inactivityReminderDuration" - private const val KEY_INACTIVITY_REMINDER_RECURRENT = "inactivityReminderRecurrent" - private const val KEY_INACTIVITY_REMINDER_DND_START = "inactivityReminderDndStart" - private const val KEY_INACTIVITY_REMINDER_DND_END = "inactivityReminderDndEnd" - private const val KEY_ACTIVITY_REMINDER_DURATION = "activityReminderDuration" - private const val KEY_ACTIVITY_REMINDER_RECURRENT = "activityReminderRecurrent" - private const val KEY_ACTIVITY_REMINDER_DND_START = "activityReminderDndStart" - private const val KEY_ACTIVITY_REMINDER_DND_END = "activityReminderDndEnd" - private const val KEY_IGNORE_SHORT_RECORDS_DURATION = "ignoreShortRecordsDuration" - private const val KEY_IGNORE_SHORT_UNTRACKED_DURATION = "ignoreShortUntrackedDuration" - private const val KEY_UNTRACKED_RANGE_ENABLED = "untrackedRangeEnabled" - private const val KEY_UNTRACKED_RANGE_START = "untrackedRangeStart" - private const val KEY_UNTRACKED_RANGE_END = "untrackedRangeEnd" - private const val KEY_DARK_MODE_2 = "darkMode2" - private const val KEY_NUMBER_OF_CARDS = "numberOfCards" // 0 - default width - private const val KEY_USE_MILITARY_TIME_FORMAT = "useMilitaryTimeFormat" - private const val KEY_USE_MONTH_DAY_TIME_FORMAT = "useMonthDayTimeFormat" - private const val KEY_USE_PROPORTIONAL_MINUTES = "useProportionalMinutes" - private const val KEY_SHOW_SECONDS = "showSeconds" - private const val KEY_KEEP_SCREEN_ON = "keepScreenOn" - private const val KEY_SHOW_RECORD_TAG_SELECTION = "showRecordTagSelection" - private const val KEY_SHOW_RECORD_TAG_SELECTION_EXCLUDE_ACTIVITIES = "showRecordTagSelectionExcludeActivities" - private const val KEY_AUTOSTART_POMODORO_ACTIVITIES = "autostartPomodoroActivities" - private const val KEY_RECORD_TAG_SELECTION_CLOSE_AFTER_ONE = "recordTagSelectionCloseAfterOne" - private const val KEY_AUTOMATED_TRACKING_SEND_EVENTS = "automatedTrackingSendEvents" + const val KEY_RECORD_TYPES_FILTERED_ON_LIST = "recordTypesFilteredOnList" + const val KEY_RECORD_TYPES_FILTERED_ON_CHART = "recordTypesFilteredOnChart" + const val KEY_CATEGORIES_TYPES_FILTERED_ON_CHART = "categoriesFilteredOnChart" + const val KEY_TAGS_FILTERED_ON_CHART = "tagsFilteredOnChart" + const val KEY_CHART_FILTER_TYPE = "chartFilterType" + const val KEY_CARD_ORDER = "cardOrder" + const val KEY_CATEGORY_ORDER = "categoryOrder" + const val KEY_TAG_ORDER = "tagOrder" + const val KEY_STATISTICS_RANGE = "statisticsRange" + const val KEY_STATISTICS_RANGE_CUSTOM_START = "statisticsRangeCustomStart" + const val KEY_STATISTICS_RANGE_CUSTOM_END = "statisticsRangeCustomEnd" + const val KEY_STATISTICS_RANGE_LAST_DAYS = "statisticsRangeLastDays" + const val KEY_STATISTICS_DETAIL_RANGE = "statisticsDetailRange" + const val KEY_STATISTICS_DETAIL_RANGE_CUSTOM_START = "statisticsDetailRangeCustomStart" + const val KEY_STATISTICS_DETAIL_RANGE_CUSTOM_END = "statisticsDetailRangeCustomEnd" + const val KEY_STATISTICS_DETAIL_RANGE_LAST_DAYS = "statisticsDetailRangeLastDays" + const val KEY_KEEP_STATISTICS_RANGE = "keepStatisticsRange" + const val KEY_FIRST_DAY_OF_WEEK = "firstDayOfWeek" + const val KEY_START_OF_DAY_SHIFT = "startOfDayShift" + const val KEY_SHOW_UNTRACKED_IN_RECORDS = "showUntrackedInRecords" + const val KEY_SHOW_UNTRACKED_IN_STATISTICS = "showUntrackedInStatistics" + const val KEY_SHOW_RECORDS_CALENDAR = "showRecordsCalendar" + const val KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB = "showCalendarButtonOnRecordsTab" + const val KEY_REVERSE_ORDER_IN_CALENDAR = "reverseOrderInCalendar" + const val KEY_DAYS_IN_CALENDAR = "daysInCalendar" + const val KEY_SHOW_ACTIVITY_FILTERS = "showActivityFilters" + const val KEY_ENABLE_REPEAT_BUTTON = "enableRepeatButton" + const val KEY_ENABLE_POMODORO_MODE = "enablePomodoroMode" + const val KEY_POMODORO_FOCUS_TIME = "pomodoroFocusTime" + const val KEY_POMODORO_BREAK_TIME = "pomodoroBreakTime" + const val KEY_POMODORO_LONG_BREAK_TIME = "pomodoroLongBreakTime" + const val KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK = "pomodoroPeriodsUntilLongBreak" + const val KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS = "allowMultipleActivityFilters" + const val KEY_SHOW_GOALS_SEPARATELY = "showGoalsSeparately" + const val KEY_ALLOW_MULTITASKING = "allowMultitasking" + const val KEY_SHOW_NOTIFICATIONS = "showNotifications" + const val KEY_SHOW_NOTIFICATIONS_CONTROLS = "showNotificationsControls" + const val KEY_INACTIVITY_REMINDER_DURATION = "inactivityReminderDuration" + const val KEY_INACTIVITY_REMINDER_RECURRENT = "inactivityReminderRecurrent" + const val KEY_INACTIVITY_REMINDER_DND_START = "inactivityReminderDndStart" + const val KEY_INACTIVITY_REMINDER_DND_END = "inactivityReminderDndEnd" + const val KEY_ACTIVITY_REMINDER_DURATION = "activityReminderDuration" + const val KEY_ACTIVITY_REMINDER_RECURRENT = "activityReminderRecurrent" + const val KEY_ACTIVITY_REMINDER_DND_START = "activityReminderDndStart" + const val KEY_ACTIVITY_REMINDER_DND_END = "activityReminderDndEnd" + const val KEY_IGNORE_SHORT_RECORDS_DURATION = "ignoreShortRecordsDuration" + const val KEY_IGNORE_SHORT_UNTRACKED_DURATION = "ignoreShortUntrackedDuration" + const val KEY_UNTRACKED_RANGE_ENABLED = "untrackedRangeEnabled" + const val KEY_UNTRACKED_RANGE_START = "untrackedRangeStart" + const val KEY_UNTRACKED_RANGE_END = "untrackedRangeEnd" + const val KEY_DARK_MODE_2 = "darkMode2" + const val KEY_NUMBER_OF_CARDS = "numberOfCards" // 0 - default width + const val KEY_USE_MILITARY_TIME_FORMAT = "useMilitaryTimeFormat" + const val KEY_USE_MONTH_DAY_TIME_FORMAT = "useMonthDayTimeFormat" + const val KEY_USE_PROPORTIONAL_MINUTES = "useProportionalMinutes" + const val KEY_SHOW_SECONDS = "showSeconds" + const val KEY_KEEP_SCREEN_ON = "keepScreenOn" + const val KEY_SHOW_RECORD_TAG_SELECTION = "showRecordTagSelection" + const val KEY_SHOW_RECORD_TAG_SELECTION_EXCLUDE_ACTIVITIES = "showRecordTagSelectionExcludeActivities" + const val KEY_AUTOSTART_POMODORO_ACTIVITIES = "autostartPomodoroActivities" + const val KEY_RECORD_TAG_SELECTION_CLOSE_AFTER_ONE = "recordTagSelectionCloseAfterOne" + const val KEY_AUTOMATED_TRACKING_SEND_EVENTS = "automatedTrackingSendEvents" + const val KEY_REPEAT_BUTTON_TYPE = "repeatButtonType" + const val KEY_WIDGET_TRANSPARENCY_PERCENT = "widgetTransparencyPercent" + const val KEY_DEFAULT_TYPES_HIDDEN = "defaultTypesHidden" + const val KEY_IS_NAV_BAR_AT_THE_BOTTOM = "isNavBarAtTheBottom" + const val KEY_CARD_ORDER_MANUAL = "cardOrderManual" + const val KEY_CATEGORY_ORDER_MANUAL = "categoryOrderManual" + const val KEY_TAG_ORDER_MANUAL = "tagOrderManual" + private const val KEY_AUTOMATIC_BACKUP_URI = "automaticBackupUri" private const val KEY_AUTOMATIC_BACKUP_ERROR = "automaticBackupError" private const val KEY_AUTOMATIC_BACKUP_LAST_SAVE_TIME = "automaticBackupLastSaveTime" private const val KEY_AUTOMATIC_EXPORT_URI = "automaticExportUri" private const val KEY_AUTOMATIC_EXPORT_ERROR = "automaticExportError" private const val KEY_AUTOMATIC_EXPORT_LAST_SAVE_TIME = "automaticExportLastSaveTime" - private const val KEY_REPEAT_BUTTON_TYPE = "repeatButtonType" - private const val KEY_WIDGET_TRANSPARENCY_PERCENT = "widgetTransparencyPercent" - private const val KEY_DEFAULT_TYPES_HIDDEN = "defaultTypesHidden" - private const val KEY_IS_NAV_BAR_AT_THE_BOTTOM = "isNavBarAtTheBottom" + private const val KEY_POMODORO_MODE_STARTED_TIMESTAMP = "pomodoroModeStartedTimestamp" private const val KEY_WIDGET = "widget_" private const val KEY_STATISTICS_WIDGET_FILTERED_TYPES = "statistics_widget_filtered_types_" private const val KEY_STATISTICS_WIDGET_FILTERED_CATEGORIES = "statistics_widget_filtered_categories_" @@ -614,9 +578,6 @@ class PrefsRepoImpl @Inject constructor( private const val KEY_STATISTICS_WIDGET_RANGE = "statistics_widget_range_" private const val KEY_STATISTICS_WIDGET_RANGE_LAST_DAYS = "statistics_widget_range_last_days_" private const val KEY_QUICK_SETTINGS_WIDGET_TYPE = "quick_settings_widget_type_" - private const val KEY_CARD_ORDER_MANUAL = "cardOrderManual" - private const val KEY_CATEGORY_ORDER_MANUAL = "categoryOrderManual" - private const val KEY_TAG_ORDER_MANUAL = "tagOrderManual" // Removed private const val KEY_SORT_RECORD_TYPES_BY_COLOR = "sortRecordTypesByColor" // Boolean diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupPrefsRepo.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupPrefsRepo.kt new file mode 100644 index 000000000..f811341d1 --- /dev/null +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupPrefsRepo.kt @@ -0,0 +1,215 @@ +package com.example.util.simpletimetracker.data_local.resolver + +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ACTIVITY_REMINDER_DND_END +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ACTIVITY_REMINDER_DND_START +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ACTIVITY_REMINDER_DURATION +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ACTIVITY_REMINDER_RECURRENT +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ALLOW_MULTITASKING +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_AUTOMATED_TRACKING_SEND_EVENTS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_AUTOSTART_POMODORO_ACTIVITIES +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CARD_ORDER +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CARD_ORDER_MANUAL +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CATEGORIES_TYPES_FILTERED_ON_CHART +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CATEGORY_ORDER +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CATEGORY_ORDER_MANUAL +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_CHART_FILTER_TYPE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_DARK_MODE_2 +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_DAYS_IN_CALENDAR +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_DEFAULT_TYPES_HIDDEN +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ENABLE_POMODORO_MODE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_ENABLE_REPEAT_BUTTON +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_FIRST_DAY_OF_WEEK +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_IGNORE_SHORT_RECORDS_DURATION +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_IGNORE_SHORT_UNTRACKED_DURATION +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_DND_END +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_DND_START +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_DURATION +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_INACTIVITY_REMINDER_RECURRENT +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_IS_NAV_BAR_AT_THE_BOTTOM +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_KEEP_SCREEN_ON +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_KEEP_STATISTICS_RANGE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_NUMBER_OF_CARDS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_POMODORO_BREAK_TIME +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_POMODORO_FOCUS_TIME +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_POMODORO_LONG_BREAK_TIME +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RECORD_TAG_SELECTION_CLOSE_AFTER_ONE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RECORD_TYPES_FILTERED_ON_CHART +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_RECORD_TYPES_FILTERED_ON_LIST +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_REPEAT_BUTTON_TYPE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_REVERSE_ORDER_IN_CALENDAR +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_ACTIVITY_FILTERS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_GOALS_SEPARATELY +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_NOTIFICATIONS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_NOTIFICATIONS_CONTROLS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_RECORDS_CALENDAR +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_RECORD_TAG_SELECTION +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_RECORD_TAG_SELECTION_EXCLUDE_ACTIVITIES +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_SECONDS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_UNTRACKED_IN_RECORDS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_SHOW_UNTRACKED_IN_STATISTICS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_START_OF_DAY_SHIFT +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_DETAIL_RANGE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_DETAIL_RANGE_CUSTOM_END +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_DETAIL_RANGE_CUSTOM_START +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_DETAIL_RANGE_LAST_DAYS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_RANGE +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_RANGE_CUSTOM_END +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_RANGE_CUSTOM_START +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_STATISTICS_RANGE_LAST_DAYS +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_TAGS_FILTERED_ON_CHART +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_TAG_ORDER +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_TAG_ORDER_MANUAL +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_UNTRACKED_RANGE_ENABLED +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_UNTRACKED_RANGE_END +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_UNTRACKED_RANGE_START +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_USE_MILITARY_TIME_FORMAT +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_USE_MONTH_DAY_TIME_FORMAT +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_USE_PROPORTIONAL_MINUTES +import com.example.util.simpletimetracker.data_local.repo.PrefsRepoImpl.Companion.KEY_WIDGET_TRANSPARENCY_PERCENT +import javax.inject.Inject +import kotlin.reflect.KMutableProperty0 + +class BackupPrefsRepo @Inject constructor( + private val prefsRepoImpl: PrefsRepoImpl, +) { + + fun saveToBackupString(): String = runCatching { + val result = StringBuilder() + + getProcessorsList().filter { + prefsRepoImpl.hasValueSaved(it.key) + }.forEach { processor -> + val valueString: String = when (val value = processor.getter()) { + is Boolean -> if (value) "1" else "0" + is Int -> value.toString() + is Long -> value.toString() + is String -> value + is Set<*> -> value.joinToString(separator = ",") + else -> null + } ?: return@forEach + + result + .append(PREFS_KEY).append("\t") + .append(processor.key).append("\t") + .append(valueString).append("\n") + } + + return result.toString() + }.getOrNull().orEmpty() + + fun restoreFromBackupString(parts: List) = runCatching { + val processors = getProcessorsList().associateBy { it.key } + val processor = parts.getOrNull(1)?.let(processors::get) ?: return@runCatching + val valueString: String = parts.getOrNull(2) ?: return@runCatching + val currentValue: Any = processor.getter() + + val value: Any = when (currentValue) { + is Boolean -> valueString.toIntOrNull() == 1 + is Int -> valueString.toIntOrNull() + is Long -> valueString.toLongOrNull() + is String -> valueString + is Set<*> -> valueString.split(',').toSet() + else -> null + } ?: return@runCatching + + processor.setter(value) + } + + private fun getProcessorsList(): List> = with(prefsRepoImpl) { + return listOf( + PrefsProcessor(KEY_RECORD_TYPES_FILTERED_ON_LIST, ::recordTypesFilteredOnList), + PrefsProcessor(KEY_RECORD_TYPES_FILTERED_ON_CHART, ::recordTypesFilteredOnChart), + PrefsProcessor(KEY_CATEGORIES_TYPES_FILTERED_ON_CHART, ::categoriesFilteredOnChart), + PrefsProcessor(KEY_TAGS_FILTERED_ON_CHART, ::tagsFilteredOnChart), + PrefsProcessor(KEY_CHART_FILTER_TYPE, ::chartFilterType), + PrefsProcessor(KEY_CARD_ORDER, ::cardOrder), + PrefsProcessor(KEY_CATEGORY_ORDER, ::categoryOrder), + PrefsProcessor(KEY_TAG_ORDER, ::tagOrder), + PrefsProcessor(KEY_CARD_ORDER_MANUAL, ::cardOrderManual), + PrefsProcessor(KEY_CATEGORY_ORDER_MANUAL, ::categoryOrderManual), + PrefsProcessor(KEY_TAG_ORDER_MANUAL, ::tagOrderManual), + PrefsProcessor(KEY_STATISTICS_RANGE, ::statisticsRange), + PrefsProcessor(KEY_STATISTICS_RANGE_CUSTOM_START, ::statisticsRangeCustomStart), + PrefsProcessor(KEY_STATISTICS_RANGE_CUSTOM_END, ::statisticsRangeCustomEnd), + PrefsProcessor(KEY_STATISTICS_RANGE_LAST_DAYS, ::statisticsRangeLastDays), + PrefsProcessor(KEY_STATISTICS_DETAIL_RANGE, ::statisticsDetailRange), + PrefsProcessor(KEY_STATISTICS_DETAIL_RANGE_CUSTOM_START, ::statisticsDetailRangeCustomStart), + PrefsProcessor(KEY_STATISTICS_DETAIL_RANGE_CUSTOM_END, ::statisticsDetailRangeCustomEnd), + PrefsProcessor(KEY_STATISTICS_DETAIL_RANGE_LAST_DAYS, ::statisticsDetailRangeLastDays), + PrefsProcessor(KEY_KEEP_STATISTICS_RANGE, ::keepStatisticsRange), + PrefsProcessor(KEY_FIRST_DAY_OF_WEEK, ::firstDayOfWeek), + PrefsProcessor(KEY_START_OF_DAY_SHIFT, ::startOfDayShift), + PrefsProcessor(KEY_SHOW_UNTRACKED_IN_RECORDS, ::showUntrackedInRecords), + PrefsProcessor(KEY_SHOW_UNTRACKED_IN_STATISTICS, ::showUntrackedInStatistics), + PrefsProcessor(KEY_SHOW_RECORDS_CALENDAR, ::showRecordsCalendar), + PrefsProcessor(KEY_SHOW_CALENDAR_BUTTON_ON_RECORDS_TAB, ::showCalendarButtonOnRecordsTab), + PrefsProcessor(KEY_REVERSE_ORDER_IN_CALENDAR, ::reverseOrderInCalendar), + PrefsProcessor(KEY_DAYS_IN_CALENDAR, ::daysInCalendar), + PrefsProcessor(KEY_SHOW_ACTIVITY_FILTERS, ::showActivityFilters), + PrefsProcessor(KEY_ENABLE_REPEAT_BUTTON, ::enableRepeatButton), + PrefsProcessor(KEY_ENABLE_POMODORO_MODE, ::enablePomodoroMode), + PrefsProcessor(KEY_POMODORO_FOCUS_TIME, ::pomodoroFocusTime), + PrefsProcessor(KEY_POMODORO_BREAK_TIME, ::pomodoroBreakTime), + PrefsProcessor(KEY_POMODORO_LONG_BREAK_TIME, ::pomodoroLongBreakTime), + PrefsProcessor(KEY_POMODORO_PERIODS_UNTIL_LONG_BREAK, ::pomodoroPeriodsUntilLongBreak), + PrefsProcessor(KEY_ALLOW_MULTIPLE_ACTIVITY_FILTERS, ::allowMultipleActivityFilters), + PrefsProcessor(KEY_SHOW_GOALS_SEPARATELY, ::showGoalsSeparately), + PrefsProcessor(KEY_ALLOW_MULTITASKING, ::allowMultitasking), + PrefsProcessor(KEY_SHOW_NOTIFICATIONS, ::showNotifications), + PrefsProcessor(KEY_SHOW_NOTIFICATIONS_CONTROLS, ::showNotificationsControls), + PrefsProcessor(KEY_INACTIVITY_REMINDER_DURATION, ::inactivityReminderDuration), + PrefsProcessor(KEY_INACTIVITY_REMINDER_RECURRENT, ::inactivityReminderRecurrent), + PrefsProcessor(KEY_INACTIVITY_REMINDER_DND_START, ::inactivityReminderDoNotDisturbStart), + PrefsProcessor(KEY_INACTIVITY_REMINDER_DND_END, ::inactivityReminderDoNotDisturbEnd), + PrefsProcessor(KEY_ACTIVITY_REMINDER_DURATION, ::activityReminderDuration), + PrefsProcessor(KEY_ACTIVITY_REMINDER_RECURRENT, ::activityReminderRecurrent), + PrefsProcessor(KEY_ACTIVITY_REMINDER_DND_START, ::activityReminderDoNotDisturbStart), + PrefsProcessor(KEY_ACTIVITY_REMINDER_DND_END, ::activityReminderDoNotDisturbEnd), + PrefsProcessor(KEY_IGNORE_SHORT_RECORDS_DURATION, ::ignoreShortRecordsDuration), + PrefsProcessor(KEY_IGNORE_SHORT_UNTRACKED_DURATION, ::ignoreShortUntrackedDuration), + PrefsProcessor(KEY_UNTRACKED_RANGE_ENABLED, ::untrackedRangeEnabled), + PrefsProcessor(KEY_UNTRACKED_RANGE_START, ::untrackedRangeStart), + PrefsProcessor(KEY_UNTRACKED_RANGE_END, ::untrackedRangeEnd), + PrefsProcessor(KEY_DARK_MODE_2, ::darkMode), + PrefsProcessor(KEY_NUMBER_OF_CARDS, ::numberOfCards), + PrefsProcessor(KEY_USE_MILITARY_TIME_FORMAT, ::useMilitaryTimeFormat), + PrefsProcessor(KEY_USE_MONTH_DAY_TIME_FORMAT, ::useMonthDayTimeFormat), + PrefsProcessor(KEY_USE_PROPORTIONAL_MINUTES, ::useProportionalMinutes), + PrefsProcessor(KEY_SHOW_SECONDS, ::showSeconds), + PrefsProcessor(KEY_KEEP_SCREEN_ON, ::keepScreenOn), + PrefsProcessor(KEY_SHOW_RECORD_TAG_SELECTION, ::showRecordTagSelection), + PrefsProcessor(KEY_RECORD_TAG_SELECTION_CLOSE_AFTER_ONE, ::recordTagSelectionCloseAfterOne), + PrefsProcessor(KEY_SHOW_RECORD_TAG_SELECTION_EXCLUDE_ACTIVITIES, ::recordTagSelectionExcludeActivities), + PrefsProcessor(KEY_AUTOSTART_POMODORO_ACTIVITIES, ::autostartPomodoroActivities), + PrefsProcessor(KEY_AUTOMATED_TRACKING_SEND_EVENTS, ::automatedTrackingSendEvents), + PrefsProcessor(KEY_REPEAT_BUTTON_TYPE, ::repeatButtonType), + PrefsProcessor(KEY_WIDGET_TRANSPARENCY_PERCENT, ::widgetBackgroundTransparencyPercent), + PrefsProcessor(KEY_DEFAULT_TYPES_HIDDEN, ::defaultTypesHidden), + PrefsProcessor(KEY_IS_NAV_BAR_AT_THE_BOTTOM, ::isNavBarAtTheBottom), + ) + } + + + private data class PrefsProcessor( + val key: String, + private val property: KMutableProperty0, + ) { + + fun getter(): T { + return property.get() + } + + @Suppress("UNCHECKED_CAST") + fun setter(value: Any) { + (value as? T)?.let { property.set(it) } + } + } + + companion object { + const val PREFS_KEY = "prefs" + } +} \ No newline at end of file diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt index e90a69fa1..3e61cdeee 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/resolver/BackupRepoImpl.kt @@ -73,6 +73,7 @@ class BackupRepoImpl @Inject constructor( private val clearDataInteractor: ClearDataInteractor, private val resourceRepo: ResourceRepo, private val daysOfWeekDataLocalMapper: DaysOfWeekDataLocalMapper, + private val backupPrefsRepo: BackupPrefsRepo, ) : BackupRepo { override suspend fun saveBackupFile( @@ -131,6 +132,9 @@ class BackupRepoImpl @Inject constructor( complexRuleRepo.getAll().forEach { fileOutputStream?.write(it.let(::toBackupString).toByteArray()) } + backupPrefsRepo.saveToBackupString().let { + fileOutputStream?.write(it.toByteArray()) + } fileOutputStream?.close() fileDescriptor?.close() @@ -267,6 +271,11 @@ class BackupRepoImpl @Inject constructor( complexRuleRepo.add(it) } } + + BackupPrefsRepo.PREFS_KEY -> { + // TODO add restore options + // backupPrefsRepo.restoreFromBackupString(parts) + } } } migrateTags(tagsMigrationData) diff --git a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/utils/PrefsUtils.kt b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/utils/PrefsUtils.kt index 14ec7cfd4..2cdd22e9e 100644 --- a/data_local/src/main/java/com/example/util/simpletimetracker/data_local/utils/PrefsUtils.kt +++ b/data_local/src/main/java/com/example/util/simpletimetracker/data_local/utils/PrefsUtils.kt @@ -12,6 +12,9 @@ import timber.log.Timber import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty +/** + * When adding new types - add support for the backups. + */ @Suppress("UNCHECKED_CAST") internal inline fun SharedPreferences.delegate( key: String, diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/PrefsInteractor.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/PrefsInteractor.kt index 3722abc4e..8c994757b 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/PrefsInteractor.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/interactor/PrefsInteractor.kt @@ -1,5 +1,6 @@ package com.example.util.simpletimetracker.domain.interactor +import com.example.util.simpletimetracker.domain.extension.orZero import com.example.util.simpletimetracker.domain.model.CardOrder import com.example.util.simpletimetracker.domain.model.CardTagOrder import com.example.util.simpletimetracker.domain.model.ChartFilterType @@ -613,27 +614,27 @@ class PrefsInteractor @Inject constructor( } suspend fun setCardOrderManual(cardsOrder: Map) = withContext(Dispatchers.IO) { - prefsRepo.setCardOrderManual(cardsOrder) + prefsRepo.cardOrderManual = mapOrderManual(cardsOrder) } suspend fun getCardOrderManual(): Map = withContext(Dispatchers.IO) { - prefsRepo.getCardOrderManual() + mapOrderManual(prefsRepo.cardOrderManual) } suspend fun setCategoryOrderManual(cardsOrder: Map) = withContext(Dispatchers.IO) { - prefsRepo.setCategoryOrderManual(cardsOrder) + prefsRepo.categoryOrderManual = mapOrderManual(cardsOrder) } suspend fun getCategoryOrderManual(): Map = withContext(Dispatchers.IO) { - prefsRepo.getCategoryOrderManual() + mapOrderManual(prefsRepo.categoryOrderManual) } suspend fun setTagOrderManual(cardsOrder: Map) = withContext(Dispatchers.IO) { - prefsRepo.setTagOrderManual(cardsOrder) + prefsRepo.tagOrderManual = mapOrderManual(cardsOrder) } suspend fun getTagOrderManual(): Map = withContext(Dispatchers.IO) { - prefsRepo.getTagOrderManual() + mapOrderManual(prefsRepo.tagOrderManual) } suspend fun setAutomaticBackupUri(uri: String) = withContext(Dispatchers.IO) { @@ -813,4 +814,30 @@ class PrefsInteractor @Inject constructor( CardTagOrder.ACTIVITY -> 3 } } + + private fun mapOrderManual( + cardOrder: Map, + ): Set { + return cardOrder.map { (typeId, order) -> + "$typeId$CARDS_ORDER_DELIMITER${order.toShort()}" + }.toSet() + } + + private fun mapOrderManual( + set: Set?, + ): Map { + return set + ?.associate { string -> + string.split(CARDS_ORDER_DELIMITER).let { parts -> + parts.getOrNull(0).orEmpty() to parts.getOrNull(1).orEmpty() + } + } + ?.mapKeys { it.key.toLongOrNull().orZero() } + ?.mapValues { it.value.toLongOrNull().orZero() } + ?: emptyMap() + } + + companion object { + private const val CARDS_ORDER_DELIMITER = "_" + } } \ No newline at end of file diff --git a/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/PrefsRepo.kt b/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/PrefsRepo.kt index dd7751be4..a79bf409d 100644 --- a/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/PrefsRepo.kt +++ b/domain/src/main/java/com/example/util/simpletimetracker/domain/repo/PrefsRepo.kt @@ -20,6 +20,10 @@ interface PrefsRepo { var categoryOrder: Int var tagOrder: Int + var cardOrderManual: Set + var categoryOrderManual: Set + var tagOrderManual: Set + var statisticsRange: Int var statisticsRangeCustomStart: Long var statisticsRangeCustomEnd: Long @@ -164,19 +168,9 @@ interface PrefsRepo { fun removeQuickSettingsWidget(widgetId: Int) - fun setCardOrderManual(cardOrder: Map) - - fun getCardOrderManual(): Map - - fun setCategoryOrderManual(cardOrder: Map) - - fun getCategoryOrderManual(): Map - - fun setTagOrderManual(cardOrder: Map) - - fun getTagOrderManual(): Map - fun clear() fun clearDefaultTypesHidden() fun clearPomodoroSettingsClick() + + fun hasValueSaved(key: String): Boolean } \ No newline at end of file diff --git a/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/BackupViewModel.kt b/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/BackupViewModel.kt index b29487649..dee1e2ab1 100644 --- a/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/BackupViewModel.kt +++ b/features/feature_settings/src/main/java/com/example/util/simpletimetracker/feature_settings/viewModel/BackupViewModel.kt @@ -418,7 +418,7 @@ class BackupViewModel @Inject constructor( companion object { private const val CSV_EXPORT_DIALOG_TAG = "csv_export_dialog_tag" private const val ICS_EXPORT_DIALOG_TAG = "ics_export_dialog_tag" - private const val ALERT_DIALOG_TAG = "alert_dialog_tag" + private const val ALERT_DIALOG_TAG = "backup_restore_dialog_tag" private const val CSV_IMPORT_ALERT_DIALOG_TAG = "csv_import_alert_dialog_tag" private const val FILE_TYPE_BIN = "application/x-binary"