6.14.6 commit
This commit is contained in:
parent
cd31132516
commit
9093c59068
|
@ -26,8 +26,8 @@ android {
|
|||
vectorDrawables.useSupportLibrary false
|
||||
vectorDrawables.generatedDensities = []
|
||||
|
||||
versionCode 3020304
|
||||
versionName "6.14.5"
|
||||
versionCode 3020305
|
||||
versionName "6.14.6"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -363,7 +363,7 @@ class PlaybackService : MediaLibraryService() {
|
|||
val item_ = realm.query(Episode::class).query("id == $0", item!!.id).first().find()
|
||||
if (item_ != null) {
|
||||
item = upsert(item_) {
|
||||
it.playState = PlayState.PLAYED.code
|
||||
if (it.playState < PlayState.PLAYED.code || it.playState == PlayState.IGNORED.code) it.playState = PlayState.PLAYED.code
|
||||
val media = it.media
|
||||
if (media != null) {
|
||||
media.startPosition = playable.startPosition
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
package ac.mdiq.podcini.preferences.fragments
|
||||
|
||||
import ac.mdiq.podcini.BuildConfig
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
class AboutFragment : PreferenceFragmentCompat() {
|
||||
@SuppressLint("CommitTransaction")
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_about)
|
||||
|
||||
findPreference<Preference>("about_version")!!.summary = String.format("%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH)
|
||||
findPreference<Preference>("about_version")!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.bug_report_title), findPreference<Preference>("about_version")!!.summary)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (Build.VERSION.SDK_INT <= 32) Snackbar.make(requireView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>("about_help")!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/")
|
||||
true
|
||||
}
|
||||
findPreference<Preference>("about_privacy_policy")!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/blob/main/PrivacyPolicy.md")
|
||||
true
|
||||
}
|
||||
findPreference<Preference>("about_licenses")!!.onPreferenceClickListener =
|
||||
Preference.OnPreferenceClickListener {
|
||||
parentFragmentManager.beginTransaction().replace(R.id.settingsContainer, LicensesFragment()).addToBackStack(getString(R.string.translators)).commit()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.about_pref)
|
||||
}
|
||||
|
||||
class LicensesFragment : Fragment() {
|
||||
private val licenses = mutableStateListOf<LicenseItem>()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val composeView = ComposeView(requireContext()).apply { setContent { CustomTheme(requireContext()) { MainView() } } }
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
licenses.clear()
|
||||
val stream = requireContext().assets.open("licenses.xml")
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val libraryList = docBuilder.parse(stream).getElementsByTagName("library")
|
||||
for (i in 0 until libraryList.length) {
|
||||
val lib = libraryList.item(i).attributes
|
||||
licenses.add(LicenseItem(lib.getNamedItem("name").textContent,
|
||||
String.format("By %s, %s license", lib.getNamedItem("author").textContent, lib.getNamedItem("license").textContent), lib.getNamedItem("website").textContent, lib.getNamedItem("licenseText").textContent))
|
||||
}
|
||||
}.invokeOnCompletion { throwable -> if (throwable!= null) Toast.makeText(context, throwable.message, Toast.LENGTH_LONG).show() }
|
||||
return composeView
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainView() {
|
||||
val lazyListState = rememberLazyListState()
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
var curLicenseIndex by remember { mutableIntStateOf(-1) }
|
||||
if (showDialog) Dialog(onDismissRequest = { showDialog = false }) {
|
||||
Surface(shape = RoundedCornerShape(16.dp), border = BorderStroke(1.dp, MaterialTheme.colorScheme.tertiary)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Text(licenses[curLicenseIndex].title, color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Row {
|
||||
Button(onClick = { openInBrowser(requireContext(), licenses[curLicenseIndex].licenseUrl) }) { Text("View website") }
|
||||
Spacer(Modifier.weight(1f))
|
||||
Button(onClick = { showLicenseText(licenses[curLicenseIndex].licenseTextFile) }) { Text("View license") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyColumn(state = lazyListState, modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
itemsIndexed(licenses) { index, item ->
|
||||
Column(Modifier.clickable(onClick = {
|
||||
curLicenseIndex = index
|
||||
showDialog = true
|
||||
})) {
|
||||
Text(item.title, color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(item.subtitle, color = textColor, style = MaterialTheme.typography.bodySmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLicenseText(licenseTextFile: String) {
|
||||
try {
|
||||
val reader = BufferedReader(InputStreamReader(requireContext().assets.open(licenseTextFile), "UTF-8"))
|
||||
val licenseText = StringBuilder()
|
||||
var line = ""
|
||||
while ((reader.readLine()?.also { line = it }) != null) licenseText.append(line).append("\n")
|
||||
MaterialAlertDialogBuilder(requireContext()).setMessage(licenseText).show()
|
||||
} catch (e: IOException) { e.printStackTrace() }
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.licenses)
|
||||
}
|
||||
|
||||
private class LicenseItem(val title: String, val subtitle: String, val licenseUrl: String, val licenseTextFile: String)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ import ac.mdiq.podcini.net.sync.model.EpisodeAction
|
|||
import ac.mdiq.podcini.net.sync.model.EpisodeAction.Companion.readFromJsonObject
|
||||
import ac.mdiq.podcini.net.sync.model.SyncServiceException
|
||||
import ac.mdiq.podcini.preferences.ExportWriter
|
||||
import ac.mdiq.podcini.preferences.OpmlTransporter.*
|
||||
import ac.mdiq.podcini.preferences.OpmlTransporter.OpmlWriter
|
||||
import ac.mdiq.podcini.storage.database.Episodes.getEpisodeByGuidOrUrl
|
||||
import ac.mdiq.podcini.storage.database.Episodes.getEpisodes
|
||||
import ac.mdiq.podcini.storage.database.Feeds.getFeedList
|
||||
|
@ -20,6 +20,7 @@ import ac.mdiq.podcini.storage.utils.FileNameGenerator.generateFileName
|
|||
import ac.mdiq.podcini.storage.utils.FilesUtils.getDataFolder
|
||||
import ac.mdiq.podcini.ui.activity.OpmlImportActivity
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.app.Activity.RESULT_OK
|
||||
import android.app.ProgressDialog
|
||||
|
@ -32,16 +33,33 @@ import android.os.Bundle
|
|||
import android.os.ParcelFileDescriptor
|
||||
import android.text.format.Formatter
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.app.ShareCompat.IntentBuilder
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
@ -57,6 +75,7 @@ import java.nio.channels.FileChannel
|
|||
import java.nio.charset.Charset
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.Throws
|
||||
|
||||
class ImportExportPreferencesFragment : PreferenceFragmentCompat() {
|
||||
|
||||
|
@ -102,77 +121,120 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() {
|
|||
|
||||
private var progressDialog: ProgressDialog? = null
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_import_export)
|
||||
setupStorageScreen()
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
(activity as PreferenceActivity).supportActionBar?.setTitle(R.string.import_export_pref)
|
||||
progressDialog = ProgressDialog(context)
|
||||
progressDialog!!.isIndeterminate = true
|
||||
progressDialog!!.setMessage(requireContext().getString(R.string.please_wait))
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
val scrollState = rememberScrollState()
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(16.dp).verticalScroll(scrollState)) {
|
||||
Text(stringResource(R.string.database), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold)
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
exportDatabase()
|
||||
})) {
|
||||
Text(stringResource(R.string.database_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.database_export_summary), color = textColor)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.import_export_pref)
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
importDatabase()
|
||||
})) {
|
||||
Text(stringResource(R.string.database_import_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.database_import_summary), color = textColor)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
|
||||
private fun dateStampFilename(fname: String): String {
|
||||
return String.format(fname, SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date()))
|
||||
Text(stringResource(R.string.media_files), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, modifier = Modifier.padding(top = 10.dp))
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
exportMediaFiles()
|
||||
})) {
|
||||
Text(stringResource(R.string.media_files_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.media_files_export_summary), color = textColor)
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
importMediaFiles()
|
||||
})) {
|
||||
Text(stringResource(R.string.media_files_import_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.media_files_import_summary), color = textColor)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
|
||||
private fun setupStorageScreen() {
|
||||
findPreference<Preference>(IExport.prefOpmlExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
Text(stringResource(R.string.preferences), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, modifier = Modifier.padding(top = 10.dp))
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
exportPreferences()
|
||||
})) {
|
||||
Text(stringResource(R.string.preferences_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.preferences_export_summary), color = textColor)
|
||||
}
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
importPreferences()
|
||||
})) {
|
||||
Text(stringResource(R.string.preferences_import_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.preferences_import_summary), color = textColor)
|
||||
}
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
|
||||
Text(stringResource(R.string.opml), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, modifier = Modifier.padding(top = 10.dp))
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
openExportPathPicker(Export.OPML, chooseOpmlExportPathLauncher, OpmlWriter())
|
||||
true
|
||||
})) {
|
||||
Text(stringResource(R.string.opml_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.opml_export_summary), color = textColor)
|
||||
}
|
||||
findPreference<Preference>(IExport.prefHtmlExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, HtmlWriter())
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefProgressExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
openExportPathPicker(Export.PROGRESS, chooseProgressExportPathLauncher, EpisodesProgressWriter())
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefProgressImport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
importEpisodeProgress()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefOpmlImport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
try {
|
||||
chooseOpmlImportPathLauncher.launch("*/*")
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e(TAG, "No activity found. Should never happen...")
|
||||
}
|
||||
true
|
||||
})) {
|
||||
Text(stringResource(R.string.opml_import_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.opml_import_summary), color = textColor)
|
||||
}
|
||||
findPreference<Preference>(IExport.prefDatabaseImport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
importDatabase()
|
||||
true
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
|
||||
Text(stringResource(R.string.progress), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, modifier = Modifier.padding(top = 10.dp))
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
openExportPathPicker(Export.PROGRESS, chooseProgressExportPathLauncher, EpisodesProgressWriter())
|
||||
})) {
|
||||
Text(stringResource(R.string.progress_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.progress_export_summary), color = textColor)
|
||||
}
|
||||
findPreference<Preference>(IExport.prefDatabaseExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
exportDatabase()
|
||||
true
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
importEpisodeProgress()
|
||||
})) {
|
||||
Text(stringResource(R.string.progress_import_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.progress_import_summary), color = textColor)
|
||||
}
|
||||
findPreference<Preference>(IExport.prefPrefImport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
importPreferences()
|
||||
true
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
|
||||
Text(stringResource(R.string.html), color = textColor, style = MaterialTheme.typography.headlineMedium, fontWeight = FontWeight.Bold, modifier = Modifier.padding(top = 10.dp))
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
openExportPathPicker(Export.HTML, chooseHtmlExportPathLauncher, HtmlWriter())
|
||||
})) {
|
||||
Text(stringResource(R.string.html_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.html_export_summary), color = textColor)
|
||||
}
|
||||
findPreference<Preference>(IExport.prefPrefExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
exportPreferences()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefMediaFilesImport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
importMediaFiles()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefMediaFilesExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
exportMediaFiles()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(IExport.prefFavoritesExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
Column(modifier = Modifier.fillMaxWidth().padding(start = 16.dp, top = 10.dp).clickable(onClick = {
|
||||
openExportPathPicker(Export.FAVORITES, chooseFavoritesExportPathLauncher, FavoritesWriter())
|
||||
true
|
||||
})) {
|
||||
Text(stringResource(R.string.favorites_export_label), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.favorites_export_summary), color = textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dateStampFilename(fname: String): String {
|
||||
return String.format(fname, SimpleDateFormat("yyyy-MM-dd", Locale.US).format(Date()))
|
||||
}
|
||||
|
||||
private fun exportWithWriter(exportWriter: ExportWriter, uri: Uri?, exportType: Export) {
|
||||
val context: Context? = activity
|
||||
|
@ -1112,22 +1174,6 @@ class ImportExportPreferencesFragment : PreferenceFragmentCompat() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
private enum class IExport {
|
||||
prefOpmlExport,
|
||||
prefOpmlImport,
|
||||
prefProgressExport,
|
||||
prefProgressImport,
|
||||
prefHtmlExport,
|
||||
prefPrefImport,
|
||||
prefPrefExport,
|
||||
prefMediaFilesImport,
|
||||
prefMediaFilesExport,
|
||||
prefDatabaseImport,
|
||||
prefDatabaseExport,
|
||||
prefFavoritesExport,
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG: String = ImportExportPreferencesFragment::class.simpleName ?: "Anonymous"
|
||||
|
||||
|
|
|
@ -1,21 +1,78 @@
|
|||
package ac.mdiq.podcini.preferences.fragments
|
||||
|
||||
import ac.mdiq.podcini.BuildConfig
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.ui.activity.BugReportActivity
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity.Companion.getTitleOfPage
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity.Screens
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreference
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.BufferedReader
|
||||
import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
class MainPreferencesFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
|
@ -79,7 +136,7 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefScreenImportExport.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
(activity as PreferenceActivity).openScreen(R.xml.preferences_import_export)
|
||||
(activity as PreferenceActivity).openScreen(Screens.preferences_import_export)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.notifications.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
|
@ -97,10 +154,7 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefAbout.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
parentFragmentManager.beginTransaction()
|
||||
.replace(R.id.settingsContainer, AboutFragment())
|
||||
.addToBackStack(getString(R.string.about_pref))
|
||||
.commit()
|
||||
parentFragmentManager.beginTransaction().replace(R.id.settingsContainer, AboutFragment()).addToBackStack(getString(R.string.about_pref)).commit()
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefDocumentation.name)!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
|
@ -131,7 +185,7 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
config.index(R.xml.preferences_user_interface).addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
|
||||
config.index(R.xml.preferences_playback).addBreadcrumb(getTitleOfPage(R.xml.preferences_playback))
|
||||
config.index(R.xml.preferences_downloads).addBreadcrumb(getTitleOfPage(R.xml.preferences_downloads))
|
||||
config.index(R.xml.preferences_import_export).addBreadcrumb(getTitleOfPage(R.xml.preferences_import_export))
|
||||
// config.index(R.xml.preferences_import_export).addBreadcrumb(getTitleOfPage(R.xml.preferences_import_export))
|
||||
config.index(R.xml.preferences_autodownload)
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_downloads))
|
||||
.addBreadcrumb(R.string.automation)
|
||||
|
@ -139,9 +193,136 @@ class MainPreferencesFragment : PreferenceFragmentCompat() {
|
|||
config.index(R.xml.preferences_synchronization).addBreadcrumb(getTitleOfPage(R.xml.preferences_synchronization))
|
||||
config.index(R.xml.preferences_notifications).addBreadcrumb(getTitleOfPage(R.xml.preferences_notifications))
|
||||
// config.index(R.xml.feed_settings).addBreadcrumb(getTitleOfPage(R.xml.feed_settings))
|
||||
config.index(R.xml.preferences_swipe)
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
|
||||
.addBreadcrumb(getTitleOfPage(R.xml.preferences_swipe))
|
||||
// config.index(R.xml.preferences_swipe)
|
||||
// .addBreadcrumb(getTitleOfPage(R.xml.preferences_user_interface))
|
||||
// .addBreadcrumb(getTitleOfPage(R.xml.preferences_swipe))
|
||||
}
|
||||
|
||||
class AboutFragment : PreferenceFragmentCompat() {
|
||||
@SuppressLint("CommitTransaction")
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
(activity as PreferenceActivity).supportActionBar?.setTitle(R.string.about_pref)
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
|
||||
Image(painter = painterResource(R.drawable.teaser), contentDescription = "")
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp, bottom = 5.dp)) {
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_star), contentDescription = "", tint = textColor)
|
||||
Column(Modifier.padding(start = 10.dp).clickable(onClick = {
|
||||
val clipboard = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(getString(R.string.bug_report_title), findPreference<Preference>("about_version")!!.summary)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
if (Build.VERSION.SDK_INT <= 32) Snackbar.make(requireView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show()
|
||||
})) {
|
||||
Text(stringResource(R.string.podcini_version), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(String.format("%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH), color = textColor)
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp, bottom = 5.dp)) {
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_questionmark), contentDescription = "", tint = textColor)
|
||||
Column(Modifier.padding(start = 10.dp).clickable(onClick = {
|
||||
openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/")
|
||||
})) {
|
||||
Text(stringResource(R.string.online_help), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.online_help_sum), color = textColor)
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp, bottom = 5.dp)) {
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_info), contentDescription = "", tint = textColor)
|
||||
Column(Modifier.padding(start = 10.dp).clickable(onClick = {
|
||||
openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/blob/main/PrivacyPolicy.md")
|
||||
})) {
|
||||
Text(stringResource(R.string.privacy_policy), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text("Podcini PrivacyPolicy", color = textColor)
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(start = 10.dp, top = 5.dp, bottom = 5.dp)) {
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_info), contentDescription = "", tint = textColor)
|
||||
Column(Modifier.padding(start = 10.dp).clickable(onClick = {
|
||||
parentFragmentManager.beginTransaction().replace(R.id.settingsContainer, LicensesFragment()).addToBackStack(getString(R.string.translators)).commit()
|
||||
})) {
|
||||
Text(stringResource(R.string.licenses), color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(stringResource(R.string.licenses_summary), color = textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LicensesFragment : Fragment() {
|
||||
private val licenses = mutableStateListOf<LicenseItem>()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val composeView = ComposeView(requireContext()).apply { setContent { CustomTheme(requireContext()) { MainView() } } }
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
licenses.clear()
|
||||
val stream = requireContext().assets.open("licenses.xml")
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val libraryList = docBuilder.parse(stream).getElementsByTagName("library")
|
||||
for (i in 0 until libraryList.length) {
|
||||
val lib = libraryList.item(i).attributes
|
||||
licenses.add(LicenseItem(lib.getNamedItem("name").textContent,
|
||||
String.format("By %s, %s license", lib.getNamedItem("author").textContent, lib.getNamedItem("license").textContent), lib.getNamedItem("website").textContent, lib.getNamedItem("licenseText").textContent))
|
||||
}
|
||||
}.invokeOnCompletion { throwable -> if (throwable!= null) Toast.makeText(context, throwable.message, Toast.LENGTH_LONG).show() }
|
||||
return composeView
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MainView() {
|
||||
val lazyListState = rememberLazyListState()
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
var curLicenseIndex by remember { mutableIntStateOf(-1) }
|
||||
if (showDialog) Dialog(onDismissRequest = { showDialog = false }) {
|
||||
Surface(shape = RoundedCornerShape(16.dp), border = BorderStroke(1.dp, MaterialTheme.colorScheme.tertiary)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
Text(licenses[curLicenseIndex].title, color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Row {
|
||||
Button(onClick = { openInBrowser(requireContext(), licenses[curLicenseIndex].licenseUrl) }) { Text("View website") }
|
||||
Spacer(Modifier.weight(1f))
|
||||
Button(onClick = { showLicenseText(licenses[curLicenseIndex].licenseTextFile) }) { Text("View license") }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LazyColumn(state = lazyListState, modifier = Modifier.fillMaxWidth().padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 20.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
itemsIndexed(licenses) { index, item ->
|
||||
Column(Modifier.clickable(onClick = {
|
||||
curLicenseIndex = index
|
||||
showDialog = true
|
||||
})) {
|
||||
Text(item.title, color = textColor, style = MaterialTheme.typography.headlineSmall, fontWeight = FontWeight.Bold)
|
||||
Text(item.subtitle, color = textColor, style = MaterialTheme.typography.bodySmall)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLicenseText(licenseTextFile: String) {
|
||||
try {
|
||||
val reader = BufferedReader(InputStreamReader(requireContext().assets.open(licenseTextFile), "UTF-8"))
|
||||
val licenseText = StringBuilder()
|
||||
var line = ""
|
||||
while ((reader.readLine()?.also { line = it }) != null) licenseText.append(line).append("\n")
|
||||
MaterialAlertDialogBuilder(requireContext()).setMessage(licenseText).show()
|
||||
} catch (e: IOException) { e.printStackTrace() }
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar!!.setTitle(R.string.licenses)
|
||||
}
|
||||
|
||||
private class LicenseItem(val title: String, val subtitle: String, val licenseUrl: String, val licenseTextFile: String)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
package ac.mdiq.podcini.preferences.fragments
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.ui.actions.SwipeActions.Companion.showSettingDialog
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.fragment.*
|
||||
import android.os.Bundle
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
|
||||
|
||||
class SwipePreferencesFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
addPreferencesFromResource(R.xml.preferences_swipe)
|
||||
|
||||
findPreference<Preference>(Prefs.prefSwipeQueue.name)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// SwipeActionsDialog(requireContext(), QueuesFragment.TAG).show(object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {}
|
||||
// })
|
||||
showSettingDialog(this, QueuesFragment.TAG)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefSwipeEpisodes.name)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// SwipeActionsDialog(requireContext(), AllEpisodesFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {}
|
||||
// })
|
||||
showSettingDialog(this, AllEpisodesFragment.TAG)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefSwipeDownloads.name)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// SwipeActionsDialog(requireContext(), DownloadsFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {}
|
||||
// })
|
||||
showSettingDialog(this, DownloadsFragment.TAG)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefSwipeFeed.name)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// SwipeActionsDialog(requireContext(), FeedEpisodesFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {}
|
||||
// })
|
||||
showSettingDialog(this, FeedEpisodesFragment.TAG)
|
||||
true
|
||||
}
|
||||
findPreference<Preference>(Prefs.prefSwipeHistory.name)?.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
// SwipeActionsDialog(requireContext(), HistoryFragment.TAG).show (object : SwipeActionsDialog.Callback {
|
||||
// override fun onCall() {}
|
||||
// })
|
||||
showSettingDialog(this, HistoryFragment.TAG)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
(activity as PreferenceActivity).supportActionBar?.setTitle(R.string.swipeactions_label)
|
||||
}
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
private enum class Prefs {
|
||||
prefSwipeQueue,
|
||||
// prefSwipeStatistics,
|
||||
prefSwipeEpisodes,
|
||||
prefSwipeDownloads,
|
||||
prefSwipeFeed,
|
||||
prefSwipeHistory
|
||||
}
|
||||
}
|
|
@ -7,6 +7,9 @@ import ac.mdiq.podcini.preferences.UserPreferences.fullNotificationButtons
|
|||
import ac.mdiq.podcini.preferences.UserPreferences.hiddenDrawerItems
|
||||
import ac.mdiq.podcini.preferences.UserPreferences.setShowRemainTimeSetting
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity.Companion.getTitleOfPage
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity.Screens
|
||||
import ac.mdiq.podcini.ui.activity.PreferenceActivity.SwipePreferencesFragment
|
||||
import ac.mdiq.podcini.ui.fragment.NavDrawerFragment.Companion.navMap
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
|
@ -91,19 +94,8 @@ class UserInterfacePreferencesFragment : PreferenceFragmentCompat() {
|
|||
showFullNotificationButtonsDialog()
|
||||
true
|
||||
}
|
||||
// findPreference<Preference>(UserPreferences.PREF_FILTER_FEED)?.onPreferenceClickListener =
|
||||
// (Preference.OnPreferenceClickListener {
|
||||
// SubscriptionsFilterDialog().show(childFragmentManager, "filter")
|
||||
// true
|
||||
// })
|
||||
|
||||
// findPreference<Preference>(UserPreferences.Prefs.prefDrawerFeedOrder.name)?.onPreferenceClickListener = (Preference.OnPreferenceClickListener {
|
||||
//// FeedSortDialog.showDialog(requireContext())
|
||||
// FeedSortDialog().show(childFragmentManager, "FeedSortDialog")
|
||||
// true
|
||||
// })
|
||||
findPreference<Preference>(PREF_SWIPE)?.setOnPreferenceClickListener {
|
||||
(activity as PreferenceActivity).openScreen(R.xml.preferences_swipe)
|
||||
(activity as PreferenceActivity).openScreen(Screens.preferences_swipe)
|
||||
true
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 26) findPreference<Preference>(UserPreferences.Prefs.prefExpandNotify.name)!!.isVisible = false
|
||||
|
|
|
@ -632,21 +632,6 @@ class SwipeActions(private val fragment: Fragment, private val tag: String) : De
|
|||
}
|
||||
}
|
||||
|
||||
fun showSettingDialog(fragment: Fragment, tag: String) {
|
||||
val composeView = ComposeView(fragment.requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(fragment.requireContext()) {
|
||||
SwipeActionsDialog(tag, onDismissRequest = {
|
||||
showDialog.value = false
|
||||
(fragment.view as? ViewGroup)?.removeView(this@apply)
|
||||
}) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
(fragment.view as? ViewGroup)?.addView(composeView)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SwipeActionsDialog(tag: String, onDismissRequest: () -> Unit, callback: ()->Unit) {
|
||||
val context = LocalContext.current
|
||||
|
|
|
@ -5,6 +5,13 @@ import ac.mdiq.podcini.databinding.SettingsActivityBinding
|
|||
import ac.mdiq.podcini.preferences.ThemeSwitcher.getTheme
|
||||
import ac.mdiq.podcini.preferences.fragments.*
|
||||
import ac.mdiq.podcini.preferences.fragments.SynchronizationPreferencesFragment
|
||||
import ac.mdiq.podcini.ui.actions.SwipeActions.Companion.SwipeActionsDialog
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.ui.fragment.AllEpisodesFragment
|
||||
import ac.mdiq.podcini.ui.fragment.DownloadsFragment
|
||||
import ac.mdiq.podcini.ui.fragment.FeedEpisodesFragment
|
||||
import ac.mdiq.podcini.ui.fragment.HistoryFragment
|
||||
import ac.mdiq.podcini.ui.fragment.QueuesFragment
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
|
@ -13,10 +20,24 @@ import android.content.Intent
|
|||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.bytehamster.lib.preferencesearch.SearchPreferenceResult
|
||||
|
@ -53,33 +74,42 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
if (intent.getBooleanExtra(OPEN_AUTO_DOWNLOAD_SETTINGS, false)) openScreen(R.xml.preferences_autodownload)
|
||||
}
|
||||
|
||||
private fun getPreferenceScreen(screen: Int): PreferenceFragmentCompat? {
|
||||
var prefFragment: PreferenceFragmentCompat? = null
|
||||
|
||||
when (screen) {
|
||||
R.xml.preferences_user_interface -> prefFragment = UserInterfacePreferencesFragment()
|
||||
R.xml.preferences_downloads -> prefFragment = DownloadsPreferencesFragment()
|
||||
R.xml.preferences_import_export -> prefFragment = ImportExportPreferencesFragment()
|
||||
R.xml.preferences_autodownload -> prefFragment = AutoDownloadPreferencesFragment()
|
||||
R.xml.preferences_synchronization -> prefFragment = SynchronizationPreferencesFragment()
|
||||
R.xml.preferences_playback -> prefFragment = PlaybackPreferencesFragment()
|
||||
R.xml.preferences_notifications -> prefFragment = NotificationPreferencesFragment()
|
||||
R.xml.preferences_swipe -> prefFragment = SwipePreferencesFragment()
|
||||
}
|
||||
return prefFragment
|
||||
}
|
||||
|
||||
@SuppressLint("CommitTransaction")
|
||||
fun openScreen(screen: Int): PreferenceFragmentCompat? {
|
||||
val fragment = getPreferenceScreen(screen)
|
||||
fun openScreen(screen: Int): PreferenceFragmentCompat {
|
||||
val fragment = when (screen) {
|
||||
R.xml.preferences_user_interface -> UserInterfacePreferencesFragment()
|
||||
R.xml.preferences_downloads -> DownloadsPreferencesFragment()
|
||||
// R.xml.preferences_import_export -> ImportExportPreferencesFragment()
|
||||
R.xml.preferences_autodownload -> AutoDownloadPreferencesFragment()
|
||||
R.xml.preferences_synchronization -> SynchronizationPreferencesFragment()
|
||||
R.xml.preferences_playback -> PlaybackPreferencesFragment()
|
||||
R.xml.preferences_notifications -> NotificationPreferencesFragment()
|
||||
// R.xml.preferences_swipe -> SwipePreferencesFragment()
|
||||
else -> UserInterfacePreferencesFragment()
|
||||
}
|
||||
|
||||
if (screen == R.xml.preferences_notifications && Build.VERSION.SDK_INT >= 26) {
|
||||
val intent = Intent()
|
||||
intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
|
||||
intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
|
||||
startActivity(intent)
|
||||
} else
|
||||
supportFragmentManager.beginTransaction().replace(binding.settingsContainer.id, fragment!!).addToBackStack(getString(getTitleOfPage(screen))).commit()
|
||||
supportFragmentManager.beginTransaction().replace(binding.settingsContainer.id, fragment).addToBackStack(getString(getTitleOfPage(screen))).commit()
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun openScreen(screen: Screens): PreferenceFragmentCompat {
|
||||
val fragment = when (screen) {
|
||||
Screens.preferences_user_interface -> UserInterfacePreferencesFragment()
|
||||
Screens.preferences_downloads -> DownloadsPreferencesFragment()
|
||||
Screens.preferences_import_export -> ImportExportPreferencesFragment()
|
||||
Screens.preferences_autodownload -> AutoDownloadPreferencesFragment()
|
||||
Screens.preferences_synchronization -> SynchronizationPreferencesFragment()
|
||||
Screens.preferences_playback -> PlaybackPreferencesFragment()
|
||||
Screens.preferences_notifications -> NotificationPreferencesFragment()
|
||||
Screens.preferences_swipe -> SwipePreferencesFragment()
|
||||
}
|
||||
supportFragmentManager.beginTransaction().replace(binding.settingsContainer.id, fragment).addToBackStack(getString(screen.titleRes)).commit()
|
||||
return fragment
|
||||
}
|
||||
|
||||
|
@ -149,6 +179,49 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
s.show()
|
||||
}
|
||||
|
||||
class SwipePreferencesFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {}
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
(activity as PreferenceActivity).supportActionBar?.setTitle(R.string.swipeactions_label)
|
||||
return ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
|
||||
for (e in Prefs.entries) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) SwipeActionsDialog(e.tag, onDismissRequest = { showDialog.value = false }) {}
|
||||
Text(stringResource(e.res), color = textColor, style = MaterialTheme.typography.headlineMedium, modifier = Modifier.padding(bottom = 10.dp).clickable(onClick = {
|
||||
showDialog.value = true
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@Suppress("EnumEntryName")
|
||||
private enum class Prefs(val res: Int, val tag: String) {
|
||||
prefSwipeQueue(R.string.queue_label, QueuesFragment.TAG),
|
||||
prefSwipeEpisodes(R.string.episodes_label, AllEpisodesFragment.TAG),
|
||||
prefSwipeDownloads(R.string.downloads_label, DownloadsFragment.TAG),
|
||||
prefSwipeFeed(R.string.individual_subscription, FeedEpisodesFragment.TAG),
|
||||
prefSwipeHistory(R.string.playback_history_label, HistoryFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("EnumEntryName")
|
||||
enum class Screens(val titleRes: Int) {
|
||||
preferences_swipe(R.string.swipeactions_label),
|
||||
preferences_downloads(R.string.downloads_pref),
|
||||
preferences_autodownload(R.string.pref_automatic_download_title),
|
||||
preferences_playback(R.string.playback_pref),
|
||||
preferences_import_export(R.string.import_export_pref),
|
||||
preferences_user_interface(R.string.user_interface_label),
|
||||
preferences_synchronization(R.string.synchronization_pref),
|
||||
preferences_notifications(R.string.notification_pref_fragment);
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val FRAGMENT_TAG = "tag_preferences"
|
||||
const val OPEN_AUTO_DOWNLOAD_SETTINGS: String = "OpenAutoDownloadSettings"
|
||||
|
@ -158,11 +231,11 @@ class PreferenceActivity : AppCompatActivity(), SearchPreferenceResultListener {
|
|||
R.xml.preferences_downloads -> R.string.downloads_pref
|
||||
R.xml.preferences_autodownload -> R.string.pref_automatic_download_title
|
||||
R.xml.preferences_playback -> R.string.playback_pref
|
||||
R.xml.preferences_import_export -> R.string.import_export_pref
|
||||
// R.xml.preferences_import_export -> R.string.import_export_pref
|
||||
R.xml.preferences_user_interface -> R.string.user_interface_label
|
||||
R.xml.preferences_synchronization -> R.string.synchronization_pref
|
||||
R.xml.preferences_notifications -> R.string.notification_pref_fragment
|
||||
R.xml.preferences_swipe -> R.string.swipeactions_label
|
||||
// R.xml.preferences_swipe -> R.string.swipeactions_label
|
||||
else -> R.string.settings_label
|
||||
}
|
||||
}
|
||||
|
|
|
@ -661,9 +661,9 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed:
|
|||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_videocam), tint = textColor, contentDescription = "isVideo", modifier = Modifier.width(16.dp).height(16.dp))
|
||||
val curContext = LocalContext.current
|
||||
val dateSizeText = " · " + formatDateTimeFlex(vm.episode.getPubDate()) +
|
||||
if (vm.viewCount > 0) " · " + formatNumber(vm.viewCount) else "" +
|
||||
" · " + getDurationStringLong(vm.durationState) + " · " +
|
||||
if ((vm.episode.media?.size ?: 0) > 0) Formatter.formatShortFileSize(curContext, vm.episode.media?.size ?: 0) else ""
|
||||
" · " + getDurationStringLong(vm.durationState) +
|
||||
(if ((vm.episode.media?.size ?: 0) > 0) " · " + Formatter.formatShortFileSize(curContext, vm.episode.media?.size ?: 0) else "") +
|
||||
(if (vm.viewCount > 0) " · " + formatNumber(vm.viewCount) else "")
|
||||
Text(dateSizeText, color = textColor, style = MaterialTheme.typography.bodySmall, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
} else {
|
||||
|
@ -679,11 +679,11 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: MutableList<EpisodeVM>, feed:
|
|||
if (vm.episode.media?.getMediaType() == MediaType.VIDEO)
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.ic_videocam), tint = textColor, contentDescription = "isVideo", modifier = Modifier.width(16.dp).height(16.dp))
|
||||
val dateSizeText = " · " + getDurationStringLong(vm.durationState) +
|
||||
if ((vm.episode.media?.size ?: 0) > 0) " · " + Formatter.formatShortFileSize(curContext, vm.episode.media?.size ?: 0) else ""
|
||||
(if ((vm.episode.media?.size ?: 0) > 0) " · " + Formatter.formatShortFileSize(curContext, vm.episode.media?.size ?: 0) else "")
|
||||
Text(dateSizeText, color = textColor, style = MaterialTheme.typography.bodySmall, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
val dateSizeText = formatDateTimeFlex(vm.episode.getPubDate()) + if (vm.viewCount > 0) " · " + formatNumber(vm.viewCount) else ""
|
||||
val dateSizeText = formatDateTimeFlex(vm.episode.getPubDate()) + (if (vm.viewCount > 0) " · " + formatNumber(vm.viewCount) else "")
|
||||
Text(dateSizeText, color = textColor, style = MaterialTheme.typography.bodySmall, maxLines = 1, overflow = TextOverflow.Ellipsis)
|
||||
if (vm.viewCount > 0)
|
||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.baseline_people_alt_24), tint = textColor, contentDescription = "people", modifier = Modifier.width(16.dp).height(16.dp))
|
||||
|
|
|
@ -244,7 +244,7 @@ fun RenameOrCreateSyntheticFeed(feed_: Feed? = null, onDismissRequest: () -> Uni
|
|||
Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) {
|
||||
Text(stringResource(R.string.rename_feed_label), color = textColor, style = MaterialTheme.typography.bodyLarge)
|
||||
var name by remember { mutableStateOf("") }
|
||||
TextField(value = name, onValueChange = { if (it.isEmpty() || it.toIntOrNull() != null) name = it }, label = { Text(stringResource(R.string.new_namee)) })
|
||||
TextField(value = name, onValueChange = { name = it }, label = { Text(stringResource(R.string.new_namee)) })
|
||||
var hasVideo by remember { mutableStateOf(true) }
|
||||
var isYoutube by remember { mutableStateOf(false) }
|
||||
if (feed_ == null) {
|
||||
|
@ -259,6 +259,7 @@ fun RenameOrCreateSyntheticFeed(feed_: Feed? = null, onDismissRequest: () -> Uni
|
|||
}
|
||||
Row {
|
||||
Button({ onDismissRequest() }) { Text(stringResource(R.string.cancel_label)) }
|
||||
Spacer(Modifier.weight(1f))
|
||||
Button({
|
||||
val feed = feed_ ?: createSynthetic(0, name, hasVideo)
|
||||
if (feed_ == null) {
|
||||
|
|
|
@ -13,6 +13,7 @@ import ac.mdiq.podcini.ui.compose.CustomTheme
|
|||
import ac.mdiq.podcini.ui.fragment.FeedEpisodesFragment.Companion.ARGUMENT_FEED_ID
|
||||
import ac.mdiq.podcini.ui.fragment.HistoryFragment.Companion.getNumberOfPlayed
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils
|
||||
import ac.mdiq.podcini.util.IntentUtils.openInBrowser
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.R.attr
|
||||
import android.app.Activity
|
||||
|
@ -121,7 +122,7 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
Column {
|
||||
for (f in feeds) {
|
||||
Row(verticalAlignment = Alignment.Top, modifier = Modifier.padding(bottom = 5.dp).clickable {
|
||||
Row(verticalAlignment = Alignment.Top, modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp).clickable {
|
||||
val args = Bundle()
|
||||
args.putLong(ARGUMENT_FEED_ID, f.id)
|
||||
(activity as MainActivity).loadFragment(FeedEpisodesFragment.TAG, args)
|
||||
|
@ -134,6 +135,10 @@ class NavDrawerFragment : Fragment(), OnSharedPreferenceChangeListener {
|
|||
}
|
||||
}
|
||||
Spacer(Modifier.weight(1f))
|
||||
Text("Currently launching on Google Play, please kindly support with closed testing. Thank you!", color = MaterialTheme.colorScheme.tertiary,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
openInBrowser(requireContext(), "https://github.com/XilinJia/Podcini/discussions/120")
|
||||
}))
|
||||
HorizontalDivider(modifier = Modifier.fillMaxWidth().height(1.dp))
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth().clickable {
|
||||
startActivity(Intent(activity, PreferenceActivity::class.java))
|
||||
|
|
|
@ -18,9 +18,7 @@ object IntentUtils {
|
|||
@JvmStatic
|
||||
fun isCallable(context: Context, intent: Intent?): Boolean {
|
||||
val list = context.packageManager.queryIntentActivities(intent!!, PackageManager.MATCH_DEFAULT_ONLY)
|
||||
for (info in list) {
|
||||
if (info.activityInfo.exported) return true
|
||||
}
|
||||
for (info in list) if (info.activityInfo.exported) return true
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ImageView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:adjustViewBounds="true"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/teaser"
|
||||
android:importantForAccessibility="no"/>
|
|
@ -1,33 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:layout="@layout/about_teaser"/>
|
||||
<Preference
|
||||
android:key="about_version"
|
||||
android:title="@string/podcini_version"
|
||||
android:icon="@drawable/ic_star"
|
||||
android:summary="1.7.2 (asd8qs)"/>
|
||||
<Preference
|
||||
android:key="about_help"
|
||||
android:icon="@drawable/ic_questionmark"
|
||||
android:summary="@string/online_help_sum"
|
||||
android:title="@string/online_help"/>
|
||||
<Preference
|
||||
android:key="about_privacy_policy"
|
||||
android:icon="@drawable/ic_questionmark"
|
||||
android:summary="Podcini PrivacyPolicy.md"
|
||||
android:title="@string/privacy_policy"/>
|
||||
<Preference
|
||||
android:key="about_licenses"
|
||||
android:icon="@drawable/ic_info"
|
||||
android:summary="@string/licenses_summary"
|
||||
android:title="@string/licenses"/>
|
||||
<!-- <Preference-->
|
||||
<!-- android:key="about_contributors"-->
|
||||
<!-- android:icon="@drawable/ic_settings"-->
|
||||
<!-- android:summary="@string/contributors_summary"-->
|
||||
<!-- android:title="@string/contributors"/>-->
|
||||
|
||||
</PreferenceScreen>
|
|
@ -1,77 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:search="http://schemas.android.com/apk/com.bytehamster.lib.preferencesearch">
|
||||
|
||||
<PreferenceCategory android:title="@string/database">
|
||||
<Preference
|
||||
android:key="prefDatabaseExport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/database_export_label"
|
||||
android:summary="@string/database_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefDatabaseImport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/database_import_label"
|
||||
android:summary="@string/database_import_summary"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/media_files">
|
||||
<Preference
|
||||
android:key="prefMediaFilesExport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/media_files_export_label"
|
||||
android:summary="@string/media_files_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefMediaFilesImport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/media_files_import_label"
|
||||
android:summary="@string/media_files_import_summary"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences">
|
||||
<Preference
|
||||
android:key="prefPrefExport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/preferences_export_label"
|
||||
android:summary="@string/preferences_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefPrefImport"
|
||||
search:keywords="@string/import_export_search_keywords"
|
||||
android:title="@string/preferences_import_label"
|
||||
android:summary="@string/preferences_import_summary"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/opml">
|
||||
<Preference
|
||||
android:key="prefOpmlExport"
|
||||
android:title="@string/opml_export_label"
|
||||
android:summary="@string/opml_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefOpmlImport"
|
||||
android:title="@string/opml_import_label"
|
||||
android:summary="@string/opml_import_summary"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/progress">
|
||||
<Preference
|
||||
android:key="prefProgressExport"
|
||||
android:title="@string/progress_export_label"
|
||||
android:summary="@string/progress_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefProgressImport"
|
||||
android:title="@string/progress_import_label"
|
||||
android:summary="@string/progress_import_summary"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/html">
|
||||
<Preference
|
||||
android:key="prefHtmlExport"
|
||||
android:title="@string/html_export_label"
|
||||
android:summary="@string/html_export_summary"/>
|
||||
<Preference
|
||||
android:key="prefFavoritesExport"
|
||||
android:title="@string/favorites_export_label"
|
||||
android:summary="@string/favorites_export_summary"/>
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
|
@ -1,28 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:key="prefSwipeQueue"
|
||||
android:title="@string/queue_label"/>
|
||||
|
||||
<Preference
|
||||
android:key="prefSwipeEpisodes"
|
||||
android:title="@string/episodes_label"/>
|
||||
|
||||
<Preference
|
||||
android:key="prefSwipeDownloads"
|
||||
android:title="@string/downloads_label"/>
|
||||
|
||||
<Preference
|
||||
android:key="prefSwipeHistory"
|
||||
android:title="@string/playback_history_label"/>
|
||||
|
||||
<!-- <Preference-->
|
||||
<!-- android:key="prefSwipeStatistics"-->
|
||||
<!-- android:title="@string/statistics_label"/>-->
|
||||
|
||||
<Preference
|
||||
android:key="prefSwipeFeed"
|
||||
android:title="@string/individual_subscription"/>
|
||||
|
||||
</PreferenceScreen>
|
|
@ -1,3 +1,11 @@
|
|||
# 6.14.6
|
||||
|
||||
* fixed issue of unable to input in rename feed
|
||||
* fixed issue of marking played after playing even when the episode has been marked as Again or Forever
|
||||
* fixed duration not shown in narrow episode lists
|
||||
* some preferences fragments are in Compose
|
||||
* temp message on NavDrawer for closed testing
|
||||
|
||||
# 6.14.5
|
||||
|
||||
* minor adjustments in episode lists layout
|
||||
|
|
Loading…
Reference in New Issue