Got rid of ts_color_light_green

Signed-off-by: Percy Wegmann <percy@tailscale.com>
ox/styling_bak
Percy Wegmann 2 years ago
parent 5c77e8377c
commit 4a82eabaff
No known key found for this signature in database
GPG Key ID: 29D8CDEB4C13D48B

@ -3,6 +3,15 @@
package com.tailscale.ipn.ui.model
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import com.tailscale.ipn.R
import com.tailscale.ipn.ui.theme.success
import com.tailscale.ipn.ui.util.ComposableStringFormatter
import com.tailscale.ipn.ui.util.DisplayAddress
import com.tailscale.ipn.ui.util.TimeUtil
import com.tailscale.ipn.ui.viewModel.PeerSettingInfo
import kotlinx.serialization.Serializable
class Tailcfg {
@ -82,6 +91,33 @@ class Tailcfg {
val isMullvadNode: Boolean
get() = Name.endsWith(".mullvad.ts.net.")
val displayName: String
get() = ComputedName ?: ""
fun connectedOrSelfNode(nm: Netmap.NetworkMap?) =
Online == true || StableID == nm?.SelfNode?.StableID
fun connectedStrRes(nm: Netmap.NetworkMap?) =
if (connectedOrSelfNode(nm)) R.string.connected else R.string.not_connected
@Composable
fun connectedColor(nm: Netmap.NetworkMap?) =
if (connectedOrSelfNode(nm)) MaterialTheme.colorScheme.success else Color.Gray
val displayAddresses: List<DisplayAddress>
get() {
var addresses = mutableListOf<DisplayAddress>()
Addresses?.let { addresses.addAll(it.map { addr -> DisplayAddress(addr) }) }
addresses.add(DisplayAddress(Name))
return addresses
}
val info: List<PeerSettingInfo>
get() =
listOf(
PeerSettingInfo(R.string.os, ComposableStringFormatter(Hostinfo.OS ?: "")),
PeerSettingInfo(R.string.key_expiry, TimeUtil().keyExpiryFromGoTime(KeyExpiry)))
}
@Serializable

@ -7,7 +7,5 @@ import androidx.compose.ui.graphics.Color
// TODO: replace references to these with references to material theme
val ts_color_light_blue = Color(0xFF4B70CC)
val ts_color_light_green = Color(0xFF1EA672)
var ts_color_dark_desctrutive_text = Color(0xFFFF0000)
var ts_color_light_desctrutive_text = Color(0xFFBB0000)

@ -5,6 +5,7 @@ package com.tailscale.ipn.ui.util
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
// FeatureStateRepresentation represents the status of a feature
@ -12,7 +13,7 @@ import androidx.compose.ui.graphics.Color
// It is typically implemented as an enumeration.
interface FeatureStateRepresentation {
@get:DrawableRes val symbolDrawable: Int
val tint: Color
@get:Composable val tint: Color
@get:StringRes val title: Int
@get:StringRes val caption: Int
}

@ -13,7 +13,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.unit.dp
object Lists {
@ -27,7 +26,7 @@ object Lists {
@Composable
fun ItemDivider() {
HorizontalDivider(modifier = Modifier.alpha(0f))
HorizontalDivider(color = MaterialTheme.colorScheme.outline)
}
}

@ -55,15 +55,12 @@ import com.tailscale.ipn.ui.model.Ipn
import com.tailscale.ipn.ui.model.IpnLocal
import com.tailscale.ipn.ui.model.Permission
import com.tailscale.ipn.ui.model.Permissions
import com.tailscale.ipn.ui.model.StableNodeID
import com.tailscale.ipn.ui.model.Tailcfg
import com.tailscale.ipn.ui.theme.ts_color_light_green
import com.tailscale.ipn.ui.util.LoadingIndicator
import com.tailscale.ipn.ui.util.PeerSet
import com.tailscale.ipn.ui.util.flag
import com.tailscale.ipn.ui.util.itemsWithDividers
import com.tailscale.ipn.ui.viewModel.MainViewModel
import kotlinx.coroutines.flow.StateFlow
// Navigation actions for the MainView
data class MainViewNavigation(
@ -122,16 +119,12 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
PromptPermissionsIfNecessary(permissions = Permissions.all)
val selfPeerId = viewModel.selfPeerId.collectAsState(initial = "")
Row(modifier = Modifier.padding(top = 10.dp, bottom = 20.dp)) {
ExitNodeStatus(
navAction = navigation.onNavigateToExitNodes, viewModel = viewModel)
}
PeerList(
searchTerm = viewModel.searchTerm,
state = viewModel.ipnState,
peers = viewModel.peers,
selfPeer = selfPeerId.value,
viewModel = viewModel,
onNavigateToPeerDetails = navigation.onNavigateToPeerDetails,
onSearch = { viewModel.searchPeers(it) })
}
@ -279,16 +272,14 @@ fun ConnectView(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PeerList(
searchTerm: StateFlow<String>,
peers: StateFlow<List<PeerSet>>,
state: StateFlow<Ipn.State>,
selfPeer: StableNodeID,
viewModel: MainViewModel,
onNavigateToPeerDetails: (Tailcfg.Node) -> Unit,
onSearch: (String) -> Unit
) {
val peerList = peers.collectAsState(initial = emptyList<PeerSet>())
val searchTermStr by searchTerm.collectAsState(initial = "")
val stateVal = state.collectAsState(initial = Ipn.State.NoState)
val peerList = viewModel.peers.collectAsState(initial = emptyList<PeerSet>())
val searchTermStr by viewModel.searchTerm.collectAsState(initial = "")
val stateVal = viewModel.ipnState.collectAsState(initial = Ipn.State.NoState)
val netmap = viewModel.netmap.collectAsState()
SearchBar(
query = searchTermStr,
@ -328,21 +319,12 @@ fun PeerList(
Row(verticalAlignment = Alignment.CenterVertically) {
// By definition, SelfPeer is online since we will not show the peer list
// unless you're connected.
val isSelfAndRunning =
(peer.StableID == selfPeer && stateVal.value == Ipn.State.Running)
val color: Color =
if ((peer.Online == true) || isSelfAndRunning) {
ts_color_light_green
} else {
Color.Gray
}
Box(modifier = Modifier.padding(top = 3.dp)) {
Box(
modifier =
Modifier.size(10.dp)
.background(
color = color, shape = RoundedCornerShape(percent = 50))) {}
}
Box(
modifier =
Modifier.size(10.dp)
.background(
color = peer.connectedColor(netmap.value),
shape = RoundedCornerShape(percent = 50))) {}
Spacer(modifier = Modifier.size(8.dp))
Text(text = peer.ComputedName, style = MaterialTheme.typography.titleMedium)
}

@ -19,6 +19,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
@ -50,32 +51,39 @@ fun PeerDetails(
.padding(horizontal = 16.dp)
.padding(top = 22.dp),
) {
Text(text = model.nodeName, style = MaterialTheme.typography.titleLarge)
Row(verticalAlignment = Alignment.CenterVertically) {
Box(
modifier =
Modifier.size(8.dp)
.background(
color = model.connectedColor, shape = RoundedCornerShape(percent = 50))) {}
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(id = model.connectedStrRes),
style = MaterialTheme.typography.bodyMedium)
}
Column(modifier = Modifier.fillMaxHeight()) {
Text(
text = stringResource(id = R.string.addresses_section),
style = MaterialTheme.typography.titleMedium)
model.netmap.collectAsState().value?.let { netmap ->
model.node.collectAsState().value?.let { node ->
Text(text = node.displayName, style = MaterialTheme.typography.titleLarge)
Row(verticalAlignment = Alignment.CenterVertically) {
Box(
modifier =
Modifier.size(8.dp)
.background(
color = node.connectedColor(netmap),
shape = RoundedCornerShape(percent = 50))) {}
Spacer(modifier = Modifier.size(8.dp))
Text(
text = stringResource(id = node.connectedStrRes(netmap)),
style = MaterialTheme.typography.bodyMedium)
}
Column(modifier = Modifier.fillMaxHeight()) {
Text(
text = stringResource(id = R.string.addresses_section),
style = MaterialTheme.typography.titleMedium)
Column(modifier = settingsRowModifier()) {
model.addresses.forEach { AddressRow(address = it.address, type = it.typeString) }
}
Column(modifier = settingsRowModifier()) {
node.displayAddresses.forEach {
AddressRow(address = it.address, type = it.typeString)
}
}
Spacer(modifier = Modifier.size(16.dp))
Spacer(modifier = Modifier.size(16.dp))
Column(modifier = settingsRowModifier()) {
model.info.forEach {
ValueRow(title = stringResource(id = it.titleRes), value = it.value.getString())
Column(modifier = settingsRowModifier()) {
node.info.forEach {
ValueRow(title = stringResource(id = it.titleRes), value = it.value.getString())
}
}
}
}
}

@ -20,7 +20,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.tailscale.ipn.ui.model.Ipn
import com.tailscale.ipn.ui.model.Tailcfg
import com.tailscale.ipn.ui.theme.ts_color_light_green
import com.tailscale.ipn.ui.theme.success
@Composable
fun PeerView(
@ -43,7 +43,7 @@ fun PeerView(
val isSelfAndRunning = (peer.StableID == selfPeer && stateVal == Ipn.State.Running)
val color: Color =
if ((peer.Online == true) || isSelfAndRunning) {
ts_color_light_green
MaterialTheme.colorScheme.success
} else {
Color.Gray
}

@ -5,6 +5,8 @@ package com.tailscale.ipn.ui.viewModel
import android.util.Log
import androidx.annotation.StringRes
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
@ -14,8 +16,7 @@ import com.tailscale.ipn.ui.localapi.Client
import com.tailscale.ipn.ui.model.Ipn
import com.tailscale.ipn.ui.model.Tailcfg
import com.tailscale.ipn.ui.notifier.Notifier
import com.tailscale.ipn.ui.theme.ts_color_light_desctrutive_text
import com.tailscale.ipn.ui.theme.ts_color_light_green
import com.tailscale.ipn.ui.theme.success
import com.tailscale.ipn.ui.util.FeatureStateRepresentation
import com.tailscale.ipn.ui.util.LoadingIndicator
import com.tailscale.ipn.ui.util.set
@ -96,7 +97,7 @@ enum class DNSEnablementState : FeatureStateRepresentation {
get() = R.string.tailscale_is_not_running_this_device_is_using_the_system_dns_resolver
override val tint: Color
get() = Color.Gray
@Composable get() = Color.Gray
override val symbolDrawable: Int
get() = R.drawable.xmark_circle
@ -109,7 +110,7 @@ enum class DNSEnablementState : FeatureStateRepresentation {
@StringRes get() = R.string.this_device_is_using_tailscale_to_resolve_dns_names
override val tint: Color
get() = ts_color_light_green
@Composable get() = MaterialTheme.colorScheme.success
override val symbolDrawable: Int
get() = R.drawable.check_circle
@ -122,7 +123,7 @@ enum class DNSEnablementState : FeatureStateRepresentation {
@StringRes get() = R.string.this_device_is_using_the_system_dns_resolver
override val tint: Color
get() = ts_color_light_desctrutive_text
@Composable get() = MaterialTheme.colorScheme.success
override val symbolDrawable: Int
get() = R.drawable.xmark_circle

@ -8,7 +8,6 @@ import com.tailscale.ipn.R
import com.tailscale.ipn.ui.localapi.Client
import com.tailscale.ipn.ui.model.Ipn
import com.tailscale.ipn.ui.model.Ipn.State
import com.tailscale.ipn.ui.model.StableNodeID
import com.tailscale.ipn.ui.notifier.Notifier
import com.tailscale.ipn.ui.util.LoadingIndicator
import com.tailscale.ipn.ui.util.PeerCategorizer
@ -38,9 +37,6 @@ class MainViewModel : IpnViewModel() {
// The active search term for filtering peers
val searchTerm: StateFlow<String> = MutableStateFlow("")
// The peerID of the local node
val selfPeerId: StateFlow<StableNodeID> = MutableStateFlow("")
private val peerCategorizer = PeerCategorizer(viewModelScope)
val userName: String
@ -59,7 +55,6 @@ class MainViewModel : IpnViewModel() {
viewModelScope.launch {
Notifier.netmap.collect { netmap ->
peers.set(peerCategorizer.groupedAndFilteredPeers(searchTerm.value))
selfPeerId.set(netmap?.SelfNode?.StableID ?: "")
}
}
}

@ -3,16 +3,18 @@
package com.tailscale.ipn.ui.viewModel
import androidx.compose.ui.graphics.Color
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.tailscale.ipn.R
import androidx.lifecycle.viewModelScope
import com.tailscale.ipn.ui.model.Netmap
import com.tailscale.ipn.ui.model.StableNodeID
import com.tailscale.ipn.ui.model.Tailcfg
import com.tailscale.ipn.ui.notifier.Notifier
import com.tailscale.ipn.ui.theme.ts_color_light_green
import com.tailscale.ipn.ui.util.ComposableStringFormatter
import com.tailscale.ipn.ui.util.DisplayAddress
import com.tailscale.ipn.ui.util.TimeUtil
import com.tailscale.ipn.ui.util.set
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import java.io.File
data class PeerSettingInfo(val titleRes: Int, val value: ComposableStringFormatter)
@ -25,29 +27,15 @@ class PeerDetailsViewModelFactory(private val nodeId: StableNodeID, private val
}
class PeerDetailsViewModel(val nodeId: StableNodeID, val filesDir: File) : IpnViewModel() {
var addresses: List<DisplayAddress> = emptyList()
var info: List<PeerSettingInfo> = emptyList()
val nodeName: String
val connectedStrRes: Int
val connectedColor: Color
val netmap: StateFlow<Netmap.NetworkMap?> = MutableStateFlow(null)
val node: StateFlow<Tailcfg.Node?> = MutableStateFlow(null)
init {
val peer = Notifier.netmap.value?.getPeer(nodeId)
peer?.Addresses?.let { addresses = it.map { addr -> DisplayAddress(addr) } }
peer?.Name?.let { addresses = listOf(DisplayAddress(it)) + addresses }
peer?.let { p ->
info =
listOf(
PeerSettingInfo(R.string.os, ComposableStringFormatter(p.Hostinfo.OS ?: "")),
PeerSettingInfo(R.string.key_expiry, TimeUtil().keyExpiryFromGoTime(p.KeyExpiry)))
viewModelScope.launch {
Notifier.netmap.collect { nm ->
netmap.set(nm)
nm?.getPeer(nodeId)?.let { peer -> node.set(peer) }
}
}
nodeName = peer?.ComputedName ?: ""
connectedStrRes = if (peer?.Online == true) R.string.connected else R.string.not_connected
connectedColor = if (peer?.Online == true) ts_color_light_green else Color.Gray
}
}

Loading…
Cancel
Save