apps\player\src\main\java\cn\nfarms\player\MainActivity.kt¶
源码路径:
apps\player\src\main\java\cn\nfarms\player\MainActivity.kt· 120 行
package cn.nfarms.player
import android.Manifest
import android.os.Build
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Bookmark
import androidx.compose.material.icons.filled.LibraryMusic
import androidx.compose.material.icons.filled.PlayCircle
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import cn.nfarms.core.ui.nfarmsColorScheme
import cn.nfarms.player.ui.BookmarksScreen
import cn.nfarms.player.ui.LibraryScreen
import cn.nfarms.player.ui.NowPlayingScreen
class MainActivity : ComponentActivity() {
private val notifPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { /* 拒绝也能用,只是没通知 */ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
// Android 13+ 通知要运行时授权:没有它,前台服务的播放控制条不显示
if (Build.VERSION.SDK_INT >= 33) {
notifPermission.launch(Manifest.permission.POST_NOTIFICATIONS)
}
val container = (application as PlayerApp).container
setContent {
MaterialTheme(colorScheme = nfarmsColorScheme(isSystemInDarkTheme())) {
Surface(Modifier.fillMaxSize()) { Root(container) }
}
}
}
}
enum class Tab(val label: String) { Library("曲库"), Playing("正在播放"), Bookmarks("书签") }
@Composable
private fun Root(container: Container) {
val vm: PlayerViewModel = viewModel(factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T = PlayerViewModel(container) as T
})
val ui by vm.ui.collectAsStateWithLifecycle()
val snack = remember { SnackbarHostState() }
var tab by remember { mutableStateOf(Tab.Library) }
LaunchedEffect(ui.message) {
ui.message?.let {
snack.showSnackbar(it)
vm.dismissMessage()
}
}
LaunchedEffect(ui.playing) {
// 在播时把界面切到"正在播放"——这是音乐 App 的惯例,用户不用自己找
if (ui.playing && tab == Tab.Library) tab = Tab.Playing
}
Scaffold(
snackbarHost = { SnackbarHost(snack) },
bottomBar = {
NavigationBar {
Tab.entries.forEach { t ->
NavigationBarItem(
selected = tab == t,
onClick = { tab = t },
icon = {
Icon(
when (t) {
Tab.Library -> Icons.Filled.LibraryMusic
Tab.Playing -> Icons.Filled.PlayCircle
Tab.Bookmarks -> Icons.Filled.Bookmark
},
contentDescription = t.label,
)
},
label = { Text(t.label) },
)
}
}
},
) { pad ->
Box(Modifier.fillMaxSize().padding(pad)) {
when (tab) {
Tab.Library -> LibraryScreen(ui, vm)
Tab.Playing -> NowPlayingScreen(ui, vm)
Tab.Bookmarks -> BookmarksScreen(ui, vm)
}
}
}
}