Skip to content

Conversation

@tungnk123
Copy link
Contributor

No description provided.

Copy link
Owner

@oxyroid oxyroid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert some unnecessary formatting changes. Including Linebreak and contraction.

@tungnk123 tungnk123 force-pushed the feature/issue-201-navigate-between-channels branch from 4ca54ae to dbb72f9 Compare November 4, 2024 15:33
@oxyroid
Copy link
Owner

oxyroid commented Nov 17, 2024

I have a new idea to find out the adjacent channels:

Define a new class to hold the SQL result.

// Channel.kt
data class AdjacentChannels(
    @ColumnInfo("prev")
    val prev: Channel?,
    @ColumnInfo("next")
    val next: Channel?
)

Add a method which returns "Flow"

// ChannelDao.kt
/**
 * Observe the two channels adjacent to a specific channel in a particular channel order.
 * If the channel is not in this channel order, a null object will be returned.
 */
@Query(
    """
        Write SQL here.
    """
)
fun observeAdjacentChannels(
    channelId: Int,
    playlistUrl: String,
    category: String
): Flow<AdjacentChannels?>
  • You can refer to the observeProgrammeRange method in ProgrammeDao. It shows you how to map a custom object to a SQL statement.
  • You can refer to the pagingAllByPlaylistUrl method in ChannelDao. It shows you how the channel order should be.

@oxyroid
Copy link
Owner

oxyroid commented Nov 17, 2024

Then, because it is not a collection, you can maintain it directly in the viewmodel through a series of operators such as combine/map/stateIn like other flows without performance problems.

// ChannelViewModel.kt
val adjacentChannels: StateFlow<AdjacentChannels?> = flatmapCombined(playlist, channel) { playlist, channel ->
    playlist?: return@flatmapCombined flowOf(null)
    channel?: return@flatmapCombined flowOf(null)
    // Don't forget to define the same method in repository because viewModel shouldn't hold the DAO instance.
    channelRepository.observeAdjacentChannels(
        channelId = channel.id,
        playlistUrl = playlist.url,
        category = channel.category
    )
}
    .stateIn(
        scope = viewModelScope,
        started = SharingStarted.Lazily,
        initialValue = null
    )

In addition, you need to modify the function flatmapCombined in the project, it has some problems.

fun <R> flatmapCombined(
    flows: Iterable<Flow<Any?>>,
    transform: (keys: Array<Any?>) -> Flow<R>
): Flow<R> = combine(flows) { it }.flatMapLatest { keys -> transform(keys) }

@Suppress("UNCHECKED_CAST")
fun <T1, T2, R> flatmapCombined(
    flow1: Flow<T1>,
    flow2: Flow<T2>,
    transform: (t1: T1, t2: T2) -> Flow<R>
): Flow<R> = flatmapCombined(listOf(flow1, flow2)) { keys ->
    transform(keys[0] as T1, keys[1] as T2)
}

@Suppress("UNCHECKED_CAST")
fun <T1, T2, T3, R> flatmapCombined(
    flow1: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    transform: (t1: T1, t2: T2, t3: T3) -> Flow<R>
): Flow<R> = flatmapCombined(listOf(flow1, flow2, flow3)) { keys ->
    transform(keys[0] as T1, keys[1] as T2, keys[2] as T3)
}

@Suppress("UNCHECKED_CAST")
fun <T1, T2, T3, T4, R> flatmapCombined(
    flow1: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    transform: (t1: T1, t2: T2, t3: T3, t4: T4) -> Flow<R>
): Flow<R> = flatmapCombined(listOf(flow1, flow2, flow3, flow4)) { keys ->
    transform(keys[0] as T1, keys[1] as T2, keys[2] as T3, keys[3] as T4)
}

Then, you can call collectAsState to convert it in the UI layer.

val adjacentChannels = viewModel.adjacentChannels.collectAsStateWithLifecycle()

This way has a great advantage, that is, you can control in real time whether the previous or next button is enabled or not.

MaskButton(
    enabled = adjacentChannels != null && adjacentChannels.prev != null,
    onClick = {
        val prev = adjacentChannels.prev
        if (adjacentChannels != null && prev != null) {
            helper.play(MediaCommand.Common(prev.id))
        }
    }
)

oxyroid and others added 6 commits November 18, 2024 02:05
* feat: overscroll effect.

* fix: remove unused import directive.
* feat: overscroll effect.

* fix: remove unused import directive.

* fix: overscroll effect.

* fix: remove unused import directive.
@tungnk123
Copy link
Contributor Author

Could you pls review this pull request?

@tungnk123 tungnk123 closed this Dec 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants