6.9.3 commit
This commit is contained in:
parent
3ba9134c6f
commit
ac6d2bd105
|
@ -31,8 +31,8 @@ android {
|
|||
testApplicationId "ac.mdiq.podcini.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020267
|
||||
versionName "6.9.2"
|
||||
versionCode 3020268
|
||||
versionName "6.9.3"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
|
|
@ -75,8 +75,8 @@ object EpisodeMenuHandler {
|
|||
setItemTitle(menu, R.id.mark_unread_item, R.string.mark_unread_label_no_media)
|
||||
}
|
||||
|
||||
setItemVisibility(menu, R.id.add_to_favorites_item, !isFavorite)
|
||||
setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite)
|
||||
// setItemVisibility(menu, R.id.add_to_favorites_item, !isFavorite)
|
||||
// setItemVisibility(menu, R.id.remove_from_favorites_item, isFavorite)
|
||||
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
val fileDownloaded = withContext(Dispatchers.IO) { hasMedia && selectedItem.media?.fileExists() ?: false }
|
||||
|
@ -167,8 +167,8 @@ object EpisodeMenuHandler {
|
|||
}
|
||||
R.id.add_to_queue_item -> addToQueue(true, selectedItem)
|
||||
R.id.remove_from_queue_item -> removeFromQueue(selectedItem)
|
||||
R.id.add_to_favorites_item -> setFavorite(selectedItem, true)
|
||||
R.id.remove_from_favorites_item -> setFavorite(selectedItem, false)
|
||||
// R.id.add_to_favorites_item -> setFavorite(selectedItem, true)
|
||||
// R.id.remove_from_favorites_item -> setFavorite(selectedItem, false)
|
||||
R.id.reset_position -> {
|
||||
selectedItem.media?.setPosition(0)
|
||||
if (curState.curMediaId == (selectedItem.media?.id ?: "")) {
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
package ac.mdiq.podcini.ui.actions
|
||||
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.databinding.SelectQueueDialogBinding
|
||||
import ac.mdiq.podcini.net.download.service.DownloadServiceInterface
|
||||
import ac.mdiq.podcini.playback.base.InTheatre.curQueue
|
||||
import ac.mdiq.podcini.storage.database.Episodes
|
||||
import ac.mdiq.podcini.storage.database.Episodes.setPlayState
|
||||
import ac.mdiq.podcini.storage.database.Queues
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueueSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesQuiet
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
import ac.mdiq.podcini.storage.model.PlayQueue
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import android.app.Activity
|
||||
import android.content.DialogInterface
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RadioButton
|
||||
import androidx.annotation.PluralsRes
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
|
||||
@UnstableApi
|
||||
class EpisodeMultiSelectHandler(private val activity: MainActivity, private val actionId: Int) {
|
||||
private var totalNumItems = 0
|
||||
private var snackbar: Snackbar? = null
|
||||
|
||||
fun handleAction(items: List<Episode>) {
|
||||
when (actionId) {
|
||||
R.id.toggle_favorite_batch -> toggleFavorite(items)
|
||||
R.id.add_to_queue_batch -> queueChecked(items)
|
||||
R.id.put_in_queue_batch -> PutToQueueDialog(activity, items).show()
|
||||
R.id.remove_from_queue_batch -> removeFromQueueChecked(items)
|
||||
R.id.toggle_played_batch -> {
|
||||
setPlayState(Episode.PlayState.UNSPECIFIED.code, false, *items.toTypedArray())
|
||||
// showMessage(R.plurals.marked_read_batch_label, items.size)
|
||||
}
|
||||
R.id.download_batch -> downloadChecked(items)
|
||||
R.id.delete_batch -> deleteChecked(items)
|
||||
else -> Log.e(TAG, "Unrecognized speed dial action item. Do nothing. id=$actionId")
|
||||
}
|
||||
}
|
||||
|
||||
private fun queueChecked(items: List<Episode>) {
|
||||
// Check if an episode actually contains any media files before adding it to queue
|
||||
// val toQueue = mutableListOf<Long>()
|
||||
// for (episode in items) {
|
||||
// if (episode.media != null) toQueue.add(episode.id)
|
||||
// }
|
||||
Queues.addToQueue(true, *items.toTypedArray())
|
||||
showMessage(R.plurals.added_to_queue_batch_label, items.size)
|
||||
}
|
||||
|
||||
private fun removeFromQueueChecked(items: List<Episode>) {
|
||||
// val checkedIds = getSelectedIds(items)
|
||||
removeFromQueue(*items.toTypedArray())
|
||||
showMessage(R.plurals.removed_from_queue_batch_label, items.size)
|
||||
}
|
||||
|
||||
private fun toggleFavorite(items: List<Episode>) {
|
||||
for (item in items) {
|
||||
Episodes.setFavorite(item, null)
|
||||
}
|
||||
showMessage(R.plurals.marked_favorite_batch_label, items.size)
|
||||
}
|
||||
|
||||
private fun downloadChecked(items: List<Episode>) {
|
||||
// download the check episodes in the same order as they are currently displayed
|
||||
for (episode in items) {
|
||||
if (episode.media != null && episode.feed != null && !episode.feed!!.isLocalFeed) DownloadServiceInterface.get()?.download(activity, episode)
|
||||
}
|
||||
showMessage(R.plurals.downloading_batch_label, items.size)
|
||||
}
|
||||
|
||||
private fun deleteChecked(items: List<Episode>) {
|
||||
LocalDeleteModal.deleteEpisodesWarnLocal(activity, items)
|
||||
showMessage(R.plurals.deleted_multi_episode_batch_label, items.size)
|
||||
}
|
||||
|
||||
private fun showMessage(@PluralsRes msgId: Int, numItems: Int) {
|
||||
totalNumItems += numItems
|
||||
activity.runOnUiThread {
|
||||
val text: String = activity.resources.getQuantityString(msgId, totalNumItems, totalNumItems)
|
||||
if (snackbar != null) {
|
||||
snackbar?.setText(text)
|
||||
snackbar?.show() // Resets the timeout
|
||||
} else snackbar = activity.showSnackbarAbovePlayer(text, Snackbar.LENGTH_LONG)
|
||||
}
|
||||
}
|
||||
|
||||
// private fun getSelectedIds(items: List<Episode>): List<Long> {
|
||||
// val checkedIds = mutableListOf<Long>()
|
||||
// for (i in items.indices) {
|
||||
// checkedIds.add(items[i].id)
|
||||
// }
|
||||
// return checkedIds
|
||||
// }
|
||||
|
||||
class PutToQueueDialog(activity: Activity, val items: List<Episode>) {
|
||||
private val activityRef: WeakReference<Activity> = WeakReference(activity)
|
||||
|
||||
fun show() {
|
||||
val activity = activityRef.get() ?: return
|
||||
val binding = SelectQueueDialogBinding.inflate(LayoutInflater.from(activity))
|
||||
binding.removeCheckbox.visibility = View.VISIBLE
|
||||
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
for (i in queues.indices) {
|
||||
val radioButton = RadioButton(activity)
|
||||
radioButton.text = queues[i].name
|
||||
radioButton.textSize = 20f
|
||||
radioButton.tag = i
|
||||
binding.radioGroup.addView(radioButton)
|
||||
}
|
||||
var toQueue: PlayQueue = curQueue
|
||||
binding.radioGroup.setOnCheckedChangeListener { group, checkedId ->
|
||||
val radioButton = group.findViewById<RadioButton>(checkedId)
|
||||
val selectedIndex = radioButton.tag as Int
|
||||
toQueue = queues[selectedIndex]
|
||||
}
|
||||
val dialog = MaterialAlertDialogBuilder(activity)
|
||||
.setView(binding.root)
|
||||
.setTitle(R.string.put_in_queue_label)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
// val queues = realm.query(PlayQueue::class).find()
|
||||
if (binding.removeCheckbox.isChecked) {
|
||||
val toRemove = mutableSetOf<Long>()
|
||||
val toRemoveCur = mutableListOf<Episode>()
|
||||
items.forEach { e ->
|
||||
if (curQueue.contains(e)) toRemoveCur.add(e)
|
||||
}
|
||||
items.forEach { e ->
|
||||
for (q in queues) {
|
||||
if (q.contains(e)) {
|
||||
toRemove.add(e.id)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove.isNotEmpty()) runBlocking { removeFromAllQueuesQuiet(toRemove.toList()) }
|
||||
if (toRemoveCur.isNotEmpty()) EventFlow.postEvent(FlowEvent.QueueEvent.removed(toRemoveCur))
|
||||
}
|
||||
items.forEach { e ->
|
||||
runBlocking { addToQueueSync(false, e, toQueue) }
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.cancel_label, null)
|
||||
dialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG: String = EpisodeMultiSelectHandler::class.simpleName ?: "Anonymous"
|
||||
}
|
||||
}
|
|
@ -399,7 +399,7 @@ class MainActivity : CastEnabledActivity() {
|
|||
navigationBarInsets.bottom + (if (visible) externalPlayerHeight else 0))
|
||||
mainView.layoutParams = params
|
||||
// val playerView = findViewById<FragmentContainerView>(R.id.playerFragment1)
|
||||
val playerView = findViewById<ComposeView>(R.id.composeView1)
|
||||
val playerView = findViewById<ComposeView>(R.id.player1)
|
||||
val playerParams = playerView?.layoutParams as? MarginLayoutParams
|
||||
playerParams?.setMargins(navigationBarInsets.left, 0, navigationBarInsets.right, 0)
|
||||
playerView?.layoutParams = playerParams
|
||||
|
|
|
@ -9,6 +9,8 @@ import ac.mdiq.podcini.ui.compose.confirmAddYoutubeEpisode
|
|||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.vista.extractor.services.youtube.YoutubeParsingHelper.isYoutubeServiceURL
|
||||
import ac.mdiq.vista.extractor.services.youtube.YoutubeParsingHelper.isYoutubeURL
|
||||
import android.app.Service.START_STICKY
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
|
@ -20,6 +22,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.work.WorkerParameters
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.net.URL
|
||||
import java.net.URLDecoder
|
||||
|
@ -49,42 +52,18 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
Logd(TAG, "feedUrl: $sharedUrl")
|
||||
val log = ShareLog(sharedUrl!!)
|
||||
upsertBlk(log) {}
|
||||
receiveShared(sharedUrl!!,this, true)
|
||||
|
||||
// val url = URL(sharedUrl)
|
||||
// when {
|
||||
//// plain text
|
||||
// sharedUrl!!.matches(Regex("^[^\\s<>/]+\$")) -> {
|
||||
// log = upsertBlk(log) {it.type = "text" }
|
||||
// val intent = MainActivity.showOnlineSearch(this, sharedUrl!!)
|
||||
// startActivity(intent)
|
||||
// finish()
|
||||
// }
|
||||
//// Youtube media
|
||||
//// sharedUrl!!.startsWith("https://youtube.com/watch?") || sharedUrl!!.startsWith("https://www.youtube.com/watch?") || sharedUrl!!.startsWith("https://music.youtube.com/watch?") -> {
|
||||
// (isYoutubeURL(url) && url.path.startsWith("/watch")) || isYoutubeServiceURL(url) -> {
|
||||
// log = upsertBlk(log) {it.type = "youtube media" }
|
||||
// Logd(TAG, "got youtube media")
|
||||
// setContent {
|
||||
// val showDialog = remember { mutableStateOf(true) }
|
||||
// CustomTheme(this@ShareReceiverActivity) {
|
||||
// confirmAddYoutubeEpisode(listOf(sharedUrl!!), showDialog.value, onDismissRequest = {
|
||||
// showDialog.value = false
|
||||
// finish()
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//// podcast or Youtube channel, Youtube playlist, or other?
|
||||
// else -> {
|
||||
// log = upsertBlk(log) {it.type = "podcast" }
|
||||
// Logd(TAG, "Activity was started with url $sharedUrl")
|
||||
// val intent = MainActivity.showOnlineFeed(this, sharedUrl!!)
|
||||
//// intent.putExtra(MainActivity.Extras.started_from_share.name, getIntent().getBooleanExtra(MainActivity.Extras.started_from_share.name, false))
|
||||
// startActivity(intent)
|
||||
// finish()
|
||||
// }
|
||||
// }
|
||||
receiveShared(sharedUrl!!,this, true) {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(this) {
|
||||
confirmAddYoutubeEpisode(listOf(sharedUrl!!), showDialog.value, onDismissRequest = {
|
||||
showDialog.value = false
|
||||
// finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showNoPodcastFoundError() {
|
||||
|
@ -105,13 +84,31 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
|
||||
}
|
||||
|
||||
// class UrlFetchWorker(appContext: Context, workerParams: WorkerParameters) : Worker(appContext, workerParams) {
|
||||
// override fun doWork(): Result {
|
||||
// val url = inputData.getString("shared_url") ?: return Result.failure()
|
||||
//
|
||||
// // Fetch the content from URL using OkHttp or another HTTP client
|
||||
// // Ensure you're on a background thread
|
||||
//
|
||||
// return Result.success()
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Schedule the worker
|
||||
// val workRequest = OneTimeWorkRequestBuilder<UrlFetchWorker>()
|
||||
// .setInputData(workDataOf("shared_url" to sharedUrl))
|
||||
// .build()
|
||||
//
|
||||
// WorkManager.getInstance(context).enqueue(workRequest)
|
||||
|
||||
companion object {
|
||||
private val TAG: String = ShareReceiverActivity::class.simpleName ?: "Anonymous"
|
||||
|
||||
const val ARG_FEEDURL: String = "arg.feedurl"
|
||||
private const val RESULT_ERROR = 2
|
||||
|
||||
fun receiveShared(sharedUrl: String, activity: AppCompatActivity, finish: Boolean) {
|
||||
fun receiveShared(sharedUrl: String, activity: AppCompatActivity, finish: Boolean, mediaCB: ()->Unit) {
|
||||
val url = URL(sharedUrl)
|
||||
val log = realm.query(ShareLog::class).query("url == $0", sharedUrl).first().find()
|
||||
when {
|
||||
|
@ -126,15 +123,7 @@ class ShareReceiverActivity : AppCompatActivity() {
|
|||
(isYoutubeURL(url) && url.path.startsWith("/watch")) || isYoutubeServiceURL(url) -> {
|
||||
if (log != null) upsertBlk(log) {it.type = "youtube media" }
|
||||
Logd(TAG, "got youtube media")
|
||||
activity.setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(activity) {
|
||||
confirmAddYoutubeEpisode(listOf(sharedUrl), showDialog.value, onDismissRequest = {
|
||||
showDialog.value = false
|
||||
if (finish) activity.finish()
|
||||
})
|
||||
}
|
||||
}
|
||||
mediaCB()
|
||||
}
|
||||
// podcast or Youtube channel, Youtube playlist, or other?
|
||||
else -> {
|
||||
|
|
|
@ -255,12 +255,12 @@ class VideoplayerActivity : CastEnabledActivity() {
|
|||
val isItemHasDownloadLink = isEpisodeMedia && (media as EpisodeMedia?)?.downloadUrl != null
|
||||
menu.findItem(R.id.share_item).setVisible(hasWebsiteLink || isItemAndHasLink || isItemHasDownloadLink)
|
||||
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(false)
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(false)
|
||||
if (isEpisodeMedia) {
|
||||
menu.findItem(R.id.add_to_favorites_item).setVisible(!videoEpisodeFragment.isFavorite)
|
||||
menu.findItem(R.id.remove_from_favorites_item).setVisible(videoEpisodeFragment.isFavorite)
|
||||
}
|
||||
// menu.findItem(R.id.add_to_favorites_item).setVisible(false)
|
||||
// menu.findItem(R.id.remove_from_favorites_item).setVisible(false)
|
||||
// if (isEpisodeMedia) {
|
||||
// menu.findItem(R.id.add_to_favorites_item).setVisible(!videoEpisodeFragment.isFavorite)
|
||||
// menu.findItem(R.id.remove_from_favorites_item).setVisible(videoEpisodeFragment.isFavorite)
|
||||
// }
|
||||
|
||||
menu.findItem(R.id.set_sleeptimer_item).setVisible(!isSleepTimerActive())
|
||||
menu.findItem(R.id.disable_sleeptimer_item).setVisible(isSleepTimerActive())
|
||||
|
@ -271,8 +271,8 @@ class VideoplayerActivity : CastEnabledActivity() {
|
|||
menu.findItem(R.id.player_show_chapters).setVisible(true)
|
||||
|
||||
if (videoMode == VideoMode.WINDOW_VIEW) {
|
||||
menu.findItem(R.id.add_to_favorites_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
menu.findItem(R.id.remove_from_favorites_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
// menu.findItem(R.id.add_to_favorites_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
// menu.findItem(R.id.remove_from_favorites_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
menu.findItem(R.id.set_sleeptimer_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
menu.findItem(R.id.disable_sleeptimer_item).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
menu.findItem(R.id.player_switch_to_audio_only).setShowAsAction(SHOW_AS_ACTION_NEVER)
|
||||
|
@ -305,16 +305,16 @@ class VideoplayerActivity : CastEnabledActivity() {
|
|||
val media = curMedia ?: return false
|
||||
val feedItem = (media as? EpisodeMedia)?.episodeOrFetch()
|
||||
when {
|
||||
item.itemId == R.id.add_to_favorites_item && feedItem != null -> {
|
||||
setFavorite(feedItem, true)
|
||||
videoEpisodeFragment.isFavorite = true
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
item.itemId == R.id.remove_from_favorites_item && feedItem != null -> {
|
||||
setFavorite(feedItem, false)
|
||||
videoEpisodeFragment.isFavorite = false
|
||||
invalidateOptionsMenu()
|
||||
}
|
||||
// item.itemId == R.id.add_to_favorites_item && feedItem != null -> {
|
||||
// setFavorite(feedItem, true)
|
||||
// videoEpisodeFragment.isFavorite = true
|
||||
// invalidateOptionsMenu()
|
||||
// }
|
||||
// item.itemId == R.id.remove_from_favorites_item && feedItem != null -> {
|
||||
// setFavorite(feedItem, false)
|
||||
// videoEpisodeFragment.isFavorite = false
|
||||
// invalidateOptionsMenu()
|
||||
// }
|
||||
item.itemId == R.id.disable_sleeptimer_item || item.itemId == R.id.set_sleeptimer_item ->
|
||||
SleepTimerDialog().show(supportFragmentManager, "SleepTimerDialog")
|
||||
item.itemId == R.id.audio_controls -> {
|
||||
|
|
|
@ -13,38 +13,19 @@ import androidx.compose.runtime.*
|
|||
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.unit.dp
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Spinner(
|
||||
items: List<String>,
|
||||
selectedItem: String,
|
||||
onItemSelected: (String) -> Unit
|
||||
) {
|
||||
fun Spinner(items: List<String>, selectedItem: String, onItemSelected: (String) -> Unit) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
expanded = expanded,
|
||||
onExpandedChange = { expanded = !expanded }
|
||||
) {
|
||||
TextField(
|
||||
readOnly = true,
|
||||
value = selectedItem,
|
||||
onValueChange = {},
|
||||
label = { Text("Select an item") },
|
||||
trailingIcon = {
|
||||
ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded)
|
||||
},
|
||||
colors = ExposedDropdownMenuDefaults.textFieldColors()
|
||||
)
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
ExposedDropdownMenuBox(expanded = expanded, onExpandedChange = { expanded = it }) {
|
||||
TextField(readOnly = true, value = selectedItem, onValueChange = {}, label = { Text("Select an item") },
|
||||
modifier = Modifier.menuAnchor(MenuAnchorType.PrimaryNotEditable, true), // Material3 requirement
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, colors = ExposedDropdownMenuDefaults.textFieldColors())
|
||||
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
|
||||
items.forEach { item ->
|
||||
DropdownMenuItem(text = { Text(item) },
|
||||
onClick = {
|
||||
|
|
|
@ -12,21 +12,25 @@ import ac.mdiq.podcini.storage.database.Episodes.setPlayState
|
|||
import ac.mdiq.podcini.storage.database.Feeds.addToMiscSyndicate
|
||||
import ac.mdiq.podcini.storage.database.Feeds.addToYoutubeSyndicate
|
||||
import ac.mdiq.podcini.storage.database.Queues
|
||||
import ac.mdiq.podcini.storage.database.Queues.addToQueueSync
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromAllQueuesQuiet
|
||||
import ac.mdiq.podcini.storage.database.Queues.removeFromQueue
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsert
|
||||
import ac.mdiq.podcini.storage.model.Episode
|
||||
import ac.mdiq.podcini.storage.model.MediaType
|
||||
import ac.mdiq.podcini.storage.model.PlayQueue
|
||||
import ac.mdiq.podcini.storage.model.ShareLog
|
||||
import ac.mdiq.podcini.storage.utils.DurationConverter
|
||||
import ac.mdiq.podcini.storage.utils.ImageResourceUtils
|
||||
import ac.mdiq.podcini.ui.actions.EpisodeActionButton
|
||||
import ac.mdiq.podcini.ui.actions.EpisodeMultiSelectHandler.PutToQueueDialog
|
||||
import ac.mdiq.podcini.ui.actions.SwipeAction
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.fragment.EpisodeInfoFragment
|
||||
import ac.mdiq.podcini.ui.fragment.FeedInfoFragment
|
||||
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.MiscFormatter.formatAbbrev
|
||||
import ac.mdiq.vista.extractor.Vista
|
||||
|
@ -173,6 +177,77 @@ class EpisodeVM(var episode: Episode) {
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChooseRatingDialog(selected: List<Episode>, onDismissRequest: () -> Unit) {
|
||||
Dialog(onDismissRequest = onDismissRequest) {
|
||||
Surface(shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
for (rating in Episode.Rating.entries) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(4.dp).clickable {
|
||||
for (item in selected) Episodes.setRating(item, rating.code)
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = rating.res), "")
|
||||
Text(rating.name, Modifier.padding(start = 4.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PutToQueueDialog(selected: List<Episode>, onDismissRequest: () -> Unit) {
|
||||
val queues = realm.query(PlayQueue::class).find()
|
||||
Dialog(onDismissRequest = onDismissRequest) {
|
||||
Surface(shape = RoundedCornerShape(16.dp)) {
|
||||
val scrollState = rememberScrollState()
|
||||
Column(modifier = Modifier.verticalScroll(scrollState).padding(16.dp), verticalArrangement = Arrangement.spacedBy(1.dp)) {
|
||||
var removeChecked by remember { mutableStateOf(false) }
|
||||
var toQueue by remember { mutableStateOf(curQueue) }
|
||||
for (q in queues) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
RadioButton(selected = toQueue == q, onClick = { toQueue = q })
|
||||
Text(q.name,)
|
||||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(checked = removeChecked, onCheckedChange = { removeChecked = it })
|
||||
Text(text = stringResource(R.string.remove_from_other_queues), style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 10.dp))
|
||||
}
|
||||
Row {
|
||||
Spacer(Modifier.weight(1f))
|
||||
Button(onClick = {
|
||||
if (removeChecked) {
|
||||
val toRemove = mutableSetOf<Long>()
|
||||
val toRemoveCur = mutableListOf<Episode>()
|
||||
selected.forEach { e ->
|
||||
if (curQueue.contains(e)) toRemoveCur.add(e)
|
||||
}
|
||||
selected.forEach { e ->
|
||||
for (q in queues) {
|
||||
if (q.contains(e)) {
|
||||
toRemove.add(e.id)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toRemove.isNotEmpty()) runBlocking { removeFromAllQueuesQuiet(toRemove.toList()) }
|
||||
if (toRemoveCur.isNotEmpty()) EventFlow.postEvent(FlowEvent.QueueEvent.removed(toRemoveCur))
|
||||
}
|
||||
selected.forEach { e ->
|
||||
runBlocking { addToQueueSync(false, e, toQueue) }
|
||||
}
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Text("Confirm")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun EpisodeLazyColumn(activity: MainActivity, vms: SnapshotStateList<EpisodeVM>, refreshCB: (()->Unit)? = null,
|
||||
|
@ -192,26 +267,11 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: SnapshotStateList<EpisodeVM>,
|
|||
showConfirmYoutubeDialog.value = false
|
||||
})
|
||||
|
||||
@Composable
|
||||
fun ChooseRatingDialog(onDismissRequest: () -> Unit) {
|
||||
Dialog(onDismissRequest = onDismissRequest) {
|
||||
Surface(shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) {
|
||||
for (rating in Episode.Rating.entries) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(4.dp).clickable {
|
||||
for (item in selected) Episodes.setRating(item, rating.code)
|
||||
onDismissRequest()
|
||||
}) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = rating.res), "")
|
||||
Text(rating.name, Modifier.padding(start = 4.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var showChooseRatingDialog by remember { mutableStateOf(false) }
|
||||
if (showChooseRatingDialog) ChooseRatingDialog { showChooseRatingDialog = false }
|
||||
if (showChooseRatingDialog) ChooseRatingDialog(selected) { showChooseRatingDialog = false }
|
||||
|
||||
var showPutToQueueDialog by remember { mutableStateOf(false) }
|
||||
if (showPutToQueueDialog) PutToQueueDialog(selected) { showPutToQueueDialog = false }
|
||||
|
||||
@Composable
|
||||
fun EpisodeSpeedDial(modifier: Modifier = Modifier) {
|
||||
|
@ -270,7 +330,8 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: SnapshotStateList<EpisodeVM>,
|
|||
isExpanded = false
|
||||
selectMode = false
|
||||
Logd(TAG, "ic_playlist_play: ${selected.size}")
|
||||
PutToQueueDialog(activity, selected).show()
|
||||
showPutToQueueDialog = true
|
||||
// PutToQueueDialog(activity, selected).show()
|
||||
}, verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(imageVector = ImageVector.vectorResource(id = R.drawable.ic_playlist_play), "")
|
||||
Text(stringResource(id = R.string.put_in_queue_label)) } },
|
||||
|
@ -325,7 +386,6 @@ fun EpisodeLazyColumn(activity: MainActivity, vms: SnapshotStateList<EpisodeVM>,
|
|||
}
|
||||
|
||||
var refreshing by remember { mutableStateOf(false)}
|
||||
|
||||
PullToRefreshBox(modifier = Modifier.fillMaxWidth(), isRefreshing = refreshing, indicator = {}, onRefresh = {
|
||||
refreshing = true
|
||||
refreshCB?.invoke()
|
||||
|
|
|
@ -36,6 +36,7 @@ import ac.mdiq.podcini.ui.actions.EpisodeMenuHandler
|
|||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.activity.VideoplayerActivity.Companion.videoMode
|
||||
import ac.mdiq.podcini.ui.activity.starter.VideoPlayerActivityStarter
|
||||
import ac.mdiq.podcini.ui.compose.ChooseRatingDialog
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.ui.dialog.MediaPlayerErrorDialog
|
||||
import ac.mdiq.podcini.ui.dialog.SkipPreferenceDialog
|
||||
|
@ -136,7 +137,7 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
private var episodeDate by mutableStateOf("")
|
||||
private var chapterControlVisible by mutableStateOf(false)
|
||||
private var hasNextChapter by mutableStateOf(true)
|
||||
// var imgLoc by mutableStateOf<String?>("")
|
||||
var rating by mutableStateOf(currentItem?.rating ?: 0)
|
||||
private val currentChapter: Chapter?
|
||||
get() {
|
||||
if (currentMedia == null || currentMedia!!.getChapters().isEmpty() || displayedChapterIndex == -1) return null
|
||||
|
@ -160,7 +161,7 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
controller!!.init()
|
||||
onCollaped()
|
||||
|
||||
binding.composeView1.setContent {
|
||||
binding.player1.setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
if (showPlayer1) PlayerUI()
|
||||
else Spacer(modifier = Modifier.size(0.dp))
|
||||
|
@ -173,7 +174,7 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
// else Spacer(modifier = Modifier.size(0.dp))
|
||||
}
|
||||
}
|
||||
binding.composeView2.setContent {
|
||||
binding.player2.setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
if (!showPlayer1) PlayerUI()
|
||||
else Spacer(modifier = Modifier.size(0.dp))
|
||||
|
@ -334,6 +335,11 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun DetailUI() {
|
||||
var showChooseRatingDialog by remember { mutableStateOf(false) }
|
||||
if (showChooseRatingDialog) ChooseRatingDialog(listOf(currentItem!!)) {
|
||||
showChooseRatingDialog = false
|
||||
}
|
||||
|
||||
val scrollState = rememberScrollState()
|
||||
Column(modifier = Modifier.fillMaxWidth().verticalScroll(scrollState)) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
|
@ -354,7 +360,16 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
}
|
||||
}, onLongClick = { copyText(currentMedia?.getFeedTitle()?:"") }))
|
||||
Text(episodeDate, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 2.dp), color = textColor, style = MaterialTheme.typography.bodyMedium)
|
||||
Row(modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 2.dp), ) {
|
||||
Spacer(modifier = Modifier.weight(0.2f))
|
||||
var ratingIconRes = Episode.Rating.fromCode(rating).res
|
||||
Icon(painter = painterResource(ratingIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "rating", modifier = Modifier.width(15.dp).height(15.dp).clickable(onClick = {
|
||||
showChooseRatingDialog = true
|
||||
}))
|
||||
Spacer(modifier = Modifier.weight(0.4f))
|
||||
Text(episodeDate, textAlign = TextAlign.Center, color = textColor, style = MaterialTheme.typography.bodyMedium)
|
||||
Spacer(modifier = Modifier.weight(0.6f))
|
||||
}
|
||||
Text(titleText, textAlign = TextAlign.Center, color = textColor, style = MaterialTheme.typography.titleLarge, modifier = Modifier.fillMaxWidth().padding(top = 2.dp, bottom = 5.dp)
|
||||
.combinedClickable(onClick = {}, onLongClick = { copyText(currentItem?.title?:"") }))
|
||||
fun restoreFromPreference(): Boolean {
|
||||
|
@ -899,7 +914,7 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
onPlaybackServiceChanged(event)
|
||||
}
|
||||
is FlowEvent.PlayEvent -> onPlayEvent(event)
|
||||
is FlowEvent.RatingEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.RatingEvent -> onRatingEvent(event)
|
||||
is FlowEvent.PlayerErrorEvent -> MediaPlayerErrorDialog.show(activity as Activity, event)
|
||||
// is FlowEvent.SleepTimerUpdatedEvent -> if (event.isCancelled || event.wasJustEnabled()) loadMediaInfo(false)
|
||||
is FlowEvent.SleepTimerUpdatedEvent -> if (event.isCancelled || event.wasJustEnabled()) setupOptionsMenu()
|
||||
|
@ -911,8 +926,11 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun onFavoriteEvent(event: FlowEvent.RatingEvent) {
|
||||
if (curEpisode?.id == event.episode.id) EpisodeMenuHandler.onPrepareMenu(toolbar.menu, event.episode)
|
||||
private fun onRatingEvent(event: FlowEvent.RatingEvent) {
|
||||
if (curEpisode?.id == event.episode.id) {
|
||||
rating = event.rating
|
||||
EpisodeMenuHandler.onPrepareMenu(toolbar.menu, event.episode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupOptionsMenu() {
|
||||
|
@ -982,7 +1000,7 @@ class AudioPlayerFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
|
||||
fun fadePlayerToToolbar(slideOffset: Float) {
|
||||
val playerFadeProgress = (max(0.0, min(0.2, (slideOffset - 0.2f).toDouble())) / 0.2f).toFloat()
|
||||
val player = binding.composeView1
|
||||
val player = binding.player1
|
||||
player.alpha = 1 - playerFadeProgress
|
||||
player.visibility = if (playerFadeProgress > 0.99f) View.GONE else View.VISIBLE
|
||||
val toolbarFadeProgress = (max(0.0, min(0.2, (slideOffset - 0.6f).toDouble())) / 0.2f).toFloat()
|
||||
|
|
|
@ -11,6 +11,7 @@ import ac.mdiq.podcini.playback.base.InTheatre
|
|||
import ac.mdiq.podcini.playback.service.PlaybackService.Companion.seekTo
|
||||
import ac.mdiq.podcini.preferences.UsageStatistics
|
||||
import ac.mdiq.podcini.preferences.UserPreferences
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.realm
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.unmanaged
|
||||
import ac.mdiq.podcini.storage.database.RealmDB.upsert
|
||||
|
@ -22,6 +23,7 @@ import ac.mdiq.podcini.storage.utils.DurationConverter
|
|||
import ac.mdiq.podcini.storage.utils.ImageResourceUtils
|
||||
import ac.mdiq.podcini.ui.actions.*
|
||||
import ac.mdiq.podcini.ui.activity.MainActivity
|
||||
import ac.mdiq.podcini.ui.compose.ChooseRatingDialog
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.ui.utils.ShownotesCleaner
|
||||
import ac.mdiq.podcini.ui.utils.ThemeUtils
|
||||
|
@ -100,6 +102,15 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
private var itemLoaded = false
|
||||
private var episode: Episode? = null // managed
|
||||
|
||||
private var txtvPodcast by mutableStateOf("")
|
||||
private var txtvTitle by mutableStateOf("")
|
||||
private var txtvPublished by mutableStateOf("")
|
||||
private var txtvSize by mutableStateOf("")
|
||||
private var txtvDuration by mutableStateOf("")
|
||||
private var itemLink by mutableStateOf("")
|
||||
var hasMedia by mutableStateOf(true)
|
||||
var rating by mutableStateOf(episode?.rating ?: 0)
|
||||
|
||||
private var webviewData by mutableStateOf("")
|
||||
|
||||
private lateinit var shownotesCleaner: ShownotesCleaner
|
||||
|
@ -188,6 +199,11 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
runOnIOScope { if (episode != null) episode = upsert(episode!!) { it.comment = commentTextState.text } }
|
||||
})
|
||||
|
||||
var showChooseRatingDialog by remember { mutableStateOf(false) }
|
||||
if (showChooseRatingDialog) ChooseRatingDialog(listOf(episode!!)) {
|
||||
showChooseRatingDialog = false
|
||||
}
|
||||
|
||||
Column {
|
||||
Row(modifier = Modifier.padding(start = 16.dp, end = 16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
val imgLoc = if (episode != null) ImageResourceUtils.getEpisodeListImageLocation(episode!!) else null
|
||||
|
@ -199,7 +215,12 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
}
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Spacer(modifier = Modifier.weight(0.4f))
|
||||
var ratingIconRes = Episode.Rating.fromCode(rating).res
|
||||
Icon(painter = painterResource(ratingIconRes), tint = MaterialTheme.colorScheme.tertiary, contentDescription = "rating", modifier = Modifier.width(15.dp).height(15.dp).clickable(onClick = {
|
||||
showChooseRatingDialog = true
|
||||
}))
|
||||
Spacer(modifier = Modifier.weight(0.2f))
|
||||
if (hasMedia) Icon(painter = painterResource(actionButton1?.getDrawable()?: R.drawable.ic_questionmark), tint = textColor, contentDescription = "butAction1",
|
||||
modifier = Modifier.width(24.dp).height(24.dp).clickable(onClick = {
|
||||
when {
|
||||
|
@ -235,7 +256,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
})
|
||||
// if (cond) CircularProgressIndicator(progress = 0.01f * dlPercent, strokeWidth = 4.dp, color = textColor)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Spacer(modifier = Modifier.weight(0.4f))
|
||||
}
|
||||
if (!hasMedia) Text("noMediaLabel", color = textColor, style = MaterialTheme.typography.bodyMedium)
|
||||
val scrollState = rememberScrollState()
|
||||
|
@ -367,12 +388,6 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
else EpisodeMenuHandler.onPrepareMenu(toolbar.menu, episode, R.id.open_podcast, R.id.mark_read_item, R.id.visit_website_item)
|
||||
}
|
||||
|
||||
private var txtvPodcast by mutableStateOf("")
|
||||
private var txtvTitle by mutableStateOf("")
|
||||
private var txtvPublished by mutableStateOf("")
|
||||
private var txtvSize by mutableStateOf("")
|
||||
private var txtvDuration by mutableStateOf("")
|
||||
private var itemLink by mutableStateOf("")
|
||||
@UnstableApi
|
||||
private fun updateAppearance() {
|
||||
if (episode == null) {
|
||||
|
@ -429,7 +444,6 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
updateButtons()
|
||||
}
|
||||
|
||||
var hasMedia by mutableStateOf(true)
|
||||
@UnstableApi
|
||||
private fun updateButtons() {
|
||||
// binding.circularProgressBar.visibility = View.GONE
|
||||
|
@ -501,7 +515,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Logd(TAG, "Received event: ${event.TAG}")
|
||||
when (event) {
|
||||
is FlowEvent.QueueEvent -> onQueueEvent(event)
|
||||
is FlowEvent.RatingEvent -> onFavoriteEvent(event)
|
||||
is FlowEvent.RatingEvent -> onRatingEvent(event)
|
||||
is FlowEvent.EpisodeEvent -> onEpisodeEvent(event)
|
||||
is FlowEvent.PlayerSettingsEvent -> updateButtons()
|
||||
is FlowEvent.EpisodePlayedEvent -> load()
|
||||
|
@ -520,10 +534,11 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun onFavoriteEvent(event: FlowEvent.RatingEvent) {
|
||||
private fun onRatingEvent(event: FlowEvent.RatingEvent) {
|
||||
if (episode?.id == event.episode.id) {
|
||||
episode = unmanaged(episode!!)
|
||||
episode!!.rating = if (event.episode.isFavorite) Episode.Rating.FAVORITE.code else Episode.Rating.NEUTRAL.code
|
||||
episode!!.rating = event.rating
|
||||
rating = episode!!.rating
|
||||
// episode = event.episode
|
||||
prepareMenu()
|
||||
}
|
||||
|
@ -587,6 +602,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
// binding.progbarLoading.visibility = View.GONE
|
||||
rating = episode!!.rating
|
||||
onFragmentLoaded()
|
||||
itemLoaded = true
|
||||
}
|
||||
|
@ -597,7 +613,7 @@ class EpisodeInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
|
||||
fun setItem(item_: Episode) {
|
||||
episode = item_
|
||||
episode = realm.query(Episode::class).query("id == ${item_.id}").first().find()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -104,14 +104,17 @@ class FeedInfoFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
txtvAuthor = feed.author ?: ""
|
||||
txtvUrl = feed.downloadUrl
|
||||
|
||||
binding.header.setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
HeaderUI()
|
||||
}
|
||||
}
|
||||
// binding.header.setContent {
|
||||
// CustomTheme(requireContext()) {
|
||||
// HeaderUI()
|
||||
// }
|
||||
// }
|
||||
binding.detailUI.setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
DetailUI()
|
||||
Column {
|
||||
HeaderUI()
|
||||
DetailUI()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,8 +36,10 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
|
@ -93,26 +95,17 @@ class FeedSettingsFragment : Fragment() {
|
|||
binding.composeView.setContent {
|
||||
CustomTheme(requireContext()) {
|
||||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
Column(
|
||||
modifier = Modifier.padding(start = 20.dp, end = 16.dp, top = 10.dp, bottom = 10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.padding(start = 20.dp, end = 16.dp, top = 10.dp, bottom = 10.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
if ((feed?.id ?: 0) > 10) {
|
||||
// refresh
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_refresh), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.keep_updated),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.keep_updated), style = MaterialTheme.typography.titleLarge, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
var checked by remember { mutableStateOf(feed?.preferences?.keepUpdated ?: true) }
|
||||
Switch(
|
||||
checked = checked,
|
||||
modifier = Modifier.height(24.dp),
|
||||
Switch(checked = checked, modifier = Modifier.height(24.dp),
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
feed = upsertBlk(feed!!) { f ->
|
||||
|
@ -121,41 +114,22 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.keep_updated_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.keep_updated_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
if ((feed?.id?:0) > 10 && feed?.hasVideoMedia == true) {
|
||||
// video mode
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) VideoModeDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_delete), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.feed_video_mode_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
VideoModeDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
Text(text = stringResource(R.string.feed_video_mode_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true })
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(videoModeSummaryResId),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(videoModeSummaryResId), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
if (feed?.type != Feed.FeedType.YOUTUBE.name) {
|
||||
|
@ -164,18 +138,12 @@ class FeedSettingsFragment : Fragment() {
|
|||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_stream), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.pref_stream_over_download_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_stream_over_download_title), style = MaterialTheme.typography.titleLarge, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
var checked by remember {
|
||||
mutableStateOf(feed?.preferences?.prefStreamOverDownload ?: false)
|
||||
}
|
||||
Switch(
|
||||
checked = checked,
|
||||
modifier = Modifier.height(24.dp),
|
||||
Switch(checked = checked, modifier = Modifier.height(24.dp),
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
feed = upsertBlk(feed!!) { f ->
|
||||
|
@ -184,61 +152,37 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.pref_stream_over_download_sum),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_stream_over_download_sum), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
// associated queue
|
||||
Column {
|
||||
curPrefQueue = feed?.preferences?.queueTextExt ?: "Default"
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
var selectedOption by remember { mutableStateOf(feed?.preferences?.queueText ?: "Default") }
|
||||
if (showDialog) SetAssociatedQueue(showDialog, selectedOption = selectedOption, onDismissRequest = { showDialog = false })
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_playlist_play), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.pref_feed_associated_queue),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
Text(text = stringResource(R.string.pref_feed_associated_queue), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val selectedOption = feed?.preferences?.queueText ?: "Default"
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
SetAssociatedQueue(showDialog.value, selectedOption = selectedOption, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
selectedOption = feed?.preferences?.queueText ?: "Default"
|
||||
showDialog = true
|
||||
})
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = curPrefQueue + " : " + stringResource(R.string.pref_feed_associated_queue_sum),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = curPrefQueue + " : " + stringResource(R.string.pref_feed_associated_queue_sum), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// auto add new to queue
|
||||
if (curPrefQueue != "None") {
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = androidx.media3.session.R.drawable.media3_icon_queue_add),
|
||||
"",
|
||||
tint = textColor)
|
||||
Icon(ImageVector.vectorResource(id = androidx.media3.session.R.drawable.media3_icon_queue_add), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.audo_add_new_queue),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.audo_add_new_queue), style = MaterialTheme.typography.titleLarge, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
var checked by remember { mutableStateOf(feed?.preferences?.autoAddNewToQueue ?: true) }
|
||||
Switch(
|
||||
checked = checked,
|
||||
modifier = Modifier.height(24.dp),
|
||||
Switch(checked = checked, modifier = Modifier.height(24.dp),
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
feed = upsertBlk(feed!!) { f ->
|
||||
|
@ -247,41 +191,21 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.audo_add_new_queue_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.audo_add_new_queue_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
if (feed?.type != Feed.FeedType.YOUTUBE.name) {
|
||||
// auto delete
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) AutoDeleteDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_delete), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.auto_delete_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
AutoDeleteDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
)
|
||||
Text(text = stringResource(R.string.auto_delete_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true }))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(autoDeleteSummaryResId),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(autoDeleteSummaryResId), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
// tags
|
||||
|
@ -289,127 +213,64 @@ class FeedSettingsFragment : Fragment() {
|
|||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_tag), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.feed_tags_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
Text(text = stringResource(R.string.feed_tags_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val dialog = TagSettingsDialog.newInstance(listOf(feed!!))
|
||||
dialog.show(parentFragmentManager, TagSettingsDialog.TAG)
|
||||
})
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.feed_tags_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.feed_tags_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// playback speed
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_playback_speed), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.playback_speed),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
Text(text = stringResource(R.string.playback_speed), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
PlaybackSpeedDialog().show()
|
||||
})
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.pref_feed_playback_speed_sum),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_feed_playback_speed_sum), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// auto skip
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) AutoSkipDialog(showDialog.value, onDismiss = { showDialog.value = false })
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_skip_24dp), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.pref_feed_skip),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
AutoSkipDialog(showDialog.value, onDismiss = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_feed_skip), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true }))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.pref_feed_skip_sum),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_feed_skip_sum), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// volume adaption
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) VolumeAdaptionDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_volume_adaption), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.feed_volume_adapdation),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
VolumeAdaptionDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
)
|
||||
Text(text = stringResource(R.string.feed_volume_adapdation), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true }))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.feed_volume_adaptation_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.feed_volume_adaptation_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// authentication
|
||||
if ((feed?.id?:0) > 0 && feed?.isLocalFeed != true) {
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) AuthenticationDialog(showDialog.value, onDismiss = { showDialog.value = false })
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_key), "", tint = textColor)
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.authentication_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
AuthenticationDialog(showDialog.value,
|
||||
onDismiss = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
)
|
||||
Text(text = stringResource(R.string.authentication_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true }))
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.authentication_descr),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.authentication_descr), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
if (isEnableAutodownload && feed?.type != Feed.FeedType.YOUTUBE.name) {
|
||||
|
@ -417,15 +278,9 @@ class FeedSettingsFragment : Fragment() {
|
|||
var audoDownloadChecked by remember { mutableStateOf(feed?.preferences?.autoDownload ?: false) }
|
||||
Column {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.auto_download_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.auto_download_label), style = MaterialTheme.typography.titleLarge, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Switch(
|
||||
checked = audoDownloadChecked,
|
||||
modifier = Modifier.height(24.dp),
|
||||
Switch(checked = audoDownloadChecked, modifier = Modifier.height(24.dp),
|
||||
onCheckedChange = {
|
||||
audoDownloadChecked = it
|
||||
feed = upsertBlk(feed!!) { f -> f.preferences?.autoDownload = audoDownloadChecked }
|
||||
|
@ -433,32 +288,18 @@ class FeedSettingsFragment : Fragment() {
|
|||
)
|
||||
}
|
||||
if (!isEnableAutodownload) {
|
||||
Text(
|
||||
text = stringResource(R.string.auto_download_disabled_globally),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.auto_download_disabled_globally), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
if (audoDownloadChecked) {
|
||||
// auto download policy
|
||||
Column (modifier = Modifier.padding(start = 20.dp)){
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.feed_auto_download_policy),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) AutoDownloadPolicyDialog(showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
Text(text = stringResource(R.string.feed_auto_download_policy), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
AutoDownloadPolicyDialog(showDialog.value,
|
||||
onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
showDialog.value = true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -466,45 +307,23 @@ class FeedSettingsFragment : Fragment() {
|
|||
// episode cache
|
||||
Column (modifier = Modifier.padding(start = 20.dp)) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.pref_episode_cache_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
val composeView = ComposeView(requireContext()).apply {
|
||||
setContent {
|
||||
val showDialog = remember { mutableStateOf(true) }
|
||||
CustomTheme(requireContext()) {
|
||||
SetEpisodesCacheDialog(showDialog.value,
|
||||
onDismiss = { showDialog.value = false })
|
||||
}
|
||||
}
|
||||
}
|
||||
(view as? ViewGroup)?.addView(composeView)
|
||||
})
|
||||
val showDialog = remember { mutableStateOf(false) }
|
||||
if (showDialog.value) SetEpisodesCacheDialog(showDialog.value, onDismiss = { showDialog.value = false })
|
||||
Text(text = stringResource(R.string.pref_episode_cache_title), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = { showDialog.value = true })
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.pref_episode_cache_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_episode_cache_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// counting played
|
||||
Column (modifier = Modifier.padding(start = 20.dp)) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.pref_auto_download_counting_played_title),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_auto_download_counting_played_title), style = MaterialTheme.typography.titleLarge, color = textColor)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
var checked by remember {
|
||||
mutableStateOf(feed?.preferences?.countingPlayed ?: true)
|
||||
}
|
||||
Switch(
|
||||
checked = checked,
|
||||
modifier = Modifier.height(24.dp),
|
||||
Switch(checked = checked, modifier = Modifier.height(24.dp),
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
feed = upsertBlk(feed!!) { f ->
|
||||
|
@ -513,19 +332,12 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.pref_auto_download_counting_played_summary),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.pref_auto_download_counting_played_summary), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// inclusive filter
|
||||
Column (modifier = Modifier.padding(start = 20.dp)) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.episode_inclusive_filters_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
Text(text = stringResource(R.string.episode_inclusive_filters_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
object : AutoDownloadFilterPrefDialog(requireContext(),
|
||||
feed?.preferences!!.autoDownloadFilter!!,
|
||||
|
@ -540,19 +352,12 @@ class FeedSettingsFragment : Fragment() {
|
|||
})
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.episode_filters_description),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.episode_filters_description), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
// exclusive filter
|
||||
Column (modifier = Modifier.padding(start = 20.dp)) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Text(
|
||||
text = stringResource(R.string.episode_exclusive_filters_label),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = textColor,
|
||||
Text(text = stringResource(R.string.episode_exclusive_filters_label), style = MaterialTheme.typography.titleLarge, color = textColor,
|
||||
modifier = Modifier.clickable(onClick = {
|
||||
object : AutoDownloadFilterPrefDialog(requireContext(),
|
||||
feed?.preferences!!.autoDownloadFilter!!,
|
||||
|
@ -567,20 +372,14 @@ class FeedSettingsFragment : Fragment() {
|
|||
})
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.episode_filters_description),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = textColor
|
||||
)
|
||||
Text(text = stringResource(R.string.episode_filters_description), style = MaterialTheme.typography.bodyMedium, color = textColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (feed != null) {
|
||||
toolbar.subtitle = feed!!.title
|
||||
}
|
||||
if (feed != null) toolbar.subtitle = feed!!.title
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -617,23 +416,11 @@ class FeedSettingsFragment : Fragment() {
|
|||
if (showDialog) {
|
||||
val (selectedOption, onOptionSelected) = remember { mutableStateOf(videoMode) }
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
videoModeTags.forEach { text ->
|
||||
Row(Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(checked = (text == selectedOption),
|
||||
onCheckedChange = {
|
||||
Logd(TAG, "row clicked: $text $selectedOption")
|
||||
|
@ -652,12 +439,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyLarge.merge(),
|
||||
// color = textColor,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
Text(text = text, style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -688,23 +470,11 @@ class FeedSettingsFragment : Fragment() {
|
|||
if (showDialog) {
|
||||
val (selectedOption, onOptionSelected) = remember { mutableStateOf(autoDeletePolicy) }
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
FeedAutoDeleteOptions.forEach { text ->
|
||||
Row(Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(checked = (text == selectedOption),
|
||||
onCheckedChange = {
|
||||
Logd(TAG, "row clicked: $text $selectedOption")
|
||||
|
@ -722,12 +492,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyLarge.merge(),
|
||||
// color = textColor,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
Text(text = text, style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -742,23 +507,11 @@ class FeedSettingsFragment : Fragment() {
|
|||
if (showDialog) {
|
||||
val (selectedOption, onOptionSelected) = remember { mutableStateOf(feed?.preferences?.volumeAdaptionSetting ?: VolumeAdaptionSetting.OFF) }
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
VolumeAdaptionSetting.entries.forEach { item ->
|
||||
Row(Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(Modifier.fillMaxWidth().padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(checked = (item == selectedOption),
|
||||
onCheckedChange = { _ ->
|
||||
Logd(TAG, "row clicked: $item $selectedOption")
|
||||
|
@ -769,12 +522,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = stringResource(item.resId),
|
||||
style = MaterialTheme.typography.bodyLarge.merge(),
|
||||
// color = textColor,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
Text(text = stringResource(item.resId), style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -789,16 +537,8 @@ class FeedSettingsFragment : Fragment() {
|
|||
if (showDialog) {
|
||||
val (selectedOption, onOptionSelected) = remember { mutableStateOf(feed?.preferences?.autoDLPolicy ?: AutoDownloadPolicy.ONLY_NEW) }
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
AutoDownloadPolicy.entries.forEach { item ->
|
||||
Row(Modifier
|
||||
|
@ -817,12 +557,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
)
|
||||
Text(
|
||||
text = stringResource(item.resId),
|
||||
style = MaterialTheme.typography.bodyLarge.merge(),
|
||||
// color = textColor,
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
Text(text = stringResource(item.resId), style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -836,17 +571,10 @@ class FeedSettingsFragment : Fragment() {
|
|||
fun SetEpisodesCacheDialog(showDialog: Boolean, onDismiss: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
var newCache by remember { mutableStateOf((feed?.preferences?.autoDLMaxEpisodes ?: 1).toString()) }
|
||||
TextField(value = newCache,
|
||||
onValueChange = { if (it.isEmpty() || it.toIntOrNull() != null) newCache = it },
|
||||
TextField(value = newCache, onValueChange = { if (it.isEmpty() || it.toIntOrNull() != null) newCache = it },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
// visualTransformation = PositiveIntegerTransform(),
|
||||
label = { Text("Max episodes allowed") }
|
||||
|
@ -870,18 +598,10 @@ class FeedSettingsFragment : Fragment() {
|
|||
var selected by remember {mutableStateOf(selectedOption)}
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = { onDismissRequest() }) {
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
queueSettingOptions.forEach { option ->
|
||||
Row(modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
|
||||
Checkbox(checked = option == selected,
|
||||
onCheckedChange = { isChecked ->
|
||||
selected = option
|
||||
|
@ -911,6 +631,7 @@ class FeedSettingsFragment : Fragment() {
|
|||
}
|
||||
if (selected == "Custom") {
|
||||
if (queues == null) queues = realm.query(PlayQueue::class).find()
|
||||
Logd(TAG, "queues: ${queues?.size}")
|
||||
Spinner(items = queues!!.map { it.name }, selectedItem = feed?.preferences?.queue?.name ?: "Default") { name ->
|
||||
Logd(TAG, "Queue selected: $name")
|
||||
val q = queues?.firstOrNull { it.name == name }
|
||||
|
@ -929,26 +650,14 @@ class FeedSettingsFragment : Fragment() {
|
|||
fun AuthenticationDialog(showDialog: Boolean, onDismiss: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
val oldName = feed?.preferences?.username?:""
|
||||
var newName by remember { mutableStateOf(oldName) }
|
||||
TextField(value = newName,
|
||||
onValueChange = { newName = it },
|
||||
label = { Text("Username") }
|
||||
)
|
||||
TextField(value = newName, onValueChange = { newName = it }, label = { Text("Username") })
|
||||
val oldPW = feed?.preferences?.password?:""
|
||||
var newPW by remember { mutableStateOf(oldPW) }
|
||||
TextField(value = newPW,
|
||||
onValueChange = { newPW = it },
|
||||
label = { Text("Password") }
|
||||
)
|
||||
TextField(value = newPW, onValueChange = { newPW = it }, label = { Text("Password") })
|
||||
Button(onClick = {
|
||||
if (newName.isNotEmpty() && oldName != newName) {
|
||||
feed = upsertBlk(feed!!) {
|
||||
|
@ -971,14 +680,8 @@ class FeedSettingsFragment : Fragment() {
|
|||
fun AutoSkipDialog(showDialog: Boolean, onDismiss: () -> Unit) {
|
||||
if (showDialog) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Card(modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
var intro by remember { mutableStateOf((feed?.preferences?.introSkip ?: 0).toString()) }
|
||||
TextField(value = intro,
|
||||
onValueChange = { if (it.isEmpty() || it.toIntOrNull() != null) intro = it },
|
||||
|
|
|
@ -7,6 +7,7 @@ import ac.mdiq.podcini.storage.database.RealmDB.runOnIOScope
|
|||
import ac.mdiq.podcini.storage.model.ShareLog
|
||||
import ac.mdiq.podcini.ui.activity.ShareReceiverActivity.Companion.receiveShared
|
||||
import ac.mdiq.podcini.ui.compose.CustomTheme
|
||||
import ac.mdiq.podcini.ui.compose.confirmAddYoutubeEpisode
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
|
@ -43,6 +44,7 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import io.realm.kotlin.query.Sort
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
@ -82,12 +84,13 @@ class SharedLogFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val showDialog = remember { mutableStateOf(false) }
|
||||
val dialogParam = remember { mutableStateOf(ShareLog()) }
|
||||
if (showDialog.value) {
|
||||
DetailDialog(
|
||||
status = dialogParam.value,
|
||||
showDialog = showDialog.value,
|
||||
onDismissRequest = { showDialog.value = false },
|
||||
)
|
||||
DetailDialog(status = dialogParam.value, showDialog = showDialog.value, onDismissRequest = { showDialog.value = false })
|
||||
}
|
||||
var showYTMediaConfirmDialog by remember { mutableStateOf(false) }
|
||||
var sharedUrl by remember { mutableStateOf("") }
|
||||
if (showYTMediaConfirmDialog)
|
||||
confirmAddYoutubeEpisode(listOf(sharedUrl), showYTMediaConfirmDialog, onDismissRequest = { showYTMediaConfirmDialog = false })
|
||||
|
||||
LazyColumn(state = lazyListState, modifier = Modifier.padding(start = 10.dp, end = 6.dp, top = 5.dp, bottom = 5.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
itemsIndexed(logs) { position, log ->
|
||||
|
@ -96,7 +99,12 @@ class SharedLogFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
if (log.status == 1) {
|
||||
showDialog.value = true
|
||||
dialogParam.value = log
|
||||
} else receiveShared(log.url!!, activity as AppCompatActivity, false)
|
||||
} else {
|
||||
receiveShared(log.url!!, activity as AppCompatActivity, false) {
|
||||
sharedUrl = log.url!!
|
||||
showYTMediaConfirmDialog = true
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Column {
|
||||
Row {
|
||||
|
@ -104,6 +112,13 @@ class SharedLogFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val iconColor = remember { if (log.status == 1) Color.Green else Color.Yellow }
|
||||
Icon(icon, "Info", tint = iconColor, modifier = Modifier.padding(end = 2.dp))
|
||||
Text(formatDateTimeFlex(Date(log.id)), color = textColor)
|
||||
Spacer(Modifier.weight(1f))
|
||||
var showAction by remember { mutableStateOf(log.status != 1) }
|
||||
if (true || showAction) {
|
||||
Icon(painter = painterResource(R.drawable.ic_delete), tint = textColor, contentDescription = null,
|
||||
modifier = Modifier.width(25.dp).height(25.dp).clickable {
|
||||
})
|
||||
}
|
||||
}
|
||||
Text(log.url?:"unknown", color = textColor)
|
||||
val statusText = remember {"" }
|
||||
|
@ -113,15 +128,6 @@ class SharedLogFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Text(stringResource(R.string.download_error_tap_for_details), color = textColor)
|
||||
}
|
||||
}
|
||||
var showAction by remember { mutableStateOf(log.status != 1) }
|
||||
if (showAction) {
|
||||
Icon(painter = painterResource(R.drawable.ic_refresh),
|
||||
tint = textColor,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.width(28.dp).height(32.dp).clickable {
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +160,7 @@ class SharedLogFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
try {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
Logd(TAG, "getDownloadLog() called")
|
||||
val dlog = realm.query(ShareLog::class).find().toMutableList()
|
||||
val dlog = realm.query(ShareLog::class).sort("id", Sort.DESCENDING).find().toMutableList()
|
||||
realm.copyFromRealm(dlog)
|
||||
}
|
||||
withContext(Dispatchers.Main) {
|
||||
|
|
|
@ -529,9 +529,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Column {
|
||||
FeedAutoDeleteOptions.forEach { text ->
|
||||
Row(
|
||||
Modifier.fillMaxWidth().padding(horizontal = 16.dp).selectable(
|
||||
selected = (text == selectedOption),
|
||||
Row(Modifier.fillMaxWidth().padding(horizontal = 16.dp)
|
||||
.selectable(selected = (text == selectedOption),
|
||||
onClick = {
|
||||
if (text != selectedOption) {
|
||||
val autoDeleteAction: AutoDeleteAction = AutoDeleteAction.fromTag(text)
|
||||
|
@ -545,11 +544,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
RadioButton(selected = (text == selectedOption), onClick = { })
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyLarge.merge(),
|
||||
modifier = Modifier.padding(start = 16.dp)
|
||||
)
|
||||
Text(text = text, style = MaterialTheme.typography.bodyLarge.merge(), modifier = Modifier.padding(start = 16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -641,27 +636,15 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
CustomTheme(activity) {
|
||||
if (showDialog.value) {
|
||||
Dialog(onDismissRequest = { showDialog.value = false }) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.wrapContentSize(align = Alignment.Center)
|
||||
.padding(16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Card(modifier = Modifier.wrapContentSize(align = Alignment.Center).padding(16.dp), shape = RoundedCornerShape(16.dp)) {
|
||||
Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.Center) {
|
||||
Row(Modifier.fillMaxWidth()) {
|
||||
Icon(ImageVector.vectorResource(id = R.drawable.ic_refresh), "")
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.keep_updated),
|
||||
style = MaterialTheme.typography.titleLarge
|
||||
)
|
||||
Text(text = stringResource(R.string.keep_updated), style = MaterialTheme.typography.titleLarge)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
var checked by remember { mutableStateOf(false) }
|
||||
Switch(
|
||||
checked = checked,
|
||||
Switch(checked = checked,
|
||||
onCheckedChange = {
|
||||
checked = it
|
||||
saveFeedPreferences { pref: FeedPreferences ->
|
||||
|
@ -670,10 +653,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(R.string.keep_updated_summary),
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Text(text = stringResource(R.string.keep_updated_summary), style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -799,9 +779,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val scrollState = rememberScrollState()
|
||||
Column(modifier = modifier.verticalScroll(scrollState), verticalArrangement = Arrangement.Bottom) {
|
||||
if (isExpanded) options.forEachIndexed { _, button ->
|
||||
FloatingActionButton(modifier = Modifier.padding(start = 4.dp, bottom = 6.dp).height(40.dp),
|
||||
containerColor = Color.LightGray,
|
||||
onClick = {}) { button() }
|
||||
FloatingActionButton(modifier = Modifier.padding(start = 4.dp, bottom = 6.dp).height(40.dp), containerColor = Color.LightGray, onClick = {}) { button() }
|
||||
}
|
||||
FloatingActionButton(containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||
contentColor = MaterialTheme.colorScheme.secondary,
|
||||
|
@ -826,10 +804,8 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}) {
|
||||
if (if (useGrid == null) useGridLayout else useGrid!!) {
|
||||
val lazyGridState = rememberLazyGridState()
|
||||
LazyVerticalGrid(state = lazyGridState,
|
||||
columns = GridCells.Fixed(3),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
LazyVerticalGrid(state = lazyGridState, columns = GridCells.Fixed(3),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
contentPadding = PaddingValues(start = 12.dp, top = 16.dp, end = 12.dp, bottom = 16.dp)
|
||||
) {
|
||||
items(feedListFiltered.size, key = {index -> feedListFiltered[index].id}) { index ->
|
||||
|
@ -867,8 +843,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
val textColor = MaterialTheme.colorScheme.onSurface
|
||||
ConstraintLayout {
|
||||
val (coverImage, episodeCount, error) = createRefs()
|
||||
AsyncImage(model = feed.imageUrl, contentDescription = "coverImage",
|
||||
placeholder = painterResource(R.mipmap.ic_launcher),
|
||||
AsyncImage(model = feed.imageUrl, contentDescription = "coverImage", placeholder = painterResource(R.mipmap.ic_launcher),
|
||||
modifier = Modifier
|
||||
.constrainAs(coverImage) {
|
||||
top.linkTo(parent.top)
|
||||
|
@ -881,24 +856,19 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
top.linkTo(coverImage.top)
|
||||
})
|
||||
// TODO: need to use state
|
||||
if (feed.lastUpdateFailed) Icon(painter = painterResource(R.drawable.ic_error), tint = Color.Red,
|
||||
contentDescription = "error",
|
||||
if (feed.lastUpdateFailed) Icon(painter = painterResource(R.drawable.ic_error), tint = Color.Red, contentDescription = "error",
|
||||
modifier = Modifier.constrainAs(error) {
|
||||
end.linkTo(parent.end)
|
||||
bottom.linkTo(coverImage.bottom)
|
||||
})
|
||||
}
|
||||
Text(feed.title ?: "No title",
|
||||
color = textColor,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis)
|
||||
Text(feed.title ?: "No title", color = textColor, maxLines = 2, overflow = TextOverflow.Ellipsis)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val lazyListState = rememberLazyListState()
|
||||
LazyColumn(state = lazyListState,
|
||||
modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 10.dp, bottom = 10.dp),
|
||||
LazyColumn(state = lazyListState, modifier = Modifier.padding(start = 10.dp, end = 10.dp, top = 10.dp, bottom = 10.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
itemsIndexed(feedListFiltered, key = {index, feed -> feed.id}) { index, feed ->
|
||||
var isSelected by remember { mutableStateOf(false) }
|
||||
|
@ -912,8 +882,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Logd(TAG, "toggleSelected: selected: ${selected.size}")
|
||||
}
|
||||
Row(Modifier.background(if (isSelected) MaterialTheme.colorScheme.secondaryContainer else MaterialTheme.colorScheme.surface)) {
|
||||
AsyncImage(model = feed.imageUrl, contentDescription = "imgvCover",
|
||||
placeholder = painterResource(R.mipmap.ic_launcher),
|
||||
AsyncImage(model = feed.imageUrl, contentDescription = "imgvCover", placeholder = painterResource(R.mipmap.ic_launcher),
|
||||
modifier = Modifier.width(80.dp).height(80.dp)
|
||||
.clickable(onClick = {
|
||||
Logd(TAG, "icon clicked!")
|
||||
|
@ -964,13 +933,9 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
}
|
||||
}
|
||||
if (selectMode) {
|
||||
Row(modifier = Modifier.align(Alignment.TopEnd).width(150.dp).height(45.dp)
|
||||
.background(Color.LightGray),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(painter = painterResource(R.drawable.baseline_arrow_upward_24),
|
||||
tint = Color.Black,
|
||||
contentDescription = null,
|
||||
Row(modifier = Modifier.align(Alignment.TopEnd).width(150.dp).height(45.dp).background(Color.LightGray),
|
||||
horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(painter = painterResource(R.drawable.baseline_arrow_upward_24), tint = Color.Black, contentDescription = null,
|
||||
modifier = Modifier.width(35.dp).height(35.dp).padding(end = 10.dp)
|
||||
.clickable(onClick = {
|
||||
selected.clear()
|
||||
|
@ -980,9 +945,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
selectedSize = selected.size
|
||||
Logd(TAG, "selectedIds: ${selected.size}")
|
||||
}))
|
||||
Icon(painter = painterResource(R.drawable.baseline_arrow_downward_24),
|
||||
tint = Color.Black,
|
||||
contentDescription = null,
|
||||
Icon(painter = painterResource(R.drawable.baseline_arrow_downward_24), tint = Color.Black, contentDescription = null,
|
||||
modifier = Modifier.width(35.dp).height(35.dp).padding(end = 10.dp)
|
||||
.clickable(onClick = {
|
||||
selected.clear()
|
||||
|
@ -993,9 +956,7 @@ class SubscriptionsFragment : Fragment(), Toolbar.OnMenuItemClickListener {
|
|||
Logd(TAG, "selectedIds: ${selected.size}")
|
||||
}))
|
||||
var selectAllRes by remember { mutableIntStateOf(R.drawable.ic_select_all) }
|
||||
Icon(painter = painterResource(selectAllRes),
|
||||
tint = Color.Black,
|
||||
contentDescription = null,
|
||||
Icon(painter = painterResource(selectAllRes), tint = Color.Black, contentDescription = null,
|
||||
modifier = Modifier.width(35.dp).height(35.dp)
|
||||
.clickable(onClick = {
|
||||
if (selectedSize != feedListFiltered.size) {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/composeView1"
|
||||
android:id="@+id/player1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/external_player_height"
|
||||
android:elevation="8dp"
|
||||
|
@ -38,7 +38,7 @@
|
|||
android:layout_marginBottom="12dp"/>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/composeView2"
|
||||
android:id="@+id/player2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/external_player_height"/>
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@
|
|||
app:navigationContentDescription="@string/toolbar_back_button_content_description"
|
||||
app:navigationIcon="?homeAsUpIndicator" />
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
<!-- <androidx.compose.ui.platform.ComposeView-->
|
||||
<!-- android:id="@+id/header"-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="wrap_content"/>-->
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
|
|
|
@ -34,17 +34,17 @@
|
|||
android:title="@string/remove_from_queue_label">
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/add_to_favorites_item"
|
||||
android:icon="@drawable/ic_star_border"
|
||||
custom:showAsAction="always"
|
||||
android:title="@string/add_to_favorite_label" />
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/add_to_favorites_item"-->
|
||||
<!-- android:icon="@drawable/ic_star_border"-->
|
||||
<!-- custom:showAsAction="always"-->
|
||||
<!-- android:title="@string/add_to_favorite_label" />-->
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_from_favorites_item"
|
||||
android:icon="@drawable/ic_star"
|
||||
custom:showAsAction="always"
|
||||
android:title="@string/remove_from_favorite_label" />
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/remove_from_favorites_item"-->
|
||||
<!-- android:icon="@drawable/ic_star"-->
|
||||
<!-- custom:showAsAction="always"-->
|
||||
<!-- android:title="@string/remove_from_favorite_label" />-->
|
||||
|
||||
<item
|
||||
android:id="@+id/reset_position"
|
||||
|
|
|
@ -30,15 +30,15 @@
|
|||
android:menuCategory="container"
|
||||
android:title="@string/delete_label" />
|
||||
|
||||
<item
|
||||
android:id="@+id/add_to_favorites_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/add_to_favorite_label" />
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/add_to_favorites_item"-->
|
||||
<!-- android:menuCategory="container"-->
|
||||
<!-- android:title="@string/add_to_favorite_label" />-->
|
||||
|
||||
<item
|
||||
android:id="@+id/remove_from_favorites_item"
|
||||
android:menuCategory="container"
|
||||
android:title="@string/remove_from_favorite_label" />
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/remove_from_favorites_item"-->
|
||||
<!-- android:menuCategory="container"-->
|
||||
<!-- android:title="@string/remove_from_favorite_label" />-->
|
||||
|
||||
<item
|
||||
android:id="@+id/reset_position"
|
||||
|
|
|
@ -18,18 +18,18 @@
|
|||
custom:showAsAction="always">
|
||||
</item>
|
||||
|
||||
<item
|
||||
android:id="@+id/add_to_favorites_item"
|
||||
android:icon="@drawable/ic_star_border"
|
||||
android:title="@string/add_to_favorite_label"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<item
|
||||
android:id="@+id/remove_from_favorites_item"
|
||||
android:icon="@drawable/ic_star"
|
||||
android:title="@string/remove_from_favorite_label"
|
||||
custom:showAsAction="always">
|
||||
</item>
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/add_to_favorites_item"-->
|
||||
<!-- android:icon="@drawable/ic_star_border"-->
|
||||
<!-- android:title="@string/add_to_favorite_label"-->
|
||||
<!-- custom:showAsAction="always">-->
|
||||
<!-- </item>-->
|
||||
<!-- <item-->
|
||||
<!-- android:id="@+id/remove_from_favorites_item"-->
|
||||
<!-- android:icon="@drawable/ic_star"-->
|
||||
<!-- android:title="@string/remove_from_favorite_label"-->
|
||||
<!-- custom:showAsAction="always">-->
|
||||
<!-- </item>-->
|
||||
|
||||
<item
|
||||
android:id="@+id/disable_sleeptimer_item"
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
# 6.9.3
|
||||
|
||||
* fixed app quit issue when repairing a shared item
|
||||
* fixed custom queue spinner not showing up (issue introduced in 6.8.3 when migrating to Material3)
|
||||
* updated dialog popup mechanism in FeedSettings
|
||||
* updated UI to reflect the new rating system
|
||||
* a couple dialog converted to Compose and removed EpisodeMultiSelectHandler
|
||||
|
||||
# 6.9.2
|
||||
|
||||
* fixed getting 0 episodes with Youtube playlist etc
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
Version 6.9.3
|
||||
|
||||
* fixed app quit issue when repairing a shared item
|
||||
* fixed custom queue spinner not showing up (issue introduced in 6.8.3 when migrating to Material3)
|
||||
* updated dialog popup mechanism in FeedSettings
|
||||
* updated UI to reflect the new rating system
|
||||
* a couple dialog converted to Compose and removed EpisodeMultiSelectHandler
|
Loading…
Reference in New Issue