Migrate some more to Jetpack Compose + Material3
This commit is contained in:
parent
643345493e
commit
c7e54f21d9
26 changed files with 223 additions and 1005 deletions
|
@ -166,9 +166,9 @@ android.productFlavors.forEach { flavor ->
|
|||
apply(plugin = "com.google.firebase.crashlytics")
|
||||
|
||||
dependencies {
|
||||
implementation("com.android.billingclient:billing:5.1.0")
|
||||
implementation("com.android.billingclient:billing:6.0.1")
|
||||
implementation("com.google.android.play:core-ktx:1.8.1")
|
||||
implementation("com.google.firebase:firebase-crashlytics:18.3.5")
|
||||
implementation("com.google.firebase:firebase-crashlytics:18.4.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package com.wbrawner.simplemarkdown.utility
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
class SupportLinkProvider(@Suppress("unused") private val activity: Activity) {
|
||||
val supportLinks = MutableLiveData<List<MaterialButton>>()
|
||||
}
|
||||
@Composable
|
||||
fun SupportLinks() {}
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding
|
|||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.text.BasicTextField
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
|
@ -26,6 +27,7 @@ import androidx.compose.material3.DropdownMenuItem
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.NavigationDrawerItem
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Tab
|
||||
|
@ -42,9 +44,13 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.navigation.NavController
|
||||
|
@ -101,7 +107,9 @@ fun MainScreen(navController: NavController, viewModel: MarkdownViewModel) {
|
|||
DropdownMenuItem(text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text("Lock Swiping")
|
||||
Checkbox(checked = lockSwiping, onCheckedChange = { lockSwiping = !lockSwiping })
|
||||
Checkbox(
|
||||
checked = lockSwiping,
|
||||
onCheckedChange = { lockSwiping = !lockSwiping })
|
||||
}
|
||||
}, onClick = {
|
||||
lockSwiping = !lockSwiping
|
||||
|
@ -138,7 +146,9 @@ fun MainScreen(navController: NavController, viewModel: MarkdownViewModel) {
|
|||
.padding(8.dp),
|
||||
value = markdown,
|
||||
onValueChange = { viewModel.updateMarkdown(it) },
|
||||
textStyle = TextStyle.Default.copy(fontFamily = FontFamily.Monospace)
|
||||
textStyle = TextStyle.Default.copy(fontFamily = FontFamily.Monospace, color = MaterialTheme.colorScheme.onSurface),
|
||||
keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
|
||||
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface)
|
||||
)
|
||||
} else {
|
||||
MarkdownPreview(modifier = Modifier.fillMaxSize(), markdown)
|
||||
|
@ -154,18 +164,26 @@ fun MarkdownNavigationDrawer(
|
|||
navigate: (Route) -> Unit, content: @Composable (drawerState: DrawerState) -> Unit
|
||||
) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
DismissibleNavigationDrawer(drawerState = drawerState, drawerContent = {
|
||||
DismissibleDrawerSheet {
|
||||
Route.entries.forEach { route ->
|
||||
if (route == Route.EDITOR) {
|
||||
return@forEach
|
||||
}
|
||||
NavigationDrawerItem(icon = {
|
||||
Icon(imageVector = route.icon, contentDescription = null)
|
||||
},
|
||||
NavigationDrawerItem(
|
||||
icon = {
|
||||
Icon(imageVector = route.icon, contentDescription = null)
|
||||
},
|
||||
label = { Text(route.title) },
|
||||
selected = false,
|
||||
onClick = { navigate(route) })
|
||||
onClick = {
|
||||
navigate(route)
|
||||
coroutineScope.launch {
|
||||
drawerState.close()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}) {
|
||||
|
|
|
@ -14,7 +14,6 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.navigation.NavController
|
||||
import com.wbrawner.simplemarkdown.utility.readAssetToString
|
||||
import com.wbrawner.simplemarkdown.utility.toHtml
|
||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
||||
|
||||
@Composable
|
||||
fun MarkdownInfoScreen(
|
||||
|
|
|
@ -1,2 +1,104 @@
|
|||
package com.wbrawner.simplemarkdown.ui
|
||||
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.browser.customtabs.CustomTabsIntent
|
||||
import androidx.browser.customtabs.CustomTabsIntent.SHARE_STATE_ON
|
||||
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Favorite
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.ContextCompat.startActivity
|
||||
import androidx.navigation.NavController
|
||||
import com.wbrawner.simplemarkdown.R
|
||||
import com.wbrawner.simplemarkdown.utility.SupportLinks
|
||||
|
||||
@Composable
|
||||
fun SupportScreen(navController: NavController) {
|
||||
Scaffold(topBar = {
|
||||
MarkdownTopAppBar(title = "Support SimpleMarkdown", navController = navController)
|
||||
}) { paddingValues ->
|
||||
val context = LocalContext.current
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.padding(16.dp)
|
||||
.verticalScroll(rememberScrollState()),
|
||||
verticalArrangement = spacedBy(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(100.dp),
|
||||
imageVector = Icons.Default.Favorite,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary
|
||||
)
|
||||
Text(context.getString(R.string.support_info), textAlign = TextAlign.Center)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
CustomTabsIntent.Builder()
|
||||
.setShareState(SHARE_STATE_ON)
|
||||
.build()
|
||||
.launchUrl(context, Uri.parse("https://github.com/wbrawner/SimpleMarkdown"))
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(context.getColor(R.color.colorBackgroundGitHub)),
|
||||
contentColor = Color.White
|
||||
)
|
||||
) {
|
||||
Text(context.getString(R.string.action_view_github))
|
||||
}
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
val playStoreIntent = Intent(Intent.ACTION_VIEW)
|
||||
.apply {
|
||||
data = Uri.parse("market://details?id=${context.packageName}")
|
||||
addFlags(
|
||||
Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
|
||||
Intent.FLAG_ACTIVITY_MULTIPLE_TASK
|
||||
)
|
||||
}
|
||||
try {
|
||||
startActivity(context, playStoreIntent, null)
|
||||
} catch (ignored: ActivityNotFoundException) {
|
||||
playStoreIntent.data =
|
||||
Uri.parse("https://play.google.com/store/apps/details?id=${context.packageName}")
|
||||
startActivity(context, playStoreIntent, null)
|
||||
}
|
||||
},
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color(context.getColor(R.color.colorBackgroundPlayStore)),
|
||||
contentColor = Color.White
|
||||
)
|
||||
) {
|
||||
Text(context.getString(R.string.action_rate))
|
||||
}
|
||||
SupportLinks()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.view
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
|
||||
class DisableableViewPager : ViewPager {
|
||||
private var isSwipeLocked = false
|
||||
|
||||
constructor(context: Context) : super(context)
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
|
||||
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
|
||||
return !isSwipeLocked && super.onInterceptTouchEvent(ev)
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
override fun onTouchEvent(ev: MotionEvent): Boolean {
|
||||
return !isSwipeLocked && super.onTouchEvent(ev)
|
||||
}
|
||||
|
||||
fun setSwipeLocked(locked: Boolean) {
|
||||
this.isSwipeLocked = locked
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.view
|
||||
|
||||
interface ViewPagerPage {
|
||||
fun onSelected()
|
||||
fun onDeselected()
|
||||
}
|
|
@ -38,6 +38,7 @@ import com.wbrawner.simplemarkdown.R
|
|||
import com.wbrawner.simplemarkdown.ui.MainScreen
|
||||
import com.wbrawner.simplemarkdown.ui.MarkdownInfoScreen
|
||||
import com.wbrawner.simplemarkdown.ui.SettingsScreen
|
||||
import com.wbrawner.simplemarkdown.ui.SupportScreen
|
||||
import com.wbrawner.simplemarkdown.ui.theme.SimpleMarkdownTheme
|
||||
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -126,7 +127,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
|||
SettingsScreen(navController = navController)
|
||||
}
|
||||
composable(Route.SUPPORT.path) {
|
||||
Text("To do")
|
||||
SupportScreen(navController = navController)
|
||||
}
|
||||
composable(Route.HELP.path) {
|
||||
MarkdownInfoScreen(title = Route.HELP.title, file = "Cheatsheet.md", navController = navController)
|
||||
|
@ -141,12 +142,6 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (!findNavController(R.id.content).navigateUp()) {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class Route(
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.view.adapter
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentPagerAdapter
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import com.wbrawner.simplemarkdown.R
|
||||
import com.wbrawner.simplemarkdown.view.fragment.EditFragment
|
||||
import com.wbrawner.simplemarkdown.view.fragment.PreviewFragment
|
||||
|
||||
class EditPagerAdapter(fm: FragmentManager, private val context: Context)
|
||||
: FragmentPagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT), ViewPager.OnPageChangeListener {
|
||||
|
||||
private val editFragment = EditFragment()
|
||||
private val previewFragment = PreviewFragment()
|
||||
|
||||
override fun getItem(position: Int): Fragment {
|
||||
return when (position) {
|
||||
FRAGMENT_EDIT -> editFragment
|
||||
FRAGMENT_PREVIEW -> previewFragment
|
||||
else -> throw IllegalStateException("Attempting to get fragment for invalid page number")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
return NUM_PAGES
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
var stringId = 0
|
||||
when (position) {
|
||||
FRAGMENT_EDIT -> stringId = R.string.action_edit
|
||||
FRAGMENT_PREVIEW -> stringId = R.string.action_preview
|
||||
}
|
||||
return context.getString(stringId)
|
||||
}
|
||||
|
||||
override fun getPageWidth(position: Int): Float {
|
||||
return if (context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
0.5f
|
||||
} else {
|
||||
super.getPageWidth(position)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPageScrollStateChanged(state: Int) {
|
||||
}
|
||||
|
||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||
}
|
||||
|
||||
override fun onPageSelected(position: Int) {
|
||||
when (position) {
|
||||
FRAGMENT_EDIT -> {
|
||||
editFragment.onSelected()
|
||||
}
|
||||
FRAGMENT_PREVIEW -> {
|
||||
editFragment.onDeselected()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FRAGMENT_EDIT = 0
|
||||
const val FRAGMENT_PREVIEW = 1
|
||||
const val NUM_PAGES = 2
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
//package com.wbrawner.simplemarkdown.view.fragment
|
||||
//
|
||||
//import android.content.res.Configuration
|
||||
//import android.os.Bundle
|
||||
//import android.view.LayoutInflater
|
||||
//import android.view.MenuItem
|
||||
//import android.view.View
|
||||
//import android.view.ViewGroup
|
||||
//import android.widget.Toast
|
||||
//import androidx.appcompat.app.AppCompatDelegate
|
||||
//import androidx.fragment.app.Fragment
|
||||
//import androidx.lifecycle.lifecycleScope
|
||||
//import androidx.navigation.fragment.findNavController
|
||||
//import androidx.navigation.ui.setupWithNavController
|
||||
//import com.wbrawner.plausible.android.Plausible
|
||||
//import com.wbrawner.simplemarkdown.R
|
||||
//import com.wbrawner.simplemarkdown.databinding.FragmentMarkdownInfoBinding
|
||||
//import com.wbrawner.simplemarkdown.utility.*
|
||||
//import kotlinx.coroutines.launch
|
||||
//
|
||||
//class MarkdownInfoFragment : Fragment() {
|
||||
// private val errorHandler: ErrorHandler by errorHandlerImpl()
|
||||
// private var _binding: FragmentMarkdownInfoBinding? = null
|
||||
// private val binding: FragmentMarkdownInfoBinding
|
||||
// get() = _binding!!
|
||||
//
|
||||
// override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// super.onCreate(savedInstanceState)
|
||||
// setHasOptionsMenu(true)
|
||||
// }
|
||||
//
|
||||
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
// _binding = FragmentMarkdownInfoBinding.inflate(inflater, container, false)
|
||||
// return binding.root
|
||||
// }
|
||||
//
|
||||
// override fun onDestroyView() {
|
||||
// super.onDestroyView()
|
||||
// _binding = null
|
||||
// }
|
||||
//
|
||||
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// val fileName = arguments?.getString(EXTRA_FILE)
|
||||
// if (fileName.isNullOrBlank()) {
|
||||
// findNavController().navigateUp()
|
||||
// return
|
||||
// }
|
||||
// binding.toolbar.setupWithNavController(findNavController())
|
||||
//
|
||||
// val isNightMode = AppCompatDelegate.getDefaultNightMode() ==
|
||||
// AppCompatDelegate.MODE_NIGHT_YES
|
||||
// || resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||
// val defaultCssId = if (isNightMode) {
|
||||
// R.string.pref_custom_css_default_dark
|
||||
// } else {
|
||||
// R.string.pref_custom_css_default
|
||||
// }
|
||||
// val css: String? = getString(defaultCssId)
|
||||
// lifecycleScope.launch {
|
||||
// try {
|
||||
// val html = view.context.assets?.readAssetToString(fileName)
|
||||
// ?.toHtml()
|
||||
// ?: throw RuntimeException("Unable to open stream to $fileName")
|
||||
// binding.infoWebview.loadDataWithBaseURL(null,
|
||||
// String.format(FORMAT_CSS, css) + html,
|
||||
// "text/html",
|
||||
// "UTF-8", null
|
||||
// )
|
||||
// } catch (e: Exception) {
|
||||
// errorHandler.reportException(e)
|
||||
// Toast.makeText(view.context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
|
||||
// findNavController().navigateUp()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
// if (item.itemId == android.R.id.home) {
|
||||
// findNavController().navigateUp()
|
||||
// return true
|
||||
// }
|
||||
// return super.onOptionsItemSelected(item)
|
||||
// }
|
||||
//
|
||||
// override fun onStart() {
|
||||
// super.onStart()
|
||||
// arguments?.getString(EXTRA_FILE)?.let {
|
||||
// Plausible.pageView(it)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// const val FORMAT_CSS = "<style>" +
|
||||
// "%s" +
|
||||
// "</style>"
|
||||
// const val EXTRA_TITLE = "title"
|
||||
// const val EXTRA_FILE = "file"
|
||||
// }
|
||||
//}
|
|
@ -1,45 +0,0 @@
|
|||
//package com.wbrawner.simplemarkdown.view.fragment
|
||||
//
|
||||
//import android.os.Bundle
|
||||
//import android.view.LayoutInflater
|
||||
//import android.view.MenuItem
|
||||
//import android.view.View
|
||||
//import android.view.ViewGroup
|
||||
//import androidx.fragment.app.Fragment
|
||||
//import androidx.navigation.fragment.findNavController
|
||||
//import androidx.navigation.ui.setupWithNavController
|
||||
//import com.wbrawner.plausible.android.Plausible
|
||||
//import com.wbrawner.simplemarkdown.R
|
||||
//import com.wbrawner.simplemarkdown.databinding.FragmentSettingsBinding
|
||||
//
|
||||
//class SettingsContainerFragment : Fragment() {
|
||||
// private var _binding: FragmentSettingsBinding? = null
|
||||
// private val binding: FragmentSettingsBinding
|
||||
// get() = _binding!!
|
||||
//
|
||||
// override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// super.onCreate(savedInstanceState)
|
||||
// setHasOptionsMenu(true)
|
||||
// }
|
||||
//
|
||||
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
// _binding = FragmentSettingsBinding.inflate(inflater, container, false)
|
||||
// return binding.root
|
||||
// }
|
||||
//
|
||||
// override fun onDestroyView() {
|
||||
// super.onDestroyView()
|
||||
// _binding = null
|
||||
// }
|
||||
//
|
||||
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// binding.toolbar.setupWithNavController(findNavController())
|
||||
// }
|
||||
//
|
||||
// override fun onOptionsItemSelected(item: MenuItem): Boolean = findNavController().navigateUp()
|
||||
//
|
||||
// override fun onStart() {
|
||||
// super.onStart()
|
||||
// Plausible.pageView("Settings")
|
||||
// }
|
||||
//}
|
|
@ -1,82 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.view.fragment
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.wbrawner.simplemarkdown.BuildConfig
|
||||
import com.wbrawner.simplemarkdown.R
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class SettingsFragment
|
||||
: PreferenceFragmentCompat(),
|
||||
SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.pref_general)
|
||||
if (BuildConfig.DEBUG) {
|
||||
preferenceScreen.addPreference(Preference(preferenceScreen.context).apply {
|
||||
title = "Force crash"
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
throw RuntimeException("Forced crash from settings")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
lifecycleScope.launch(context = Dispatchers.IO) {
|
||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
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) {
|
||||
findPreference<Preference>(getString(R.string.pref_custom_css))?.let {
|
||||
preferenceScreen.removePreference(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
||||
if (!isAdded || sharedPreferences == null || key == null) return
|
||||
val preference = findPreference(key) as? ListPreference ?: return
|
||||
setListPreferenceSummary(sharedPreferences, preference)
|
||||
if (preference.key != getString(R.string.pref_key_dark_mode)) {
|
||||
return
|
||||
}
|
||||
var darkMode: Int = if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||
AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY
|
||||
} else {
|
||||
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
|
||||
}
|
||||
val darkModeValue = sharedPreferences.getString(preference.key, null)
|
||||
if (!darkModeValue.isNullOrEmpty()) {
|
||||
if (darkModeValue.equals(getString(R.string.pref_value_light), ignoreCase = true)) {
|
||||
darkMode = AppCompatDelegate.MODE_NIGHT_NO
|
||||
} else if (darkModeValue.equals(getString(R.string.pref_value_dark), ignoreCase = true)) {
|
||||
darkMode = AppCompatDelegate.MODE_NIGHT_YES
|
||||
}
|
||||
}
|
||||
AppCompatDelegate.setDefaultNightMode(darkMode)
|
||||
activity?.recreate()
|
||||
}
|
||||
|
||||
private fun setListPreferenceSummary(sharedPreferences: SharedPreferences, preference: ListPreference) {
|
||||
val storedValue = sharedPreferences.getString(
|
||||
preference.key,
|
||||
null
|
||||
) ?: return
|
||||
val index = preference.findIndexOfValue(storedValue)
|
||||
if (index < 0) return
|
||||
preference.summary = preference.entries[index].toString()
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
//package com.wbrawner.simplemarkdown.view.fragment
|
||||
//
|
||||
//import android.content.ActivityNotFoundException
|
||||
//import android.content.Intent
|
||||
//import android.net.Uri
|
||||
//import android.os.Bundle
|
||||
//import android.view.LayoutInflater
|
||||
//import android.view.View
|
||||
//import android.view.ViewGroup
|
||||
//import androidx.browser.customtabs.CustomTabsIntent
|
||||
//import androidx.fragment.app.Fragment
|
||||
//import androidx.lifecycle.Observer
|
||||
//import androidx.navigation.fragment.findNavController
|
||||
//import androidx.navigation.ui.setupWithNavController
|
||||
//import com.wbrawner.plausible.android.Plausible
|
||||
//import com.wbrawner.simplemarkdown.databinding.FragmentSupportBinding
|
||||
//import com.wbrawner.simplemarkdown.utility.SupportLinkProvider
|
||||
//
|
||||
//class SupportFragment : Fragment() {
|
||||
// private var _binding: FragmentSupportBinding? = null
|
||||
// private val binding: FragmentSupportBinding
|
||||
// get() = _binding!!
|
||||
//
|
||||
// override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
// _binding = FragmentSupportBinding.inflate(inflater, container, false)
|
||||
// return binding.root
|
||||
// }
|
||||
//
|
||||
// override fun onDestroyView() {
|
||||
// super.onDestroyView()
|
||||
// _binding = null
|
||||
// }
|
||||
//
|
||||
// override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
// binding.toolbar.setupWithNavController(findNavController())
|
||||
// binding.githubButton.setOnClickListener {
|
||||
// CustomTabsIntent.Builder()
|
||||
// .addDefaultShareMenuItem()
|
||||
// .build()
|
||||
// .launchUrl(view.context, Uri.parse("https://github" +
|
||||
// ".com/wbrawner/SimpleMarkdown"))
|
||||
// }
|
||||
// binding.rateButton.setOnClickListener {
|
||||
// val playStoreIntent = Intent(Intent.ACTION_VIEW)
|
||||
// .apply {
|
||||
// data = Uri.parse("market://details?id=${view.context.packageName}")
|
||||
// addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY or
|
||||
// Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
|
||||
// Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
|
||||
// }
|
||||
// try {
|
||||
// startActivity(playStoreIntent)
|
||||
// } catch (ignored: ActivityNotFoundException) {
|
||||
// playStoreIntent.data = Uri.parse("https://play.google.com/store/apps/details?id=${view.context.packageName}")
|
||||
// startActivity(playStoreIntent)
|
||||
// }
|
||||
// }
|
||||
// SupportLinkProvider(requireActivity()).supportLinks.observe(viewLifecycleOwner, Observer { links ->
|
||||
// links.forEach {
|
||||
// binding.supportButtons.addView(it)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// override fun onStart() {
|
||||
// super.onStart()
|
||||
// Plausible.pageView("Support")
|
||||
// }
|
||||
//}
|
|
@ -1,61 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/drawerLayout">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.wbrawner.simplemarkdown.view.DisableableViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/bottomSheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/colorBackground"
|
||||
app:layout_scrollFlags="scroll|enterAlways" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/colorBackground"
|
||||
android:visibility="gone">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:id="@+id/editTab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_edit" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:id="@+id/previewTab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_preview" />
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/navigationView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:menu="@menu/menu_main" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/content"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:defaultNavHost="true"
|
||||
app:navGraph="@navigation/nav_graph" />
|
|
@ -1,23 +0,0 @@
|
|||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/markdown_edit_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.wbrawner.simplemarkdown.view.fragment.EditFragment">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/markdown_edit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@null"
|
||||
android:gravity="top"
|
||||
android:fontFamily="monospace"
|
||||
android:hint="@string/markdown_here"
|
||||
android:imeOptions="flagNoExtractUi"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:scrollHorizontally="false"
|
||||
android:importantForAutofill="no" />
|
||||
</androidx.core.widget.NestedScrollView>
|
|
@ -1,63 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/colorBackground"
|
||||
android:id="@+id/drawerLayout">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.wbrawner.simplemarkdown.view.DisableableViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/bottomSheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:liftOnScroll="true">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/colorBackground"
|
||||
app:layout_scrollFlags="scroll|enterAlways|snap" />
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:background="@color/colorBackground">
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:id="@+id/editTab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_edit" />
|
||||
|
||||
<com.google.android.material.tabs.TabItem
|
||||
android:id="@+id/previewTab"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_preview" />
|
||||
</com.google.android.material.tabs.TabLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
<com.google.android.material.navigation.NavigationView
|
||||
android:id="@+id/navigationView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:menu="@menu/menu_main" />
|
||||
|
||||
</androidx.drawerlayout.widget.DrawerLayout>
|
|
@ -1,43 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
|
||||
tools:context="com.wbrawner.simplemarkdown.view.fragment.MarkdownInfoFragment">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="128dp"
|
||||
android:background="@color/colorBackground">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:elevation="0dp"
|
||||
app:layout_collapseMode="pin" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/infoWebview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:nestedScrollingEnabled="false" />
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -1,13 +0,0 @@
|
|||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="com.wbrawner.simplemarkdown.view.fragment.PreviewFragment">
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:id="@+id/markdown_view" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
|
@ -1,26 +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:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/colorBackground" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment_settings"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.SettingsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
|
@ -1,78 +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"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="@color/colorBackground"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
android:padding="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/heartIcon"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:src="@drawable/ic_favorite_black_24dp"
|
||||
android:tint="@color/colorAccent"
|
||||
android:contentDescription="@string/description_heart"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/supportInfoText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:text="@string/support_info"
|
||||
android:textAlignment="center"
|
||||
android:textColor="@color/colorOnBackground"
|
||||
app:layout_constraintTop_toBottomOf="@+id/heartIcon" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/githubButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/colorBackgroundGitHub"
|
||||
android:textColor="@color/colorWhite"
|
||||
android:text="@string/action_view_github"
|
||||
app:layout_constraintTop_toBottomOf="@+id/supportInfoText" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/rateButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/colorBackgroundPlayStore"
|
||||
android:textColor="@color/colorWhite"
|
||||
android:text="@string/action_rate"
|
||||
app:layout_constraintTop_toBottomOf="@+id/githubButton" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/supportButtons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintTop_toBottomOf="@+id/rateButton" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_share"
|
||||
android:icon="@drawable/ic_share"
|
||||
android:title="@string/action_share"
|
||||
app:showAsAction="ifRoom" />
|
||||
<item
|
||||
android:id="@+id/action_new"
|
||||
android:title="@string/action_new"
|
||||
android:alphabeticShortcut="N"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_load"
|
||||
android:title="@string/action_open"
|
||||
android:alphabeticShortcut="O"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_save"
|
||||
android:alphabeticShortcut="S"
|
||||
android:title="@string/action_save" />
|
||||
<item
|
||||
android:id="@+id/action_save_as"
|
||||
android:title="@string/action_save_as"
|
||||
tools:ignore="UnusedAttribute" />
|
||||
<item
|
||||
android:id="@+id/action_lock_swipe"
|
||||
android:checkable="true"
|
||||
android:title="@string/action_lock_swipe"
|
||||
app:showAsAction="never" />
|
||||
</menu>
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<group android:id="@+id/mainGroup">
|
||||
<item
|
||||
android:id="@+id/action_mainFragment_to_settingsContainerFragment"
|
||||
android:title="@string/action_settings"
|
||||
android:icon="@drawable/ic_settings_black_24dp"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_mainFragment_to_supportFragment"
|
||||
android:title="@string/support_title"
|
||||
android:icon="@drawable/ic_favorite_black_24dp"
|
||||
app:showAsAction="never" />
|
||||
</group>
|
||||
<group android:id="@+id/addtionalInfoGroup">
|
||||
<item
|
||||
android:id="@+id/action_mainFragment_to_helpFragment"
|
||||
android:title="@string/action_help"
|
||||
android:icon="@drawable/ic_help_black_24dp"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_mainFragment_to_librariesFragment"
|
||||
android:title="@string/action_libraries"
|
||||
android:icon="@drawable/ic_info_black_24dp"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_mainFragment_to_privacyFragment"
|
||||
android:title="@string/action_privacy"
|
||||
android:icon="@drawable/ic_eye_black_24dp"
|
||||
app:showAsAction="never" />
|
||||
</group>
|
||||
</menu>
|
|
@ -1,87 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation 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:id="@+id/nav_graph"
|
||||
app:startDestination="@+id/mainFragment">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/settingsContainerFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.SettingsContainerFragment"
|
||||
android:label="@string/title_activity_settings" />
|
||||
<fragment
|
||||
android:id="@+id/mainFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.MainFragment"
|
||||
android:label="">
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_helpFragment"
|
||||
app:destination="@id/helpFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popExitAnim="@android:anim/slide_out_right"
|
||||
app:popUpTo="@id/mainFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_privacyFragment"
|
||||
app:destination="@id/privacyFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popExitAnim="@android:anim/slide_out_right"
|
||||
app:popUpTo="@id/mainFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_librariesFragment"
|
||||
app:destination="@id/librariesFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popExitAnim="@android:anim/slide_out_right"
|
||||
app:popUpTo="@id/mainFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_settingsContainerFragment"
|
||||
app:destination="@id/settingsContainerFragment"
|
||||
app:enterAnim="@android:anim/slide_in_left"
|
||||
app:exitAnim="@android:anim/slide_out_right"
|
||||
app:popExitAnim="@android:anim/slide_out_right"
|
||||
app:popUpTo="@id/mainFragment" />
|
||||
<action
|
||||
android:id="@+id/action_mainFragment_to_supportFragment"
|
||||
app:destination="@id/supportFragment"
|
||||
app:enterAnim="@anim/nav_default_enter_anim"
|
||||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim"
|
||||
app:popUpTo="@id/mainFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/supportFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.SupportFragment"
|
||||
android:label="@string/support_title" />
|
||||
<fragment
|
||||
android:id="@+id/helpFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.MarkdownInfoFragment"
|
||||
android:label="@string/action_help"
|
||||
tools:layout="@layout/fragment_markdown_info">
|
||||
<argument
|
||||
android:name="file"
|
||||
app:argType="string"
|
||||
android:defaultValue="Cheatsheet.md" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/privacyFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.MarkdownInfoFragment"
|
||||
android:label="@string/action_privacy"
|
||||
tools:layout="@layout/fragment_markdown_info">
|
||||
<argument
|
||||
android:name="file"
|
||||
android:defaultValue="Privacy Policy.md"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/librariesFragment"
|
||||
android:name="com.wbrawner.simplemarkdown.view.fragment.MarkdownInfoFragment"
|
||||
android:label="@string/action_libraries"
|
||||
tools:layout="@layout/fragment_markdown_info">
|
||||
<argument
|
||||
android:name="file"
|
||||
android:defaultValue="Libraries.md"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
</navigation>
|
|
@ -1,27 +0,0 @@
|
|||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<SwitchPreference
|
||||
android:defaultValue="true"
|
||||
android:key="autosave"
|
||||
android:summaryOff="@string/pref_autosave_off"
|
||||
android:summaryOn="@string/pref_autosave_on"
|
||||
android:title="@string/pref_title_autosave" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/pref_custom_css_default"
|
||||
android:key="@string/pref_custom_css"
|
||||
android:summary="@string/pref_description_custom_css"
|
||||
android:title="@string/pref_title_custom_css" />
|
||||
<ListPreference
|
||||
android:entries="@array/pref_entries_dark_mode"
|
||||
android:entryValues="@array/pref_values_dark_mode"
|
||||
android:defaultValue="@string/pref_key_dark_mode_auto"
|
||||
android:key="@string/pref_key_dark_mode"
|
||||
android:title="@string/title_dark_mode" />
|
||||
<SwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="@string/readability_enabled"
|
||||
android:summaryOff="@string/pref_readability_off"
|
||||
android:summaryOn="@string/pref_readability_on"
|
||||
android:title="@string/pref_title_readability" />
|
||||
|
||||
</PreferenceScreen>
|
|
@ -1,105 +1,107 @@
|
|||
package com.wbrawner.simplemarkdown.utility
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.android.billingclient.api.*
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import com.android.billingclient.api.BillingClient
|
||||
import com.android.billingclient.api.BillingClientStateListener
|
||||
import com.android.billingclient.api.BillingFlowParams
|
||||
import com.android.billingclient.api.BillingFlowParams.ProductDetailsParams
|
||||
import com.android.billingclient.api.BillingResult
|
||||
import com.android.billingclient.api.ConsumeParams
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import com.android.billingclient.api.QueryProductDetailsParams
|
||||
import com.wbrawner.simplemarkdown.R
|
||||
|
||||
class SupportLinkProvider(private val activity: Activity) : BillingClientStateListener,
|
||||
PurchasesUpdatedListener {
|
||||
val supportLinks = MutableLiveData<List<MaterialButton>>()
|
||||
|
||||
private val billingClient: BillingClient = BillingClient.newBuilder(activity.applicationContext)
|
||||
.setListener(this)
|
||||
@Composable
|
||||
fun SupportLinks() {
|
||||
val context = LocalContext.current
|
||||
var products by remember { mutableStateOf(emptyList<ProductDetails>()) }
|
||||
var billingClient by remember { mutableStateOf<BillingClient?>(null) }
|
||||
DisposableEffect(context) {
|
||||
billingClient = BillingClient.newBuilder(context.applicationContext)
|
||||
.setListener { _, purchases ->
|
||||
purchases?.forEach { purchase ->
|
||||
val consumeParams = ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.purchaseToken)
|
||||
.build()
|
||||
billingClient?.consumeAsync(consumeParams) { _, _ ->
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.support_thank_you),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
.enablePendingPurchases()
|
||||
.build()
|
||||
|
||||
init {
|
||||
billingClient.startConnection(this)
|
||||
activity.application.registerActivityLifecycleCallbacks(
|
||||
object : Application.ActivityLifecycleCallbacks {
|
||||
override fun onActivityPaused(activity: Activity) {
|
||||
}
|
||||
billingClient?.startConnection(object : BillingClientStateListener {
|
||||
override fun onBillingServiceDisconnected() {
|
||||
billingClient?.startConnection(this)
|
||||
}
|
||||
|
||||
override fun onActivityStarted(activity: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivityDestroyed(activity: Activity) {
|
||||
billingClient.endConnection()
|
||||
}
|
||||
|
||||
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
|
||||
}
|
||||
|
||||
override fun onActivityStopped(activity: Activity) {
|
||||
}
|
||||
|
||||
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
}
|
||||
override fun onBillingSetupFinished(result: BillingResult) {
|
||||
if (result.responseCode != BillingClient.BillingResponseCode.OK) {
|
||||
return
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onBillingSetupFinished(result: BillingResult) {
|
||||
if (result.responseCode != BillingClient.BillingResponseCode.OK) {
|
||||
return
|
||||
}
|
||||
|
||||
val skuDetails = SkuDetailsParams.newBuilder()
|
||||
.setSkusList(listOf("support_the_developer", "tip_coffee", "tip_beer"))
|
||||
.setType(BillingClient.SkuType.INAPP)
|
||||
.build()
|
||||
billingClient.querySkuDetailsAsync(skuDetails) { skuDetailsResponse, skuDetailsList ->
|
||||
// Process the result.
|
||||
if (skuDetailsResponse.responseCode != BillingClient.BillingResponseCode.OK || skuDetailsList.isNullOrEmpty()) {
|
||||
return@querySkuDetailsAsync
|
||||
}
|
||||
|
||||
skuDetailsList.sortedBy { it.priceAmountMicros }
|
||||
.map { skuDetails ->
|
||||
val supportButton = MaterialButton(activity)
|
||||
supportButton.text = activity.getString(
|
||||
R.string.support_button_purchase,
|
||||
skuDetails.title,
|
||||
skuDetails.price
|
||||
)
|
||||
supportButton.setOnClickListener {
|
||||
val flowParams = BillingFlowParams.newBuilder()
|
||||
.setSkuDetails(skuDetails)
|
||||
.build()
|
||||
billingClient.launchBillingFlow(activity, flowParams)
|
||||
}
|
||||
supportButton
|
||||
val productsQuery = listOf("support_the_developer", "tip_coffee", "tip_beer")
|
||||
.map {
|
||||
QueryProductDetailsParams.Product.newBuilder()
|
||||
.setProductId(it)
|
||||
.setProductType(BillingClient.ProductType.INAPP)
|
||||
.build()
|
||||
}
|
||||
.let {
|
||||
supportLinks.postValue(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBillingServiceDisconnected() {
|
||||
billingClient.startConnection(this)
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(result: BillingResult, purchases: MutableList<Purchase>?) {
|
||||
purchases?.forEach { purchase ->
|
||||
val consumeParams = ConsumeParams.newBuilder()
|
||||
.setPurchaseToken(purchase.purchaseToken)
|
||||
val productDetailsQuery = QueryProductDetailsParams.newBuilder()
|
||||
.setProductList(productsQuery)
|
||||
.build()
|
||||
billingClient.consumeAsync(consumeParams) { _, _ ->
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(R.string.support_thank_you),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
billingClient?.queryProductDetailsAsync(productDetailsQuery) { result, productDetails ->
|
||||
if (result.responseCode != BillingClient.BillingResponseCode.OK || productDetails.isEmpty()) {
|
||||
return@queryProductDetailsAsync
|
||||
}
|
||||
products =
|
||||
productDetails.sortedBy { it.oneTimePurchaseOfferDetails?.priceAmountMicros }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
onDispose {
|
||||
billingClient?.endConnection()
|
||||
}
|
||||
}
|
||||
|
||||
products.forEach { product ->
|
||||
Button(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
onClick = {
|
||||
val productDetails = ProductDetailsParams.newBuilder()
|
||||
.setProductDetails(product)
|
||||
.build()
|
||||
val flowParams = BillingFlowParams.newBuilder()
|
||||
.setProductDetailsParamsList(listOf(productDetails))
|
||||
.build()
|
||||
billingClient?.launchBillingFlow(context as Activity, flowParams)
|
||||
}
|
||||
) {
|
||||
Text(
|
||||
context.getString(
|
||||
R.string.support_button_purchase,
|
||||
product.name,
|
||||
product.oneTimePurchaseOfferDetails?.formattedPrice
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue