WIP: Implement undo/redo commands

Signed-off-by: William Brawner <me@wbrawner.com>
This commit is contained in:
William Brawner 2020-07-09 21:48:28 -07:00
parent 0ff680d648
commit dfd771adfe
8 changed files with 80 additions and 26 deletions

View file

@ -24,6 +24,7 @@ import com.wbrawner.simplemarkdown.model.Readability
import com.wbrawner.simplemarkdown.utility.hideKeyboard import com.wbrawner.simplemarkdown.utility.hideKeyboard
import com.wbrawner.simplemarkdown.utility.showKeyboard import com.wbrawner.simplemarkdown.utility.showKeyboard
import com.wbrawner.simplemarkdown.view.ViewPagerPage import com.wbrawner.simplemarkdown.view.ViewPagerPage
import com.wbrawner.simplemarkdown.viewmodel.EditorCommand
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -94,8 +95,11 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
} }
false false
} }
markdownEditor?.setText(viewModel.markdownUpdates.value) markdownEditor?.setText(viewModel.markdown.value)
viewModel.originalMarkdown.observe(viewLifecycleOwner, Observer { viewModel.editorCommands.observe(viewLifecycleOwner, Observer {
when (it) {
is EditorCommand.Undo -> markdownEditor?.text?.
}
markdownEditor?.setText(it) markdownEditor?.setText(it)
}) })
launch { launch {

View file

@ -75,7 +75,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
R.id.action_share -> { R.id.action_share -> {
val shareIntent = Intent(Intent.ACTION_SEND) val shareIntent = Intent(Intent.ACTION_SEND)
shareIntent.putExtra(Intent.EXTRA_TEXT, viewModel.markdownUpdates.value) shareIntent.putExtra(Intent.EXTRA_TEXT, viewModel.markdown.value)
shareIntent.type = "text/plain" shareIntent.type = "text/plain"
startActivity(Intent.createChooser( startActivity(Intent.createChooser(
shareIntent, shareIntent,
@ -223,7 +223,7 @@ class MainFragment : Fragment(), ActivityCompat.OnRequestPermissionsResultCallba
} }
private fun promptSaveOrDiscardChanges() { private fun promptSaveOrDiscardChanges() {
if (viewModel.originalMarkdown.value == viewModel.markdownUpdates.value) { if (viewModel.originalMarkdown.value == viewModel.markdown.value) {
viewModel.reset("Untitled.md") viewModel.reset("Untitled.md")
return return
} }

View file

@ -63,8 +63,8 @@ class PreviewFragment : Fragment(), CoroutineScope {
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
updateWebContent(viewModel.markdownUpdates.value ?: "") updateWebContent(viewModel.markdown.value ?: "")
viewModel.markdownUpdates.observe(this, Observer { viewModel.markdown.observe(this, Observer {
updateWebContent(it) updateWebContent(it)
}) })
} }

View file

@ -12,12 +12,12 @@ import java.io.Reader
class MarkdownViewModel : ViewModel() { class MarkdownViewModel : ViewModel() {
val fileName = MutableLiveData<String>("Untitled.md") val fileName = MutableLiveData<String>("Untitled.md")
val markdownUpdates = MutableLiveData<String>() val editorCommands = MutableLiveData<EditorCommand>()
val originalMarkdown = MutableLiveData<String>() val markdown = MutableLiveData<String>()
val uri = MutableLiveData<Uri>() val uri = MutableLiveData<Uri>()
fun updateMarkdown(markdown: String?) { fun updateMarkdown(markdown: String?) {
this.markdownUpdates.postValue(markdown ?: "") this.markdown.postValue(markdown ?: "")
} }
suspend fun load(context: Context, uri: Uri?): Boolean { suspend fun load(context: Context, uri: Uri?): Boolean {
@ -28,8 +28,8 @@ class MarkdownViewModel : ViewModel() {
val fileInput = FileInputStream(it.fileDescriptor) val fileInput = FileInputStream(it.fileDescriptor)
val fileName = uri.getName(context) val fileName = uri.getName(context)
val content = fileInput.reader().use(Reader::readText) val content = fileInput.reader().use(Reader::readText)
originalMarkdown.postValue(content) markdown.postValue(content)
markdownUpdates.postValue(content) editorCommands.postValue(EditorCommand.Load(content))
this@MarkdownViewModel.fileName.postValue(fileName) this@MarkdownViewModel.fileName.postValue(fileName)
this@MarkdownViewModel.uri.postValue(uri) this@MarkdownViewModel.uri.postValue(uri)
true true
@ -48,7 +48,7 @@ class MarkdownViewModel : ViewModel() {
context.contentResolver.openOutputStream(uri, "rwt") context.contentResolver.openOutputStream(uri, "rwt")
?.writer() ?.writer()
?.use { ?.use {
it.write(markdownUpdates.value ?: "") it.write(markdown.value ?: "")
} }
?: return@withContext false ?: return@withContext false
this@MarkdownViewModel.fileName.postValue(fileName) this@MarkdownViewModel.fileName.postValue(fileName)
@ -62,7 +62,23 @@ class MarkdownViewModel : ViewModel() {
fun reset(untitledFileName: String) { fun reset(untitledFileName: String) {
fileName.postValue(untitledFileName) fileName.postValue(untitledFileName)
originalMarkdown.postValue("") editorCommands.postValue(EditorCommand.Load(""))
markdownUpdates.postValue("") markdown.postValue("")
}
fun undo() {
editorCommands.postValue(EditorCommand.Undo())
}
fun redo() {
editorCommands.postValue(EditorCommand.Redo())
} }
} }
sealed class EditorCommand {
val consumed = false
class Undo: EditorCommand()
class Redo: EditorCommand()
class Load(val text: String): EditorCommand()
}

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.65,0 -8.58,3.03 -9.96,7.22L3.9,16c1.05,-3.19 4.05,-5.5 7.6,-5.5 1.95,0 3.73,0.72 5.12,1.88L13,16h9V7l-3.6,3.6z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L2,7v9h9l-3.62,-3.62c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.54,0 6.55,2.31 7.6,5.5l2.37,-0.78C21.08,11.03 17.15,8 12.5,8z"/>
</vector>

View file

@ -6,6 +6,17 @@
android:icon="@drawable/ic_share" android:icon="@drawable/ic_share"
android:title="@string/action_share" android:title="@string/action_share"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/action_undo"
android:icon="@drawable/ic_undo"
android:title="@string/action_undo"
app:showAsAction="ifRoom" />
<item
android:id="@+id/action_redo"
android:icon="@drawable/ic_redo"
android:title="@string/action_redo"
app:showAsAction="ifRoom" />
<group android:id="@+id/editGroup">
<item <item
android:id="@+id/action_new" android:id="@+id/action_new"
android:title="@string/action_new" android:title="@string/action_new"
@ -20,6 +31,7 @@
<item <item
android:id="@+id/action_save_as" android:id="@+id/action_save_as"
android:title="@string/action_save_as" /> android:title="@string/action_save_as" />
</group>
<item <item
android:id="@+id/action_lock_swipe" android:id="@+id/action_lock_swipe"
android:checkable="true" android:checkable="true"

View file

@ -77,6 +77,8 @@
<string name="action_rate">Rate SimpleMarkdown</string> <string name="action_rate">Rate SimpleMarkdown</string>
<string name="support_thank_you">Thank you so much for your support!</string> <string name="support_thank_you">Thank you so much for your support!</string>
<string name="description_heart">Heart</string> <string name="description_heart">Heart</string>
<string name="action_undo">Undo</string>
<string name="action_redo">Redo</string>
<string-array name="pref_entries_dark_mode"> <string-array name="pref_entries_dark_mode">
<item>@string/pref_value_light</item> <item>@string/pref_value_light</item>
<item>@string/pref_value_dark</item> <item>@string/pref_value_dark</item>