From 50d762217280b240f84944c7b0c801a55f2ca8fb Mon Sep 17 00:00:00 2001 From: William Brawner Date: Sun, 21 Feb 2021 18:32:53 -0700 Subject: [PATCH] Consolidate autosave URI persistence management --- .../view/activity/SplashActivity.kt | 20 ++----- .../view/fragment/MainFragment.kt | 39 +++++--------- .../viewmodel/MarkdownViewModel.kt | 52 ++++++++++++------- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.kt index 8ebb565..833b864 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/SplashActivity.kt @@ -1,7 +1,6 @@ package com.wbrawner.simplemarkdown.view.activity import android.content.Intent -import android.net.Uri import android.os.Build import android.os.Bundle import androidx.appcompat.app.AppCompatActivity @@ -9,7 +8,6 @@ import androidx.appcompat.app.AppCompatDelegate import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager import com.wbrawner.simplemarkdown.R -import com.wbrawner.simplemarkdown.viewmodel.PREF_KEY_AUTOSAVE_URI import kotlinx.coroutines.* import timber.log.Timber @@ -40,20 +38,12 @@ class SplashActivity : AppCompatActivity() { } AppCompatDelegate.setDefaultNightMode(darkMode) - val uri = withContext(Dispatchers.IO) { - intent?.data?.let { - Timber.d("Using uri from intent: $it") - it - } ?: PreferenceManager.getDefaultSharedPreferences(this@SplashActivity) - .getString(PREF_KEY_AUTOSAVE_URI, null) - ?.let { - Timber.d("Using uri from shared preferences: $it") - Uri.parse(it) - } - } - - if (uri == null) { + val uri = intent?.data?.let { + Timber.d("Using uri from intent: $it") + it + } ?: run { Timber.d("No intent provided to load data from") + null } val startIntent = Intent(this@SplashActivity, MainActivity::class.java) diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt index 86a7d0c..4f6111c 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/MainFragment.kt @@ -15,7 +15,6 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import androidx.core.content.edit import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope @@ -28,7 +27,6 @@ import com.wbrawner.simplemarkdown.utility.ErrorHandler import com.wbrawner.simplemarkdown.utility.errorHandlerImpl import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel -import com.wbrawner.simplemarkdown.viewmodel.PREF_KEY_AUTOSAVE_URI import kotlinx.android.synthetic.main.fragment_main.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -212,21 +210,9 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba } lifecycleScope.launch { - val fileLoaded = context?.let { - viewModel.load(it, data.data) - } - if (fileLoaded == false) { - context?.let { - Toast.makeText(it, R.string.file_load_error, Toast.LENGTH_SHORT) - .show() - } - } else { - Timber.d( - "File load succeeded, updating autosave uri in shared prefs: %s", - data.data.toString() - ) - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { - putString(PREF_KEY_AUTOSAVE_URI, data.data.toString()) + context?.let { + if (!viewModel.load(it, data.data)) { + Toast.makeText(it, R.string.file_load_error, Toast.LENGTH_SHORT).show() } } } @@ -253,11 +239,10 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba private fun promptSaveOrDiscardChanges() { if (!viewModel.shouldPromptSave()) { - viewModel.reset("Untitled.md") - Timber.i("Removing autosave uri from shared prefs") - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { - remove(PREF_KEY_AUTOSAVE_URI) - } + viewModel.reset( + "Untitled.md", + PreferenceManager.getDefaultSharedPreferences(requireContext()) + ) return } val context = context ?: run { @@ -268,11 +253,11 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba .setTitle(R.string.save_changes) .setMessage(R.string.prompt_save_changes) .setNegativeButton(R.string.action_discard) { _, _ -> - Timber.d("Discarding changes and deleting autosave uri from shared preferences") - viewModel.reset("Untitled.md") - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { - remove(PREF_KEY_AUTOSAVE_URI) - } + Timber.d("Discarding changes") + viewModel.reset( + "Untitled.md", + PreferenceManager.getDefaultSharedPreferences(requireContext()) + ) } .setPositiveButton(R.string.action_save) { _, _ -> Timber.d("Saving changes") diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/viewmodel/MarkdownViewModel.kt b/app/src/main/java/com/wbrawner/simplemarkdown/viewmodel/MarkdownViewModel.kt index a6225a5..cd1aeb2 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/viewmodel/MarkdownViewModel.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/viewmodel/MarkdownViewModel.kt @@ -3,8 +3,10 @@ package com.wbrawner.simplemarkdown.viewmodel import android.content.Context import android.content.SharedPreferences import android.net.Uri +import androidx.core.content.edit import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.preference.PreferenceManager import com.wbrawner.simplemarkdown.utility.getName import com.wbrawner.simplemarkdown.view.fragment.MainFragment import kotlinx.coroutines.Dispatchers @@ -32,10 +34,18 @@ class MarkdownViewModel(val timber: Timber.Tree = Timber.asTree()) : ViewModel() isDirty.set(true) } - suspend fun load(context: Context, uri: Uri?): Boolean { + suspend fun load( + context: Context, + uri: Uri?, + sharedPrefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + ): Boolean { if (uri == null) { - timber.i("Ignoring call to load null uri") - return false + timber.i("No URI provided to load, attempting to load last autosaved file") + sharedPrefs.getString(PREF_KEY_AUTOSAVE_URI, null) + ?.let { + Timber.d("Using uri from shared preferences: $it") + return load(context, Uri.parse(it), sharedPrefs) + } ?: return false } return withContext(Dispatchers.IO) { try { @@ -55,6 +65,10 @@ class MarkdownViewModel(val timber: Timber.Tree = Timber.asTree()) : ViewModel() timber.i("Loaded file $fileName from $fileInput") timber.v("File contents:\n$content") isDirty.set(false) + timber.i("Persisting autosave uri in shared prefs: $uri") + sharedPrefs.edit() + .putString(PREF_KEY_AUTOSAVE_URI, uri.toString()) + .apply() true } ?: run { timber.w("Open file descriptor returned null for uri: $uri") @@ -67,7 +81,11 @@ class MarkdownViewModel(val timber: Timber.Tree = Timber.asTree()) : ViewModel() } } - suspend fun save(context: Context, givenUri: Uri? = null): Boolean = saveMutex.withLock { + suspend fun save( + context: Context, + givenUri: Uri? = null, + sharedPrefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + ): Boolean = saveMutex.withLock { val uri = givenUri?.let { timber.i("Saving file with given uri: $it") it @@ -94,6 +112,10 @@ class MarkdownViewModel(val timber: Timber.Tree = Timber.asTree()) : ViewModel() this@MarkdownViewModel.uri.postValue(uri) isDirty.set(false) timber.i("Saved file $fileName to uri $uri") + timber.i("Persisting autosave uri in shared prefs: $uri") + sharedPrefs.edit() + .putString(PREF_KEY_AUTOSAVE_URI, uri.toString()) + .apply() true } catch (e: Exception) { timber.e(e, "Failed to save file at uri: $uri") @@ -114,37 +136,29 @@ class MarkdownViewModel(val timber: Timber.Tree = Timber.asTree()) : ViewModel() return } - val uri = if (save(context)) { + if (save(context)) { timber.i("Autosave with cached uri succeeded: ${uri.value}") - 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")) timber.i("No cached uri for autosave, saving to $fileUri instead") - if (save(context, fileUri)) { - fileUri - } else { - null - } - } ?: run { - timber.w("Unable to perform autosave, uri was null") - return@autosave + save(context, fileUri) } - timber.i("Persisting autosave uri in shared prefs: $uri") - sharedPrefs.edit() - .putString(PREF_KEY_AUTOSAVE_URI, uri.toString()) - .apply() } - fun reset(untitledFileName: String) { + fun reset(untitledFileName: String, sharedPrefs: SharedPreferences) { timber.i("Resetting view model to default state") fileName.postValue(untitledFileName) uri.postValue(null) markdownUpdates.postValue("") editorActions.postValue(EditorAction.Load("")) isDirty.set(false) + timber.i("Removing autosave uri from shared prefs") + sharedPrefs.edit { + remove(PREF_KEY_AUTOSAVE_URI) + } } fun shouldPromptSave() = isDirty.get()