kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Fix shared contact deeplink (#3302)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com> Co-authored-by: James Rich <2199651+jamesarich@users.noreply.github.com>pull/3305/head
rodzic
2accdd7f77
commit
5d95dca354
|
@ -66,6 +66,7 @@
|
||||||
<ID>FinalNewline:UsbRepositoryModule.kt$com.geeksville.mesh.repository.usb.UsbRepositoryModule.kt</ID>
|
<ID>FinalNewline:UsbRepositoryModule.kt$com.geeksville.mesh.repository.usb.UsbRepositoryModule.kt</ID>
|
||||||
<ID>ForbiddenComment:SafeBluetooth.kt$SafeBluetooth$// TODO: display some kind of UI about restarting BLE</ID>
|
<ID>ForbiddenComment:SafeBluetooth.kt$SafeBluetooth$// TODO: display some kind of UI about restarting BLE</ID>
|
||||||
<ID>LambdaParameterEventTrailing:Channel.kt$onConfirm</ID>
|
<ID>LambdaParameterEventTrailing:Channel.kt$onConfirm</ID>
|
||||||
|
<ID>LambdaParameterEventTrailing:ContactSharing.kt$onSharedContactRequested</ID>
|
||||||
<ID>LambdaParameterEventTrailing:Message.kt$onClick</ID>
|
<ID>LambdaParameterEventTrailing:Message.kt$onClick</ID>
|
||||||
<ID>LambdaParameterEventTrailing:Message.kt$onSendMessage</ID>
|
<ID>LambdaParameterEventTrailing:Message.kt$onSendMessage</ID>
|
||||||
<ID>LambdaParameterEventTrailing:MessageList.kt$onReply</ID>
|
<ID>LambdaParameterEventTrailing:MessageList.kt$onReply</ID>
|
||||||
|
@ -178,6 +179,7 @@
|
||||||
<ID>ModifierMissing:SecurityConfigItemList.kt$SecurityConfigScreen</ID>
|
<ID>ModifierMissing:SecurityConfigItemList.kt$SecurityConfigScreen</ID>
|
||||||
<ID>ModifierMissing:SettingsScreen.kt$SettingsScreen</ID>
|
<ID>ModifierMissing:SettingsScreen.kt$SettingsScreen</ID>
|
||||||
<ID>ModifierMissing:Share.kt$ShareScreen</ID>
|
<ID>ModifierMissing:Share.kt$ShareScreen</ID>
|
||||||
|
<ID>ModifierMissing:SharedContactDialog.kt$SharedContactDialog</ID>
|
||||||
<ID>ModifierMissing:SignalMetrics.kt$SignalMetricsScreen</ID>
|
<ID>ModifierMissing:SignalMetrics.kt$SignalMetricsScreen</ID>
|
||||||
<ID>ModifierMissing:TopLevelNavIcon.kt$TopLevelNavIcon</ID>
|
<ID>ModifierMissing:TopLevelNavIcon.kt$TopLevelNavIcon</ID>
|
||||||
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
|
<ID>ModifierNotUsedAtRoot:DeviceMetrics.kt$modifier = modifier.weight(weight = Y_AXIS_WEIGHT)</ID>
|
||||||
|
|
|
@ -42,7 +42,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.geeksville.mesh.model.UIViewModel
|
import com.geeksville.mesh.model.UIViewModel
|
||||||
import com.geeksville.mesh.ui.MainScreen
|
import com.geeksville.mesh.ui.MainScreen
|
||||||
import com.geeksville.mesh.ui.intro.AppIntroductionScreen
|
import com.geeksville.mesh.ui.intro.AppIntroductionScreen
|
||||||
import com.geeksville.mesh.ui.sharing.toSharedContact
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import org.meshtastic.core.datastore.UiPreferencesDataSource
|
import org.meshtastic.core.datastore.UiPreferencesDataSource
|
||||||
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
|
import org.meshtastic.core.navigation.DEEP_LINK_BASE_URI
|
||||||
|
@ -118,9 +117,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
Timber.d("App link data is a channel set")
|
Timber.d("App link data is a channel set")
|
||||||
model.requestChannelUrl(it)
|
model.requestChannelUrl(it)
|
||||||
} else if (it.path?.startsWith("/v/") == true || it.path?.startsWith("/V/") == true) {
|
} else if (it.path?.startsWith("/v/") == true || it.path?.startsWith("/V/") == true) {
|
||||||
val sharedContact = it.toSharedContact()
|
Timber.d("App link data is a shared contact")
|
||||||
Timber.d("App link data is a shared contact: ${sharedContact.user.longName}")
|
model.setSharedContactRequested(it)
|
||||||
model.setSharedContactRequested(sharedContact)
|
|
||||||
} else {
|
} else {
|
||||||
Timber.d("App link data is not a channel set")
|
Timber.d("App link data is not a channel set")
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import com.geeksville.mesh.copy
|
||||||
import com.geeksville.mesh.repository.radio.MeshActivity
|
import com.geeksville.mesh.repository.radio.MeshActivity
|
||||||
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
import com.geeksville.mesh.repository.radio.RadioInterfaceService
|
||||||
import com.geeksville.mesh.service.MeshServiceNotifications
|
import com.geeksville.mesh.service.MeshServiceNotifications
|
||||||
|
import com.geeksville.mesh.ui.sharing.toSharedContact
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
@ -297,8 +298,17 @@ constructor(
|
||||||
val sharedContactRequested: StateFlow<AdminProtos.SharedContact?>
|
val sharedContactRequested: StateFlow<AdminProtos.SharedContact?>
|
||||||
get() = _sharedContactRequested.asStateFlow()
|
get() = _sharedContactRequested.asStateFlow()
|
||||||
|
|
||||||
fun setSharedContactRequested(sharedContact: AdminProtos.SharedContact?) {
|
fun setSharedContactRequested(url: Uri) {
|
||||||
_sharedContactRequested.value = sharedContact
|
runCatching { _sharedContactRequested.value = url.toSharedContact() }
|
||||||
|
.onFailure { ex ->
|
||||||
|
Timber.e(ex, "Shared contact error")
|
||||||
|
showSnackBar(R.string.contact_invalid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called immediately after activity observes requestChannelUrl */
|
||||||
|
fun clearSharedContactRequested() {
|
||||||
|
_sharedContactRequested.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connection state to our radio device
|
// Connection state to our radio device
|
||||||
|
|
|
@ -91,6 +91,7 @@ import com.geeksville.mesh.ui.common.components.ScannedQrCodeDialog
|
||||||
import com.geeksville.mesh.ui.connections.DeviceType
|
import com.geeksville.mesh.ui.connections.DeviceType
|
||||||
import com.geeksville.mesh.ui.connections.components.TopLevelNavIcon
|
import com.geeksville.mesh.ui.connections.components.TopLevelNavIcon
|
||||||
import com.geeksville.mesh.ui.metrics.annotateTraceroute
|
import com.geeksville.mesh.ui.metrics.annotateTraceroute
|
||||||
|
import com.geeksville.mesh.ui.sharing.SharedContactDialog
|
||||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.isGranted
|
import com.google.accompanist.permissions.isGranted
|
||||||
import com.google.accompanist.permissions.rememberPermissionState
|
import com.google.accompanist.permissions.rememberPermissionState
|
||||||
|
@ -139,6 +140,7 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle()
|
val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle()
|
||||||
val requestChannelSet by uIViewModel.requestChannelSet.collectAsStateWithLifecycle()
|
val requestChannelSet by uIViewModel.requestChannelSet.collectAsStateWithLifecycle()
|
||||||
|
val sharedContactRequested by uIViewModel.sharedContactRequested.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
val notificationPermissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
|
val notificationPermissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
@ -150,6 +152,10 @@ fun MainScreen(uIViewModel: UIViewModel = hiltViewModel(), scanModel: BTScanMode
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionState == ConnectionState.CONNECTED) {
|
if (connectionState == ConnectionState.CONNECTED) {
|
||||||
|
sharedContactRequested?.let {
|
||||||
|
SharedContactDialog(sharedContact = it, onDismiss = { uIViewModel.clearSharedContactRequested() })
|
||||||
|
}
|
||||||
|
|
||||||
requestChannelSet?.let { newChannelSet ->
|
requestChannelSet?.let { newChannelSet ->
|
||||||
ScannedQrCodeDialog(newChannelSet, onDismiss = { uIViewModel.clearRequestChannelUrl() })
|
ScannedQrCodeDialog(newChannelSet, onDismiss = { uIViewModel.clearRequestChannelUrl() })
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,17 +109,15 @@ fun NodeListScreen(viewModel: NodeListViewModel = hiltViewModel(), navigateToNod
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
val firmwareVersion = DeviceVersion(ourNode?.metadata?.firmwareVersion ?: "0.0.0")
|
val firmwareVersion = DeviceVersion(ourNode?.metadata?.firmwareVersion ?: "0.0.0")
|
||||||
val shareCapable = firmwareVersion.supportsQrCodeSharing()
|
val shareCapable = firmwareVersion.supportsQrCodeSharing()
|
||||||
val scannedContact: AdminProtos.SharedContact? by
|
val sharedContact: AdminProtos.SharedContact? by
|
||||||
viewModel.sharedContactRequested.collectAsStateWithLifecycle(null)
|
viewModel.sharedContactRequested.collectAsStateWithLifecycle(null)
|
||||||
AddContactFAB(
|
AddContactFAB(
|
||||||
unfilteredNodes = unfilteredNodes,
|
sharedContact = sharedContact,
|
||||||
scannedContact = scannedContact,
|
|
||||||
modifier =
|
modifier =
|
||||||
Modifier.animateFloatingActionButton(
|
Modifier.animateFloatingActionButton(
|
||||||
visible = !isScrollInProgress && connectionState == ConnectionState.CONNECTED && shareCapable,
|
visible = !isScrollInProgress && connectionState == ConnectionState.CONNECTED && shareCapable,
|
||||||
alignment = Alignment.BottomEnd,
|
alignment = Alignment.BottomEnd,
|
||||||
),
|
),
|
||||||
onSharedContactImport = { contact -> viewModel.addSharedContact(contact) },
|
|
||||||
onSharedContactRequested = { contact -> viewModel.setSharedContactRequested(contact) },
|
onSharedContactRequested = { contact -> viewModel.setSharedContactRequested(contact) },
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
|
@ -30,9 +30,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.twotone.QrCodeScanner
|
import androidx.compose.material.icons.twotone.QrCodeScanner
|
||||||
import androidx.compose.material3.FloatingActionButton
|
import androidx.compose.material3.FloatingActionButton
|
||||||
import androidx.compose.material3.HorizontalDivider
|
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
@ -72,17 +70,14 @@ import java.net.MalformedURLException
|
||||||
* requests using Accompanist Permissions.
|
* requests using Accompanist Permissions.
|
||||||
*
|
*
|
||||||
* @param modifier Modifier for this composable.
|
* @param modifier Modifier for this composable.
|
||||||
* @param onSharedContactImport Callback invoked when a shared contact is successfully imported.
|
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalPermissionsApi::class)
|
@OptIn(ExperimentalPermissionsApi::class)
|
||||||
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
@Composable
|
@Composable
|
||||||
fun AddContactFAB(
|
fun AddContactFAB(
|
||||||
unfilteredNodes: List<Node>,
|
sharedContact: AdminProtos.SharedContact?,
|
||||||
scannedContact: AdminProtos.SharedContact?,
|
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onSharedContactImport: (AdminProtos.SharedContact) -> Unit = {},
|
onSharedContactRequested: (AdminProtos.SharedContact?) -> Unit,
|
||||||
onSharedContactRequested: (AdminProtos.SharedContact?) -> Unit = {},
|
|
||||||
) {
|
) {
|
||||||
val barcodeLauncher =
|
val barcodeLauncher =
|
||||||
rememberLauncherForActivityResult(ScanContract()) { result ->
|
rememberLauncherForActivityResult(ScanContract()) { result ->
|
||||||
|
@ -101,37 +96,7 @@ fun AddContactFAB(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
scannedContact?.let { contactToImport ->
|
sharedContact?.let { SharedContactDialog(sharedContact = it, onDismiss = { onSharedContactRequested(null) }) }
|
||||||
val nodeNum = contactToImport.nodeNum
|
|
||||||
val node = unfilteredNodes.find { it.num == nodeNum }
|
|
||||||
SimpleAlertDialog(
|
|
||||||
title = R.string.import_shared_contact,
|
|
||||||
text = {
|
|
||||||
Column {
|
|
||||||
if (node != null) {
|
|
||||||
Text(text = stringResource(R.string.import_known_shared_contact_text))
|
|
||||||
if (node.user.publicKey.size() > 0 && node.user.publicKey != contactToImport.user?.publicKey) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.public_key_changed),
|
|
||||||
color = MaterialTheme.colorScheme.error,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
HorizontalDivider()
|
|
||||||
Text(text = compareUsers(node.user, contactToImport.user))
|
|
||||||
} else {
|
|
||||||
Text(text = userFieldsToString(contactToImport.user))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dismissText = stringResource(R.string.cancel),
|
|
||||||
onDismiss = { onSharedContactRequested(null) },
|
|
||||||
confirmText = stringResource(R.string.import_label),
|
|
||||||
onConfirm = {
|
|
||||||
onSharedContactImport(contactToImport)
|
|
||||||
onSharedContactRequested(null)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun zxingScan() {
|
fun zxingScan() {
|
||||||
Timber.d("Starting zxing QR code scanner")
|
Timber.d("Starting zxing QR code scanner")
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* 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.ui.sharing
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.geeksville.mesh.AdminProtos
|
||||||
|
import org.meshtastic.core.strings.R
|
||||||
|
import org.meshtastic.core.ui.component.SimpleAlertDialog
|
||||||
|
|
||||||
|
/** A dialog for importing a shared contact that was scanned from a QR code. */
|
||||||
|
@Composable
|
||||||
|
fun SharedContactDialog(
|
||||||
|
sharedContact: AdminProtos.SharedContact,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
viewModel: SharedContactViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val unfilteredNodes by viewModel.unfilteredNodes.collectAsStateWithLifecycle()
|
||||||
|
|
||||||
|
val nodeNum = sharedContact.nodeNum
|
||||||
|
val node = unfilteredNodes.find { it.num == nodeNum }
|
||||||
|
|
||||||
|
SimpleAlertDialog(
|
||||||
|
title = R.string.import_shared_contact,
|
||||||
|
text = {
|
||||||
|
Column {
|
||||||
|
if (node != null) {
|
||||||
|
Text(text = stringResource(R.string.import_known_shared_contact_text))
|
||||||
|
if (node.user.publicKey.size() > 0 && node.user.publicKey != sharedContact.user?.publicKey) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.public_key_changed),
|
||||||
|
color = MaterialTheme.colorScheme.error,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
HorizontalDivider()
|
||||||
|
Text(text = compareUsers(node.user, sharedContact.user))
|
||||||
|
} else {
|
||||||
|
Text(text = userFieldsToString(sharedContact.user))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dismissText = stringResource(R.string.cancel),
|
||||||
|
onDismiss = onDismiss,
|
||||||
|
confirmText = stringResource(R.string.import_label),
|
||||||
|
onConfirm = {
|
||||||
|
viewModel.addSharedContact(sharedContact)
|
||||||
|
onDismiss()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.ui.sharing
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.geeksville.mesh.AdminProtos
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.meshtastic.core.data.repository.NodeRepository
|
||||||
|
import org.meshtastic.core.database.model.Node
|
||||||
|
import org.meshtastic.core.service.ServiceAction
|
||||||
|
import org.meshtastic.core.service.ServiceRepository
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class SharedContactViewModel
|
||||||
|
@Inject
|
||||||
|
constructor(
|
||||||
|
nodeRepository: NodeRepository,
|
||||||
|
private val serviceRepository: ServiceRepository,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
val unfilteredNodes: StateFlow<List<Node>> =
|
||||||
|
nodeRepository
|
||||||
|
.getNodes()
|
||||||
|
.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.WhileSubscribed(5_000),
|
||||||
|
initialValue = emptyList(),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun addSharedContact(sharedContact: AdminProtos.SharedContact) =
|
||||||
|
viewModelScope.launch { serviceRepository.onServiceAction(ServiceAction.ImportContact(sharedContact)) }
|
||||||
|
}
|
|
@ -214,6 +214,7 @@
|
||||||
<string name="meshtastic_service_notifications">Service notifications</string>
|
<string name="meshtastic_service_notifications">Service notifications</string>
|
||||||
<string name="about">About</string>
|
<string name="about">About</string>
|
||||||
<string name="channel_invalid">This Channel URL is invalid and can not be used</string>
|
<string name="channel_invalid">This Channel URL is invalid and can not be used</string>
|
||||||
|
<string name="contact_invalid">This contact is invalid and can not be added</string>
|
||||||
<string name="debug_panel">Debug Panel</string>
|
<string name="debug_panel">Debug Panel</string>
|
||||||
<string name="debug_decoded_payload">Decoded Payload:</string>
|
<string name="debug_decoded_payload">Decoded Payload:</string>
|
||||||
<string name="debug_logs_export">Export Logs</string>
|
<string name="debug_logs_export">Export Logs</string>
|
||||||
|
|
|
@ -14,6 +14,5 @@
|
||||||
<ID>ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored</ID>
|
<ID>ParameterNaming:NodeFilterTextField.kt$onToggleShowIgnored</ID>
|
||||||
<ID>PreviewPublic:NodeItem.kt$NodeInfoPreview</ID>
|
<ID>PreviewPublic:NodeItem.kt$NodeInfoPreview</ID>
|
||||||
<ID>PreviewPublic:NodeItem.kt$NodeInfoSimplePreview</ID>
|
<ID>PreviewPublic:NodeItem.kt$NodeInfoSimplePreview</ID>
|
||||||
<ID>TooManyFunctions:NodeListViewModel.kt$NodeListViewModel : ViewModel</ID>
|
|
||||||
</CurrentIssues>
|
</CurrentIssues>
|
||||||
</SmellBaseline>
|
</SmellBaseline>
|
||||||
|
|
|
@ -161,9 +161,6 @@ constructor(
|
||||||
uiPreferencesDataSource.setNodeSort(sort.ordinal)
|
uiPreferencesDataSource.setNodeSort(sort.ordinal)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addSharedContact(sharedContact: AdminProtos.SharedContact) =
|
|
||||||
viewModelScope.launch { serviceRepository.onServiceAction(ServiceAction.ImportContact(sharedContact)) }
|
|
||||||
|
|
||||||
fun setSharedContactRequested(sharedContact: AdminProtos.SharedContact?) {
|
fun setSharedContactRequested(sharedContact: AdminProtos.SharedContact?) {
|
||||||
_sharedContactRequested.value = sharedContact
|
_sharedContactRequested.value = sharedContact
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue