refactor: replace Scaffold with internal component

This commit is contained in:
andrekir 2025-01-06 19:17:55 -03:00 committed by Andre K
parent 1c863f35f6
commit 7794c08190
7 changed files with 72 additions and 135 deletions

View file

@ -23,7 +23,6 @@ import android.view.View
import android.view.ViewGroup
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@ -36,13 +35,9 @@ import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.Button
import androidx.compose.material.Card
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.outlined.CloudDownload
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -64,13 +59,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.database.entity.MeshLog
import com.geeksville.mesh.model.DebugViewModel
import com.geeksville.mesh.ui.components.BaseScaffold
import com.geeksville.mesh.ui.theme.AppTheme
import dagger.hilt.android.AndroidEntryPoint
import java.text.DateFormat
@ -85,36 +80,9 @@ class DebugFragment : Fragment() {
): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setBackgroundColor(ContextCompat.getColor(context, R.color.colorAdvancedBackground))
setContent {
val viewModel: DebugViewModel = hiltViewModel()
AppTheme {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(id = R.string.debug_panel)) },
navigationIcon = {
IconButton(onClick = { parentFragmentManager.popBackStack() }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
stringResource(id = R.string.navigate_back),
)
}
},
actions = {
Button(onClick = viewModel::deleteAllLogs) {
Text(text = stringResource(R.string.clear))
}
}
)
},
) { innerPadding ->
DebugScreen(
viewModel = viewModel,
contentPadding = innerPadding,
)
}
DebugScreen { parentFragmentManager.popBackStack() }
}
}
}
@ -185,7 +153,7 @@ private fun Int.asNodeId(): String {
@Composable
internal fun DebugScreen(
viewModel: DebugViewModel = hiltViewModel(),
contentPadding: PaddingValues,
navigateUp: () -> Unit
) {
val listState = rememberLazyListState()
val logs by viewModel.meshLog.collectAsStateWithLifecycle()
@ -199,13 +167,22 @@ internal fun DebugScreen(
}
}
SelectionContainer {
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
contentPadding = contentPadding,
) {
items(logs, key = { it.uuid }) { log -> DebugItem(annotateMeshLog(log)) }
BaseScaffold(
title = stringResource(id = R.string.debug_panel),
navigateUp = navigateUp,
actions = {
Button(onClick = viewModel::deleteAllLogs) {
Text(text = stringResource(R.string.clear))
}
}
) {
SelectionContainer {
LazyColumn(
modifier = Modifier.fillMaxSize(),
state = listState,
) {
items(logs, key = { it.uuid }) { log -> DebugItem(annotateMeshLog(log)) }
}
}
}
}

View file

@ -22,14 +22,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Forward
import androidx.compose.material.icons.automirrored.filled.List
import androidx.compose.material.icons.automirrored.filled.Message
@ -61,7 +54,6 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.res.stringResource
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels
@ -77,6 +69,7 @@ import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.model.MetricsViewModel
import com.geeksville.mesh.model.RadioConfigViewModel
import com.geeksville.mesh.ui.components.BaseScaffold
import com.geeksville.mesh.ui.components.DeviceMetricsScreen
import com.geeksville.mesh.ui.components.EnvironmentMetricsScreen
import com.geeksville.mesh.ui.components.NodeMapScreen
@ -143,32 +136,26 @@ class NavGraphFragment : ScreenFragment("NavGraph"), Logging {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setBackgroundColor(ContextCompat.getColor(context, R.color.colorAdvancedBackground))
setContent {
val node by model.destNode.collectAsStateWithLifecycle()
AppTheme {
val navController: NavHostController = rememberNavController()
Scaffold(
topBar = {
MeshAppBar(
currentScreen = node?.user?.longName
?: stringResource(R.string.unknown_username),
canNavigateBack = true,
navigateUp = {
if (navController.previousBackStackEntry != null) {
navController.navigateUp()
} else {
parentFragmentManager.popBackStack()
}
},
)
}
) { innerPadding ->
BaseScaffold(
title = node?.user?.longName
?: stringResource(R.string.unknown_username),
canNavigateBack = true,
navigateUp = {
if (navController.previousBackStackEntry != null) {
navController.navigateUp()
} else {
parentFragmentManager.popBackStack()
}
},
) {
NavGraph(
navController = navController,
startDestination = startDestination,
modifier = Modifier.padding(innerPadding),
)
}
}
@ -294,29 +281,6 @@ sealed class ResponseState<out T> {
fun isWaiting() = this !is Empty
}
@Composable
private fun MeshAppBar(
currentScreen: String,
canNavigateBack: Boolean,
navigateUp: () -> Unit,
modifier: Modifier = Modifier,
) {
TopAppBar(
title = { Text(currentScreen) },
modifier = modifier,
navigationIcon = {
if (canNavigateBack) {
IconButton(onClick = navigateUp) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(id = R.string.navigate_back),
)
}
}
}
)
}
@Suppress("LongMethod")
@Composable
fun NavGraph(

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:Suppress("TooManyFunctions", "LongMethod")
@file:Suppress("TooManyFunctions")
package com.geeksville.mesh.ui
@ -108,7 +108,7 @@ import kotlin.math.ln
fun NodeDetailScreen(
modifier: Modifier = Modifier,
viewModel: MetricsViewModel = hiltViewModel(),
onNavigate: (Any) -> Unit,
onNavigate: (Route) -> Unit,
) {
val state by viewModel.state.collectAsStateWithLifecycle()
@ -135,7 +135,7 @@ private fun NodeDetailList(
modifier: Modifier = Modifier,
node: Node,
metricsState: MetricsState,
onNavigate: (Any) -> Unit = {},
onNavigate: (Route) -> Unit = {},
) {
LazyColumn(
modifier = modifier.fillMaxSize(),
@ -320,7 +320,7 @@ private fun NodeDetailsContent(
}
@Composable
fun LogNavigationList(state: MetricsState, onNavigate: (Any) -> Unit) {
fun LogNavigationList(state: MetricsState, onNavigate: (Route) -> Unit) {
NavCard(
title = stringResource(R.string.device_metrics_log),
icon = Icons.Default.ChargingStation,

View file

@ -49,22 +49,22 @@ import androidx.compose.material.IconButton
import androidx.compose.material.ListItem
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Scaffold
import androidx.compose.material.Switch
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.FastForward
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.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.onFocusEvent
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalHapticFeedback
@ -76,13 +76,13 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.geeksville.mesh.R
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.ui.components.BaseScaffold
import com.geeksville.mesh.ui.components.dragContainer
import com.geeksville.mesh.ui.components.dragDropItemsIndexed
import com.geeksville.mesh.ui.components.rememberDragDropState
@ -98,28 +98,9 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat Settings"), Logging
): View {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setBackgroundColor(ContextCompat.getColor(context, R.color.colorAdvancedBackground))
setContent {
AppTheme {
Scaffold(
topBar = {
TopAppBar(
title = { Text(stringResource(id = R.string.quick_chat)) },
navigationIcon = {
IconButton(onClick = { parentFragmentManager.popBackStack() }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
stringResource(id = R.string.navigate_back),
)
}
},
)
},
) { innerPadding ->
QuickChatScreen(
modifier = Modifier.padding(innerPadding)
)
}
QuickChatScreen { parentFragmentManager.popBackStack() }
}
}
}
@ -129,7 +110,19 @@ class QuickChatSettingsFragment : ScreenFragment("Quick Chat Settings"), Logging
@Composable
internal fun QuickChatScreen(
viewModel: UIViewModel = hiltViewModel(),
modifier: Modifier = Modifier,
navigateUp: () -> Unit
) {
BaseScaffold(
title = stringResource(id = R.string.quick_chat),
navigateUp = navigateUp,
) {
QuickChatContent(viewModel)
}
}
@Composable
private fun QuickChatContent(
viewModel: UIViewModel = hiltViewModel(),
) {
val actions by viewModel.quickChatActions.collectAsStateWithLifecycle()
var showActionDialog by remember { mutableStateOf<QuickChatAction?>(null) }
@ -140,7 +133,7 @@ internal fun QuickChatScreen(
viewModel.updateActionPositions(list)
}
Box(modifier = modifier.fillMaxSize()) {
Box(modifier = Modifier.fillMaxSize()) {
if (showActionDialog != null) {
val action = showActionDialog ?: return
EditQuickChatDialog(
@ -212,10 +205,17 @@ private fun EditQuickChatDialog(
onDismiss: () -> Unit,
) {
var actionInput by remember { mutableStateOf(action) }
val newQuickChat = action.uuid == 0L
val newQuickChat = remember { action.uuid == 0L }
val isInstant = actionInput.mode == QuickChatAction.Mode.Instant
val title = if (newQuickChat) R.string.quick_chat_new else R.string.quick_chat_edit
val focusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) {
if (newQuickChat) {
focusRequester.requestFocus()
}
}
AlertDialog(
onDismissRequest = onDismiss,
shape = RoundedCornerShape(16.dp),
@ -246,9 +246,11 @@ private fun EditQuickChatDialog(
OutlinedTextFieldWithCounter(
label = stringResource(id = R.string.message),
value = actionInput.message,
maxSize = 235,
maxSize = 200,
getSize = { it.toByteArray().size + 1 },
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),
) {
actionInput = actionInput.copy(message = it)
if (newQuickChat) {

View file

@ -42,7 +42,7 @@ import androidx.lifecycle.compose.dropUnlessResumed
import com.geeksville.mesh.R
@Composable
fun BaseScaffold(
internal fun BaseScaffold(
title: String,
modifier: Modifier = Modifier,
canNavigateBack: Boolean = true,
@ -82,7 +82,7 @@ fun BaseScaffold(
}
@Composable
fun BaseScaffold(
internal fun BaseScaffold(
modifier: Modifier = Modifier,
topBar: @Composable () -> Unit = {},
bottomBar: @Composable () -> Unit = {},

View file

@ -40,7 +40,6 @@ import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.material.TextField
@ -80,7 +79,6 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
@ -94,6 +92,7 @@ import com.geeksville.mesh.database.entity.QuickChatAction
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.model.getChannel
import com.geeksville.mesh.ui.components.BaseScaffold
import com.geeksville.mesh.ui.components.NodeKeyStatusIcon
import com.geeksville.mesh.ui.components.NodeMenuAction
import com.geeksville.mesh.ui.message.components.MessageList
@ -139,7 +138,6 @@ class MessagesFragment : Fragment(), Logging {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setBackgroundColor(ContextCompat.getColor(context, R.color.colorAdvancedBackground))
setContent {
AppTheme {
MessageScreen(
@ -213,7 +211,7 @@ internal fun MessageScreen(
)
}
Scaffold(
BaseScaffold(
topBar = {
if (inSelectionMode) {
ActionModeTopBar(selectedIds.value) { action ->
@ -269,13 +267,12 @@ internal fun MessageScreen(
TextInput(isConnected, messageInput) { viewModel.sendMessage(it, contactKey) }
}
}
) { innerPadding ->
) {
if (messages.isNotEmpty()) {
MessageList(
messages = messages,
selectedIds = selectedIds,
onUnreadChanged = { viewModel.clearUnreadCount(contactKey, it) },
contentPadding = innerPadding,
onSendReaction = { emoji, id -> viewModel.sendReaction(emoji, id, contactKey) },
) { action ->
when (action) {

View file

@ -18,7 +18,6 @@
package com.geeksville.mesh.ui.message.components
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.wrapContentSize
import androidx.compose.foundation.lazy.LazyColumn
@ -54,7 +53,6 @@ internal fun MessageList(
messages: List<Message>,
selectedIds: MutableState<Set<Long>>,
onUnreadChanged: (Long) -> Unit,
contentPadding: PaddingValues,
onSendReaction: (String, Int) -> Unit,
onNodeMenuAction: (NodeMenuAction) -> Unit = {}
) {
@ -89,7 +87,6 @@ internal fun MessageList(
modifier = Modifier.fillMaxSize(),
state = listState,
reverseLayout = true,
contentPadding = contentPadding
) {
items(messages, key = { it.uuid }) { msg ->
val fromLocal = msg.node.user.id == DataPacket.ID_LOCAL