Flatten `BluetoothViewModel` (#3138)

pull/3146/head
Phil Oliver 2025-09-18 12:08:10 -04:00 zatwierdzone przez GitHub
rodzic eedc3ef963
commit f2d29d4582
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
6 zmienionych plików z 15 dodań i 58 usunięć

Wyświetl plik

@ -42,7 +42,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.android.GeeksvilleApplication
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.prefs.UiPrefs
import com.geeksville.mesh.model.BluetoothViewModel
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.navigation.DEEP_LINK_BASE_URI
import com.geeksville.mesh.ui.MainScreen
@ -58,7 +57,6 @@ import javax.inject.Inject
class MainActivity :
AppCompatActivity(),
Logging {
private val bluetoothViewModel: BluetoothViewModel by viewModels()
private val model: UIViewModel by viewModels()
// This is aware of the Activity lifecycle and handles binding to the mesh service.
@ -108,7 +106,7 @@ class MainActivity :
val appIntroCompleted by model.appIntroCompleted.collectAsStateWithLifecycle()
if (appIntroCompleted) {
MainScreen(uIViewModel = model, bluetoothViewModel = bluetoothViewModel)
MainScreen(uIViewModel = model)
} else {
AppIntroductionScreen(
onDone = {

Wyświetl plik

@ -1,33 +0,0 @@
/*
* Copyright (c) 2025 Meshtastic LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.geeksville.mesh.model
import androidx.lifecycle.ViewModel
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.map
import javax.inject.Inject
/** Thin view model which adapts the view layer to the `BluetoothRepository`. */
@HiltViewModel
class BluetoothViewModel @Inject constructor(private val bluetoothRepository: BluetoothRepository) : ViewModel() {
/** Called when permissions have been updated. This causes an explicit refresh of the bluetooth state. */
fun permissionsUpdated() = bluetoothRepository.refreshState()
val enabled = bluetoothRepository.state.map { it.enabled }
}

Wyświetl plik

@ -24,12 +24,11 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import androidx.navigation.navDeepLink
import androidx.navigation.navigation
import com.geeksville.mesh.model.BluetoothViewModel
import com.geeksville.mesh.ui.connections.ConnectionsScreen
import com.geeksville.mesh.ui.settings.radio.components.LoRaConfigScreen
/** Navigation graph for for the top level ConnectionsScreen - [ConnectionsRoutes.Connections]. */
fun NavGraphBuilder.connectionsGraph(navController: NavHostController, bluetoothViewModel: BluetoothViewModel) {
fun NavGraphBuilder.connectionsGraph(navController: NavHostController) {
@Suppress("ktlint:standard:max-line-length")
navigation<ConnectionsRoutes.ConnectionsGraph>(startDestination = ConnectionsRoutes.Connections) {
composable<ConnectionsRoutes.Connections>(
@ -40,7 +39,6 @@ fun NavGraphBuilder.connectionsGraph(navController: NavHostController, bluetooth
val parentEntry =
remember(backStackEntry) { navController.getBackStackEntry(ConnectionsRoutes.ConnectionsGraph) }
ConnectionsScreen(
bluetoothViewModel = bluetoothViewModel,
radioConfigViewModel = hiltViewModel(parentEntry),
onClickNodeChip = {
navController.navigate(NodesRoutes.NodeDetailGraph(it)) {

Wyświetl plik

@ -81,7 +81,6 @@ import com.geeksville.mesh.android.AddNavigationTracking
import com.geeksville.mesh.android.BuildUtils.debug
import com.geeksville.mesh.android.setAttributes
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.BluetoothViewModel
import com.geeksville.mesh.model.DeviceVersion
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
@ -148,11 +147,7 @@ enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector,
@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@Suppress("LongMethod", "CyclomaticComplexMethod")
@Composable
fun MainScreen(
uIViewModel: UIViewModel = hiltViewModel(),
bluetoothViewModel: BluetoothViewModel = hiltViewModel(),
scanModel: BTScanModel = hiltViewModel(),
) {
fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanModel = hiltViewModel()) {
val navController = rememberNavController()
val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle()
val requestChannelSet by uIViewModel.requestChannelSet.collectAsStateWithLifecycle()
@ -396,7 +391,7 @@ fun MainScreen(
nodesGraph(navController, uiViewModel = uIViewModel)
mapGraph(navController, uiViewModel = uIViewModel)
channelsGraph(navController, uiViewModel = uIViewModel)
connectionsGraph(navController, bluetoothViewModel)
connectionsGraph(navController)
settingsGraph(navController)
}
}

Wyświetl plik

@ -62,7 +62,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.ConfigProtos
import com.geeksville.mesh.R
import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.BluetoothViewModel
import com.geeksville.mesh.model.DeviceListEntry
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.navigation.ConfigRoute
@ -102,7 +101,6 @@ fun String?.isIPAddress(): Boolean = if (Build.VERSION.SDK_INT < Build.VERSION_C
fun ConnectionsScreen(
connectionsViewModel: ConnectionsViewModel = hiltViewModel(),
scanModel: BTScanModel = hiltViewModel(),
bluetoothViewModel: BluetoothViewModel = hiltViewModel(),
radioConfigViewModel: RadioConfigViewModel = hiltViewModel(),
onClickNodeChip: (Int) -> Unit,
onNavigateToSettings: () -> Unit,
@ -120,7 +118,7 @@ fun ConnectionsScreen(
val info by connectionsViewModel.myNodeInfo.collectAsStateWithLifecycle()
val ourNode by connectionsViewModel.ourNodeInfo.collectAsStateWithLifecycle()
val selectedDevice by scanModel.selectedNotNullFlow.collectAsStateWithLifecycle()
val bluetoothEnabled by bluetoothViewModel.enabled.collectAsStateWithLifecycle(false)
val bluetoothState by connectionsViewModel.bluetoothState.collectAsStateWithLifecycle()
val regionUnset = config.lora.region == ConfigProtos.Config.LoRaConfig.RegionCode.UNSET
val bleDevices by scanModel.bleDevicesForUi.collectAsStateWithLifecycle()
@ -264,7 +262,7 @@ fun ConnectionsScreen(
btDevices = bleDevices,
selectedDevice = selectedDevice,
scanModel = scanModel,
bluetoothEnabled = bluetoothEnabled,
bluetoothEnabled = bluetoothState.enabled,
)
}

Wyświetl plik

@ -24,6 +24,7 @@ import com.geeksville.mesh.android.prefs.UiPrefs
import com.geeksville.mesh.database.NodeRepository
import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.repository.bluetooth.BluetoothRepository
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
@ -37,8 +38,9 @@ import javax.inject.Inject
class ConnectionsViewModel
@Inject
constructor(
private val radioConfigRepository: RadioConfigRepository,
private val nodeRepository: NodeRepository,
radioConfigRepository: RadioConfigRepository,
nodeRepository: NodeRepository,
bluetoothRepository: BluetoothRepository,
private val uiPrefs: UiPrefs,
) : ViewModel() {
val localConfig: StateFlow<LocalConfig> =
@ -48,14 +50,13 @@ constructor(
LocalConfig.getDefaultInstance(),
)
val connectionState
get() = radioConfigRepository.connectionState
val connectionState = radioConfigRepository.connectionState
val myNodeInfo: StateFlow<MyNodeEntity?>
get() = nodeRepository.myNodeInfo
val myNodeInfo: StateFlow<MyNodeEntity?> = nodeRepository.myNodeInfo
val ourNodeInfo: StateFlow<Node?>
get() = nodeRepository.ourNodeInfo
val ourNodeInfo: StateFlow<Node?> = nodeRepository.ourNodeInfo
val bluetoothState = bluetoothRepository.state
private val _hasShownNotPairedWarning = MutableStateFlow(uiPrefs.hasShownNotPairedWarning)
val hasShownNotPairedWarning: StateFlow<Boolean> = _hasShownNotPairedWarning.asStateFlow()