Skip to content

Commit

Permalink
added about cast in readme
Browse files Browse the repository at this point in the history
  • Loading branch information
XilinJia committed Sep 25, 2024
1 parent 8b4747b commit 0b68607
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 30 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ An open source podcast instrument, attuned to Puccini ![Puccini](./images/Puccin
#### Podcini.R version 6.5 as a major step forward brings YouTube contents in the app. Channels can be searched, received from share, subscribed. Since 6.6, podcasts, playlists as well as single media from Youtube and YT Music can be shared to Podcini. For more see the Youtube section below or the changelogs
That means finally: [Nessun dorma](https://www.youtube.com/watch?v=cWc7vYjgnTs)
#### For Podcini to show up on car's HUD with Android Auto, please read AnroidAuto.md for instructions.
#### If you need to cast to an external speaker, you should install the "play" apk, not the "free" apk, that's about the difference between the two.
#### If you are migrating from Podcini version 5, please read the migrationTo5.md file for migration instructions.

This project was developed from a fork of [AntennaPod](<https://github.com/AntennaPod/AntennaPod>) as of Feb 5 2024.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ import kotlin.math.sin
open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private val tag: String)
: ItemTouchHelper.SimpleCallback(dragDirs, ItemTouchHelper.RIGHT or ItemTouchHelper.LEFT), DefaultLifecycleObserver {

private var filter: EpisodeFilter? = null
@set:JvmName("setFilterProperty")
var filter: EpisodeFilter? = null

var actions: Actions? = null
var swipeOutEnabled: Boolean = true
Expand All @@ -79,6 +80,7 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
actions = null
}

@JvmName("setFilterFunction")
fun setFilter(filter: EpisodeFilter?) {
this.filter = filter
}
Expand Down Expand Up @@ -186,7 +188,8 @@ open class SwipeActions(dragDirs: Int, private val fragment: Fragment, private v
return if (swipeOutEnabled) 0.6f else 1.0f
}

@UnstableApi override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
@UnstableApi
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)

if (swipedOutTo != 0) {
Expand Down
98 changes: 77 additions & 21 deletions app/src/main/kotlin/ac/mdiq/podcini/ui/compose/Episodes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,19 @@ 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.removeFromQueue
import ac.mdiq.podcini.storage.database.RealmDB.realm
import ac.mdiq.podcini.storage.model.Episode
import ac.mdiq.podcini.storage.model.MediaType
import ac.mdiq.podcini.storage.utils.DurationConverter
import ac.mdiq.podcini.storage.utils.ImageResourceUtils
import ac.mdiq.podcini.ui.actions.handler.EpisodeMultiSelectHandler.PutToQueueDialog
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeAction
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.adapter.EpisodesAdapter.EpisodeInfoFragment
import ac.mdiq.podcini.ui.fragment.FeedInfoFragment
import ac.mdiq.podcini.ui.utils.LocalDeleteModal
import ac.mdiq.podcini.ui.view.EpisodeViewHolder
import ac.mdiq.podcini.ui.view.EpisodeViewHolder.Companion
import ac.mdiq.podcini.util.Logd
import ac.mdiq.podcini.util.MiscFormatter.formatAbbrev
import android.text.format.Formatter
Expand Down Expand Up @@ -49,24 +53,25 @@ import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.constraintlayout.compose.ConstraintLayout
import coil.compose.AsyncImage
import kotlinx.coroutines.launch
import io.realm.kotlin.notifications.SingleQueryChange
import io.realm.kotlin.notifications.UpdatedObject
import kotlinx.coroutines.*
import kotlin.math.roundToInt

@Composable
fun InforBar(text: MutableState<String>, leftActionConfig: () -> Unit, rightActionConfig: () -> Unit) {
// val textState by remember { mutableStateOf(text) }
fun InforBar(text: MutableState<String>, leftAction: MutableState<SwipeAction?>, rightAction: MutableState<SwipeAction?>, actionConfig: () -> Unit) {
val textColor = MaterialTheme.colors.onSurface
Logd("InforBar", "textState: ${text.value}")
Row {
Image(painter = painterResource(R.drawable.ic_questionmark), contentDescription = "left_action_icon",
Modifier.width(24.dp).height(24.dp).clickable(onClick = leftActionConfig))
Image(painter = painterResource(leftAction.value?.getActionIcon() ?:R.drawable.ic_questionmark), contentDescription = "left_action_icon",
Modifier.width(24.dp).height(24.dp).clickable(onClick = actionConfig))
Image(painter = painterResource(R.drawable.baseline_arrow_left_alt_24), contentDescription = "left_arrow", Modifier.width(24.dp).height(24.dp))
Spacer(modifier = Modifier.weight(1f))
Text(text.value, color = textColor, style = MaterialTheme.typography.body2)
Spacer(modifier = Modifier.weight(1f))
Image(painter = painterResource(R.drawable.baseline_arrow_right_alt_24), contentDescription = "right_arrow", Modifier.width(24.dp).height(24.dp))
Image(painter = painterResource(R.drawable.ic_questionmark), contentDescription = "right_action_icon",
Modifier.width(24.dp).height(24.dp).clickable(onClick = rightActionConfig))
Image(painter = painterResource(rightAction.value?.getActionIcon() ?:R.drawable.ic_questionmark), contentDescription = "right_action_icon",
Modifier.width(24.dp).height(24.dp).clickable(onClick = actionConfig))
}
}

Expand Down Expand Up @@ -144,10 +149,8 @@ fun EpisodeSpeedDialOptions(activity: MainActivity, selected: List<Episode>): Li
}

@Composable
fun EpisodeLazyColumn(activity: MainActivity, episodes: SnapshotStateList<Episode>, leftAction: (Episode) -> Unit, rightAction: (Episode) -> Unit) {
fun EpisodeLazyColumn(activity: MainActivity, episodes: SnapshotStateList<Episode>, leftActionCB: (Episode) -> Unit, rightActionCB: (Episode) -> Unit) {
var selectMode by remember { mutableStateOf(false) }
var longPressedItem by remember { mutableStateOf<Episode?>(null) }
var longPressedPosition by remember { mutableStateOf(0) }
val selectedIds by remember { mutableStateOf(mutableSetOf<Long>()) }
val selected = remember { mutableListOf<Episode>()}
val coroutineScope = rememberCoroutineScope()
Expand All @@ -173,10 +176,10 @@ fun EpisodeLazyColumn(activity: MainActivity, episodes: SnapshotStateList<Episod
if (velocity > 1000f || velocity < -1000f) {
if (velocity > 0) {
Logd("EpisodeLazyColumn","Fling to the right with velocity: $velocity")
rightAction(episode)
rightActionCB(episode)
} else {
Logd("EpisodeLazyColumn","Fling to the left with velocity: $velocity")
leftAction(episode)
leftActionCB(episode)
}
}
offsetX.animateTo(
Expand Down Expand Up @@ -216,8 +219,6 @@ fun EpisodeLazyColumn(activity: MainActivity, episodes: SnapshotStateList<Episod
selectedIds.clear()
}
Logd("EpisodeLazyColumn", "long clicked: ${episode.title}")
longPressedItem = episode
longPressedPosition = index
},
iconOnClick = {
Logd("EpisodeLazyColumn", "icon clicked!")
Expand Down Expand Up @@ -249,8 +250,65 @@ fun EpisodeLazyColumn(activity: MainActivity, episodes: SnapshotStateList<Episod

@OptIn(ExperimentalFoundationApi::class)
@Composable
fun EpisodeRow(episode: Episode, isSelected: MutableState<Boolean>, onClick: () -> Unit, onLongClick: () -> Unit, iconOnClick: () -> Unit = {}) {
fun EpisodeRow(episode_: Episode, isSelected: MutableState<Boolean>, onClick: () -> Unit, onLongClick: () -> Unit, iconOnClick: () -> Unit = {}) {
var episode = episode_
val textColor = MaterialTheme.colors.onSurface
var positionState by remember(episode) { mutableStateOf(episode.media?.position?:0) }
var playedState by remember { mutableStateOf(episode.isPlayed()) }
var farvoriteState by remember { mutableStateOf(episode.isFavorite) }
var inProgressState by remember { mutableStateOf(episode.isInProgress) }

var episodeMonitor: Job? by remember { mutableStateOf(null) }
var mediaMonitor: Job? by remember { mutableStateOf(null) }
if (episodeMonitor == null) {
val item_ = realm.query(Episode::class).query("id == ${episode.id}").first()
episodeMonitor = CoroutineScope(Dispatchers.Default).launch {
val episodeFlow = item_.asFlow()
episodeFlow.collect { changes: SingleQueryChange<Episode> ->
when (changes) {
is UpdatedObject -> {
Logd("EpisodeRow", "episodeMonitor UpdatedObject ${changes.obj.title} ${changes.changedFields.joinToString()}")
episode = changes.obj
playedState = episode.isPlayed()
farvoriteState = episode.isFavorite
// withContext(Dispatchers.Main) {
//// bind(changes.obj)
//// if (posIndex >= 0) refreshAdapterPosCallback?.invoke(posIndex, changes.obj)
// }
}
else -> {}
}
}
}
}
if (mediaMonitor == null) {
val item_ = realm.query(Episode::class).query("id == ${episode.id}").first()
mediaMonitor = CoroutineScope(Dispatchers.Default).launch {
val episodeFlow = item_.asFlow(listOf("media.*"))
episodeFlow.collect { changes: SingleQueryChange<Episode> ->
when (changes) {
is UpdatedObject -> {
Logd("EpisodeRow", "mediaMonitor UpdatedObject ${changes.obj.title} ${changes.changedFields.joinToString()}")
episode = changes.obj
positionState = episode.media?.position?:0
inProgressState = episode.isInProgress
// withContext(Dispatchers.Main) {
//// updatePlaybackPositionNew(changes.obj)
////// bind(changes.obj)
//// if (posIndex >= 0) refreshAdapterPosCallback?.invoke(posIndex, changes.obj)
// }
}
else -> {}
}
}
}
}
DisposableEffect(Unit) {
onDispose {
episodeMonitor?.cancel()
mediaMonitor?.cancel()
}
}
Row (Modifier.background(if (isSelected.value) MaterialTheme.colors.secondary else MaterialTheme.colors.surface)) {
if (false) {
val typedValue = TypedValue()
Expand All @@ -260,8 +318,6 @@ fun EpisodeRow(episode: Episode, isSelected: MutableState<Boolean>, onClick: ()
modifier = Modifier.width(16.dp).align(Alignment.CenterVertically))
}
ConstraintLayout(modifier = Modifier.width(56.dp).height(56.dp)) {
var playedState by remember { mutableStateOf(false) }
playedState = episode.isPlayed()
Logd("EpisodeRow", "playedState: $playedState")
val (image1, image2) = createRefs()
val imgLoc = ImageResourceUtils.getEpisodeListImageLocation(episode)
Expand All @@ -286,7 +342,7 @@ fun EpisodeRow(episode: Episode, isSelected: MutableState<Boolean>, onClick: ()
Row {
if (episode.media?.getMediaType() == MediaType.VIDEO)
Image(painter = painterResource(R.drawable.ic_videocam), contentDescription = "isVideo", Modifier.width(14.dp).height(14.dp))
if (episode.isFavorite)
if (farvoriteState)
Image(painter = painterResource(R.drawable.ic_star), contentDescription = "isFavorite", Modifier.width(14.dp).height(14.dp))
if (curQueue.contains(episode))
Image(painter = painterResource(R.drawable.ic_playlist_play), contentDescription = "ivInPlaylist", Modifier.width(14.dp).height(14.dp))
Expand All @@ -296,9 +352,9 @@ fun EpisodeRow(episode: Episode, isSelected: MutableState<Boolean>, onClick: ()
Text(if((episode.media?.size?:0) > 0) Formatter.formatShortFileSize(LocalContext.current, episode.media!!.size) else "", color = textColor, style = MaterialTheme.typography.body2)
}
Text(episode.title?:"", color = textColor, maxLines = 2, overflow = TextOverflow.Ellipsis)
if (InTheatre.isCurMedia(episode.media) || episode.isInProgress) {
val pos = episode.media!!.getPosition()
val dur = episode.media!!.getDuration()
if (InTheatre.isCurMedia(episode.media) || inProgressState) {
val pos = positionState
val dur = remember(episode, episode.media) { episode.media!!.getDuration()}
val prog = if (dur > 0 && pos >= 0 && dur >= pos) 1.0f * pos / dur else 0f
Row {
Text(DurationConverter.getDurationStringLong(pos), color = textColor)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ac.mdiq.podcini.storage.model.EpisodeFilter
import ac.mdiq.podcini.storage.model.EpisodeMedia
import ac.mdiq.podcini.storage.model.EpisodeSortOrder
import ac.mdiq.podcini.storage.utils.EpisodeUtil
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeAction
import ac.mdiq.podcini.ui.actions.swipeactions.SwipeActions
import ac.mdiq.podcini.ui.activity.MainActivity
import ac.mdiq.podcini.ui.compose.CustomTheme
Expand All @@ -36,8 +37,7 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.*
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import androidx.media3.common.util.UnstableApi
Expand Down Expand Up @@ -65,6 +65,8 @@ import java.util.*
private var episodes = mutableStateListOf<Episode>()

private var infoBarText = mutableStateOf("")
var leftActionState = mutableStateOf<SwipeAction?>(null)
var rightActionState = mutableStateOf<SwipeAction?>(null)

private lateinit var toolbar: MaterialToolbar
// private lateinit var recyclerView: EpisodesRecyclerView
Expand Down Expand Up @@ -94,26 +96,26 @@ import java.util.*
(activity as MainActivity).setupToolbarToggle(toolbar, displayUpArrow)

swipeActions = SwipeActions(this, TAG)
swipeActions.setFilter(EpisodeFilter(EpisodeFilter.States.downloaded.name))
binding.infobar.setContent {
CustomTheme(requireContext()) {
InforBar(infoBarText, leftActionConfig = {swipeActions.showDialog()}, rightActionConfig = { swipeActions.showDialog() })
InforBar(infoBarText, leftAction = leftActionState, rightAction = rightActionState, actionConfig = {swipeActions.showDialog()})
}
}

binding.lazyColumn.setContent {
CustomTheme(requireContext()) {
EpisodeLazyColumn(activity as MainActivity, episodes = episodes,
leftAction = { swipeActions.actions?.left?.performAction(it, this, EpisodeFilter())},
rightAction = { swipeActions.actions?.right?.performAction(it, this, EpisodeFilter())})
leftActionCB = { leftActionState.value?.performAction(it, this, swipeActions.filter ?: EpisodeFilter())},
rightActionCB = { rightActionState.value?.performAction(it, this, swipeActions.filter ?: EpisodeFilter())})
}
}
// recyclerView.setRecycledViewPool((activity as MainActivity).recycledViewPool)
// adapter.setOnSelectModeListener(this)
// recyclerView.addOnScrollListener(LiftOnScrollListener(binding.appbar))

// swipeActions = SwipeActions(this, TAG).attachTo(recyclerView)
lifecycle.addObserver(swipeActions)
swipeActions.setFilter(EpisodeFilter(EpisodeFilter.States.downloaded.name))
// lifecycle.addObserver(swipeActions)
refreshSwipeTelltale()
// binding.leftActionIcon.setOnClickListener { swipeActions.showDialog() }
// binding.rightActionIcon.setOnClickListener { swipeActions.showDialog() }
Expand Down Expand Up @@ -363,6 +365,8 @@ import java.util.*
}

private fun refreshSwipeTelltale() {
leftActionState.value = swipeActions.actions?.left
rightActionState.value = swipeActions.actions?.right
// if (swipeActions.actions?.left != null) binding.leftActionIcon.setImageResource(swipeActions.actions!!.left!!.getActionIcon())
// if (swipeActions.actions?.right != null) binding.rightActionIcon.setImageResource(swipeActions.actions!!.right!!.getActionIcon())
}
Expand Down

0 comments on commit 0b68607

Please sign in to comment.