wip: put SimFragment between DeviceFragment and ConversationFragment
This commit is contained in:
@@ -121,6 +121,8 @@ dependencies {
|
|||||||
implementation(libs.ktor.client.auth)
|
implementation(libs.ktor.client.auth)
|
||||||
implementation(libs.ktor.client.core)
|
implementation(libs.ktor.client.core)
|
||||||
implementation(libs.ktor.client.cio)
|
implementation(libs.ktor.client.cio)
|
||||||
|
implementation(libs.ktor.client.content.negotiation)
|
||||||
|
implementation(libs.ktor.serialization.kotlinx.json)
|
||||||
|
|
||||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
|
|
||||||
|
|||||||
@@ -89,10 +89,10 @@ import androidx.compose.ui.unit.dp
|
|||||||
import xyz.magicalbits.smsremote.FunctionalityNotAvailablePopup
|
import xyz.magicalbits.smsremote.FunctionalityNotAvailablePopup
|
||||||
import xyz.magicalbits.smsremote.R
|
import xyz.magicalbits.smsremote.R
|
||||||
import xyz.magicalbits.smsremote.components.JetchatAppBar
|
import xyz.magicalbits.smsremote.components.JetchatAppBar
|
||||||
import xyz.magicalbits.smsremote.data.exampleUiState
|
|
||||||
import xyz.magicalbits.smsremote.theme.JetchatTheme
|
import xyz.magicalbits.smsremote.theme.JetchatTheme
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import xyz.magicalbits.smsremote.data.exampleUiStateNew
|
import xyz.magicalbits.smsremote.data.exampleUiStateNew
|
||||||
|
import xyz.magicalbits.smsremote.network.NetworkClient
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point for a conversation screen.
|
* Entry point for a conversation screen.
|
||||||
@@ -168,9 +168,8 @@ fun ConversationContent(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
ChannelNameBar(
|
ChannelNameBar(
|
||||||
channelName = uiState.phoneNumber,
|
channelName = uiState.remotePhoneNumber,
|
||||||
// TODO remove?
|
channelMembers = 2, // TODO remove?
|
||||||
channelMembers = 2,
|
|
||||||
onNavIconPressed = onNavIconPressed,
|
onNavIconPressed = onNavIconPressed,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
)
|
)
|
||||||
@@ -205,6 +204,11 @@ fun ConversationContent(
|
|||||||
uiState.addMessage(
|
uiState.addMessage(
|
||||||
Message(authorMe, content, timeNow),
|
Message(authorMe, content, timeNow),
|
||||||
)
|
)
|
||||||
|
scope.launch {
|
||||||
|
val networkClient = NetworkClient()
|
||||||
|
// FIXME
|
||||||
|
// networkClient.sendSmsMessage(content, uiState.localPhoneNumber, uiState.remotePhoneNumber)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
resetScroll = {
|
resetScroll = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
|
|||||||
+4
-4
@@ -9,13 +9,13 @@ import kotlinx.coroutines.launch
|
|||||||
import xyz.magicalbits.smsremote.network.NetworkClient
|
import xyz.magicalbits.smsremote.network.NetworkClient
|
||||||
|
|
||||||
class ConversationViewModel : ViewModel() {
|
class ConversationViewModel : ViewModel() {
|
||||||
private var phoneNumber: String = ""
|
private var remotePhoneNumber: String = ""
|
||||||
private val _conversationData = MutableLiveData<ConversationScreenState>()
|
private val _conversationData = MutableLiveData<ConversationScreenState>()
|
||||||
val conversationData: LiveData<ConversationScreenState> = _conversationData
|
val conversationData: LiveData<ConversationScreenState> = _conversationData
|
||||||
|
|
||||||
fun setConversationData(phoneNumber: String?) {
|
fun setConversationData(phoneNumber: String?) {
|
||||||
if (phoneNumber != null) {
|
if (phoneNumber != null) {
|
||||||
this.phoneNumber = phoneNumber
|
this.remotePhoneNumber = phoneNumber
|
||||||
|
|
||||||
var messageDtoList: List<NetworkClient.SmsMessageDto> = listOf()
|
var messageDtoList: List<NetworkClient.SmsMessageDto> = listOf()
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
@@ -24,7 +24,7 @@ class ConversationViewModel : ViewModel() {
|
|||||||
}.invokeOnCompletion {
|
}.invokeOnCompletion {
|
||||||
_conversationData.value =
|
_conversationData.value =
|
||||||
ConversationScreenState(
|
ConversationScreenState(
|
||||||
phoneNumber = this.phoneNumber,
|
remotePhoneNumber = this.remotePhoneNumber,
|
||||||
initialMessages = messageDtoList.map {
|
initialMessages = messageDtoList.map {
|
||||||
Message(
|
Message(
|
||||||
if (it.msg_type == "INCOMING") {
|
if (it.msg_type == "INCOMING") {
|
||||||
@@ -46,7 +46,7 @@ class ConversationViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class ConversationScreenState(
|
data class ConversationScreenState(
|
||||||
val phoneNumber: String,
|
val remotePhoneNumber: String,
|
||||||
val initialMessages: List<Message>,
|
val initialMessages: List<Message>,
|
||||||
) {
|
) {
|
||||||
private val _messages: MutableList<Message> = initialMessages.toMutableStateList()
|
private val _messages: MutableList<Message> = initialMessages.toMutableStateList()
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ val unreadMessages = initialMessages.filter { it.author != "me" }
|
|||||||
|
|
||||||
val exampleUiStateNew =
|
val exampleUiStateNew =
|
||||||
ConversationScreenState(
|
ConversationScreenState(
|
||||||
phoneNumber = "",
|
remotePhoneNumber = "",
|
||||||
initialMessages = mutableListOf()
|
initialMessages = mutableListOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class DeviceFragment : Fragment() {
|
|||||||
onPhoneNumberClicked = {
|
onPhoneNumberClicked = {
|
||||||
val args = Bundle(1)
|
val args = Bundle(1)
|
||||||
args.putString("phoneNumber", it)
|
args.putString("phoneNumber", it)
|
||||||
navController.navigate(R.id.action_device_to_conversation, args)
|
navController.navigate(R.id.action_device_to_sim, args)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,14 @@ import io.ktor.client.engine.cio.CIO
|
|||||||
import io.ktor.client.plugins.auth.Auth
|
import io.ktor.client.plugins.auth.Auth
|
||||||
import io.ktor.client.plugins.auth.providers.BearerTokens
|
import io.ktor.client.plugins.auth.providers.BearerTokens
|
||||||
import io.ktor.client.plugins.auth.providers.bearer
|
import io.ktor.client.plugins.auth.providers.bearer
|
||||||
|
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.post
|
||||||
|
import io.ktor.client.request.setBody
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import io.ktor.http.ContentType
|
||||||
|
import io.ktor.http.contentType
|
||||||
|
import io.ktor.serialization.kotlinx.json.json
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -20,6 +26,9 @@ class NetworkClient {
|
|||||||
// TODO ask user for creds, call login endpoint, store tokens in local encrypted storage
|
// TODO ask user for creds, call login endpoint, store tokens in local encrypted storage
|
||||||
|
|
||||||
private val networkClient = HttpClient(CIO) {
|
private val networkClient = HttpClient(CIO) {
|
||||||
|
install(ContentNegotiation) {
|
||||||
|
json()
|
||||||
|
}
|
||||||
install(Auth) {
|
install(Auth) {
|
||||||
bearer {
|
bearer {
|
||||||
// TODO configure refresh token so it refreshes the access token
|
// TODO configure refresh token so it refreshes the access token
|
||||||
@@ -43,6 +52,12 @@ class NetworkClient {
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class SmsMessageDto(val content: String, val ts_received: Int, val ts_sent: Int, val msg_type: String, val local_phone_number: String, val remote_phone_number: String)
|
data class SmsMessageDto(val content: String, val ts_received: Int, val ts_sent: Int, val msg_type: String, val local_phone_number: String, val remote_phone_number: String)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class OutgoingMessage(val content: String, val local_phone_number: String, val remote_phone_number: String)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ConversationPreviewDto(val remote_phone_number: String, val last_message_content: String, val message_timestamp: Int)
|
||||||
|
|
||||||
// GET /api/v1/devices
|
// GET /api/v1/devices
|
||||||
suspend fun getDevices(): List<DeviceDto> {
|
suspend fun getDevices(): List<DeviceDto> {
|
||||||
// TODO handle non-200 status codes
|
// TODO handle non-200 status codes
|
||||||
@@ -70,4 +85,24 @@ class NetworkClient {
|
|||||||
val data = networkClient.get("$apiBaseUrl/api/v1/sms-messages?local_phone_number=$encodedPhoneNumber").bodyAsText()
|
val data = networkClient.get("$apiBaseUrl/api/v1/sms-messages?local_phone_number=$encodedPhoneNumber").bodyAsText()
|
||||||
return Json.decodeFromString(data)
|
return Json.decodeFromString(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST /api/v1/send-message
|
||||||
|
suspend fun sendSmsMessage(content: String, localPhoneNumber: String, remotePhoneNumber: String) {
|
||||||
|
println("sending SMS message: content=$content, lPN=$localPhoneNumber, rPN=$remotePhoneNumber")
|
||||||
|
val response = networkClient.post("$apiBaseUrl/api/v1/send-message") {
|
||||||
|
contentType(ContentType.Application.Json)
|
||||||
|
setBody(OutgoingMessage(content, localPhoneNumber, remotePhoneNumber))
|
||||||
|
}
|
||||||
|
println("sending SMS message: status code ${response.status}")
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/v1/conversation-previews
|
||||||
|
suspend fun getConversationPreviews(simPhoneNumber: String): List<ConversationPreviewDto> {
|
||||||
|
// TODO extract encoder to a function here or to a utility class
|
||||||
|
val encodedPhoneNumber = withContext(Dispatchers.IO) {
|
||||||
|
URLEncoder.encode(simPhoneNumber, "UTF-8")
|
||||||
|
}
|
||||||
|
val response = networkClient.get("$apiBaseUrl/api/v1/conversation-previews?local_phone_number=$encodedPhoneNumber")
|
||||||
|
return Json.decodeFromString(response.bodyAsText())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package xyz.magicalbits.smsremote.sim
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import xyz.magicalbits.smsremote.R
|
||||||
|
import xyz.magicalbits.smsremote.components.baselineHeight
|
||||||
|
import xyz.magicalbits.smsremote.theme.JetchatTheme
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimScreen(
|
||||||
|
simData: SimScreenState,
|
||||||
|
nestedScrollInteropConnection: NestedScrollConnection = rememberNestedScrollInteropConnection(),
|
||||||
|
onConversationClicked: (String) -> Unit = { },
|
||||||
|
) {
|
||||||
|
val scrollState = rememberScrollState()
|
||||||
|
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize().nestedScroll(nestedScrollInteropConnection)
|
||||||
|
) {
|
||||||
|
Surface {
|
||||||
|
Column(modifier = Modifier.fillMaxSize().verticalScroll(scrollState).padding(horizontal = 16.dp)) {
|
||||||
|
Name(simData, Modifier.baselineHeight(32.dp))
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
simData.conversations.forEach {
|
||||||
|
ConversationPreview(it, onConversationClicked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun Name(
|
||||||
|
simData: SimScreenState,
|
||||||
|
modifier: Modifier
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = simData.phoneNumber,
|
||||||
|
modifier = modifier,
|
||||||
|
style = MaterialTheme.typography.headlineSmall
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ConversationPreview(
|
||||||
|
conversation: ConversationRowState,
|
||||||
|
onConversationClicked: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier
|
||||||
|
.clickable(
|
||||||
|
onClick = {
|
||||||
|
onConversationClicked(conversation.phoneNumber)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
HorizontalDivider()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.wrapContentHeight()
|
||||||
|
.padding(start = 16.dp, end = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = conversation.phoneNumber)
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
Text(text = conversation.messageTimestamp.toString())
|
||||||
|
}
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 16.dp, end = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(text = conversation.lastMessage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview
|
||||||
|
@Composable
|
||||||
|
fun SimScreenPreview() {
|
||||||
|
JetchatTheme {
|
||||||
|
SimScreen(
|
||||||
|
simData = SimScreenState(
|
||||||
|
phoneNumber = "+420123456789",
|
||||||
|
conversations = listOf(
|
||||||
|
ConversationRowState("+15558880000", "last msg", 12345),
|
||||||
|
ConversationRowState("+15558880000", "last msg", 12345),
|
||||||
|
ConversationRowState("+15558880000", "last msg", 12345),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SimError() {
|
||||||
|
Text(stringResource(R.string.sim_error))
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package xyz.magicalbits.smsremote.sim
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
import androidx.compose.ui.platform.rememberNestedScrollInteropConnection
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.findNavController
|
||||||
|
import xyz.magicalbits.smsremote.MainViewModel
|
||||||
|
import xyz.magicalbits.smsremote.R
|
||||||
|
import xyz.magicalbits.smsremote.components.JetchatAppBar
|
||||||
|
import xyz.magicalbits.smsremote.theme.JetchatTheme
|
||||||
|
|
||||||
|
class SimFragment : Fragment() {
|
||||||
|
private val viewModel: SimViewModel by viewModels()
|
||||||
|
private val activityViewModel: MainViewModel by activityViewModels()
|
||||||
|
|
||||||
|
override fun onAttach(context: Context) {
|
||||||
|
super.onAttach(context)
|
||||||
|
// Consider using safe args plugin
|
||||||
|
val phoneNumber = arguments?.getString("phoneNumber")
|
||||||
|
viewModel.setSimData(phoneNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View {
|
||||||
|
val rootView: View = inflater.inflate(R.layout.fragment_profile, container, false)
|
||||||
|
|
||||||
|
rootView.findViewById<ComposeView>(R.id.toolbar_compose_view).apply {
|
||||||
|
setContent {
|
||||||
|
JetchatTheme {
|
||||||
|
JetchatAppBar(
|
||||||
|
// Reset the minimum bounds that are passed to the root of a compose tree
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
onNavIconPressed = { activityViewModel.openDrawer() },
|
||||||
|
title = { },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootView.findViewById<ComposeView>(R.id.profile_compose_view).apply {
|
||||||
|
setContent {
|
||||||
|
val simData by viewModel.simData.observeAsState()
|
||||||
|
val nestedScrollInteropConnection = rememberNestedScrollInteropConnection()
|
||||||
|
|
||||||
|
JetchatTheme {
|
||||||
|
// TODO flip if condition after integrating API call
|
||||||
|
if (simData != null) {
|
||||||
|
SimError()
|
||||||
|
println("calling sim error")
|
||||||
|
} else {
|
||||||
|
val navController: NavController = rootView.findNavController()
|
||||||
|
SimScreen(
|
||||||
|
// simData = simData!!,
|
||||||
|
// TODO remove fake data after integrating API call
|
||||||
|
simData = SimScreenState(
|
||||||
|
phoneNumber = "+420123456789",
|
||||||
|
conversations = listOf(
|
||||||
|
ConversationRowState("+15558880000", "last msg", 12345),
|
||||||
|
ConversationRowState("+15558880111", "last msg", 12345),
|
||||||
|
ConversationRowState("+15558880333", "last msg", 12345),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
nestedScrollInteropConnection = nestedScrollInteropConnection,
|
||||||
|
onConversationClicked = {
|
||||||
|
val args = Bundle(1)
|
||||||
|
args.putString("phoneNumber", it)
|
||||||
|
navController.navigate(R.id.action_sim_to_conversation, args)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootView
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package xyz.magicalbits.smsremote.sim
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Immutable
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import xyz.magicalbits.smsremote.network.NetworkClient
|
||||||
|
|
||||||
|
class SimViewModel : ViewModel() {
|
||||||
|
private var simPhoneNumber: String = ""
|
||||||
|
private val _simConversations = MutableLiveData<SimScreenState>()
|
||||||
|
val simData: LiveData<SimScreenState> = _simConversations
|
||||||
|
|
||||||
|
fun setSimData(phoneNumber: String?) {
|
||||||
|
if (phoneNumber != null) {
|
||||||
|
simPhoneNumber = phoneNumber
|
||||||
|
|
||||||
|
var conversationDtoList: List<NetworkClient.ConversationPreviewDto> = listOf()
|
||||||
|
// TODO uncomment after adding the corresponding API endpoint
|
||||||
|
// viewModelScope.launch {
|
||||||
|
// val networkClient = NetworkClient()
|
||||||
|
// conversationDtoList = networkClient.getConversationPreviews(simPhoneNumber)
|
||||||
|
// println("conv previews: $conversationDtoList")
|
||||||
|
// }.invokeOnCompletion {
|
||||||
|
// _simConversations.value =
|
||||||
|
// SimScreenState(
|
||||||
|
// phoneNumber = simPhoneNumber,
|
||||||
|
// conversations = conversationDtoList.map { convertFromDto(it) }.toList()
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertFromDto(conversation: NetworkClient.ConversationPreviewDto): ConversationRowState {
|
||||||
|
return ConversationRowState(
|
||||||
|
phoneNumber = conversation.remote_phone_number,
|
||||||
|
lastMessage = conversation.last_message_content,
|
||||||
|
messageTimestamp = conversation.message_timestamp,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class SimScreenState(
|
||||||
|
val phoneNumber: String,
|
||||||
|
val conversations: List<ConversationRowState>,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class ConversationRowState(
|
||||||
|
val phoneNumber: String,
|
||||||
|
val lastMessage: String,
|
||||||
|
val messageTimestamp: Int,
|
||||||
|
)
|
||||||
@@ -50,7 +50,20 @@
|
|||||||
android:name="type"
|
android:name="type"
|
||||||
app:argType="string" />
|
app:argType="string" />
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_device_to_conversation"
|
android:id="@+id/action_device_to_sim"
|
||||||
|
app:destination="@id/nav_sim"
|
||||||
|
/>
|
||||||
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/nav_sim"
|
||||||
|
android:name="xyz.magicalbits.smsremote.sim.SimFragment"
|
||||||
|
android:label="Sim">
|
||||||
|
<argument
|
||||||
|
android:name="phoneNumber"
|
||||||
|
app:argType="string" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_sim_to_conversation"
|
||||||
app:destination="@id/nav_conversation"
|
app:destination="@id/nav_conversation"
|
||||||
/>
|
/>
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|||||||
@@ -53,6 +53,9 @@
|
|||||||
<!-- Device -->
|
<!-- Device -->
|
||||||
<string name="device_error">There was an error loading the device</string>
|
<string name="device_error">There was an error loading the device</string>
|
||||||
|
|
||||||
|
<!-- Sim -->
|
||||||
|
<string name="sim_error">There was an error loading the SIM</string>
|
||||||
|
|
||||||
<!-- Accessibility descriptions -->
|
<!-- Accessibility descriptions -->
|
||||||
|
|
||||||
<string name="emoji_selector_desc">Emoji selector</string>
|
<string name="emoji_selector_desc">Emoji selector</string>
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa
|
|||||||
ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor-client"}
|
ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktor-client"}
|
||||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-client"}
|
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor-client"}
|
||||||
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor-client"}
|
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor-client"}
|
||||||
|
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor-client"}
|
||||||
|
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor-client"}
|
||||||
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
|
okhttp-logging = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" }
|
||||||
okhttp3 = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
okhttp3 = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
|
||||||
play-services-wearable = { module = "com.google.android.gms:play-services-wearable", version.ref = "play-services-wearable" }
|
play-services-wearable = { module = "com.google.android.gms:play-services-wearable", version.ref = "play-services-wearable" }
|
||||||
|
|||||||
Reference in New Issue
Block a user