Skip to content

Commit

Permalink
feat: tv layout for settings.
Browse files Browse the repository at this point in the history
  • Loading branch information
oxyroid committed Jan 12, 2024
1 parent 4bc218e commit 249642b
Show file tree
Hide file tree
Showing 19 changed files with 258 additions and 316 deletions.
19 changes: 13 additions & 6 deletions androidApp/src/main/java/com/m3u/androidApp/ui/AppRootGraph.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
Expand All @@ -24,6 +25,7 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -95,12 +97,17 @@ internal fun AppRootGraph(
}
},
actions = {
actions.forEach { action ->
IconButton(
icon = action.icon,
contentDescription = action.contentDescription,
onClick = action.onClick
)

CompositionLocalProvider(
androidx.tv.material3.LocalContentColor provides LocalContentColor.current
) {
actions.forEach { action ->
IconButton(
icon = action.icon,
contentDescription = action.contentDescription,
onClick = action.onClick
)
}
}
},
modifier = Modifier.fillMaxWidth()
Expand Down
18 changes: 11 additions & 7 deletions data/src/main/java/com/m3u/data/service/impl/MessageServiceImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,28 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import java.util.concurrent.atomic.AtomicReference
import javax.inject.Inject

class MessageServiceImpl @Inject constructor() : MessageService {
private val _message: MutableStateFlow<Message> = MutableStateFlow(Message.Dynamic.EMPTY)
override val message: StateFlow<Message> get() = _message.asStateFlow()

private val coroutineScope = CoroutineScope(Dispatchers.Main)
private val coroutineScope = CoroutineScope(Dispatchers.IO) + Job()
private val job = AtomicReference<Job?>()

override fun emit(message: Message) {
job.getAndUpdate { prev ->
prev?.cancel()
coroutineScope.launch {
_message.update { message }
delay(message.duration)
_message.update { Message.Dynamic.EMPTY }
coroutineScope.launch {
job.getAndUpdate { prev ->
prev?.cancel()
coroutineScope.launch {
_message.update { message }
delay(message.duration)
_message.update { Message.Dynamic.EMPTY }
}
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.m3u.core.util.basic.title
import com.m3u.features.about.components.ContributorItem
Expand All @@ -26,7 +27,6 @@ import com.m3u.material.ktx.plus
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.LocalHelper
import com.m3u.ui.MonoText
import com.m3u.ui.repeatOnLifecycle

@Composable
internal fun AboutRoute(
Expand All @@ -36,8 +36,9 @@ internal fun AboutRoute(
) {
val helper = LocalHelper.current
val title = stringResource(string.feat_about_title)
helper.repeatOnLifecycle {
this.title = title.title()
LifecycleResumeEffect(Unit) {
helper.title = title.title()
onPauseOrDispose { }
}

val state by viewModel.s.collectAsStateWithLifecycle()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.m3u.core.util.basic.title
import com.m3u.i18n.R.string
import com.m3u.material.components.Background
import com.m3u.material.components.TextField
import com.m3u.material.ktx.plus
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.LocalHelper
import com.m3u.ui.MonoText
import com.m3u.ui.repeatOnLifecycle

@Composable
internal fun ConsoleRoute(
Expand All @@ -41,8 +42,9 @@ internal fun ConsoleRoute(
) {
val helper = LocalHelper.current
val title = stringResource(string.feat_console_title)
helper.repeatOnLifecycle {
this.title = title
LifecycleResumeEffect(Unit) {
helper.title = title.title()
onPauseOrDispose { }
}
val state by viewModel.state.collectAsStateWithLifecycle()
ConsoleScreen(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private fun FavouriteGalleryImpl(
LazyVerticalStaggeredGrid(
columns = StaggeredGridCells.Fixed(rowCount),
verticalItemSpacing = spacing.medium,
horizontalArrangement = Arrangement.spacedBy(spacing.medium),
horizontalArrangement = Arrangement.spacedBy(spacing.large),
contentPadding = PaddingValues(spacing.medium) + contentPadding,
modifier = modifier.fillMaxSize(),
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private fun PlaylistGalleryImpl(
horizontal = spacing.large
) + contentPadding,
verticalArrangement = Arrangement.spacedBy(spacing.medium),
horizontalArrangement = Arrangement.spacedBy(spacing.medium),
horizontalArrangement = Arrangement.spacedBy(spacing.large),
modifier = modifier.fillMaxSize()
) {
items(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.google.accompanist.permissions.rememberPermissionState
import com.m3u.core.architecture.pref.LocalPref
import com.m3u.core.util.compose.observableStateOf
import com.m3u.core.wrapper.Event
import com.m3u.core.wrapper.Message
import com.m3u.data.database.model.Stream
import com.m3u.features.playlist.impl.PlaylistScreenImpl
import com.m3u.features.playlist.impl.TvPlaylistScreenImpl
Expand Down Expand Up @@ -70,6 +71,8 @@ internal fun PlaylistRoute(
val sorts = viewModel.sorts
val sort by viewModel.sort.collectAsStateWithLifecycle()

val message by viewModel.message.collectAsStateWithLifecycle()


// If you try to check or request the WRITE_EXTERNAL_STORAGE on Android 13+,
// it will always return false.
Expand Down Expand Up @@ -107,6 +110,7 @@ internal fun PlaylistRoute(
Background {
PlaylistScreen(
title = playlist?.title.orEmpty(),
message = message,
query = query,
onQuery = { viewModel.onEvent(PlaylistEvent.Query(it)) },
rowCount = pref.rowCount,
Expand Down Expand Up @@ -142,6 +146,7 @@ internal fun PlaylistRoute(
private fun PlaylistScreen(
title: String,
query: String,
message: Message,
onQuery: (String) -> Unit,
rowCount: Int,
zapping: Stream?,
Expand Down Expand Up @@ -202,6 +207,7 @@ private fun PlaylistScreen(
} else {
TvPlaylistScreenImpl(
title = title,
message = message,
channels = channels,
query = query,
onQuery = onQuery,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class PlaylistViewModel @Inject constructor(
started = SharingStarted.WhileSubscribed(5_000)
)

val zapping: StateFlow<Stream?> = combine(
internal val zapping: StateFlow<Stream?> = combine(
zappingMode,
playerService.url,
streamRepository.observeAll()
Expand All @@ -99,7 +99,7 @@ class PlaylistViewModel @Inject constructor(
)

private var _refreshing = MutableStateFlow(false)
val refreshing = _refreshing.asStateFlow()
internal val refreshing = _refreshing.asStateFlow()

private fun refresh() {
val url = playlistUrl.value
Expand Down Expand Up @@ -201,7 +201,7 @@ class PlaylistViewModel @Inject constructor(
}

private val _query: MutableStateFlow<String> = MutableStateFlow("")
val query: StateFlow<String> = _query.asStateFlow()
internal val query: StateFlow<String> = _query.asStateFlow()
private fun query(event: PlaylistEvent.Query) {
val text = event.text
_query.update { text }
Expand Down Expand Up @@ -240,23 +240,23 @@ class PlaylistViewModel @Inject constructor(
started = SharingStarted.WhileSubscribed(5_000L)
)

val sorts: ImmutableList<Sort> = Sort.entries.toPersistentList()
internal val sorts: ImmutableList<Sort> = Sort.entries.toPersistentList()

private val sortIndex: MutableStateFlow<Int> = MutableStateFlow(0)

val sort: StateFlow<Sort> = sortIndex
internal val sort: StateFlow<Sort> = sortIndex
.map { sorts[it] }
.stateIn(
scope = viewModelScope,
initialValue = Sort.UNSPECIFIED,
started = SharingStarted.WhileSubscribed(5_000L)
)

fun sort(sort: Sort) {
internal fun sort(sort: Sort) {
sortIndex.update { sorts.indexOf(sort).coerceAtLeast(0) }
}

val channels: StateFlow<ImmutableList<Channel>> = combine(
internal val channels: StateFlow<ImmutableList<Channel>> = combine(
unsorted,
sort,
recommend
Expand All @@ -273,4 +273,6 @@ class PlaylistViewModel @Inject constructor(
initialValue = persistentListOf(),
started = SharingStarted.WhileSubscribed(5_000L)
)

internal val message = messageService.message
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,12 @@ import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.windowsizeclass.WindowSizeClass
import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.m3u.core.Contracts
import com.m3u.core.architecture.logger.Logger
Expand All @@ -37,10 +31,8 @@ import com.m3u.core.util.context.isPortraitMode
import com.m3u.core.wrapper.Message
import com.m3u.data.service.MessageService
import com.m3u.data.service.PlayerService
import com.m3u.material.model.LocalSpacing
import com.m3u.ui.Action
import com.m3u.ui.AppLocalProvider
import com.m3u.ui.AppSnackHost
import com.m3u.ui.Fob
import com.m3u.ui.Helper
import com.m3u.ui.OnPipModeChanged
Expand Down Expand Up @@ -84,40 +76,29 @@ class TvPlaylistActivity : AppCompatActivity() {
helper = helper,
pref = pref
) {
val spacing = LocalSpacing.current
val message by messageService.message.collectAsStateWithLifecycle()

val darkMode = pref.darkMode
LaunchedEffect(darkMode) {
helper.darkMode = darkMode.unspecifiable
}

Box {
PlaylistRoute(
navigateToStream = {
val options = ActivityOptions.makeCustomAnimation(
this@TvPlaylistActivity,
0,
0
)
startActivity(
Intent().apply {
component = ComponentName.createRelative(
this@TvPlaylistActivity,
Contracts.PLAYER_ACTIVITY
)
},
options.toBundle()
)
}
)
AppSnackHost(
message = message,
modifier = Modifier
.align(Alignment.TopStart)
.padding(spacing.medium)
)
}
PlaylistRoute(
navigateToStream = {
val options = ActivityOptions.makeCustomAnimation(
this@TvPlaylistActivity,
0,
0
)
startActivity(
Intent().apply {
component = ComponentName.createRelative(
this@TvPlaylistActivity,
Contracts.PLAYER_ACTIVITY
)
},
options.toBundle()
)
}
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.LifecycleResumeEffect
import com.m3u.core.wrapper.Event
import com.m3u.data.database.model.Stream
import com.m3u.features.playlist.Channel
Expand All @@ -58,7 +59,6 @@ import com.m3u.ui.EventHandler
import com.m3u.ui.LocalHelper
import com.m3u.ui.Sort
import com.m3u.ui.SortBottomSheet
import com.m3u.ui.repeatOnLifecycle
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -111,9 +111,8 @@ internal fun PlaylistScreenImpl(
var dialogStatus: DialogStatus by remember { mutableStateOf(DialogStatus.Idle) }
var isSortSheetVisible by rememberSaveable { mutableStateOf(false) }


helper.repeatOnLifecycle {
actions = persistentListOf(
LifecycleResumeEffect(Unit) {
helper.actions = persistentListOf(
Action(
icon = Icons.AutoMirrored.Rounded.Sort,
contentDescription = "sort",
Expand All @@ -125,6 +124,7 @@ internal fun PlaylistScreenImpl(
onClick = onRefresh
)
)
onPauseOrDispose { }
}

Background {
Expand Down
Loading

0 comments on commit 249642b

Please sign in to comment.