diff --git a/apps/android/.idea/codeStyles/codeStyleConfig.xml b/apps/android/.idea/codeStyles/codeStyleConfig.xml
index 79ee123c2..6e6eec114 100644
--- a/apps/android/.idea/codeStyles/codeStyleConfig.xml
+++ b/apps/android/.idea/codeStyles/codeStyleConfig.xml
@@ -1,5 +1,6 @@
+
\ No newline at end of file
diff --git a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt
index 7a6ca488a..f5dcef32e 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt
@@ -22,8 +22,7 @@ import chat.simplex.app.views.chat.ChatView
import chat.simplex.app.views.chatlist.ChatListView
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.newchat.*
-import chat.simplex.app.views.usersettings.HelpView
-import chat.simplex.app.views.usersettings.UserProfileView
+import chat.simplex.app.views.usersettings.*
import com.google.accompanist.insets.ExperimentalAnimatedInsets
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import kotlinx.coroutines.DelicateCoroutinesApi
@@ -54,6 +53,7 @@ class SimplexViewModel(application: Application): AndroidViewModel(application)
val chatModel = getApplication().chatModel
}
+@ExperimentalTextApi
@DelicateCoroutinesApi
@ExperimentalPermissionsApi
@ExperimentalMaterialApi
@@ -116,6 +116,9 @@ fun Navigation(chatModel: ChatModel) {
composable(route = Pages.UserProfile.route) {
UserProfileView(chatModel, nav)
}
+ composable(route = Pages.UserAddress.route) {
+ UserAddressView(chatModel, nav)
+ }
composable(route = Pages.Help.route) {
HelpView(chatModel, nav)
}
@@ -136,6 +139,7 @@ sealed class Pages(val route: String) {
object Connect: Pages("connect")
object ChatInfo: Pages("chat_info")
object UserProfile: Pages("user_profile")
+ object UserAddress: Pages("user_address")
object Help: Pages("help")
}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt
index 2602960e8..cb8fa644f 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt
@@ -58,8 +58,40 @@ class SimplexApp: Application() {
alertView.value = null
}
- fun showAlertMsg(title: String, text: String? = null,
- confirmText: String = "Ok", onConfirm: (() -> Unit)? = null) {
+ fun showAlertDialog(
+ title: String,
+ text: String? = null,
+ confirmText: String = "Ok",
+ onConfirm: (() -> Unit)? = null,
+ dismissText: String = "Cancel",
+ onDismiss: (() -> Unit)? = null
+ ) {
+ val alertText: (@Composable () -> Unit)? = if (text == null) null else { -> Text(text) }
+ showAlert {
+ AlertDialog(
+ onDismissRequest = this::hideAlert,
+ title = { Text(title) },
+ text = alertText,
+ confirmButton = {
+ Button(onClick = {
+ onConfirm?.invoke()
+ hideAlert()
+ }) { Text(confirmText) }
+ },
+ dismissButton = {
+ Button(onClick = {
+ onDismiss?.invoke()
+ hideAlert()
+ }) { Text(dismissText) }
+ }
+ )
+ }
+ }
+
+ fun showAlertMsg(
+ title: String, text: String? = null,
+ confirmText: String = "Ok", onConfirm: (() -> Unit)? = null
+ ) {
val alertText: (@Composable () -> Unit)? = if (text == null) null else { -> Text(text) }
showAlert {
AlertDialog(
diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
index 7330da333..de38fc063 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/model/ChatModel.kt
@@ -23,6 +23,7 @@ class ChatModel(val controller: ChatController, val alertManager: SimplexApp.Ale
var connReqInvitation: String? = null
var terminalItems = mutableStateListOf()
+ var userAddress = mutableStateOf(null)
// set when app is opened via contact or invitation URI
var appOpenUrl = mutableStateOf(null)
@@ -60,14 +61,15 @@ class ChatModel(val controller: ChatController, val alertManager: SimplexApp.Ale
}
}
-// func replaceChat(_ id: String, _ chat: Chat) {
-// if let i = getChatIndex(id) {
-// chats[i] = chat
-// } else {
-// // invalid state, correcting
-// chats.insert(chat, at: 0)
-// }
-// }
+ fun replaceChat(id: String, chat: Chat) {
+ val i = getChatIndex(id)
+ if (i >= 0) {
+ chats[i] = chat
+ } else {
+ // invalid state, correcting
+ chats.add(index = 0, chat)
+ }
+ }
fun addChatItem(cInfo: ChatInfo, cItem: ChatItem) {
// update previews
diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
index a1c790134..2548f20e4 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt
@@ -23,6 +23,7 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
Log.d("SIMPLEX (user)", u.toString())
try {
apiStartChat()
+ chatModel.userAddress.value = apiGetUserAddress()
chatModel.chats.addAll(apiGetChats())
chatModel.chatsLoaded.value = true
startReceiver()
@@ -221,7 +222,12 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
chatModel.updateNetworkStatus(r.contact, Chat.NetworkStatus.Connected())
// NtfManager.shared.notifyContactConnected(contact)
}
-// is CR.ReceivedContactRequest -> return
+ is CR.ReceivedContactRequest -> {
+ val contactRequest = r.contactRequest
+ val cInfo = ChatInfo.ContactRequest(contactRequest)
+ chatModel.addChat(Chat(chatInfo = cInfo, chatItems = listOf()))
+// NtfManager.shared.notifyContactRequest(contactRequest)
+ }
is CR.ContactUpdated -> {
val cInfo = ChatInfo.Direct(r.toContact)
if (chatModel.hasChat(r.toContact.id)) {
@@ -257,15 +263,6 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
chatModel.addChatItem(cInfo, cItem)
// NtfManager.shared.notifyMessageReceived(cInfo, cItem)
}
-
-// switch res {
-// case let .receivedContactRequest(contactRequest):
- // chatModel.addChat(Chat(
- // chatInfo: ChatInfo.contactRequest(contactRequest: contactRequest),
- // chatItems: []
- // ))
-// NtfManager.shared.notifyContactRequest(contactRequest)
-//
// case let .chatItemUpdated(aChatItem):
// let cInfo = aChatItem.chatInfo
// let cItem = aChatItem.chatItem
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt
new file mode 100644
index 000000000..d13f2863a
--- /dev/null
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListNavLinkView.kt
@@ -0,0 +1,193 @@
+package chat.simplex.app.views.chatlist
+
+import android.content.res.Configuration
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.Divider
+import androidx.compose.material.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.toMutableStateList
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.ExperimentalTextApi
+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.helpers.withApi
+import kotlinx.coroutines.DelicateCoroutinesApi
+import kotlinx.datetime.Clock
+
+@ExperimentalTextApi
+@Composable
+fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel, nav: NavController) {
+ ChatListNavLink(
+ chat = chat,
+ action = {
+ when (chat.chatInfo) {
+ is ChatInfo.Direct -> chatNavLink(chat, chatModel, nav)
+ is ChatInfo.Group -> chatNavLink(chat, chatModel, nav)
+ is ChatInfo.ContactRequest -> contactRequestNavLink(chat.chatInfo, chatModel, nav)
+ }
+ }
+ )
+}
+
+@DelicateCoroutinesApi
+fun chatNavLink(chatPreview: Chat, chatModel: ChatModel, navController: NavController) {
+ withApi {
+ val chatInfo = chatPreview.chatInfo
+ val chat = chatModel.controller.apiGetChat(chatInfo.chatType, chatInfo.apiId)
+ if (chat != null) {
+ chatModel.chatId.value = chatInfo.id
+ chatModel.chatItems = chat.chatItems.toMutableStateList()
+ navController.navigate(Pages.Chat.route)
+ } else {
+ // TODO show error? or will apiGetChat show it
+ }
+ }
+}
+
+@DelicateCoroutinesApi
+fun contactRequestNavLink(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel, navController: NavController) {
+ chatModel.alertManager.showAlertDialog(
+ title = "Accept connection request?",
+ text = "If you choose to reject sender will NOT be notified",
+ confirmText = "Accept",
+ onConfirm = {
+ withApi {
+ val contact = chatModel.controller.apiAcceptContactRequest(contactRequest.apiId)
+ if (contact != null) {
+ val chat = Chat(ChatInfo.Direct(contact), listOf())
+ chatModel.replaceChat(contactRequest.id, chat)
+ }
+ }
+ },
+ dismissText = "Reject",
+ onDismiss = {
+ withApi {
+ chatModel.controller.apiRejectContactRequest(contactRequest.apiId)
+ chatModel.removeChat(contactRequest.id)
+ }
+ }
+ )
+}
+
+@ExperimentalTextApi
+@Composable
+fun ChatListNavLink(chat: Chat, action: () -> Unit) {
+ ChatListNavLinkLayout(
+ content = {
+ when (chat.chatInfo) {
+ is ChatInfo.Direct -> ChatPreviewView(chat)
+ is ChatInfo.Group -> ChatPreviewView(chat)
+ is ChatInfo.ContactRequest -> ContactRequestView(chat)
+ }
+ },
+ action = action
+ )
+}
+
+@Composable
+fun ChatListNavLinkLayout(content: (@Composable () -> Unit), action: () -> Unit) {
+ Surface(
+ modifier = Modifier
+ .fillMaxWidth()
+ .clickable(onClick = action)
+ .height(88.dp)
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp)
+ .padding(start = 8.dp)
+ .padding(end = 12.dp),
+ verticalAlignment = Alignment.Top,
+// TODO?
+// verticalAlignment = Alignment.CenterVertically,
+// horizontalArrangement = Arrangement.SpaceEvenly
+ ) {
+ content.invoke()
+ }
+ }
+ Divider(Modifier.padding(horizontal = 8.dp))
+}
+
+@ExperimentalTextApi
+@Preview
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
+@Composable
+fun PreviewChatListNavLinkDirect() {
+ SimpleXTheme {
+ ChatListNavLink(
+ chat = Chat(
+ chatInfo = ChatInfo.Direct.sampleData,
+ chatItems = listOf(
+ ChatItem.getSampleData(
+ 1,
+ CIDirection.DirectSnd(),
+ Clock.System.now(),
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
+ )
+ ),
+ chatStats = Chat.ChatStats()
+ ),
+ action = {}
+ )
+ }
+}
+
+@ExperimentalTextApi
+@Preview
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
+@Composable
+fun PreviewChatListNavLinkGroup() {
+ SimpleXTheme {
+ ChatListNavLink(
+ chat = Chat(
+ chatInfo = ChatInfo.Group.sampleData,
+ chatItems = listOf(
+ ChatItem.getSampleData(
+ 1,
+ CIDirection.DirectSnd(),
+ Clock.System.now(),
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
+ )
+ ),
+ chatStats = Chat.ChatStats()
+ ),
+ action = {}
+ )
+ }
+}
+
+@ExperimentalTextApi
+@Preview
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
+@Composable
+fun PreviewChatListNavLinkContactRequest() {
+ SimpleXTheme {
+ ChatListNavLink(
+ chat = Chat(
+ chatInfo = ChatInfo.ContactRequest.sampleData,
+ chatItems = listOf(),
+ chatStats = Chat.ChatStats()
+ ),
+ action = {}
+ )
+ }
+}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
index 73474a4c3..179ed1919 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatListView.kt
@@ -14,15 +14,12 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
-import androidx.navigation.NavOptions
-import chat.simplex.app.Pages
-import chat.simplex.app.model.Chat
import chat.simplex.app.model.ChatModel
import chat.simplex.app.views.chat.ChatHelpView
-import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.newchat.NewChatSheet
import chat.simplex.app.views.usersettings.SettingsView
import com.google.accompanist.permissions.ExperimentalPermissionsApi
@@ -67,6 +64,7 @@ fun scaffoldController(): ScaffoldController {
return ctrl
}
+@ExperimentalTextApi
@DelicateCoroutinesApi
@ExperimentalPermissionsApi
@ExperimentalMaterialApi
@@ -180,29 +178,16 @@ fun ChatListToolbar(scaffoldCtrl: ScaffoldController) {
}
}
-@DelicateCoroutinesApi
-fun goToChat(chatPreview: Chat, chatModel: ChatModel, navController: NavController) {
- withApi {
- val cInfo = chatPreview.chatInfo
- val chat = chatModel.controller.apiGetChat(cInfo.chatType, cInfo.apiId)
- if (chat != null) {
- chatModel.chatId.value = cInfo.id
- chatModel.chatItems = chat.chatItems.toMutableStateList()
- navController.navigate(Pages.Chat.route)
- } else {
- // TODO show error? or will apiGetChat show it
- }
- }
-}
-
+@ExperimentalTextApi
@DelicateCoroutinesApi
@Composable
fun ChatList(chatModel: ChatModel, navController: NavController) {
+ Divider(Modifier.padding(horizontal = 8.dp))
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
items(chatModel.chats) { chat ->
- ChatPreviewView(chat) { goToChat(chat, chatModel, navController) }
+ ChatListNavLinkView(chat, chatModel, navController)
}
}
}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
index 9c36141c7..fc2a85c64 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ChatPreviewView.kt
@@ -1,108 +1,76 @@
package chat.simplex.app.views.chatlist
-import androidx.compose.foundation.*
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material.*
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import chat.simplex.app.model.*
+import chat.simplex.app.model.Chat
+import chat.simplex.app.model.getTimestampText
import chat.simplex.app.ui.theme.HighOrLowlight
-import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.ChatInfoImage
import chat.simplex.app.views.helpers.badgeLayout
-import kotlinx.datetime.Clock
@ExperimentalTextApi
@Composable
-fun ChatPreviewView(chat: Chat, goToChat: () -> Unit) {
- Surface(
- border = BorderStroke(0.5.dp, MaterialTheme.colors.secondary),
- modifier = Modifier
- .fillMaxWidth()
- .clickable(onClick = goToChat)
- .height(88.dp)
- ) {
- Row(
+fun ChatPreviewView(chat: Chat) {
+ Row {
+ ChatInfoImage(chat, size = 72.dp)
+ Column(
modifier = Modifier
- .fillMaxWidth()
- .padding(vertical = 8.dp)
- .padding(start = 8.dp)
- .padding(end = 12.dp),
- verticalAlignment = Alignment.Top
- ) {
- ChatInfoImage(chat, size = 72.dp)
- Column(modifier = Modifier
.padding(horizontal = 8.dp)
- .weight(1F)) {
- Text(
- chat.chatInfo.chatViewName,
- maxLines = 1,
- overflow = TextOverflow.Ellipsis,
- style = MaterialTheme.typography.h3,
- fontWeight = FontWeight.Bold
- )
- if (chat.chatItems.count() > 0) {
- MarkdownText(
- chat.chatItems.last(),
- maxLines = 2,
- overflow = TextOverflow.Ellipsis
- )
- }
- }
- val ts = chat.chatItems.lastOrNull()?.timestampText ?: getTimestampText(chat.chatInfo.createdAt)
- Column(Modifier.fillMaxHeight(),
- verticalArrangement = Arrangement.Top) {
- Text(ts,
- color = HighOrLowlight,
- style = MaterialTheme.typography.body2,
- modifier = Modifier.padding(bottom = 5.dp)
- )
+ .weight(1F)
+ ) {
+ Text(
+ chat.chatInfo.chatViewName,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ style = MaterialTheme.typography.h3,
+ fontWeight = FontWeight.Bold
+ )
- val n = chat.chatStats.unreadCount
- if (n > 0) {
- Text(
- if (n < 1000) "$n" else "${n / 1000}k",
- color = MaterialTheme.colors.onPrimary,
- fontSize = 14.sp,
- modifier = Modifier
- .background(MaterialTheme.colors.primary, shape = CircleShape)
- .align(Alignment.End)
- .badgeLayout()
- .padding(horizontal = 3.dp)
- .padding(vertical = 1.dp)
- )
- }
+ if (chat.chatItems.count() > 0) {
+ MarkdownText(
+ chat.chatItems.last(),
+ maxLines = 2,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ }
+ val ts = chat.chatItems.lastOrNull()?.timestampText ?: getTimestampText(chat.chatInfo.createdAt)
+ Column(
+ Modifier.fillMaxHeight(),
+ verticalArrangement = Arrangement.Top
+ ) {
+ Text(
+ ts,
+ color = HighOrLowlight,
+ style = MaterialTheme.typography.body2,
+ modifier = Modifier.padding(bottom = 5.dp)
+ )
+ val n = chat.chatStats.unreadCount
+ if (n > 0) {
+ Text(
+ if (n < 1000) "$n" else "${n / 1000}k",
+ color = MaterialTheme.colors.onPrimary,
+ fontSize = 14.sp,
+ modifier = Modifier
+ .background(MaterialTheme.colors.primary, shape = CircleShape)
+ .align(Alignment.End)
+ .badgeLayout()
+ .padding(horizontal = 3.dp)
+ .padding(vertical = 1.dp)
+ )
}
}
}
}
-
-@ExperimentalTextApi
-@Preview
-@Composable
-fun ChatPreviewViewExample() {
- SimpleXTheme {
- ChatPreviewView(
- chat = Chat(
- chatInfo = ChatInfo.Direct.sampleData,
- chatItems = listOf(ChatItem.getSampleData(
- 1,
- CIDirection.DirectSnd(),
- Clock.System.now(),
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
- )),
- chatStats = Chat.ChatStats(unreadCount = 3)
- ),
- goToChat = {}
- )
- }
-}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt
new file mode 100644
index 000000000..4cfa5c48c
--- /dev/null
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactRequestView.kt
@@ -0,0 +1,52 @@
+package chat.simplex.app.views.chatlist
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import chat.simplex.app.model.Chat
+import chat.simplex.app.model.getTimestampText
+import chat.simplex.app.ui.theme.HighOrLowlight
+import chat.simplex.app.views.helpers.ChatInfoImage
+
+@Composable
+fun ContactRequestView(chat: Chat) {
+ Row {
+ ChatInfoImage(chat, size = 72.dp)
+ Column(
+ modifier = Modifier
+ .padding(horizontal = 8.dp)
+ .weight(1F)
+ ) {
+ Text(
+ chat.chatInfo.chatViewName,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ style = MaterialTheme.typography.h3,
+ fontWeight = FontWeight.Bold,
+ color = MaterialTheme.colors.primary
+ )
+ Text(
+ "wants to connect to you!",
+ maxLines = 2,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ val ts = getTimestampText(chat.chatInfo.createdAt)
+ Column(
+ Modifier.fillMaxHeight(),
+ verticalArrangement = Arrangement.Top
+ ) {
+ Text(
+ ts,
+ color = HighOrLowlight,
+ style = MaterialTheme.typography.body2,
+ modifier = Modifier.padding(bottom = 5.dp)
+ )
+ }
+ }
+}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Share.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Share.kt
new file mode 100644
index 000000000..be5141276
--- /dev/null
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/Share.kt
@@ -0,0 +1,14 @@
+package chat.simplex.app.views.helpers
+
+import android.content.Context
+import android.content.Intent
+
+fun shareText(cxt: Context, text: String) {
+ val sendIntent: Intent = Intent().apply {
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_TEXT, text)
+ type = "text/plain"
+ }
+ val shareIntent = Intent.createChooser(sendIntent, null)
+ cxt.startActivity(shareIntent)
+}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt
index 7066024bf..f221c9756 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/AddContactView.kt
@@ -1,7 +1,6 @@
package chat.simplex.app.views.newchat
-import android.content.Context
-import android.content.Intent
+import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
@@ -22,6 +21,7 @@ import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.SimpleButton
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.CloseSheetBar
+import chat.simplex.app.views.helpers.shareText
@Composable
fun AddContactView(chatModel: ChatModel, nav: NavController) {
@@ -40,54 +40,53 @@ fun AddContactView(chatModel: ChatModel, nav: NavController) {
fun AddContactLayout(connReq: String, close: () -> Unit, share: () -> Unit) {
Column(
modifier = Modifier
- .padding(horizontal = 8.dp)
.fillMaxSize()
- .background(MaterialTheme.colors.background),
- horizontalAlignment = Alignment.CenterHorizontally
+ .background(MaterialTheme.colors.background)
+ .padding(horizontal = 8.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(12.dp)
) {
CloseSheetBar(close)
Text(
"Add contact",
style = MaterialTheme.typography.h1,
- modifier = Modifier.padding(bottom = 8.dp)
+ color = MaterialTheme.colors.onBackground
)
Text(
"Show QR code to your contact\nto scan from the app",
style = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
- modifier = Modifier.padding(bottom = 8.dp)
+ color = MaterialTheme.colors.onBackground
)
QRCode(connReq)
Text(
buildAnnotatedString {
- append("If you cannot meet in person, you can ")
- withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
+ append("If you cannot meet in person, you can ")
+ }
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)) {
append("scan QR code in the video call")
}
- append(", or you can share the invitation link via any other channel.")
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
+ append(", or you can share the invitation link via any other channel.")
+ }
},
textAlign = TextAlign.Center,
style = MaterialTheme.typography.caption,
modifier = Modifier
.padding(horizontal = 16.dp)
- .padding(top = 8.dp)
.padding(bottom = 16.dp)
)
SimpleButton("Share invitation link", icon = Icons.Outlined.Share, click = share)
}
}
-fun shareText(cxt: Context, text: String) {
- val sendIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_TEXT, text)
- type = "text/plain"
- }
- val shareIntent = Intent.createChooser(sendIntent, null)
- cxt.startActivity(shareIntent)
-}
-
@Preview
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
@Composable
fun PreviewAddContactView() {
SimpleXTheme {
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectContactView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectContactView.kt
index 2a7274a1b..5a82ea51c 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectContactView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/newchat/ConnectContactView.kt
@@ -1,5 +1,6 @@
package chat.simplex.app.views.newchat
+import android.content.res.Configuration
import android.net.Uri
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
@@ -30,7 +31,7 @@ fun ConnectContactView(chatModel: ChatModel, nav: NavController) {
withUriAction(chatModel, uri) { action ->
connectViaUri(chatModel, action, uri)
}
- } catch(e: RuntimeException) {
+ } catch (e: RuntimeException) {
chatModel.alertManager.showAlertMsg(
title = "Invalid QR code",
text = "This QR code is not a link!"
@@ -44,8 +45,10 @@ fun ConnectContactView(chatModel: ChatModel, nav: NavController) {
}
@DelicateCoroutinesApi
-fun withUriAction(chatModel: ChatModel, uri: Uri,
- run: suspend (String) -> Unit) {
+fun withUriAction(
+ chatModel: ChatModel, uri: Uri,
+ run: suspend (String) -> Unit
+) {
val action = uri.path?.drop(1)
if (action == "contact" || action == "invitation") {
withApi { run(action) }
@@ -74,46 +77,57 @@ suspend fun connectViaUri(chatModel: ChatModel, action: String, uri: Uri) {
fun ConnectContactLayout(qrCodeScanner: @Composable () -> Unit, close: () -> Unit) {
Column(
modifier = Modifier
- .padding(horizontal = 8.dp)
.fillMaxSize()
- .background(MaterialTheme.colors.background),
- horizontalAlignment = Alignment.CenterHorizontally
+ .background(MaterialTheme.colors.background)
+ .padding(horizontal = 8.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(12.dp)
) {
CloseSheetBar(close)
Text(
"Scan QR code",
style = MaterialTheme.typography.h1,
- modifier = Modifier.padding(bottom = 8.dp)
+ color = MaterialTheme.colors.onBackground
)
Text(
"Your chat profile will be sent\nto your contact",
style = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
- modifier = Modifier.padding(bottom = 16.dp)
+ color = MaterialTheme.colors.onBackground,
+ modifier = Modifier.padding(bottom = 4.dp)
)
- Box (
+ Box(
Modifier
.fillMaxWidth()
.aspectRatio(ratio = 1F)
) { qrCodeScanner() }
Text(
buildAnnotatedString {
- append("If you cannot meet in person, you can ")
- withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
+ append("If you cannot meet in person, you can ")
+ }
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)) {
append("scan QR code in the video call")
}
- append(", or you can create the invitation link.")
+ withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
+ append(", or you can create the invitation link.")
+ }
},
textAlign = TextAlign.Center,
style = MaterialTheme.typography.caption,
modifier = Modifier
.padding(horizontal = 16.dp)
- .padding(top = 16.dp)
+ .padding(top = 4.dp)
)
}
}
@Preview
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
@Composable
fun PreviewConnectContactLayout() {
SimpleXTheme {
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt
index aff3dea98..a949d0630 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/SettingsView.kt
@@ -21,7 +21,6 @@ import chat.simplex.app.Pages
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.Profile
-import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.SimpleXTheme
@Composable
@@ -49,6 +48,7 @@ fun SettingsLayout(
.fillMaxSize()
// .background(MaterialTheme.colors.background)
.padding(8.dp)
+ .padding(top = 16.dp)
) {
Text(
"Your Settings",
@@ -87,15 +87,15 @@ fun SettingsLayout(
Icon(
Icons.Outlined.QrCode,
contentDescription = "Address",
- tint = HighOrLowlight,
+ tint = MaterialTheme.colors.onBackground,
)
Spacer(Modifier.padding(horizontal = 4.dp))
Text(
"Your SimpleX contact address",
- color = HighOrLowlight
+ color = MaterialTheme.colors.onBackground
)
},
- func = { println("navigate to address") }
+ func = { navigate(Pages.UserAddress.route) }
)
Spacer(Modifier.height(24.dp))
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt
new file mode 100644
index 000000000..d082048f8
--- /dev/null
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserAddressView.kt
@@ -0,0 +1,147 @@
+package chat.simplex.app.views.usersettings
+
+import android.content.res.Configuration
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.*
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import chat.simplex.app.model.ChatModel
+import chat.simplex.app.ui.theme.SimpleButton
+import chat.simplex.app.ui.theme.SimpleXTheme
+import chat.simplex.app.views.helpers.*
+import chat.simplex.app.views.newchat.QRCode
+
+@Composable
+fun UserAddressView(chatModel: ChatModel, nav: NavController) {
+ val cxt = LocalContext.current
+ UserAddressLayout(
+ userAddress = chatModel.userAddress.value,
+ back = { nav.popBackStack() },
+ createAddress = {
+ withApi {
+ chatModel.userAddress.value = chatModel.controller.apiCreateUserAddress()
+ }
+ },
+ share = { userAddress: String -> shareText(cxt, userAddress) },
+ deleteAddress = {
+ chatModel.alertManager.showAlertMsg(
+ title = "Delete address?",
+ text = "All your contacts will remain connected",
+ confirmText = "Delete",
+ onConfirm = {
+ withApi {
+ chatModel.controller.apiDeleteUserAddress()
+ chatModel.userAddress.value = null
+ }
+ }
+ )
+ }
+ )
+}
+
+@Composable
+fun UserAddressLayout(
+ userAddress: String?,
+ back: () -> Unit,
+ createAddress: () -> Unit,
+ share: (String) -> Unit,
+ deleteAddress: () -> Unit
+) {
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(MaterialTheme.colors.background)
+ .padding(horizontal = 8.dp),
+ horizontalAlignment = Alignment.Start,
+ verticalArrangement = Arrangement.Top
+ ) {
+ CloseSheetBar(back)
+ Text(
+ "Your chat address",
+ Modifier.padding(bottom = 24.dp),
+ style = MaterialTheme.typography.h1,
+ color = MaterialTheme.colors.onBackground
+ )
+ Text(
+ "You can share your address as a link or as a QR code - anybody will be able to connect to you, " +
+ "and if you later delete it - you won't lose your contacts.",
+ Modifier.padding(bottom = 24.dp),
+ color = MaterialTheme.colors.onBackground
+ )
+ Column(
+ Modifier
+ .fillMaxWidth()
+ .padding(top = 12.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(24.dp)
+ ) {
+ if (userAddress == null) {
+ SimpleButton("Create address", icon = Icons.Outlined.QrCode, click = createAddress)
+ } else {
+ QRCode(userAddress)
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(12.dp)
+ ) {
+ SimpleButton(
+ "Share link",
+ icon = Icons.Outlined.Share,
+ click = { share(userAddress) })
+ SimpleButton(
+ "Delete address",
+ icon = Icons.Outlined.Delete,
+ color = Color.Red,
+ click = deleteAddress
+ )
+ }
+ }
+ }
+ }
+}
+
+@Preview(showBackground = true)
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
+@Composable
+fun PreviewUserAddressLayoutNoAddress() {
+ SimpleXTheme {
+ UserAddressLayout(
+ userAddress = null,
+ back = {},
+ createAddress = {},
+ share = { _ -> },
+ deleteAddress = {},
+ )
+ }
+}
+
+@Preview(showBackground = true)
+@Preview(
+ uiMode = Configuration.UI_MODE_NIGHT_YES,
+ showBackground = true,
+ name = "Dark Mode"
+)
+@Composable
+fun PreviewUserAddressLayoutAddressCreated() {
+ SimpleXTheme {
+ UserAddressLayout(
+ userAddress = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
+ back = {},
+ createAddress = {},
+ share = { _ -> },
+ deleteAddress = {},
+ )
+ }
+}
diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt
index dffa108ce..6af1f44db 100644
--- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt
+++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/UserProfileView.kt
@@ -179,7 +179,6 @@ fun UserProfileLayout(
showBackground = true,
name = "Dark Mode"
)
-
@Composable
fun PreviewUserProfileLayoutEditOff() {
SimpleXTheme {
diff --git a/apps/ios/Shared/Views/UserSettings/UserAddress.swift b/apps/ios/Shared/Views/UserSettings/UserAddress.swift
index 6ed2d0374..8b467316c 100644
--- a/apps/ios/Shared/Views/UserSettings/UserAddress.swift
+++ b/apps/ios/Shared/Views/UserSettings/UserAddress.swift
@@ -66,7 +66,11 @@ struct UserAddress_Previews: PreviewProvider {
static var previews: some View {
let chatModel = ChatModel()
chatModel.userAddress = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D"
- return UserAddress()
- .environmentObject(chatModel)
+ return Group {
+ UserAddress()
+ .environmentObject(chatModel)
+ UserAddress()
+ .environmentObject(ChatModel())
+ }
}
}