Add Save as... and improve preview/edit performance
This commit is contained in:
parent
04954b96f7
commit
112b776080
6 changed files with 116 additions and 85 deletions
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<String> {
|
||||
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<String> {
|
||||
updateWebContent(it)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateWebContent(markdown: String) {
|
||||
markdownPreview?.post {
|
||||
launch {
|
||||
markdownPreview?.loadDataWithBaseURL(null,
|
||||
style + markdown.toHtml(),
|
||||
"text/html",
|
||||
"UTF-8", null
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:title="@string/action_save" />
|
||||
<item
|
||||
android:id="@+id/action_save_as"
|
||||
android:title="@string/action_save_as" />
|
||||
<item
|
||||
android:id="@+id/action_lock_swipe"
|
||||
android:checkable="true"
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
<string name="save_changes">Save Changes</string>
|
||||
<string name="prompt_save_changes">Would you like to save your changes?</string>
|
||||
<string name="action_discard">Discard</string>
|
||||
<string name="action_save_as">Save as...</string>
|
||||
<string-array name="pref_entries_dark_mode">
|
||||
<item>@string/pref_value_light</item>
|
||||
<item>@string/pref_value_dark</item>
|
||||
|
|
Loading…
Reference in a new issue