跳转至

apps\hub\src\main\java\cn\nfarms\hub\MainActivity.kt

源码路径:apps\hub\src\main\java\cn\nfarms\hub\MainActivity.kt · 112 行

package cn.nfarms.hub

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
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.Build
import androidx.compose.material.icons.filled.CloudDownload
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material.icons.filled.Settings
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.setValue
import androidx.compose.runtime.remember
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import cn.nfarms.core.ui.nfarmsColorScheme
import cn.nfarms.hub.ui.FfmpegScreen
import cn.nfarms.hub.ui.HarnessScreen
import cn.nfarms.hub.ui.ModelsScreen
import cn.nfarms.hub.ui.TasksScreen

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        val container = (application as HubApp).container
        // 一进来就把前台服务挂上:任务可能在上一次就被杀了,通知要接得住
        HubService.start(this)
        setContent {
            MaterialTheme(colorScheme = nfarmsColorScheme(isSystemInDarkTheme())) {
                Surface(Modifier.fillMaxSize()) { HubRoot(container) }
            }
        }
    }
}

enum class HubTab(val label: String) { Tasks("任务"), Models("模型"), Media("媒体"), Harness("Harness") }

@Composable
private fun HubRoot(container: Container) {
    val vm: HubViewModel = viewModel(factory = viewModelFactory { HubViewModel(container) })
    val ui by vm.ui.collectAsStateWithLifecycle()
    val snackbar = remember { SnackbarHostState() }
    var tab by androidx.compose.runtime.remember { androidx.compose.runtime.mutableStateOf(HubTab.Tasks) }

    LaunchedEffect(ui.message) {
        ui.message?.let {
            snackbar.showSnackbar(it)
            vm.dismissMessage()
        }
    }

    Scaffold(
        snackbarHost = { SnackbarHost(snackbar) },
        bottomBar = {
            NavigationBar {
                HubTab.entries.forEach { t ->
                    NavigationBarItem(
                        selected = tab == t,
                        onClick = { tab = t },
                        icon = {
                            Icon(
                                when (t) {
                                    HubTab.Tasks -> Icons.Filled.PlayArrow
                                    HubTab.Models -> Icons.Filled.CloudDownload
                                    HubTab.Media -> Icons.Filled.Build
                                    HubTab.Harness -> Icons.Filled.Settings
                                },
                                contentDescription = t.label,
                            )
                        },
                        label = { Text(t.label) },
                    )
                }
            }
        },
    ) { pad ->
        Box(Modifier.fillMaxSize().padding(pad)) {
            when (tab) {
                HubTab.Tasks -> TasksScreen(ui, vm)
                HubTab.Models -> ModelsScreen(ui, vm)
                HubTab.Media -> FfmpegScreen(ui, vm)
                HubTab.Harness -> HarnessScreen(ui, vm)
            }
        }
    }
}

/** 极简 ViewModel 工厂 —— 只为把 Container 传进去,不引额外依赖。 */
private fun <T : androidx.lifecycle.ViewModel> viewModelFactory(create: () -> T):
    androidx.lifecycle.ViewModelProvider.Factory = object : androidx.lifecycle.ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <V : androidx.lifecycle.ViewModel> create(modelClass: Class<V>): V = create() as V
}