list of chats and chat messages (#327)
This commit is contained in:
committed by
GitHub
parent
423f54e95d
commit
290a88fd90
@@ -13,9 +13,10 @@ import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import chat.simplex.app.views.DetailView
|
||||
import chat.simplex.app.views.TerminalView
|
||||
import chat.simplex.app.views.WelcomeView
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.views.*
|
||||
import chat.simplex.app.views.chat.ChatView
|
||||
import chat.simplex.app.views.chatlist.*
|
||||
|
||||
|
||||
class MainActivity: ComponentActivity() {
|
||||
@@ -25,7 +26,7 @@ class MainActivity: ComponentActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
SimpleXTheme {
|
||||
Navigation(viewModel=viewModel)
|
||||
Navigation(viewModel.chatModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,18 +37,28 @@ class SimplexViewModel(application: Application) : AndroidViewModel(application)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Navigation(viewModel: SimplexViewModel) {
|
||||
val navController = rememberNavController()
|
||||
fun Navigation(chatModel: ChatModel) {
|
||||
val nav = rememberNavController()
|
||||
|
||||
NavHost(navController=navController, startDestination=Pages.Home.route){
|
||||
NavHost(navController = nav, startDestination=Pages.Home.route){
|
||||
composable(route=Pages.Home.route){
|
||||
MainPage(vm = viewModel, navController = navController)
|
||||
MainPage(chatModel, nav)
|
||||
}
|
||||
composable(route = Pages.Welcome.route){
|
||||
WelcomeView(vm = viewModel) {navController.navigate(Pages.Home.route) { popUpTo(Pages.Home.route) { inclusive = true }}}
|
||||
WelcomeView(chatModel) {
|
||||
nav.navigate(Pages.Home.route) {
|
||||
popUpTo(Pages.Home.route) { inclusive = true }
|
||||
}
|
||||
}
|
||||
}
|
||||
composable(route = Pages.Chats.route) {
|
||||
ChatListView(chatModel, nav)
|
||||
}
|
||||
composable(route = Pages.Chat.route) {
|
||||
ChatView(chatModel, nav)
|
||||
}
|
||||
composable(route = Pages.Terminal.route) {
|
||||
TerminalView(chatModel = viewModel.chatModel, navController = navController)
|
||||
TerminalView(chatModel, navController = nav)
|
||||
}
|
||||
composable(
|
||||
Pages.TerminalItemDetails.route + "/{identifier}",
|
||||
@@ -56,7 +67,7 @@ fun Navigation(viewModel: SimplexViewModel) {
|
||||
type = NavType.LongType
|
||||
}
|
||||
)
|
||||
) { entry -> DetailView( entry.arguments!!.getLong("identifier"), viewModel.chatModel.terminalItems, navController) }
|
||||
) { entry -> DetailView( entry.arguments!!.getLong("identifier"), chatModel.terminalItems, nav) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,4 +76,6 @@ sealed class Pages(val route: String) {
|
||||
object Terminal : Pages("terminal")
|
||||
object Welcome : Pages("welcome")
|
||||
object TerminalItemDetails : Pages("details")
|
||||
object Chats: Pages("chats")
|
||||
object Chat: Pages("chat")
|
||||
}
|
||||
|
||||
@@ -2,13 +2,15 @@ package chat.simplex.app
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NavController
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.views.TerminalView
|
||||
import chat.simplex.app.views.WelcomeView
|
||||
import chat.simplex.app.views.chatlist.ChatListView
|
||||
|
||||
@Composable
|
||||
fun MainPage(vm: SimplexViewModel, navController: NavController) {
|
||||
if (vm.chatModel.currentUser.value == null) WelcomeView(vm=vm) {
|
||||
navController.navigate(Pages.Terminal.route)
|
||||
fun MainPage(chatModel: ChatModel, nav: NavController) {
|
||||
if (chatModel.currentUser.value == null) WelcomeView(chatModel) {
|
||||
nav.navigate(Pages.Chats.route)
|
||||
}
|
||||
else TerminalView(vm.chatModel, navController)
|
||||
else ChatListView(chatModel, nav)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ package chat.simplex.app
|
||||
import android.app.Application
|
||||
import android.net.LocalServerSocket
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||
import chat.simplex.app.model.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -35,19 +37,7 @@ class SimplexApp: Application() {
|
||||
GlobalScope.launch {
|
||||
withContext(Dispatchers.Main) {
|
||||
var user = controller.apiGetActiveUser()
|
||||
controller.setCurrentUser(user)
|
||||
if (user == null) {
|
||||
user = controller.apiCreateActiveUser(Profile("android", "Android test"))
|
||||
}
|
||||
Log.d("SIMPLEX (user)", user.toString())
|
||||
chatModel.currentUser = user
|
||||
try {
|
||||
controller.apiStartChat()
|
||||
Log.d("SIMPLEX", "started chat")
|
||||
} catch(e: Error) {
|
||||
Log.d("SIMPLEX", "failed starting chat $e")
|
||||
// throw e
|
||||
}
|
||||
if (user != null) controller.startChat(user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@ package chat.simplex.app.model
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.serialization.*
|
||||
import java.util.*
|
||||
|
||||
class ChatModel(val controller: ChatController) {
|
||||
var currentUser = mutableStateOf<User?>(null)
|
||||
var terminalItems = mutableStateListOf<TerminalItem>()
|
||||
var chats = mutableStateListOf<Chat>()
|
||||
var chatId = mutableStateOf<String?>(null)
|
||||
var chatItems = mutableStateListOf<ChatItem>()
|
||||
|
||||
fun setCurrentUser(u: User?){
|
||||
currentUser = mutableStateOf<User?>(u)
|
||||
}
|
||||
var terminalItems = mutableStateListOf<TerminalItem>()
|
||||
|
||||
companion object {
|
||||
val sampleData: ChatModel get() {
|
||||
@@ -36,7 +37,7 @@ class User (
|
||||
val localDisplayName: String,
|
||||
val profile: Profile,
|
||||
val activeUser: Boolean
|
||||
) : NamedChat {
|
||||
): NamedChat {
|
||||
override val displayName: String get() = profile.displayName
|
||||
override val fullName: String get() = profile.fullName
|
||||
|
||||
@@ -61,6 +62,7 @@ interface NamedChat {
|
||||
}
|
||||
|
||||
interface SomeChat {
|
||||
val chatType: ChatType
|
||||
val localDisplayName: String
|
||||
val id: ChatId
|
||||
val apiId: Long
|
||||
@@ -102,6 +104,7 @@ class Chat (
|
||||
sealed class ChatInfo: SomeChat, NamedChat {
|
||||
@Serializable @SerialName("direct")
|
||||
class Direct(val contact: Contact): ChatInfo() {
|
||||
override val chatType get() = ChatType.Direct
|
||||
override val localDisplayName get() = contact.localDisplayName
|
||||
override val id get() = contact.id
|
||||
override val apiId get() = contact.apiId
|
||||
@@ -116,6 +119,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
|
||||
@Serializable @SerialName("group")
|
||||
class Group(val groupInfo: GroupInfo): ChatInfo() {
|
||||
override val chatType get() = ChatType.Group
|
||||
override val localDisplayName get() = groupInfo.localDisplayName
|
||||
override val id get() = groupInfo.id
|
||||
override val apiId get() = groupInfo.apiId
|
||||
@@ -130,6 +134,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
|
||||
|
||||
@Serializable @SerialName("contactRequest")
|
||||
class ContactRequest(val contactRequest: UserContactRequest): ChatInfo() {
|
||||
override val chatType get() = ChatType.ContactRequest
|
||||
override val localDisplayName get() = contactRequest.localDisplayName
|
||||
override val id get() = contactRequest.id
|
||||
override val apiId get() = contactRequest.apiId
|
||||
@@ -153,6 +158,7 @@ class Contact(
|
||||
// no serializer for type Date?
|
||||
// val createdAt: Date
|
||||
): SomeChat, NamedChat {
|
||||
override val chatType get() = ChatType.Direct
|
||||
override val id get() = "@$contactId"
|
||||
override val apiId get() = contactId
|
||||
override val ready get() = activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready"
|
||||
@@ -197,6 +203,7 @@ class GroupInfo (
|
||||
val groupProfile: GroupProfile,
|
||||
// var createdAt: Date
|
||||
): SomeChat, NamedChat {
|
||||
override val chatType get() = ChatType.Group
|
||||
override val id get() = "#$groupId"
|
||||
override val apiId get() = groupId
|
||||
override val ready get() = true
|
||||
@@ -257,6 +264,7 @@ class UserContactRequest (
|
||||
val profile: Profile
|
||||
// val createdAt: Date
|
||||
): SomeChat, NamedChat {
|
||||
override val chatType get() = ChatType.ContactRequest
|
||||
override val id get() = "<@$contactRequestId"
|
||||
override val apiId get() = contactRequestId
|
||||
override val ready get() = true
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package chat.simplex.app.model
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import chat.simplex.app.chatRecvMsg
|
||||
import chat.simplex.app.chatSendCmd
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -21,8 +24,18 @@ open class ChatController(val ctrl: ChatCtrl) {
|
||||
fun setModel(m: ChatModel) {
|
||||
chatModel = m
|
||||
}
|
||||
suspend fun setCurrentUser(u: User?){
|
||||
chatModel!!.setCurrentUser(u)
|
||||
|
||||
suspend fun startChat(u: User) {
|
||||
chatModel!!.currentUser = mutableStateOf(u)
|
||||
Log.d("SIMPLEX (user)", u.toString())
|
||||
apiStartChat()
|
||||
try {
|
||||
Log.d("SIMPLEX", "started chat")
|
||||
chatModel!!.chats = apiGetChats().toMutableStateList()
|
||||
} catch(e: Error) {
|
||||
Log.d("SIMPLEX", "failed starting chat $e")
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
fun startReceiver() {
|
||||
@@ -75,12 +88,26 @@ open class ChatController(val ctrl: ChatCtrl) {
|
||||
throw Error("failed starting chat: ${r.toString()}")
|
||||
}
|
||||
|
||||
suspend fun apiGetChats() {
|
||||
suspend fun apiGetChats(): List<Chat> {
|
||||
val r = sendCmd(CC.ApiGetChats())
|
||||
if (r is CR.ApiChats ) return
|
||||
if (r is CR.ApiChats ) return r.chats
|
||||
throw Error("failed getting the list of chats: ${r.toString()}")
|
||||
}
|
||||
|
||||
suspend fun apiGetChat(type: ChatType, id: Long): Chat? {
|
||||
val r = sendCmd(CC.ApiGetChat(type, id))
|
||||
if (r is CR.ApiChat ) return r.chat
|
||||
Log.d("SIMPLEX", "apiGetChat bad response: ${r.toString()}")
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun apiSendMessage(type: ChatType, id: Long, mc: MsgContent): AChatItem? {
|
||||
val r = sendCmd(CC.ApiSendMessage(type, id, mc))
|
||||
if (r is CR.NewChatItem ) return r.chatItem
|
||||
Log.d("SIMPLEX", "apiSendMessage bad response: ${r.toString()}")
|
||||
return null
|
||||
}
|
||||
|
||||
class Mock: ChatController(0) {}
|
||||
}
|
||||
|
||||
@@ -125,7 +152,7 @@ abstract class CC {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun chatRef(type: ChatType, id: Long) = "${type}${id}"
|
||||
fun chatRef(chatType: ChatType, id: Long) = "${chatType.type}${id}"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ import kotlinx.coroutines.withContext
|
||||
@Composable
|
||||
fun TerminalView(chatModel: ChatModel, navController: NavController) {
|
||||
Column {
|
||||
Button(onClick = { navController.popBackStack() }) {
|
||||
Text("Back")
|
||||
}
|
||||
TerminalLog(chatModel.terminalItems, navController)
|
||||
SendMsgView(sendMessage = { cmd ->
|
||||
GlobalScope.launch {
|
||||
@@ -59,7 +62,7 @@ fun TerminalLog(terminalItems: List<TerminalItem>, navController: NavController)
|
||||
@Composable
|
||||
fun DetailView(identifier: Long, terminalItems: List<TerminalItem>, navController: NavController){
|
||||
Column(
|
||||
modifier=Modifier.verticalScroll(rememberScrollState())
|
||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Button(onClick = { navController.popBackStack() }) {
|
||||
Text("Back")
|
||||
|
||||
@@ -14,6 +14,7 @@ import androidx.compose.material.Button
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.Modifier
|
||||
import chat.simplex.app.SimplexViewModel
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import chat.simplex.app.model.Profile
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@@ -21,7 +22,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun WelcomeView(vm: SimplexViewModel, routeHome: () -> Unit) {
|
||||
fun WelcomeView(chatModel: ChatModel, routeHome: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
@@ -33,12 +34,12 @@ fun WelcomeView(vm: SimplexViewModel, routeHome: () -> Unit) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
Text("We don't store any of your contacts or messages (once delivered) on the servers.")
|
||||
Spacer(Modifier.height(24.dp))
|
||||
CreateProfilePanel(vm, routeHome)
|
||||
CreateProfilePanel(chatModel, routeHome)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CreateProfilePanel(vm: SimplexViewModel, routeHome: () -> Unit) {
|
||||
fun CreateProfilePanel(chatModel: ChatModel, routeHome: () -> Unit) {
|
||||
var displayName by remember { mutableStateOf("") }
|
||||
var fullName by remember { mutableStateOf("") }
|
||||
|
||||
@@ -52,10 +53,10 @@ fun CreateProfilePanel(vm: SimplexViewModel, routeHome: () -> Unit) {
|
||||
Button(onClick={
|
||||
GlobalScope.launch {
|
||||
withContext(Dispatchers.Main) {
|
||||
val user = vm.chatModel.controller.apiCreateActiveUser(
|
||||
val user = chatModel.controller.apiCreateActiveUser(
|
||||
Profile(displayName, fullName)
|
||||
)
|
||||
vm.chatModel.setCurrentUser(user)
|
||||
chatModel.controller.startChat(user)
|
||||
routeHome()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,66 @@
|
||||
package chat.simplex.app.views.chat
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.Chat
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.navigation.NavController
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.views.chat.item.ChatItemView
|
||||
import chat.simplex.app.views.chatlist.ChatPreviewView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun ChatView(chat: Chat) {
|
||||
Text("ChatView")
|
||||
fun ChatView(chatModel: ChatModel, nav: NavController) {
|
||||
if (chatModel.chatId.value != null && chatModel.chats.count() > 0) {
|
||||
val chat: Chat = chatModel.chats.first { chat -> chat.chatInfo.id == chatModel.chatId.value }
|
||||
Column {
|
||||
ChatInfoToolbar(chat, nav)
|
||||
ChatItemsList(chatModel.chatItems)
|
||||
SendMsgView(sendMessage = { msg ->
|
||||
GlobalScope.launch {
|
||||
withContext(Dispatchers.Main) {
|
||||
// show "in progress"
|
||||
val cInfo = chat.chatInfo
|
||||
val newItem = chatModel.controller.apiSendMessage(
|
||||
type = cInfo.chatType,
|
||||
id = cInfo.apiId,
|
||||
mc = MsgContent.MCText(msg)
|
||||
)
|
||||
// hide "in progress"
|
||||
// TODO add new item
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatInfoToolbar(chat: Chat, nav: NavController) {
|
||||
Row {
|
||||
Button(onClick = { nav.popBackStack() }) {
|
||||
Text("Back")
|
||||
}
|
||||
Column {
|
||||
Text(chat.chatInfo.displayName)
|
||||
Text(chat.chatInfo.fullName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatItemsList(chatItems: List<ChatItem>) {
|
||||
LazyColumn {
|
||||
items(chatItems) { cItem ->
|
||||
ChatItemView(cItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ import chat.simplex.app.model.ChatItem
|
||||
|
||||
@Composable
|
||||
fun ChatItemView(chatItem: ChatItem) {
|
||||
Text("ChatItemView")
|
||||
Text(chatItem.content.text)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,78 @@
|
||||
package chat.simplex.app.views.chatlist
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.ChatModel
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import chat.simplex.app.Pages
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.SimpleXTheme
|
||||
import chat.simplex.app.views.TerminalView
|
||||
import chat.simplex.app.views.chat.SendMsgView
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
fun ChatListView(chatModel: ChatModel) {
|
||||
Text("ChatListView")
|
||||
fun ChatListView(chatModel: ChatModel, navController: NavController) {
|
||||
Column(modifier = Modifier.padding(all = 8.dp)) {
|
||||
ChatListToolbar()
|
||||
Button (onClick = { navController.navigate(Pages.Terminal.route) }) {
|
||||
Text("Terminal")
|
||||
}
|
||||
ChatList(chatModel, navController)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatListToolbar() {
|
||||
Text("ChatListToolbar")
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ChatList(chatModel: ChatModel, navController: NavController) {
|
||||
LazyColumn {
|
||||
items(chatModel.chats) { chat ->
|
||||
Button(onClick = {
|
||||
GlobalScope.launch {
|
||||
withContext(Dispatchers.Main) {
|
||||
val cInfo = chat.chatInfo
|
||||
val chat = chatModel.controller.apiGetChat(cInfo.chatType, cInfo.apiId)
|
||||
if (chat != null ) {
|
||||
chatModel.chatId = mutableStateOf(cInfo.id)
|
||||
chatModel.chatItems = chat.chatItems.toMutableStateList()
|
||||
navController.navigate(Pages.Chat.route)
|
||||
} else {
|
||||
// TODO show error? or will apiGetChat show it
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
ChatPreviewView(chat)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//@Preview
|
||||
//@Composable
|
||||
//fun PreviewSendMsgView() {
|
||||
// SimpleXTheme {
|
||||
// ChatListView(
|
||||
// chats = listOf(
|
||||
// Chat()
|
||||
// ),
|
||||
//
|
||||
// )
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,10 +1,34 @@
|
||||
package chat.simplex.app.views.chatlist
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.Chat
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.app.model.*
|
||||
import chat.simplex.app.ui.theme.SimpleXTheme
|
||||
|
||||
@Composable
|
||||
fun ChatPreviewView(chat: Chat) {
|
||||
Text("ChatPreviewView")
|
||||
Column(modifier = Modifier.padding(all = 8.dp)) {
|
||||
Text(chat.chatInfo.chatViewName)
|
||||
if (chat.chatItems.count() > 0) {
|
||||
Text(chat.chatItems.last().content.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun ChatPreviewView() {
|
||||
SimpleXTheme {
|
||||
ChatPreviewView(
|
||||
chat = Chat(
|
||||
chatInfo = ChatInfo.Direct.sampleData,
|
||||
chatItems = listOf(),
|
||||
chatStats = Chat.ChatStats()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user