Persist preference for Lock Swiping #26
5 changed files with 55 additions and 22 deletions
|
@ -11,6 +11,8 @@ import com.wbrawner.simplemarkdown.utility.PreferenceHelper
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
@ -31,6 +33,7 @@ data class EditorState(
|
||||||
* a new file
|
* a new file
|
||||||
*/
|
*/
|
||||||
val reloadToggle: Int = 0,
|
val reloadToggle: Int = 0,
|
||||||
|
val lockSwiping: Boolean = false,
|
||||||
private val initialMarkdown: String = "",
|
private val initialMarkdown: String = "",
|
||||||
) {
|
) {
|
||||||
val dirty: Boolean
|
val dirty: Boolean
|
||||||
|
@ -49,6 +52,11 @@ class MarkdownViewModel(
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
load(null)
|
load(null)
|
||||||
}
|
}
|
||||||
|
preferenceHelper.observe<Boolean>(Preference.LOCK_SWIPING)
|
||||||
|
.onEach {
|
||||||
|
_state.value = _state.value.copy(lockSwiping = it)
|
||||||
|
}
|
||||||
|
.launchIn(viewModelScope)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMarkdown(markdown: String?) {
|
fun updateMarkdown(markdown: String?) {
|
||||||
|
@ -210,11 +218,19 @@ class MarkdownViewModel(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_state.value =
|
_state.value =
|
||||||
EditorState(fileName = untitledFileName, reloadToggle = _state.value.reloadToggle.inv())
|
EditorState(
|
||||||
|
fileName = untitledFileName,
|
||||||
|
reloadToggle = _state.value.reloadToggle.inv(),
|
||||||
|
lockSwiping = preferenceHelper[Preference.LOCK_SWIPING] as Boolean
|
||||||
|
)
|
||||||
Timber.i("Removing autosave uri from shared prefs")
|
Timber.i("Removing autosave uri from shared prefs")
|
||||||
preferenceHelper[Preference.AUTOSAVE_URI] = null
|
preferenceHelper[Preference.AUTOSAVE_URI] = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setLockSwiping(enabled: Boolean) {
|
||||||
|
preferenceHelper[Preference.LOCK_SWIPING] = enabled
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun factory(
|
fun factory(
|
||||||
fileHelper: FileHelper,
|
fileHelper: FileHelper,
|
||||||
|
|
|
@ -86,6 +86,7 @@ fun MainScreen(
|
||||||
val dirty by viewModel.collectAsState(EditorState::dirty, false)
|
val dirty by viewModel.collectAsState(EditorState::dirty, false)
|
||||||
val alert by viewModel.collectAsState(EditorState::alert, null)
|
val alert by viewModel.collectAsState(EditorState::alert, null)
|
||||||
val saveCallback by viewModel.collectAsState(EditorState::saveCallback, null)
|
val saveCallback by viewModel.collectAsState(EditorState::saveCallback, null)
|
||||||
|
val lockSwiping by viewModel.collectAsState(EditorState::lockSwiping, false)
|
||||||
LaunchedEffect(enableAutosave) {
|
LaunchedEffect(enableAutosave) {
|
||||||
if (!enableAutosave) return@LaunchedEffect
|
if (!enableAutosave) return@LaunchedEffect
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
|
@ -101,6 +102,8 @@ fun MainScreen(
|
||||||
initialMarkdown = initialMarkdown,
|
initialMarkdown = initialMarkdown,
|
||||||
markdown = markdown,
|
markdown = markdown,
|
||||||
setMarkdown = viewModel::updateMarkdown,
|
setMarkdown = viewModel::updateMarkdown,
|
||||||
|
lockSwiping = lockSwiping,
|
||||||
|
toggleLockSwiping = viewModel::setLockSwiping,
|
||||||
message = toast?.stringRes(),
|
message = toast?.stringRes(),
|
||||||
dismissMessage = viewModel::dismissToast,
|
dismissMessage = viewModel::dismissToast,
|
||||||
alert = alert,
|
alert = alert,
|
||||||
|
@ -137,6 +140,8 @@ private fun MainScreen(
|
||||||
initialMarkdown: String = "",
|
initialMarkdown: String = "",
|
||||||
markdown: String = "",
|
markdown: String = "",
|
||||||
setMarkdown: (String) -> Unit = {},
|
setMarkdown: (String) -> Unit = {},
|
||||||
|
lockSwiping: Boolean,
|
||||||
|
toggleLockSwiping: (Boolean) -> Unit,
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
dismissMessage: () -> Unit = {},
|
dismissMessage: () -> Unit = {},
|
||||||
alert: AlertDialogModel? = null,
|
alert: AlertDialogModel? = null,
|
||||||
|
@ -150,7 +155,6 @@ private fun MainScreen(
|
||||||
enableWideLayout: Boolean = false,
|
enableWideLayout: Boolean = false,
|
||||||
enableReadability: Boolean = false
|
enableReadability: Boolean = false
|
||||||
) {
|
) {
|
||||||
var lockSwiping by remember { mutableStateOf(true) }
|
|
||||||
val openFileLauncher =
|
val openFileLauncher =
|
||||||
rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
|
rememberLauncherForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||||
loadFile(it)
|
loadFile(it)
|
||||||
|
@ -250,10 +254,11 @@ private fun MainScreen(
|
||||||
Text(stringResource(R.string.action_lock_swipe))
|
Text(stringResource(R.string.action_lock_swipe))
|
||||||
Checkbox(
|
Checkbox(
|
||||||
checked = lockSwiping,
|
checked = lockSwiping,
|
||||||
onCheckedChange = { lockSwiping = !lockSwiping })
|
onCheckedChange = toggleLockSwiping
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}, onClick = {
|
}, onClick = {
|
||||||
lockSwiping = !lockSwiping
|
toggleLockSwiping(!lockSwiping)
|
||||||
menuExpanded = false
|
menuExpanded = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
package com.wbrawner.simplemarkdown.utility
|
package com.wbrawner.simplemarkdown.utility
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.coroutineScope
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import timber.log.Timber
|
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
interface PreferenceHelper {
|
interface PreferenceHelper {
|
||||||
operator fun get(preference: Preference): Any?
|
operator fun get(preference: Preference): Any?
|
||||||
|
@ -25,15 +20,7 @@ interface PreferenceHelper {
|
||||||
|
|
||||||
class AndroidPreferenceHelper(context: Context, private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO)): PreferenceHelper {
|
class AndroidPreferenceHelper(context: Context, private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.IO)): PreferenceHelper {
|
||||||
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
private val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
private val states = mapOf(
|
private val states = Preference.entries.associateWith { MutableStateFlow(get(it)) }
|
||||||
Preference.ANALYTICS_ENABLED to MutableStateFlow(get(Preference.ANALYTICS_ENABLED)),
|
|
||||||
Preference.AUTOSAVE_ENABLED to MutableStateFlow(get(Preference.AUTOSAVE_ENABLED)),
|
|
||||||
Preference.AUTOSAVE_URI to MutableStateFlow(get(Preference.AUTOSAVE_URI)),
|
|
||||||
Preference.CUSTOM_CSS to MutableStateFlow(get(Preference.CUSTOM_CSS)),
|
|
||||||
Preference.DARK_MODE to MutableStateFlow(get(Preference.DARK_MODE)),
|
|
||||||
Preference.ERROR_REPORTS_ENABLED to MutableStateFlow(get(Preference.ERROR_REPORTS_ENABLED)),
|
|
||||||
Preference.READABILITY_ENABLED to MutableStateFlow(get(Preference.READABILITY_ENABLED)),
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun get(preference: Preference): Any? = sharedPreferences.all[preference.key]?: preference.default
|
override fun get(preference: Preference): Any? = sharedPreferences.all[preference.key]?: preference.default
|
||||||
|
|
||||||
|
@ -63,5 +50,6 @@ enum class Preference(val key: String, val default: Any?) {
|
||||||
CUSTOM_CSS("pref.custom_css", null),
|
CUSTOM_CSS("pref.custom_css", null),
|
||||||
DARK_MODE("darkMode", "Auto"),
|
DARK_MODE("darkMode", "Auto"),
|
||||||
ERROR_REPORTS_ENABLED("acra.enable", true),
|
ERROR_REPORTS_ENABLED("acra.enable", true),
|
||||||
|
LOCK_SWIPING("lockSwiping", false),
|
||||||
READABILITY_ENABLED("readability.enable", false)
|
READABILITY_ENABLED("readability.enable", false)
|
||||||
}
|
}
|
|
@ -2,17 +2,27 @@ package com.wbrawner.simplemarkdown
|
||||||
|
|
||||||
import com.wbrawner.simplemarkdown.utility.Preference
|
import com.wbrawner.simplemarkdown.utility.Preference
|
||||||
import com.wbrawner.simplemarkdown.utility.PreferenceHelper
|
import com.wbrawner.simplemarkdown.utility.PreferenceHelper
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
||||||
class FakePreferenceHelper: PreferenceHelper {
|
class FakePreferenceHelper: PreferenceHelper {
|
||||||
val preferences = mutableMapOf<Preference, Any?>()
|
val preferences = mutableMapOf<Preference, Any?>()
|
||||||
override fun get(preference: Preference): Any? = preferences[preference]?: preference.default
|
private val preferenceFlows = mutableMapOf<Preference, MutableStateFlow<Any?>>()
|
||||||
|
|
||||||
|
private fun preferenceFlow(preference: Preference) = preferenceFlows.getOrPut(preference) {
|
||||||
|
MutableStateFlow(preference.default)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun get(preference: Preference): Any? =
|
||||||
|
(preferences[preference] ?: preference.default).also {
|
||||||
|
preferenceFlow(preference)
|
||||||
|
}
|
||||||
|
|
||||||
override fun set(preference: Preference, value: Any?) {
|
override fun set(preference: Preference, value: Any?) {
|
||||||
|
preferenceFlow(preference).value = value
|
||||||
preferences[preference] = value
|
preferences[preference] = value
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun <T> observe(preference: Preference): StateFlow<T> {
|
override fun <T> observe(preference: Preference): StateFlow<T> =
|
||||||
TODO("Not yet implemented")
|
preferenceFlow(preference) as StateFlow<T>
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -288,4 +288,18 @@ class MarkdownViewModelTest {
|
||||||
viewModel.autosave()
|
viewModel.autosave()
|
||||||
assertEquals(2, fileHelper.savedData.count())
|
assertEquals(2, fileHelper.savedData.count())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetLockSwiping() = runTest {
|
||||||
|
preferenceHelper[Preference.LOCK_SWIPING] = false
|
||||||
|
assertFalse(viewModel.state.value.lockSwiping)
|
||||||
|
viewModel.setLockSwiping(true)
|
||||||
|
viewModelScope.advanceUntilIdle()
|
||||||
|
assertTrue(preferenceHelper.preferences[Preference.LOCK_SWIPING] as Boolean)
|
||||||
|
assertTrue(viewModel.state.value.lockSwiping)
|
||||||
|
viewModel.setLockSwiping(false)
|
||||||
|
viewModelScope.advanceUntilIdle()
|
||||||
|
assertFalse(preferenceHelper.preferences[Preference.LOCK_SWIPING] as Boolean)
|
||||||
|
assertFalse(viewModel.state.value.lockSwiping)
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue