-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UpdateSettingsFragment: Migrate to Jetpack Compose (#586)
* Add `UpdateSettingsScreen` composable in `:features:settings` module (for #369) * Use `ViewModel` for data storage, handled by the `flow-preferences` library (https://github.com/tfcporciuncula/flow-preferences) * Add drawables and update pref strings from app module * Update fragment to use screen composable * Add `coreLibraryDesugaring`
- Loading branch information
1 parent
43026b6
commit 67db42c
Showing
11 changed files
with
393 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
204 changes: 61 additions & 143 deletions
204
...main/java/com/edricchan/studybuddy/ui/modules/settings/fragment/UpdateSettingsFragment.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,150 +1,68 @@ | ||
package com.edricchan.studybuddy.ui.modules.settings.fragment | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.content.SharedPreferences | ||
import android.os.Bundle | ||
import android.text.format.DateUtils | ||
import androidx.preference.Preference | ||
import com.edricchan.studybuddy.R | ||
import com.edricchan.studybuddy.constants.Constants | ||
import com.edricchan.studybuddy.core.settings.updates.UpdateInfoPrefConstants | ||
import com.edricchan.studybuddy.exts.android.getSerializableCompat | ||
import com.edricchan.studybuddy.ui.modules.updates.UpdatesActivity | ||
import com.edricchan.studybuddy.ui.preference.MaterialPreferenceFragment | ||
import java.time.Instant | ||
|
||
class UpdateSettingsFragment : MaterialPreferenceFragment(), | ||
SharedPreferences.OnSharedPreferenceChangeListener { | ||
|
||
private lateinit var updateInfoPreferences: SharedPreferences | ||
private var lastUpdatedInstant: Instant? = null | ||
private var lastCheckedForUpdatesInstant: Instant? = null | ||
|
||
private fun setLastCheckedForUpdates(lastCheckedForUpdatesMs: Long) { | ||
lastCheckedForUpdatesInstant = | ||
lastCheckedForUpdatesMs.takeIf { it <= DEFAULT_INSTANT } | ||
?.let { Instant.ofEpochMilli(it) } | ||
} | ||
|
||
private fun setLastUpdated(lastUpdatedMs: Long) { | ||
lastUpdatedInstant = | ||
lastUpdatedMs.takeIf { it <= DEFAULT_INSTANT } | ||
?.let { Instant.ofEpochMilli(it) } | ||
} | ||
|
||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { | ||
if (key == UpdateInfoPrefConstants.PREF_LAST_CHECKED_FOR_UPDATES_DATE || key == UpdateInfoPrefConstants.PREF_LAST_UPDATED_DATE) { | ||
when (key) { | ||
UpdateInfoPrefConstants.PREF_LAST_CHECKED_FOR_UPDATES_DATE -> { | ||
setLastCheckedForUpdates( | ||
updateInfoPreferences.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_UPDATED_DATE, | ||
DEFAULT_INSTANT | ||
) | ||
) | ||
} | ||
|
||
UpdateInfoPrefConstants.PREF_LAST_UPDATED_DATE -> { | ||
setLastUpdated( | ||
updateInfoPreferences.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_CHECKED_FOR_UPDATES_DATE, | ||
DEFAULT_INSTANT | ||
) | ||
) | ||
} | ||
} | ||
updateUpdatesPreferenceSummary() | ||
} | ||
} | ||
|
||
override fun onSaveInstanceState(outState: Bundle) { | ||
outState.putSerializable( | ||
LAST_CHECK_FOR_UPDATES_DATE_TAG, | ||
lastCheckedForUpdatesInstant | ||
) | ||
outState.putSerializable(LAST_UPDATED_DATE_TAG, lastUpdatedInstant) | ||
super.onSaveInstanceState(outState) | ||
} | ||
|
||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { | ||
setPreferencesFromResource(R.xml.pref_updates, rootKey) | ||
|
||
updateInfoPreferences = requireContext().getSharedPreferences( | ||
UpdateInfoPrefConstants.FILE_UPDATE_INFO, | ||
Context.MODE_PRIVATE | ||
).apply { | ||
registerOnSharedPreferenceChangeListener(this@UpdateSettingsFragment) | ||
} | ||
|
||
savedInstanceState?.run { | ||
lastCheckedForUpdatesInstant = getSerializableCompat( | ||
LAST_CHECK_FOR_UPDATES_DATE_TAG | ||
) | ||
lastUpdatedInstant = getSerializableCompat( | ||
LAST_UPDATED_DATE_TAG | ||
) | ||
} ?: run { | ||
setLastCheckedForUpdates( | ||
updateInfoPreferences | ||
.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_CHECKED_FOR_UPDATES_DATE, | ||
DEFAULT_INSTANT | ||
) | ||
) | ||
setLastUpdated( | ||
updateInfoPreferences | ||
.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_UPDATED_DATE, | ||
DEFAULT_INSTANT | ||
) | ||
import android.view.LayoutInflater | ||
import android.view.ViewGroup | ||
import androidx.compose.foundation.layout.WindowInsets | ||
import androidx.compose.foundation.layout.navigationBars | ||
import androidx.compose.foundation.layout.windowInsetsPadding | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.input.nestedscroll.nestedScroll | ||
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection | ||
import androidx.fragment.app.viewModels | ||
import androidx.fragment.compose.content | ||
import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
import com.edricchan.studybuddy.core.compat.navigation.navigateToUpdates | ||
import com.edricchan.studybuddy.features.settings.updates.model.CheckFrequencyCompat | ||
import com.edricchan.studybuddy.features.settings.updates.ui.UpdateSettingsScreen | ||
import com.edricchan.studybuddy.ui.common.fragment.BaseFragment | ||
import com.edricchan.studybuddy.ui.modules.settings.fragment.vm.UpdateSettingsViewModel | ||
import com.edricchan.studybuddy.ui.theming.compose.StudyBuddyTheme | ||
import dagger.hilt.android.AndroidEntryPoint | ||
|
||
@AndroidEntryPoint | ||
class UpdateSettingsFragment : BaseFragment() { | ||
|
||
private val viewModel by viewModels<UpdateSettingsViewModel>() | ||
|
||
override fun onCreateView( | ||
inflater: LayoutInflater, | ||
container: ViewGroup?, | ||
savedInstanceState: Bundle? | ||
) = content { | ||
val nestedScrollInterop = rememberNestedScrollInteropConnection() | ||
|
||
val checkFrequency by viewModel.prefCheckFrequency.asFlow() | ||
.collectAsStateWithLifecycle(initialValue = CheckFrequencyCompat.SixHours) | ||
|
||
val canDownloadMetered by viewModel.prefCanDownloadMetered.asFlow() | ||
.collectAsStateWithLifecycle(initialValue = false) | ||
|
||
val onlyDownloadCharging by viewModel.prefOnlyDownloadCharging.asFlow() | ||
.collectAsStateWithLifecycle(initialValue = false) | ||
|
||
val lastChecked by viewModel.lastChecked.asFlow() | ||
.collectAsStateWithLifecycle(initialValue = null) | ||
|
||
val lastUpdated by viewModel.lastUpdated.asFlow() | ||
.collectAsStateWithLifecycle(initialValue = null) | ||
|
||
StudyBuddyTheme { | ||
UpdateSettingsScreen( | ||
modifier = Modifier | ||
.nestedScroll(nestedScrollInterop) | ||
.windowInsetsPadding(WindowInsets.navigationBars), | ||
onUpdatesClick = navController::navigateToUpdates, | ||
lastChecked = lastChecked, | ||
lastUpdated = lastUpdated, | ||
checkFrequency = checkFrequency, | ||
onCheckFrequencyChange = viewModel.prefCheckFrequency::set, | ||
canDownloadMetered = canDownloadMetered, | ||
onCanDownloadMeteredChange = viewModel.prefCanDownloadMetered::set, | ||
onlyDownloadCharging = onlyDownloadCharging, | ||
onOnlyDownloadCharging = viewModel.prefOnlyDownloadCharging::set, | ||
) | ||
} | ||
|
||
findPreference<Preference>(Constants.prefUpdates)?.intent = | ||
Intent(context, UpdatesActivity::class.java) | ||
|
||
updateUpdatesPreferenceSummary() | ||
} | ||
|
||
override fun onPause() { | ||
super.onPause() | ||
updateInfoPreferences.unregisterOnSharedPreferenceChangeListener(this) | ||
} | ||
|
||
override fun onResume() { | ||
super.onResume() | ||
updateInfoPreferences.registerOnSharedPreferenceChangeListener(this) | ||
} | ||
|
||
private fun updateUpdatesPreferenceSummary() { | ||
findPreference<Preference>(Constants.prefUpdates)?.apply { | ||
val lastCheckedForUpdates = | ||
lastCheckedForUpdatesInstant?.let { getRelativeDateTimeString(it) } | ||
?: getString(R.string.pref_updates_summary_never) | ||
val lastUpdated = lastUpdatedInstant?.let { getRelativeDateTimeString(it) } | ||
?: getString(R.string.pref_updates_summary_never) | ||
summary = getString(R.string.pref_updates_summary, lastCheckedForUpdates, lastUpdated) | ||
} | ||
} | ||
|
||
private fun getRelativeDateTimeString(instant: Instant): CharSequence = | ||
DateUtils.getRelativeDateTimeString( | ||
context, | ||
instant.toEpochMilli(), | ||
DateUtils.MINUTE_IN_MILLIS, | ||
DateUtils.WEEK_IN_MILLIS, | ||
0 | ||
) | ||
|
||
companion object { | ||
// Indicates when the app was last updated | ||
private const val LAST_UPDATED_DATE_TAG = "lastUpdatedDate" | ||
|
||
// Indicates when the app last checked for updates | ||
private const val LAST_CHECK_FOR_UPDATES_DATE_TAG = "lastCheckForUpdatesDate" | ||
|
||
private const val DEFAULT_INSTANT = -1L | ||
} | ||
|
||
} |
73 changes: 73 additions & 0 deletions
73
.../java/com/edricchan/studybuddy/ui/modules/settings/fragment/vm/UpdateSettingsViewModel.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.edricchan.studybuddy.ui.modules.settings.fragment.vm | ||
|
||
import android.content.Context | ||
import androidx.lifecycle.ViewModel | ||
import com.edricchan.studybuddy.core.settings.updates.UpdateInfoPrefConstants | ||
import com.edricchan.studybuddy.core.settings.updates.keyPrefCanDownloadMetered | ||
import com.edricchan.studybuddy.core.settings.updates.keyPrefOnlyDownloadCharging | ||
import com.edricchan.studybuddy.core.settings.updates.keyPrefUpdatesFrequency | ||
import com.edricchan.studybuddy.exts.androidx.preference.defaultSharedPreferences | ||
import com.edricchan.studybuddy.features.settings.updates.model.CheckFrequencyCompat | ||
import com.edricchan.studybuddy.features.settings.updates.model.hourValue | ||
import com.fredporciuncula.flow.preferences.FlowSharedPreferences | ||
import com.fredporciuncula.flow.preferences.Preference | ||
import com.fredporciuncula.flow.preferences.map | ||
import dagger.hilt.android.lifecycle.HiltViewModel | ||
import dagger.hilt.android.qualifiers.ApplicationContext | ||
import java.time.Instant | ||
import javax.inject.Inject | ||
|
||
@HiltViewModel | ||
class UpdateSettingsViewModel @Inject constructor( | ||
@ApplicationContext context: Context | ||
) : ViewModel() { | ||
private val updateInfoPreferences = FlowSharedPreferences( | ||
context.getSharedPreferences( | ||
UpdateInfoPrefConstants.FILE_UPDATE_INFO, | ||
Context.MODE_PRIVATE | ||
) | ||
) | ||
|
||
private val appPreferences = FlowSharedPreferences( | ||
context.defaultSharedPreferences | ||
) | ||
|
||
val prefCheckFrequency: Preference<CheckFrequencyCompat> = appPreferences | ||
// ListPreference uses a string to persist its data, see | ||
// https://stackoverflow.com/q/11346916 | ||
.getString( | ||
keyPrefUpdatesFrequency, | ||
defaultValue = CheckFrequencyCompat.SixHours.hourValue.toString() | ||
).map( | ||
mapper = { | ||
CheckFrequencyCompat.fromHoursOrNull(it.toInt()) ?: CheckFrequencyCompat.SixHours | ||
}, | ||
reverse = { it.hourValue.toString() } | ||
) | ||
|
||
val prefCanDownloadMetered: Preference<Boolean> = | ||
appPreferences.getBoolean(keyPrefCanDownloadMetered) | ||
|
||
val prefOnlyDownloadCharging: Preference<Boolean> = | ||
appPreferences.getBoolean(keyPrefOnlyDownloadCharging) | ||
|
||
val lastChecked: Preference<Instant?> = updateInfoPreferences.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_CHECKED_FOR_UPDATES_DATE, | ||
Long.MIN_VALUE | ||
).map( | ||
mapper = { valLong -> | ||
valLong.takeIf { it >= Instant.EPOCH.toEpochMilli() }?.let { Instant.ofEpochMilli(it) } | ||
}, | ||
reverse = { it?.toEpochMilli() ?: Long.MIN_VALUE } | ||
) | ||
|
||
val lastUpdated: Preference<Instant?> = updateInfoPreferences.getLong( | ||
UpdateInfoPrefConstants.PREF_LAST_UPDATED_DATE, | ||
Long.MIN_VALUE | ||
).map( | ||
mapper = { valLong -> | ||
valLong.takeIf { it >= Instant.EPOCH.toEpochMilli() }?.let { Instant.ofEpochMilli(it) } | ||
}, | ||
reverse = { it?.toEpochMilli() ?: Long.MIN_VALUE } | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
...n/kotlin/com/edricchan/studybuddy/features/settings/updates/model/CheckFrequencyCompat.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.edricchan.studybuddy.features.settings.updates.model | ||
|
||
import androidx.annotation.StringRes | ||
import com.edricchan.studybuddy.features.settings.R | ||
|
||
private val hourToEnumMap = mapOf( | ||
CheckFrequencyCompat.Manual to 0, | ||
CheckFrequencyCompat.ThreeHours to 3, | ||
CheckFrequencyCompat.SixHours to 6, | ||
CheckFrequencyCompat.TwelveHours to 12, | ||
CheckFrequencyCompat.Daily to 24, | ||
CheckFrequencyCompat.Weekly to 24 * 7 | ||
) | ||
|
||
enum class CheckFrequencyCompat(@StringRes val stringResource: Int) { | ||
Manual(R.string.pref_check_for_update_freq_manual), | ||
ThreeHours(R.string.pref_check_for_update_freq_three_hour), | ||
SixHours(R.string.pref_check_for_update_freq_six_hour), | ||
TwelveHours(R.string.pref_check_for_update_freq_twelve_hour), | ||
Daily(R.string.pref_check_for_update_freq_daily), | ||
Weekly(R.string.pref_check_for_update_freq_weekly); | ||
|
||
companion object { | ||
fun fromHoursOrNull(hours: Int): CheckFrequencyCompat? = | ||
hourToEnumMap.entries | ||
.find { entry -> entry.value == hours } | ||
?.key | ||
} | ||
} | ||
|
||
val CheckFrequencyCompat.hourValue: Int | ||
get() = hourToEnumMap[this] ?: 0 |
Oops, something went wrong.