Migrate autosave logic to viewmodel and fix failing UI tests

This commit is contained in:
William Brawner 2021-02-20 20:35:28 -07:00
parent f2ed687b02
commit ed57785d0a
5 changed files with 49 additions and 36 deletions

View file

@ -66,7 +66,7 @@ class MarkdownTests {
} }
@Test @Test
fun newMarkdownTest() { fun newMarkdownTest() {
onView(withId(R.id.markdown_edit)) onView(withId(R.id.markdown_edit))
.perform(typeText("# UI Testing\n\nThe quick brown fox jumped over the lazy dog.")) .perform(typeText("# UI Testing\n\nThe quick brown fox jumped over the lazy dog."))
openActionBarOverflowOrOptionsMenu(getApplicationContext()) openActionBarOverflowOrOptionsMenu(getApplicationContext())

View file

@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.R import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.viewmodel.PREF_KEY_AUTOSAVE_URI
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -43,10 +44,8 @@ class SplashActivity : AppCompatActivity(), CoroutineScope {
val uri = withContext(Dispatchers.IO) { val uri = withContext(Dispatchers.IO) {
intent?.data intent?.data
?: PreferenceManager.getDefaultSharedPreferences(this@SplashActivity) ?: PreferenceManager.getDefaultSharedPreferences(this@SplashActivity)
.getString( .getString(PREF_KEY_AUTOSAVE_URI, null)
getString(R.string.pref_key_autosave_uri), ?.let {
null
)?.let {
Uri.parse(it) Uri.parse(it)
} }
} }

View file

@ -9,6 +9,7 @@ import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.* import android.view.*
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.widget.Toast import android.widget.Toast
@ -29,6 +30,7 @@ import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.utility.errorHandlerImpl import com.wbrawner.simplemarkdown.utility.errorHandlerImpl
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
import com.wbrawner.simplemarkdown.viewmodel.PREF_KEY_AUTOSAVE_URI
import kotlinx.android.synthetic.main.fragment_main.* import kotlinx.android.synthetic.main.fragment_main.*
import kotlinx.coroutines.* import kotlinx.coroutines.*
import java.io.File import java.io.File
@ -98,6 +100,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
R.id.action_save -> { R.id.action_save -> {
launch { launch {
Log.d("SimpleMarkdown", "Saving file from onOptionsItemSelected")
if (!viewModel.save(requireContext())) { if (!viewModel.save(requireContext())) {
requestFileOp(REQUEST_SAVE_FILE) requestFileOp(REQUEST_SAVE_FILE)
} else { } else {
@ -154,32 +157,9 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
val context = context?.applicationContext ?: return
launch { launch {
val context = context?.applicationContext ?: return@launch viewModel.autosave(context, PreferenceManager.getDefaultSharedPreferences(context))
withContext(Dispatchers.IO) {
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
val isAutoSaveEnabled = sharedPrefs.getBoolean(KEY_AUTOSAVE, true)
if (!shouldAutoSave || !isAutoSaveEnabled) {
return@withContext
}
val uri = if (viewModel.save(context)) {
viewModel.uri.value
} else {
// The user has left the app, with autosave enabled, and we don't already have a
// Uri for them or for some reason we were unable to save to the original Uri. In
// this case, we need to just save to internal file storage so that we can recover
val fileUri = Uri.fromFile(File(context.filesDir, viewModel.fileName.value!!))
if (viewModel.save(context, fileUri)) {
fileUri
} else {
null
}
} ?: return@withContext
sharedPrefs.edit()
.putString(getString(R.string.pref_key_autosave_uri), uri.toString())
.apply()
}
} }
} }
@ -231,7 +211,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
} else { } else {
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
putString(getString(R.string.pref_key_autosave_uri), data.data.toString()) putString(PREF_KEY_AUTOSAVE_URI, data.data.toString())
} }
} }
} }
@ -243,6 +223,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
launch { launch {
context?.let { context?.let {
Log.d("SimpleMarkdown", "Saving file from onActivityResult")
viewModel.save(it, data.data) viewModel.save(it, data.data)
} }
} }
@ -252,10 +233,10 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
private fun promptSaveOrDiscardChanges() { private fun promptSaveOrDiscardChanges() {
if (viewModel.shouldPromptSave()) { if (!viewModel.shouldPromptSave()) {
viewModel.reset("Untitled.md") viewModel.reset("Untitled.md")
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
remove(getString(R.string.pref_key_autosave_uri)) remove(PREF_KEY_AUTOSAVE_URI)
} }
return return
} }
@ -266,7 +247,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
.setNegativeButton(R.string.action_discard) { _, _ -> .setNegativeButton(R.string.action_discard) { _, _ ->
viewModel.reset("Untitled.md") viewModel.reset("Untitled.md")
PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { PreferenceManager.getDefaultSharedPreferences(requireContext()).edit {
remove(getString(R.string.pref_key_autosave_uri)) remove(PREF_KEY_AUTOSAVE_URI)
} }
} }
.setPositiveButton(R.string.action_save) { _, _ -> .setPositiveButton(R.string.action_save) { _, _ ->

View file

@ -1,18 +1,26 @@
package com.wbrawner.simplemarkdown.viewmodel package com.wbrawner.simplemarkdown.viewmodel
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.util.Log
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.getName import com.wbrawner.simplemarkdown.utility.getName
import com.wbrawner.simplemarkdown.view.fragment.MainFragment
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.Reader import java.io.Reader
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
const val PREF_KEY_AUTOSAVE_URI = "autosave.uri"
class MarkdownViewModel : ViewModel() { class MarkdownViewModel : ViewModel() {
val fileName = MutableLiveData<String>("Untitled.md") val fileName = MutableLiveData<String?>("Untitled.md")
val markdownUpdates = MutableLiveData<String>() val markdownUpdates = MutableLiveData<String>()
val editorActions = MutableLiveData<EditorAction>() val editorActions = MutableLiveData<EditorAction>()
val uri = MutableLiveData<Uri?>() val uri = MutableLiveData<Uri?>()
@ -68,6 +76,32 @@ class MarkdownViewModel : ViewModel() {
} }
} }
suspend fun autosave(context: Context, sharedPrefs: SharedPreferences) {
val isAutoSaveEnabled = sharedPrefs.getBoolean(MainFragment.KEY_AUTOSAVE, true)
if (!isDirty.get() || !isAutoSaveEnabled) {
return
}
val uri = if (save(context)) {
Log.d("SimpleMarkdown", "Saving file from onPause")
uri.value
} else {
// The user has left the app, with autosave enabled, and we don't already have a
// Uri for them or for some reason we were unable to save to the original Uri. In
// this case, we need to just save to internal file storage so that we can recover
val fileUri = Uri.fromFile(File(context.filesDir, fileName.value?: "Untitled.md"))
Log.d("SimpleMarkdown", "Saving file from onPause failed, trying again")
if (save(context, fileUri)) {
fileUri
} else {
null
}
} ?: return
sharedPrefs.edit()
.putString(PREF_KEY_AUTOSAVE_URI, uri.toString())
.apply()
}
fun reset(untitledFileName: String) { fun reset(untitledFileName: String) {
fileName.postValue(untitledFileName) fileName.postValue(untitledFileName)
uri.postValue(null) uri.postValue(null)

View file

@ -58,7 +58,6 @@
<string name="pref_key_dark_mode_light" translatable="false">light</string> <string name="pref_key_dark_mode_light" translatable="false">light</string>
<string name="pref_key_dark_mode_dark" translatable="false">dark</string> <string name="pref_key_dark_mode_dark" translatable="false">dark</string>
<string name="pref_key_dark_mode_auto" translatable="false">auto</string> <string name="pref_key_dark_mode_auto" translatable="false">auto</string>
<string name="pref_key_autosave_uri" translatable="false">autosave.uri</string>
<string name="save_changes">Save Changes</string> <string name="save_changes">Save Changes</string>
<string name="prompt_save_changes">Would you like to save your changes?</string> <string name="prompt_save_changes">Would you like to save your changes?</string>
<string name="action_discard">Discard</string> <string name="action_discard">Discard</string>