Fix various concurrency issues and simplify some logic throughout the app
This commit is contained in:
parent
810a334bb0
commit
d841fd0225
13 changed files with 143 additions and 255 deletions
|
@ -4,12 +4,8 @@ import android.app.Application
|
||||||
import android.os.StrictMode
|
import android.os.StrictMode
|
||||||
import com.wbrawner.simplemarkdown.utility.CrashlyticsErrorHandler
|
import com.wbrawner.simplemarkdown.utility.CrashlyticsErrorHandler
|
||||||
import com.wbrawner.simplemarkdown.utility.ErrorHandler
|
import com.wbrawner.simplemarkdown.utility.ErrorHandler
|
||||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModelFactory
|
|
||||||
|
|
||||||
class MarkdownApplication : Application() {
|
class MarkdownApplication : Application() {
|
||||||
val viewModelFactory: MarkdownViewModelFactory by lazy {
|
|
||||||
MarkdownViewModelFactory()
|
|
||||||
}
|
|
||||||
val errorHandler: ErrorHandler by lazy {
|
val errorHandler: ErrorHandler by lazy {
|
||||||
CrashlyticsErrorHandler()
|
CrashlyticsErrorHandler()
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,8 +20,8 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.MarkdownApplication
|
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
|
import com.wbrawner.simplemarkdown.utility.hideKeyboard
|
||||||
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
|
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
|
||||||
import com.wbrawner.simplemarkdown.view.fragment.MainMenuFragment
|
import com.wbrawner.simplemarkdown.view.fragment.MainMenuFragment
|
||||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
||||||
|
@ -49,10 +49,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
||||||
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
viewModel = ViewModelProviders.of(
|
viewModel = ViewModelProviders.of(this).get(MarkdownViewModel::class.java)
|
||||||
this,
|
|
||||||
(application as MarkdownApplication).viewModelFactory
|
|
||||||
).get(MarkdownViewModel::class.java)
|
|
||||||
val adapter = EditPagerAdapter(supportFragmentManager, this@MainActivity)
|
val adapter = EditPagerAdapter(supportFragmentManager, this@MainActivity)
|
||||||
pager.adapter = adapter
|
pager.adapter = adapter
|
||||||
pager.addOnPageChangeListener(adapter)
|
pager.addOnPageChangeListener(adapter)
|
||||||
|
@ -66,6 +63,11 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
||||||
viewModel.fileName.observe(this, Observer<String> {
|
viewModel.fileName.observe(this, Observer<String> {
|
||||||
title = it
|
title = it
|
||||||
})
|
})
|
||||||
|
intent?.data?.let {
|
||||||
|
launch {
|
||||||
|
viewModel.load(this@MainActivity, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onUserLeaveHint() {
|
override fun onUserLeaveHint() {
|
||||||
|
@ -114,11 +116,8 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
MainMenuFragment()
|
MainMenuFragment().show(supportFragmentManager, null)
|
||||||
.apply {
|
window.decorView.hideKeyboard()
|
||||||
errorHandler = (application as MarkdownApplication).errorHandler
|
|
||||||
}
|
|
||||||
.show(supportFragmentManager, null)
|
|
||||||
}
|
}
|
||||||
R.id.action_save -> {
|
R.id.action_save -> {
|
||||||
launch {
|
launch {
|
||||||
|
|
|
@ -3,24 +3,32 @@ package com.wbrawner.simplemarkdown.view.activity
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import com.wbrawner.simplemarkdown.MarkdownApplication
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
|
import com.wbrawner.simplemarkdown.utility.readAssetToString
|
||||||
|
import com.wbrawner.simplemarkdown.utility.toHtml
|
||||||
import kotlinx.android.synthetic.main.activity_markdown_info.*
|
import kotlinx.android.synthetic.main.activity_markdown_info.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class MarkdownInfoActivity : AppCompatActivity() {
|
class MarkdownInfoActivity : AppCompatActivity(), CoroutineScope {
|
||||||
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContentView(R.layout.activity_markdown_info)
|
setContentView(R.layout.activity_markdown_info)
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||||
val intent = intent
|
val title = intent?.getStringExtra(EXTRA_TITLE)
|
||||||
if (intent == null || !intent.hasExtra("title") || !intent.hasExtra("html")) {
|
val fileName = intent?.getStringExtra(EXTRA_FILE)
|
||||||
|
if (title.isNullOrBlank() || fileName.isNullOrBlank()) {
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
title = intent.getStringExtra("title")
|
|
||||||
val isNightMode = AppCompatDelegate.getDefaultNightMode() ==
|
val isNightMode = AppCompatDelegate.getDefaultNightMode() ==
|
||||||
AppCompatDelegate.MODE_NIGHT_YES
|
AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|| resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
|| resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||||
|
@ -30,12 +38,29 @@ class MarkdownInfoActivity : AppCompatActivity() {
|
||||||
R.string.pref_custom_css_default
|
R.string.pref_custom_css_default
|
||||||
}
|
}
|
||||||
val css: String? = getString(defaultCssId)
|
val css: String? = getString(defaultCssId)
|
||||||
|
launch {
|
||||||
|
try {
|
||||||
|
val html = assets?.readAssetToString(fileName)
|
||||||
|
?.toHtml()
|
||||||
|
?: throw RuntimeException("Unable to open stream to $fileName")
|
||||||
|
infoWebview.loadDataWithBaseURL(null,
|
||||||
|
String.format(FORMAT_CSS, css) + html,
|
||||||
|
"text/html",
|
||||||
|
"UTF-8", null
|
||||||
|
)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
(application as MarkdownApplication).errorHandler.reportException(e)
|
||||||
|
Toast.makeText(this@MarkdownInfoActivity, R.string.file_load_error, Toast.LENGTH_SHORT).show()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
infoWebview.loadDataWithBaseURL(null,
|
override fun onDestroy() {
|
||||||
String.format(FORMAT_CSS, css) + intent.getStringExtra("html"),
|
coroutineContext[Job]?.let {
|
||||||
"text/html",
|
cancel()
|
||||||
"UTF-8", null
|
}
|
||||||
)
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,8 +73,10 @@ class MarkdownInfoActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var FORMAT_CSS = "<style>" +
|
const val FORMAT_CSS = "<style>" +
|
||||||
"%s" +
|
"%s" +
|
||||||
"</style>"
|
"</style>"
|
||||||
|
const val EXTRA_TITLE = "title"
|
||||||
|
const val EXTRA_FILE = "file"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,10 @@ import android.content.Intent
|
||||||
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.preference.PreferenceManager
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.MarkdownApplication
|
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
@ -18,15 +15,8 @@ class SplashActivity : AppCompatActivity(), CoroutineScope {
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
|
|
||||||
lateinit var viewModel: MarkdownViewModel
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
viewModel = ViewModelProviders.of(
|
|
||||||
this,
|
|
||||||
(application as MarkdownApplication).viewModelFactory
|
|
||||||
).get(MarkdownViewModel::class.java)
|
|
||||||
|
|
||||||
launch {
|
launch {
|
||||||
val darkMode = withContext(Dispatchers.IO) {
|
val darkMode = withContext(Dispatchers.IO) {
|
||||||
val darkModeValue = PreferenceManager.getDefaultSharedPreferences(this@SplashActivity)
|
val darkModeValue = PreferenceManager.getDefaultSharedPreferences(this@SplashActivity)
|
||||||
|
@ -40,7 +30,7 @@ class SplashActivity : AppCompatActivity(), CoroutineScope {
|
||||||
darkModeValue.equals(getString(R.string.pref_value_dark), ignoreCase = true) -> AppCompatDelegate.MODE_NIGHT_YES
|
darkModeValue.equals(getString(R.string.pref_value_dark), ignoreCase = true) -> AppCompatDelegate.MODE_NIGHT_YES
|
||||||
else -> {
|
else -> {
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||||
AppCompatDelegate.MODE_NIGHT_AUTO
|
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
||||||
} else {
|
} else {
|
||||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
}
|
}
|
||||||
|
@ -50,21 +40,21 @@ class SplashActivity : AppCompatActivity(), CoroutineScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
AppCompatDelegate.setDefaultNightMode(darkMode)
|
AppCompatDelegate.setDefaultNightMode(darkMode)
|
||||||
withContext(Dispatchers.IO) {
|
val uri = withContext(Dispatchers.IO) {
|
||||||
var uri = intent?.data
|
intent?.data
|
||||||
if (uri == null) {
|
?: PreferenceManager.getDefaultSharedPreferences(this@SplashActivity)
|
||||||
uri = PreferenceManager.getDefaultSharedPreferences(this@SplashActivity)
|
.getString(
|
||||||
.getString(
|
getString(R.string.pref_key_autosave_uri),
|
||||||
getString(R.string.pref_key_autosave_uri),
|
null
|
||||||
null
|
)?.let {
|
||||||
)?.let {
|
Uri.parse(it)
|
||||||
Uri.parse(it)
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.load(this@SplashActivity, uri)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val startIntent = Intent(this@SplashActivity, MainActivity::class.java)
|
val startIntent = Intent(this@SplashActivity, MainActivity::class.java)
|
||||||
|
.apply {
|
||||||
|
data = uri
|
||||||
|
}
|
||||||
startActivity(startIntent)
|
startActivity(startIntent)
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package com.wbrawner.simplemarkdown.view.fragment
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.SpannableString
|
import android.text.SpannableString
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
|
@ -19,7 +18,7 @@ import android.widget.TextView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import com.wbrawner.simplemarkdown.MarkdownApplication
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import com.wbrawner.simplemarkdown.model.Readability
|
import com.wbrawner.simplemarkdown.model.Readability
|
||||||
import com.wbrawner.simplemarkdown.utility.hideKeyboard
|
import com.wbrawner.simplemarkdown.utility.hideKeyboard
|
||||||
|
@ -33,7 +32,7 @@ import kotlin.math.abs
|
||||||
class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
|
class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
|
||||||
private var markdownEditor: EditText? = null
|
private var markdownEditor: EditText? = null
|
||||||
private var markdownEditorScroller: ScrollView? = null
|
private var markdownEditorScroller: ScrollView? = null
|
||||||
private lateinit var viewModel: MarkdownViewModel
|
lateinit var viewModel: MarkdownViewModel
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
private var readabilityWatcher: TextWatcher? = null
|
private var readabilityWatcher: TextWatcher? = null
|
||||||
|
|
||||||
|
@ -45,6 +44,9 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
activity?.let {
|
||||||
|
viewModel = ViewModelProviders.of(it).get(MarkdownViewModel::class.java)
|
||||||
|
} ?: return
|
||||||
markdownEditor = view.findViewById(R.id.markdown_edit)
|
markdownEditor = view.findViewById(R.id.markdown_edit)
|
||||||
markdownEditorScroller = view.findViewById(R.id.markdown_edit_container)
|
markdownEditorScroller = view.findViewById(R.id.markdown_edit_container)
|
||||||
markdownEditor?.addTextChangedListener(object : TextWatcher {
|
markdownEditor?.addTextChangedListener(object : TextWatcher {
|
||||||
|
@ -95,21 +97,9 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
viewModel = ViewModelProviders.of(
|
|
||||||
this,
|
|
||||||
(requireActivity().application as MarkdownApplication).viewModelFactory
|
|
||||||
).get(MarkdownViewModel::class.java)
|
|
||||||
viewModel.originalMarkdown.observe(this, Observer<String> {
|
viewModel.originalMarkdown.observe(this, Observer<String> {
|
||||||
markdownEditor?.setText(it)
|
markdownEditor?.setText(it)
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
override fun onStart() {
|
|
||||||
super.onStart()
|
|
||||||
launch {
|
launch {
|
||||||
val enableReadability = withContext(Dispatchers.IO) {
|
val enableReadability = withContext(Dispatchers.IO) {
|
||||||
context?.let {
|
context?.let {
|
||||||
|
@ -132,11 +122,11 @@ class EditFragment : Fragment(), ViewPagerPage, CoroutineScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroyView() {
|
||||||
coroutineContext[Job]?.let {
|
coroutineContext[Job]?.let {
|
||||||
cancel()
|
cancel()
|
||||||
}
|
}
|
||||||
super.onDestroy()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSelected() {
|
override fun onSelected() {
|
||||||
|
|
|
@ -1,31 +1,21 @@
|
||||||
package com.wbrawner.simplemarkdown.view.fragment
|
package com.wbrawner.simplemarkdown.view.fragment
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import com.wbrawner.simplemarkdown.utility.ErrorHandler
|
|
||||||
import com.wbrawner.simplemarkdown.utility.readAssetToString
|
|
||||||
import com.wbrawner.simplemarkdown.utility.toHtml
|
|
||||||
import com.wbrawner.simplemarkdown.view.activity.MainActivity
|
import com.wbrawner.simplemarkdown.view.activity.MainActivity
|
||||||
import com.wbrawner.simplemarkdown.view.activity.MarkdownInfoActivity
|
import com.wbrawner.simplemarkdown.view.activity.MarkdownInfoActivity
|
||||||
|
import com.wbrawner.simplemarkdown.view.activity.MarkdownInfoActivity.Companion.EXTRA_FILE
|
||||||
|
import com.wbrawner.simplemarkdown.view.activity.MarkdownInfoActivity.Companion.EXTRA_TITLE
|
||||||
import com.wbrawner.simplemarkdown.view.activity.SettingsActivity
|
import com.wbrawner.simplemarkdown.view.activity.SettingsActivity
|
||||||
import com.wbrawner.simplemarkdown.view.activity.SupportActivity
|
import com.wbrawner.simplemarkdown.view.activity.SupportActivity
|
||||||
import kotlinx.android.synthetic.main.fragment_menu_main.*
|
import kotlinx.android.synthetic.main.fragment_menu_main.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
|
||||||
|
|
||||||
class MainMenuFragment : BottomSheetDialogFragment(), CoroutineScope {
|
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
|
||||||
lateinit var errorHandler: ErrorHandler
|
|
||||||
|
|
||||||
|
class MainMenuFragment : BottomSheetDialogFragment() {
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
@ -34,20 +24,47 @@ class MainMenuFragment : BottomSheetDialogFragment(), CoroutineScope {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
mainMenuNavigationView.setNavigationItemSelectedListener {
|
mainMenuNavigationView.setNavigationItemSelectedListener { menuItem ->
|
||||||
when (it.itemId) {
|
val (intentClass, fileName, title) = when (menuItem.itemId) {
|
||||||
R.id.action_help -> showInfoActivity(context, R.id.action_help)
|
R.id.action_help -> Triple(
|
||||||
R.id.action_settings -> {
|
MarkdownInfoActivity::class.java,
|
||||||
val settingsIntent = Intent(context, SettingsActivity::class.java)
|
"Cheatsheet.md",
|
||||||
startActivityForResult(settingsIntent, MainActivity.REQUEST_DARK_MODE)
|
R.string.action_help
|
||||||
}
|
)
|
||||||
R.id.action_libraries -> showInfoActivity(context, R.id.action_libraries)
|
R.id.action_settings -> Triple(
|
||||||
R.id.action_privacy -> showInfoActivity(context, R.id.action_privacy)
|
SettingsActivity::class.java,
|
||||||
R.id.action_support -> Intent(context, SupportActivity::class.java)
|
null,
|
||||||
.apply {
|
null
|
||||||
startActivity(this)
|
)
|
||||||
dialog?.dismiss()
|
R.id.action_libraries -> Triple(
|
||||||
}
|
MarkdownInfoActivity::class.java,
|
||||||
|
"Libraries.md",
|
||||||
|
R.id.action_libraries
|
||||||
|
)
|
||||||
|
R.id.action_privacy -> Triple(
|
||||||
|
MarkdownInfoActivity::class.java,
|
||||||
|
"Privacy Policy.md",
|
||||||
|
R.id.action_libraries
|
||||||
|
)
|
||||||
|
R.id.action_support -> Triple(
|
||||||
|
SupportActivity::class.java,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
else -> throw IllegalStateException("This shouldn't happen")
|
||||||
|
}
|
||||||
|
val intent = Intent(context, intentClass)
|
||||||
|
fileName?.let {
|
||||||
|
intent.putExtra(EXTRA_FILE, it)
|
||||||
|
}
|
||||||
|
title?.let {
|
||||||
|
intent.putExtra(EXTRA_TITLE, getString(it))
|
||||||
|
}
|
||||||
|
if (intentClass == SettingsActivity::class.java) {
|
||||||
|
startActivityForResult(intent, MainActivity.REQUEST_DARK_MODE)
|
||||||
|
} else {
|
||||||
|
startActivity(intent)
|
||||||
|
dialog?.dismiss()
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -61,40 +78,4 @@ class MainMenuFragment : BottomSheetDialogFragment(), CoroutineScope {
|
||||||
}
|
}
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showInfoActivity(context: Context?, action: Int) {
|
|
||||||
val infoIntent = Intent(context, MarkdownInfoActivity::class.java)
|
|
||||||
var fileName = ""
|
|
||||||
var title = ""
|
|
||||||
when (action) {
|
|
||||||
R.id.action_help -> {
|
|
||||||
fileName = "Cheatsheet.md"
|
|
||||||
title = getString(R.string.action_help)
|
|
||||||
}
|
|
||||||
R.id.action_libraries -> {
|
|
||||||
fileName = "Libraries.md"
|
|
||||||
title = getString(R.string.action_libraries)
|
|
||||||
}
|
|
||||||
R.id.action_privacy -> {
|
|
||||||
fileName = "Privacy Policy.md"
|
|
||||||
title = getString(R.string.action_privacy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
infoIntent.putExtra("title", title)
|
|
||||||
launch {
|
|
||||||
// TODO: Refactor this to have the info activity load the markdown instead of doing
|
|
||||||
// it here
|
|
||||||
try {
|
|
||||||
val html = context?.assets?.readAssetToString(fileName)
|
|
||||||
?.toHtml()
|
|
||||||
?: throw RuntimeException("Unable to open stream to $fileName")
|
|
||||||
infoIntent.putExtra("html", html)
|
|
||||||
startActivity(infoIntent, null)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
errorHandler.reportException(e)
|
|
||||||
Toast.makeText(context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
|
|
||||||
}
|
|
||||||
dialog?.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@ package com.wbrawner.simplemarkdown.view.fragment
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
|
import android.content.res.Configuration.UI_MODE_NIGHT_MASK
|
||||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -12,8 +11,8 @@ import androidx.appcompat.app.AppCompatDelegate
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.BuildConfig
|
import com.wbrawner.simplemarkdown.BuildConfig
|
||||||
import com.wbrawner.simplemarkdown.MarkdownApplication
|
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import com.wbrawner.simplemarkdown.utility.toHtml
|
import com.wbrawner.simplemarkdown.utility.toHtml
|
||||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
||||||
|
@ -35,14 +34,9 @@ class PreviewFragment : Fragment(), CoroutineScope {
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
markdownPreview = view.findViewById(R.id.markdown_view)
|
markdownPreview = view.findViewById(R.id.markdown_view)
|
||||||
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
|
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
|
||||||
}
|
activity?.let {
|
||||||
|
viewModel = ViewModelProviders.of(it).get(MarkdownViewModel::class.java)
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
} ?: return
|
||||||
super.onActivityCreated(savedInstanceState)
|
|
||||||
viewModel = ViewModelProviders.of(
|
|
||||||
this,
|
|
||||||
(requireActivity().application as MarkdownApplication).viewModelFactory
|
|
||||||
).get(MarkdownViewModel::class.java)
|
|
||||||
launch {
|
launch {
|
||||||
val isNightMode = AppCompatDelegate.getDefaultNightMode() ==
|
val isNightMode = AppCompatDelegate.getDefaultNightMode() ==
|
||||||
AppCompatDelegate.MODE_NIGHT_YES
|
AppCompatDelegate.MODE_NIGHT_YES
|
||||||
|
@ -53,18 +47,19 @@ class PreviewFragment : Fragment(), CoroutineScope {
|
||||||
R.string.pref_custom_css_default
|
R.string.pref_custom_css_default
|
||||||
}
|
}
|
||||||
val css = withContext(Dispatchers.IO) {
|
val css = withContext(Dispatchers.IO) {
|
||||||
|
val context = context ?: return@withContext null
|
||||||
@Suppress("ConstantConditionIf")
|
@Suppress("ConstantConditionIf")
|
||||||
if (!BuildConfig.ENABLE_CUSTOM_CSS) {
|
if (!BuildConfig.ENABLE_CUSTOM_CSS) {
|
||||||
requireActivity().getString(defaultCssId)
|
context.getString(defaultCssId)
|
||||||
} else {
|
} else {
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireActivity())
|
PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getString(
|
.getString(
|
||||||
getString(R.string.pref_custom_css),
|
getString(R.string.pref_custom_css),
|
||||||
getString(defaultCssId)
|
getString(defaultCssId)
|
||||||
) ?: ""
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style = String.format(FORMAT_CSS, css)
|
style = String.format(FORMAT_CSS, css ?: "")
|
||||||
updateWebContent(viewModel.markdownUpdates.value ?: "")
|
updateWebContent(viewModel.markdownUpdates.value ?: "")
|
||||||
viewModel.markdownUpdates.observe(this@PreviewFragment, Observer<String> {
|
viewModel.markdownUpdates.observe(this@PreviewFragment, Observer<String> {
|
||||||
updateWebContent(it)
|
updateWebContent(it)
|
||||||
|
@ -85,6 +80,9 @@ class PreviewFragment : Fragment(), CoroutineScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
coroutineContext[Job]?.let {
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
markdownPreview?.let {
|
markdownPreview?.let {
|
||||||
(it.parent as ViewGroup).removeView(it)
|
(it.parent as ViewGroup).removeView(it)
|
||||||
it.destroy()
|
it.destroy()
|
||||||
|
@ -93,13 +91,6 @@ class PreviewFragment : Fragment(), CoroutineScope {
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
coroutineContext[Job]?.let {
|
|
||||||
cancel()
|
|
||||||
}
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var FORMAT_CSS = "<style>" +
|
var FORMAT_CSS = "<style>" +
|
||||||
"%s" +
|
"%s" +
|
||||||
|
|
|
@ -3,61 +3,42 @@ package com.wbrawner.simplemarkdown.view.fragment
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.StrictMode
|
|
||||||
import android.preference.ListPreference
|
|
||||||
import android.preference.Preference
|
|
||||||
import android.preference.PreferenceFragment
|
|
||||||
import android.preference.PreferenceManager
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
import androidx.appcompat.app.AppCompatDelegate
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import com.wbrawner.simplemarkdown.BuildConfig
|
import com.wbrawner.simplemarkdown.BuildConfig
|
||||||
import com.wbrawner.simplemarkdown.R
|
import com.wbrawner.simplemarkdown.R
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import java.lang.Exception
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class SettingsFragment
|
class SettingsFragment
|
||||||
: PreferenceFragment(),
|
: PreferenceFragmentCompat(),
|
||||||
SharedPreferences.OnSharedPreferenceChangeListener,
|
SharedPreferences.OnSharedPreferenceChangeListener,
|
||||||
CoroutineScope {
|
CoroutineScope {
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
addPreferencesFromResource(R.xml.pref_general)
|
||||||
|
}
|
||||||
|
|
||||||
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
override val coroutineContext: CoroutineContext = Dispatchers.Main
|
||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
launch {
|
launch(context = Dispatchers.IO) {
|
||||||
withContext(Dispatchers.IO) {
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
try {
|
sharedPreferences.registerOnSharedPreferenceChangeListener(this@SettingsFragment)
|
||||||
// This can be thrown when recreating the activity for theme changes
|
(findPreference(getString(R.string.pref_key_dark_mode)) as? ListPreference)?.let {
|
||||||
addPreferencesFromResource(R.xml.pref_general)
|
setListPreferenceSummary(sharedPreferences, it)
|
||||||
} catch (ignored: Exception) {
|
}
|
||||||
return@withContext
|
@Suppress("ConstantConditionIf")
|
||||||
}
|
if (!BuildConfig.ENABLE_CUSTOM_CSS) {
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(activity)
|
preferenceScreen.removePreference(findPreference(getString(R.string.pref_custom_css)))
|
||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this@SettingsFragment)
|
|
||||||
(findPreference(getString(R.string.pref_key_dark_mode)) as? ListPreference)?.let {
|
|
||||||
setListPreferenceSummary(sharedPreferences, it)
|
|
||||||
}
|
|
||||||
@Suppress("ConstantConditionIf")
|
|
||||||
if (!BuildConfig.ENABLE_CUSTOM_CSS) {
|
|
||||||
preferenceScreen.removePreference(findPreference(getString(R.string.pref_custom_css)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?
|
|
||||||
): View? {
|
|
||||||
return inflater.inflate(R.layout.preference_list_fragment_safe, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
if (!isAdded) return
|
if (!isAdded) return
|
||||||
val preference = findPreference(key) as? ListPreference ?: return
|
val preference = findPreference(key) as? ListPreference ?: return
|
||||||
|
@ -66,7 +47,7 @@ class SettingsFragment
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var darkMode: Int = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
var darkMode: Int = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||||
AppCompatDelegate.MODE_NIGHT_AUTO
|
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
||||||
} else {
|
} else {
|
||||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.wbrawner.simplemarkdown.view.overrides
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.widget.ListView
|
|
||||||
|
|
||||||
class SafeListView : ListView {
|
|
||||||
constructor(context: Context) : super(context)
|
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
|
||||||
|
|
||||||
override fun onDetachedFromWindow() {
|
|
||||||
try {
|
|
||||||
super.onDetachedFromWindow()
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,6 @@ import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
|
||||||
import com.wbrawner.simplemarkdown.utility.getName
|
import com.wbrawner.simplemarkdown.utility.getName
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
@ -78,7 +77,7 @@ class MarkdownViewModel : ViewModel() {
|
||||||
return try {
|
return try {
|
||||||
withContext(coroutineContext) {
|
withContext(coroutineContext) {
|
||||||
outputStream.writer().use {
|
outputStream.writer().use {
|
||||||
it.write(markdownUpdates.value)
|
it.write(markdownUpdates.value ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -93,14 +92,3 @@ class MarkdownViewModel : ViewModel() {
|
||||||
markdownUpdates.postValue("")
|
markdownUpdates.postValue("")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MarkdownViewModelFactory : ViewModelProvider.Factory {
|
|
||||||
private val markdownViewModel: MarkdownViewModel by lazy {
|
|
||||||
MarkdownViewModel()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
return markdownViewModel as T
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -38,5 +38,4 @@
|
||||||
android:background="@color/colorBackground" />
|
android:background="@color/colorBackground" />
|
||||||
</com.google.android.material.card.MaterialCardView>
|
</com.google.android.material.card.MaterialCardView>
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -1,20 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
|
||||||
tools:context="com.wbrawner.simplemarkdown.view.activity.ExplorerActivity"
|
|
||||||
tools:showIn="@layout/activity_explorer">
|
|
||||||
|
|
||||||
<com.wbrawner.simplemarkdown.view.overrides.SafeListView
|
|
||||||
android:id="@+id/file_list"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:background="@android:color/transparent"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.wbrawner.simplemarkdown.view.overrides.SafeListView
|
|
||||||
android:id="@android:id/list"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
Loading…
Reference in a new issue