mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-04-16 02:46:10 +00:00
chats in android app (#324)
* view placeholders for chats list and chat views * classes for chats * set the user to the model * use Long for IDs * chats/messages API (not working yet) * android api works * line breaks
This commit is contained in:
committed by
GitHub
parent
9e46b5117d
commit
423f54e95d
2
apps/android/.gitignore
vendored
2
apps/android/.gitignore
vendored
@@ -7,6 +7,8 @@
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
/.idea/deploymentTargetDropDown.xml
|
||||
/.idea/misc.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
|
||||
21
apps/android/.idea/misc.xml
generated
21
apps/android/.idea/misc.xml
generated
@@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="../../../../../../../layout/compose-model-1644940819446.xml" value="0.4484797297297297" />
|
||||
<entry key="../../../../../../../layout/compose-model-1644941851914.xml" value="0.28378378378378377" />
|
||||
<entry key="../../../../../../../layout/compose-model-1644956742665.xml" value="1.0" />
|
||||
<entry key="../../../../../../../layout/compose-model-1644963789622.xml" value="0.8420454545454545" />
|
||||
<entry key="../../../../../../../layout/compose-model-1645006324692.xml" value="0.36363636363636365" />
|
||||
<entry key="../../../../../../../layout/compose-model-1645006342272.xml" value="0.36363636363636365" />
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
<option name="id" value="Android" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -37,9 +37,10 @@ class SimplexApp: Application() {
|
||||
var user = controller.apiGetActiveUser()
|
||||
controller.setCurrentUser(user)
|
||||
if (user == null) {
|
||||
// user = controller.apiCreateActiveUser(Profile("android", "Android test"))
|
||||
user = controller.apiCreateActiveUser(Profile("android", "Android test"))
|
||||
}
|
||||
Log.d("SIMPLEX (user)", user.toString())
|
||||
chatModel.currentUser = user
|
||||
try {
|
||||
controller.apiStartChat()
|
||||
Log.d("SIMPLEX", "started chat")
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
package chat.simplex.app.model
|
||||
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import kotlinx.serialization.Serializable
|
||||
import androidx.compose.runtime.*
|
||||
import kotlinx.serialization.*
|
||||
|
||||
class ChatModel(val controller: ChatController) {
|
||||
var currentUser = mutableStateOf<User?>(null)
|
||||
@@ -32,8 +31,8 @@ enum class ChatType(val type: String) {
|
||||
|
||||
@Serializable
|
||||
class User (
|
||||
val userId: Int,
|
||||
val userContactId: Int,
|
||||
val userId: Long,
|
||||
val userContactId: Long,
|
||||
val localDisplayName: String,
|
||||
val profile: Profile,
|
||||
val activeUser: Boolean
|
||||
@@ -54,21 +53,111 @@ class User (
|
||||
|
||||
typealias ChatId = String
|
||||
|
||||
interface NamedChat {
|
||||
val displayName: String
|
||||
val fullName: String
|
||||
val chatViewName: String
|
||||
get() = displayName + (if (fullName == "" || fullName == displayName) "" else " / $fullName")
|
||||
}
|
||||
|
||||
interface SomeChat {
|
||||
val localDisplayName: String
|
||||
val id: ChatId
|
||||
val apiId: Long
|
||||
val ready: Boolean
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class Chat (
|
||||
val chatInfo: ChatInfo,
|
||||
val chatItems: List<ChatItem>,
|
||||
val chatStats: ChatStats,
|
||||
val serverInfo: ServerInfo = ServerInfo(NetworkStatus.Unknown())
|
||||
) {
|
||||
|
||||
@Serializable
|
||||
class ChatStats {
|
||||
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ServerInfo(val networkStatus: NetworkStatus)
|
||||
|
||||
@Serializable
|
||||
sealed class NetworkStatus {
|
||||
abstract val statusString: String
|
||||
abstract val statusExplanation: String
|
||||
abstract val imageName: String
|
||||
|
||||
@Serializable
|
||||
class Unknown: NetworkStatus() {
|
||||
override val statusString get() = "Server connected"
|
||||
override val statusExplanation get() = "You are connected to the server you use to receve messages from this contact."
|
||||
override val imageName get() = "circle.dotted" // ?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class ChatInfo: SomeChat, NamedChat {
|
||||
@Serializable @SerialName("direct")
|
||||
class Direct(val contact: Contact): ChatInfo() {
|
||||
override val localDisplayName get() = contact.localDisplayName
|
||||
override val id get() = contact.id
|
||||
override val apiId get() = contact.apiId
|
||||
override val ready get() = contact.ready
|
||||
override val displayName get() = contact.displayName
|
||||
override val fullName get() = contact.displayName
|
||||
|
||||
companion object {
|
||||
val sampleData = Direct(Contact.sampleData)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable @SerialName("group")
|
||||
class Group(val groupInfo: GroupInfo): ChatInfo() {
|
||||
override val localDisplayName get() = groupInfo.localDisplayName
|
||||
override val id get() = groupInfo.id
|
||||
override val apiId get() = groupInfo.apiId
|
||||
override val ready get() = groupInfo.ready
|
||||
override val displayName get() = groupInfo.displayName
|
||||
override val fullName get() = groupInfo.displayName
|
||||
|
||||
companion object {
|
||||
val sampleData = Group(GroupInfo.sampleData)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable @SerialName("contactRequest")
|
||||
class ContactRequest(val contactRequest: UserContactRequest): ChatInfo() {
|
||||
override val localDisplayName get() = contactRequest.localDisplayName
|
||||
override val id get() = contactRequest.id
|
||||
override val apiId get() = contactRequest.apiId
|
||||
override val ready get() = contactRequest.ready
|
||||
override val displayName get() = contactRequest.displayName
|
||||
override val fullName get() = contactRequest.displayName
|
||||
|
||||
companion object {
|
||||
val sampleData = ContactRequest(UserContactRequest.sampleData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class Contact(
|
||||
val contactId: Int,
|
||||
val localDisplayName: String,
|
||||
val contactId: Long,
|
||||
override val localDisplayName: String,
|
||||
val profile: Profile,
|
||||
val activeConn: Connection,
|
||||
val viaGroup: Int? = null,
|
||||
val viaGroup: Long? = null,
|
||||
// no serializer for type Date?
|
||||
// val createdAt: Date
|
||||
): NamedChat {
|
||||
val id: ChatId get() = "@$contactId"
|
||||
val apiId: Int get() = contactId
|
||||
val ready: Boolean get() = activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready"
|
||||
override val displayName: String get() = profile.displayName
|
||||
override val fullName: String get() = profile.fullName
|
||||
): SomeChat, NamedChat {
|
||||
override val id get() = "@$contactId"
|
||||
override val apiId get() = contactId
|
||||
override val ready get() = activeConn.connStatus == "ready" || activeConn.connStatus == "snd-ready"
|
||||
override val displayName get() = profile.displayName
|
||||
override val fullName get() = profile.fullName
|
||||
|
||||
companion object {
|
||||
val sampleData = Contact(
|
||||
@@ -101,9 +190,228 @@ class Profile(
|
||||
}
|
||||
}
|
||||
|
||||
interface NamedChat {
|
||||
abstract val displayName: String
|
||||
abstract val fullName: String
|
||||
val chatViewName: String
|
||||
get() = displayName + (if (fullName == "" || fullName == displayName) "" else " / $fullName")
|
||||
@Serializable
|
||||
class GroupInfo (
|
||||
val groupId: Long,
|
||||
override val localDisplayName: String,
|
||||
val groupProfile: GroupProfile,
|
||||
// var createdAt: Date
|
||||
): SomeChat, NamedChat {
|
||||
override val id get() = "#$groupId"
|
||||
override val apiId get() = groupId
|
||||
override val ready get() = true
|
||||
override val displayName get() = groupProfile.displayName
|
||||
override val fullName get() = groupProfile.fullName
|
||||
|
||||
companion object {
|
||||
val sampleData = GroupInfo(
|
||||
groupId = 1,
|
||||
localDisplayName = "team",
|
||||
groupProfile = GroupProfile.sampleData,
|
||||
// createdAt: Date()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class GroupProfile (
|
||||
override val displayName: String,
|
||||
override val fullName: String
|
||||
): NamedChat {
|
||||
companion object {
|
||||
val sampleData = GroupProfile(
|
||||
displayName = "team",
|
||||
fullName = "My Team"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class GroupMember (
|
||||
val groupMemberId: Long,
|
||||
val memberId: String,
|
||||
// var memberRole: GroupMemberRole
|
||||
// var memberCategory: GroupMemberCategory
|
||||
// var memberStatus: GroupMemberStatus
|
||||
// var invitedBy: InvitedBy
|
||||
val localDisplayName: String,
|
||||
val memberProfile: Profile,
|
||||
val memberContactId: Long?
|
||||
// var activeConn: Connection?
|
||||
) {
|
||||
companion object {
|
||||
val sampleData = GroupMember(
|
||||
groupMemberId = 1,
|
||||
memberId = "abcd",
|
||||
localDisplayName = "alice",
|
||||
memberProfile = Profile.sampleData,
|
||||
memberContactId = 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class UserContactRequest (
|
||||
val contactRequestId: Long,
|
||||
override val localDisplayName: String,
|
||||
val profile: Profile
|
||||
// val createdAt: Date
|
||||
): SomeChat, NamedChat {
|
||||
override val id get() = "<@$contactRequestId"
|
||||
override val apiId get() = contactRequestId
|
||||
override val ready get() = true
|
||||
override val displayName get() = profile.displayName
|
||||
override val fullName get() = profile.fullName
|
||||
|
||||
companion object {
|
||||
val sampleData = UserContactRequest(
|
||||
contactRequestId = 1,
|
||||
localDisplayName = "alice",
|
||||
profile = Profile.sampleData,
|
||||
// createdAt: Date()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class AChatItem (
|
||||
val chatInfo: ChatInfo,
|
||||
val chatItem: ChatItem
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class ChatItem (
|
||||
val chatDir: CIDirection,
|
||||
val meta: CIMeta,
|
||||
val content: CIContent
|
||||
) {
|
||||
val id: Long get() = meta.itemId
|
||||
// val timestampText: String get() = meta.timestampText
|
||||
val isRcvNew: Boolean get() = meta.itemStatus is CIStatus.RcvNew
|
||||
|
||||
companion object {
|
||||
fun getSampleData(id: Long, dir: CIDirection, ts: Date, text: String,status: CIStatus = CIStatus.SndNew()) =
|
||||
ChatItem(
|
||||
chatDir = dir,
|
||||
meta = CIMeta.getSample(id, ts, text, status),
|
||||
content = CIContent.SndMsgContent(msgContent = MsgContent.MCText(text))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class CIDirection {
|
||||
abstract val sent: Boolean
|
||||
|
||||
@Serializable @SerialName("directSnd")
|
||||
class DirectSnd: CIDirection() {
|
||||
override val sent get() = true
|
||||
}
|
||||
|
||||
@Serializable @SerialName("directRcv")
|
||||
class DirectRcv: CIDirection() {
|
||||
override val sent get() = false
|
||||
}
|
||||
|
||||
@Serializable @SerialName("groupSnd")
|
||||
class GroupSnd: CIDirection() {
|
||||
override val sent get() = true
|
||||
}
|
||||
|
||||
@Serializable @SerialName("groupRcv")
|
||||
class GroupRcv(val groupMember: GroupMember): CIDirection() {
|
||||
override val sent get() = false
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class CIMeta (
|
||||
val itemId: Long,
|
||||
// val itemTs: Date,
|
||||
val itemText: String,
|
||||
val itemStatus: CIStatus,
|
||||
// val createdAt: Date
|
||||
) {
|
||||
// val timestampText: String get() = getTimestampText(itemTs)
|
||||
|
||||
companion object {
|
||||
fun getSample(id: Long, ts: Date, text: String, status: CIStatus = CIStatus.SndNew()): CIMeta =
|
||||
CIMeta(
|
||||
itemId = id,
|
||||
// itemTs = ts,
|
||||
itemText = text,
|
||||
itemStatus = status,
|
||||
// createdAt = ts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
fun getTimestampText(d: Date): String = ""
|
||||
|
||||
@Serializable
|
||||
sealed class CIStatus {
|
||||
@Serializable @SerialName("sndNew")
|
||||
class SndNew: CIStatus()
|
||||
|
||||
@Serializable @SerialName("sndSent")
|
||||
class SndSent: CIStatus()
|
||||
|
||||
@Serializable @SerialName("sndErrorAuth")
|
||||
class SndErrorAuth: CIStatus()
|
||||
|
||||
@Serializable @SerialName("sndError")
|
||||
class SndError(val agentError: AgentErrorType): CIStatus()
|
||||
|
||||
@Serializable @SerialName("rcvNew")
|
||||
class RcvNew: CIStatus()
|
||||
|
||||
@Serializable @SerialName("rcvRead")
|
||||
class RcvRead: CIStatus()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class CIContent {
|
||||
abstract val text: String
|
||||
|
||||
@Serializable @SerialName("sndMsgContent")
|
||||
class SndMsgContent(val msgContent: MsgContent): CIContent() {
|
||||
override val text get() = msgContent.text
|
||||
}
|
||||
|
||||
@Serializable @SerialName("rcvMsgContent")
|
||||
class RcvMsgContent(val msgContent: MsgContent): CIContent() {
|
||||
override val text get() = msgContent.text
|
||||
}
|
||||
|
||||
@Serializable @SerialName("sndFileInvitation")
|
||||
class SndFileInvitation(val fileId: Long, val filePath: String): CIContent() {
|
||||
override val text get() = "sending files is not supported yet"
|
||||
}
|
||||
|
||||
@Serializable @SerialName("rcvFileInvitation")
|
||||
class RcvFileInvitation(val rcvFileTransfer: RcvFileTransfer): CIContent() {
|
||||
override val text get() = "receiving files is not supported yet"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
sealed class MsgContent {
|
||||
abstract val text: String
|
||||
abstract val cmdString: String
|
||||
|
||||
@Serializable @SerialName("text")
|
||||
class MCText(override val text: String): MsgContent() {
|
||||
override val cmdString get() = "text $text"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class RcvFileTransfer {
|
||||
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class AgentErrorType {
|
||||
|
||||
}
|
||||
|
||||
@@ -46,9 +46,10 @@ open class ChatController(val ctrl: ChatCtrl) {
|
||||
val c = cmd.cmdString
|
||||
chatModel?.terminalItems?.add(TerminalItem.Cmd(System.currentTimeMillis(), cmd))
|
||||
val json = chatSendCmd(ctrl, c)
|
||||
Log.d("SIMPLEX", "sendCmd: $c")
|
||||
Log.d("SIMPLEX", "sendCmd response $json")
|
||||
Log.d("SIMPLEX", "sendCmd: ${cmd.cmdType}")
|
||||
Log.d("SIMPLEX", "sendCmd response json $json")
|
||||
val r = APIResponse.decodeStr(json)
|
||||
Log.d("SIMPLEX", "sendCmd response type ${r.resp.responseType}")
|
||||
chatModel?.terminalItems?.add(TerminalItem.Resp(System.currentTimeMillis(), r.resp))
|
||||
r.resp
|
||||
}
|
||||
@@ -74,6 +75,12 @@ open class ChatController(val ctrl: ChatCtrl) {
|
||||
throw Error("failed starting chat: ${r.toString()}")
|
||||
}
|
||||
|
||||
suspend fun apiGetChats() {
|
||||
val r = sendCmd(CC.ApiGetChats())
|
||||
if (r is CR.ApiChats ) return
|
||||
throw Error("failed getting the list of chats: ${r.toString()}")
|
||||
}
|
||||
|
||||
class Mock: ChatController(0) {}
|
||||
}
|
||||
|
||||
@@ -89,26 +96,36 @@ abstract class CC {
|
||||
|
||||
class ShowActiveUser: CC() {
|
||||
override val cmdString get() = "/u"
|
||||
override val cmdType get() = "ShowActiveUser"
|
||||
override val cmdType get() = "showActiveUser"
|
||||
}
|
||||
|
||||
class CreateActiveUser(val profile: Profile): CC() {
|
||||
override val cmdString get() = "/u ${profile.displayName} ${profile.fullName}"
|
||||
override val cmdType get() = "CreateActiveUser"
|
||||
override val cmdType get() = "createActiveUser"
|
||||
}
|
||||
|
||||
class StartChat: CC() {
|
||||
override val cmdString get() = "/_start"
|
||||
override val cmdType get() = "StartChat"
|
||||
override val cmdType get() = "startChat"
|
||||
}
|
||||
|
||||
class ApiGetChats: CC() {
|
||||
override val cmdString get() = "/_get chats"
|
||||
override val cmdType get() = "ApiGetChats"
|
||||
override val cmdType get() = "apiGetChats"
|
||||
}
|
||||
|
||||
class ApiGetChat(val type: ChatType, val id: Long): CC() {
|
||||
override val cmdString get() = "/_get chat ${CC.chatRef(type, id)} count=100"
|
||||
override val cmdType get() = "apiGetChat"
|
||||
}
|
||||
|
||||
class ApiSendMessage(val type: ChatType, val id: Long, val mc: MsgContent): CC() {
|
||||
override val cmdString get() = "/_send ${CC.chatRef(type, id)} ${mc.cmdString}"
|
||||
override val cmdType get() = "apiGetChat"
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun chatRef(type: ChatType, id: String) = "${type}${id}"
|
||||
fun chatRef(type: ChatType, id: Long) = "${type}${id}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,29 +161,49 @@ sealed class CR {
|
||||
abstract val responseType: String
|
||||
abstract val details: String
|
||||
|
||||
@Serializable
|
||||
@SerialName("activeUser")
|
||||
@Serializable @SerialName("activeUser")
|
||||
class ActiveUser(val user: User): CR() {
|
||||
override val responseType get() = "activeUser"
|
||||
override val details get() = user.toString()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("chatStarted")
|
||||
@Serializable @SerialName("chatStarted")
|
||||
class ChatStarted: CR() {
|
||||
override val responseType get() = "chatStarted"
|
||||
override val details get() = CR.noDetails(this)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("contactSubscribed")
|
||||
@Serializable @SerialName("apiChats")
|
||||
class ApiChats(val chats: List<Chat>): CR() {
|
||||
override val responseType get() = "apiChats"
|
||||
override val details get() = chats.toString()
|
||||
}
|
||||
|
||||
@Serializable @SerialName("apiChat")
|
||||
class ApiChat(val chat: Chat): CR() {
|
||||
override val responseType get() = "apiChats"
|
||||
override val details get() = chat.toString()
|
||||
}
|
||||
|
||||
@Serializable @SerialName("contactSubscribed")
|
||||
class ContactSubscribed(val contact: Contact): CR() {
|
||||
override val responseType get() = "contactSubscribed"
|
||||
override val details get() = contact.toString()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("cmdAccepted")
|
||||
@Serializable @SerialName("newChatItem")
|
||||
class NewChatItem(val chatItem: AChatItem): CR() {
|
||||
override val responseType get() = "newChatItem"
|
||||
override val details get() = chatItem.toString()
|
||||
}
|
||||
|
||||
@Serializable @SerialName("chatItemUpdated")
|
||||
class ChatItemUpdated(val chatItem: AChatItem): CR() {
|
||||
override val responseType get() = "chatItemUpdated"
|
||||
override val details get() = chatItem.toString()
|
||||
}
|
||||
|
||||
@Serializable @SerialName("cmdAccepted")
|
||||
class CmdAccepted(val corr: String): CR() {
|
||||
override val responseType get() = "cmdAccepted"
|
||||
override val details get() = "corrId: $corr"
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.ClickableText
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.Button
|
||||
@@ -60,9 +61,11 @@ fun DetailView(identifier: Long, terminalItems: List<TerminalItem>, navControlle
|
||||
Column(
|
||||
modifier=Modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
Text((terminalItems.filter {it.id == identifier}).first().details)
|
||||
Button(onClick = { navController.popBackStack() }) {
|
||||
Text("Back")
|
||||
}
|
||||
SelectionContainer {
|
||||
Text((terminalItems.filter { it.id == identifier }).first().details)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.app.views.chat
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.Chat
|
||||
|
||||
@Composable
|
||||
fun ChatView(chat: Chat) {
|
||||
Text("ChatView")
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.app.views.chat.item
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.ChatItem
|
||||
|
||||
@Composable
|
||||
fun ChatItemView(chatItem: ChatItem) {
|
||||
Text("ChatItemView")
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.app.views.chat.item
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.ChatItem
|
||||
|
||||
@Composable
|
||||
fun TextItemView(chatItem: ChatItem) {
|
||||
Text("TextItemView")
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.app.views.chatlist
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.ChatModel
|
||||
|
||||
@Composable
|
||||
fun ChatListView(chatModel: ChatModel) {
|
||||
Text("ChatListView")
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package chat.simplex.app.views.chatlist
|
||||
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import chat.simplex.app.model.Chat
|
||||
|
||||
@Composable
|
||||
fun ChatPreviewView(chat: Chat) {
|
||||
Text("ChatPreviewView")
|
||||
}
|
||||
Reference in New Issue
Block a user