From 112b776080db1504c3cf22db93c578a8dbda59c6 Mon Sep 17 00:00:00 2001 From: William 'Billy' Brawner Date: Sun, 18 Aug 2019 20:55:25 -0700 Subject: [PATCH] Add Save as... and improve preview/edit performance --- .../simplemarkdown/MarkdownApplication.kt | 10 +- .../view/activity/MainActivity.kt | 5 +- .../view/fragment/EditFragment.kt | 116 ++++++++++-------- .../view/fragment/PreviewFragment.kt | 66 +++++----- app/src/main/res/menu/menu_edit.xml | 3 + app/src/main/res/values/strings.xml | 1 + 6 files changed, 116 insertions(+), 85 deletions(-) diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt index 4081488..9a96bb7 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt @@ -15,11 +15,11 @@ class MarkdownApplication : Application() { .detectAll() .penaltyDeath() .build()) -// StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder() -// .detectAll() -// .penaltyLog() -// .penaltyDeath() -// .build()) + StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder() + .detectAll() + .penaltyLog() + .penaltyDeath() + .build()) } super.onCreate() } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt index 57ffe16..ef410f9 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/activity/MainActivity.kt @@ -95,7 +95,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes } else { null } - }?: return@withContext + } ?: return@withContext sharedPrefs.edit() .putString(getString(R.string.pref_key_autosave_uri), uri.toString()) .apply() @@ -131,6 +131,9 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes } } } + R.id.action_save_as -> { + requestFileOp(REQUEST_SAVE_FILE) + } R.id.action_share -> { val shareIntent = Intent(Intent.ACTION_SEND) shareIntent.putExtra(Intent.EXTRA_TEXT, viewModel.markdownUpdates.value) diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/EditFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/EditFragment.kt index fd3b39f..22a4ce3 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/EditFragment.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/EditFragment.kt @@ -35,6 +35,7 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope { private var markdownEditorScroller: ScrollView? = null private lateinit var viewModel: MarkdownViewModel override val coroutineContext: CoroutineContext = Dispatchers.Main + private var readabilityWatcher: TextWatcher? = null @SuppressLint("ClickableViewAccessibility") override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, @@ -71,56 +72,6 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope { } }) - var enableReadability = false - launch { - enableReadability = withContext(Dispatchers.IO) { - context?.let { - PreferenceManager.getDefaultSharedPreferences(it) - .getBoolean(getString(R.string.readability_enabled), false) - }?: false - } - } - if (enableReadability) { - markdownEditor?.addTextChangedListener(object : TextWatcher { - private var previousValue = "" - private var searchFor = "" - - override fun afterTextChanged(s: Editable?) { - val searchText = s.toString().trim() - if (searchText == searchFor) - return - - searchFor = searchText - - launch { - delay(250) - if (searchText != searchFor) - return@launch - val start = System.currentTimeMillis() - if (searchFor.isEmpty()) return@launch - if (previousValue == searchFor) return@launch - val readability = Readability(searchFor) - val span = SpannableString(searchFor) - for (sentence in readability.sentences()) { - var color = Color.TRANSPARENT - if (sentence.syllableCount() > 25) color = Color.argb(100, 229, 232, 42) - if (sentence.syllableCount() > 35) color = Color.argb(100, 193, 66, 66) - span.setSpan(BackgroundColorSpan(color), sentence.start(), sentence.end(), 0) - } - markdownEditor?.setTextKeepState(span, TextView.BufferType.SPANNABLE) - previousValue = searchFor - val timeTakenMs = System.currentTimeMillis() - start - Log.d("SimpleMarkdown", "Handled markdown in " + timeTakenMs + "ms") - } - } - - override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { - } - - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - } - }) - } var touchDown = 0L var oldX = 0f @@ -157,6 +108,30 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope { }) } + override fun onStart() { + super.onStart() + launch { + val enableReadability = withContext(Dispatchers.IO) { + context?.let { + PreferenceManager.getDefaultSharedPreferences(it) + .getBoolean(getString(R.string.readability_enabled), false) + }?: false + } + if (enableReadability) { + if (readabilityWatcher == null) { + readabilityWatcher = ReadabilityTextWatcher() + } + markdownEditor?.addTextChangedListener(readabilityWatcher) + } else { + readabilityWatcher?.let { + markdownEditor?.removeTextChangedListener(it) + } + readabilityWatcher = null + } + + } + } + override fun onDestroy() { coroutineContext[Job]?.let { cancel() @@ -171,4 +146,45 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope { override fun onDeselected() { markdownEditor?.hideKeyboard() } + + inner class ReadabilityTextWatcher : TextWatcher { + private var previousValue = "" + private var searchFor = "" + + override fun afterTextChanged(s: Editable?) { + val searchText = s.toString().trim() + if (searchText == searchFor) + return + + searchFor = searchText + + launch { + delay(250) + if (searchText != searchFor) + return@launch + val start = System.currentTimeMillis() + if (searchFor.isEmpty()) return@launch + if (previousValue == searchFor) return@launch + val readability = Readability(searchFor) + val span = SpannableString(searchFor) + for (sentence in readability.sentences()) { + var color = Color.TRANSPARENT + if (sentence.syllableCount() > 25) color = Color.argb(100, 229, 232, 42) + if (sentence.syllableCount() > 35) color = Color.argb(100, 193, 66, 66) + Log.d("SimpleMarkdown", "Sentence start: ${sentence.start()} end: ${sentence.end()}") + span.setSpan(BackgroundColorSpan(color), sentence.start(), sentence.end(), 0) + } + markdownEditor?.setTextKeepState(span, TextView.BufferType.SPANNABLE) + previousValue = searchFor + val timeTakenMs = System.currentTimeMillis() - start + Log.d("SimpleMarkdown", "Handled markdown in $timeTakenMs ms") + } + } + + override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { + } + + override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { + } + } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt index 0555d53..3d6726f 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/view/fragment/PreviewFragment.kt @@ -24,6 +24,7 @@ class PreviewFragment : Fragment(), CoroutineScope { override val coroutineContext: CoroutineContext = Dispatchers.Main lateinit var viewModel: MarkdownViewModel private var markdownPreview: WebView? = null + private var style: String = "" override fun onCreateView( inflater: LayoutInflater, @@ -42,38 +43,45 @@ class PreviewFragment : Fragment(), CoroutineScope { this, (requireActivity().application as MarkdownApplication).viewModelFactory ).get(MarkdownViewModel::class.java) - viewModel.markdownUpdates.observe(this, Observer { - markdownPreview?.post { - val isNightMode = AppCompatDelegate.getDefaultNightMode() == - AppCompatDelegate.MODE_NIGHT_YES - || context!!.resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES - val defaultCssId = if (isNightMode) { - R.string.pref_custom_css_default_dark + launch { + val isNightMode = AppCompatDelegate.getDefaultNightMode() == + AppCompatDelegate.MODE_NIGHT_YES + || context!!.resources.configuration.uiMode and UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES + val defaultCssId = if (isNightMode) { + R.string.pref_custom_css_default_dark + } else { + R.string.pref_custom_css_default + } + val css = withContext(Dispatchers.IO) { + @Suppress("ConstantConditionIf") + if (!BuildConfig.ENABLE_CUSTOM_CSS) { + requireActivity().getString(defaultCssId) } else { - R.string.pref_custom_css_default - } - launch { - val css = withContext(Dispatchers.IO) { - @Suppress("ConstantConditionIf") - if (!BuildConfig.ENABLE_CUSTOM_CSS) { - requireActivity().getString(defaultCssId) - } else { - PreferenceManager.getDefaultSharedPreferences(requireActivity()) - .getString( - getString(R.string.pref_custom_css), - getString(defaultCssId) - )?: "" - } - } - val style = String.format(FORMAT_CSS, css) - markdownPreview?.loadDataWithBaseURL(null, - style + it.toHtml(), - "text/html", - "UTF-8", null - ) + PreferenceManager.getDefaultSharedPreferences(requireActivity()) + .getString( + getString(R.string.pref_custom_css), + getString(defaultCssId) + ) ?: "" } } - }) + style = String.format(FORMAT_CSS, css) + updateWebContent(viewModel.markdownUpdates.value ?: "") + viewModel.markdownUpdates.observe(this@PreviewFragment, Observer { + updateWebContent(it) + }) + } + } + + private fun updateWebContent(markdown: String) { + markdownPreview?.post { + launch { + markdownPreview?.loadDataWithBaseURL(null, + style + markdown.toHtml(), + "text/html", + "UTF-8", null + ) + } + } } override fun onDestroyView() { diff --git a/app/src/main/res/menu/menu_edit.xml b/app/src/main/res/menu/menu_edit.xml index f2f4a2f..0c70280 100644 --- a/app/src/main/res/menu/menu_edit.xml +++ b/app/src/main/res/menu/menu_edit.xml @@ -17,6 +17,9 @@ + Save Changes Would you like to save your changes? Discard + Save as... @string/pref_value_light @string/pref_value_dark