android: refactor modal views without navigation controller (#381)

* android: refactor modal views without navigation controller

* refactor navigation

* make alert manager global

* disable CRPendingSubSummary in terminal, hamburger menu instead of gear
This commit is contained in:
Evgeny Poberezkin
2022-02-27 18:16:38 +00:00
committed by GitHub
parent 3f3a503def
commit 0a94e740d2
25 changed files with 447 additions and 560 deletions
@@ -8,22 +8,27 @@ import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.*
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.lifecycle.AndroidViewModel
import androidx.navigation.*
import androidx.navigation.compose.*
import chat.simplex.app.model.*
import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.NtfManager
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.*
import chat.simplex.app.views.chat.ChatInfoView
import chat.simplex.app.views.SplashView
import chat.simplex.app.views.WelcomeView
import chat.simplex.app.views.chat.ChatView
import chat.simplex.app.views.chatlist.ChatListView
import chat.simplex.app.views.chatlist.openChat
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.newchat.*
import chat.simplex.app.views.usersettings.*
import kotlinx.serialization.decodeFromString
//import kotlinx.serialization.decodeFromString
class MainActivity: ComponentActivity() {
private val vm by viewModels<SimplexViewModel>()
@@ -35,7 +40,13 @@ class MainActivity: ComponentActivity() {
// vm.app.initiateBackgroundWork()
setContent {
SimpleXTheme {
Navigation(vm.chatModel)
Surface(
Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
MainPage(vm.chatModel)
}
}
}
}
@@ -47,84 +58,20 @@ class SimplexViewModel(application: Application): AndroidViewModel(application)
}
@Composable
fun MainPage(chatModel: ChatModel, nav: NavController) {
when (chatModel.userCreated.value) {
null -> SplashView()
false -> WelcomeView(chatModel) // { nav.navigate(Pages.ChatList.route) }
true -> if (chatModel.chatId.value == null) {
ChatListView(chatModel, nav)
} else {
ChatView(chatModel, nav)
}
}
}
@Composable
fun Navigation(chatModel: ChatModel) {
println("*** in Navigation")
val nav = rememberNavController()
val scope = rememberCoroutineScope()
fun MainPage(chatModel: ChatModel) {
Box {
NavHost(navController = nav, startDestination = Pages.Home.route) {
composable(route = Pages.Home.route) {
println("*** composable MainPage")
MainPage(chatModel, nav)
}
composable(route = Pages.Welcome.route) {
WelcomeView(chatModel)
}
composable(route = Pages.AddContact.route) {
AddContactView(chatModel, nav)
}
composable(route = Pages.Connect.route) {
ConnectContactView(chatModel, nav)
}
composable(route = Pages.ChatInfo.route) {
ChatInfoView(chatModel, nav)
}
composable(route = Pages.Terminal.route) {
TerminalView(chatModel, nav)
}
composable(
Pages.TerminalItemDetails.route + "/{identifier}",
arguments = listOf(
navArgument("identifier") {
type = NavType.LongType
}
)
) { entry -> DetailView(entry.arguments!!.getLong("identifier"), chatModel.terminalItems, nav) }
composable(route = Pages.UserProfile.route) {
UserProfileView(chatModel, nav)
}
composable(route = Pages.UserAddress.route) {
UserAddressView(chatModel, nav)
}
composable(route = Pages.Help.route) {
HelpView(chatModel, nav)
}
composable(route = Pages.Markdown.route) {
MarkdownHelpView(nav)
}
when (chatModel.userCreated.value) {
null -> SplashView()
false -> WelcomeView(chatModel)
true ->
if (chatModel.chatId.value == null) ChatListView(chatModel)
else ChatView(chatModel)
}
val am = chatModel.alertManager
if (am.presentAlert.value) am.alertView.value?.invoke()
ModalManager.shared.showInView()
AlertManager.shared.showInView()
}
}
sealed class Pages(val route: String) {
object Home: Pages("home")
object Terminal: Pages("terminal")
object Welcome: Pages("welcome")
object TerminalItemDetails: Pages("details")
object AddContact: Pages("add_contact")
object Connect: Pages("connect")
object ChatInfo: Pages("chat_info")
object UserProfile: Pages("user_profile")
object UserAddress: Pages("user_address")
object Help: Pages("help")
object Markdown: Pages("markdown")
}
fun processIntent(intent: Intent?, chatModel: ChatModel) {
when (intent?.action) {
NtfManager.OpenChatAction -> {
@@ -148,8 +95,8 @@ fun connectIfOpenedViaUri(uri: Uri, chatModel: ChatModel) {
// TODO open from chat list view
chatModel.appOpenUrl.value = uri
} else {
withUriAction(chatModel, uri) { action ->
chatModel.alertManager.showAlertMsg(
withUriAction(uri) { action ->
AlertManager.shared.showAlertMsg(
title = "Connect via $action link?",
text = "Your profile will be sent to the contact that you received this link from.",
confirmText = "Connect",
@@ -164,10 +111,10 @@ fun connectIfOpenedViaUri(uri: Uri, chatModel: ChatModel) {
}
}
fun testJson() {
val str = """
{}
""".trimIndent()
println(json.decodeFromString<ChatItem>(str))
}
//fun testJson() {
// val str = """
// {}
// """.trimIndent()
//
// println(json.decodeFromString<ChatItem>(str))
//}
@@ -3,9 +3,6 @@ package chat.simplex.app
import android.app.Application
import android.net.LocalServerSocket
import android.util.Log
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.work.*
import chat.simplex.app.model.*
import chat.simplex.app.views.helpers.withApi
@@ -48,7 +45,7 @@ class SimplexApp: Application() {
super.onCreate()
ntfManager = NtfManager(applicationContext)
val ctrl = chatInit(applicationContext.filesDir.toString())
controller = ChatController(ctrl, AlertManager(), ntfManager, applicationContext)
controller = ChatController(ctrl, ntfManager, applicationContext)
chatModel = controller.chatModel
withApi {
val user = controller.apiGetActiveUser()
@@ -56,72 +53,6 @@ class SimplexApp: Application() {
}
}
class AlertManager {
var alertView = mutableStateOf<(@Composable () -> Unit)?>(null)
var presentAlert = mutableStateOf<Boolean>(false)
fun showAlert(alert: @Composable () -> Unit) {
Log.d("SIMPLEX", "AlertManager.showAlert")
alertView.value = alert
presentAlert.value = true
}
fun hideAlert() {
presentAlert.value = false
alertView.value = 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(
onDismissRequest = this::hideAlert,
title = { Text(title) },
text = alertText,
confirmButton = {
Button(onClick = {
onConfirm?.invoke()
hideAlert()
}) { Text(confirmText) }
}
)
}
}
}
companion object {
init {
val socketName = "local.socket.address.listen.native.cmd2"
@@ -7,13 +7,12 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.*
import androidx.compose.ui.text.style.TextDecoration
import chat.simplex.app.SimplexApp
import chat.simplex.app.ui.theme.SecretColor
import kotlinx.datetime.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
class ChatModel(val controller: ChatController, val alertManager: SimplexApp.AlertManager) {
class ChatModel(val controller: ChatController) {
var currentUser = mutableStateOf<User?>(null)
var userCreated = mutableStateOf<Boolean?>(null)
var chats = mutableStateListOf<Chat>()
@@ -5,7 +5,9 @@ import android.app.ActivityManager.RunningAppProcessInfo
import android.content.Context
import android.util.Log
import androidx.compose.runtime.mutableStateOf
import chat.simplex.app.*
import chat.simplex.app.chatRecvMsg
import chat.simplex.app.chatSendCmd
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.withApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -18,8 +20,8 @@ import kotlin.concurrent.thread
typealias ChatCtrl = Long
open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.AlertManager, val ntfManager: NtfManager, val appContext: Context) {
var chatModel = ChatModel(this, alertManager)
open class ChatController(val ctrl: ChatCtrl, val ntfManager: NtfManager, val appContext: Context) {
var chatModel = ChatModel(this)
suspend fun startChat(u: User) {
Log.d("SIMPLEX (user)", u.toString())
@@ -139,14 +141,14 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
when {
r is CR.SentConfirmation || r is CR.SentInvitation -> return true
r is CR.ContactAlreadyExists -> {
alertManager.showAlertMsg("Contact already exists",
AlertManager.shared.showAlertMsg("Contact already exists",
"You are already connected to ${r.contact.displayName} via this link"
)
return false
}
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat
&& r.chatError.errorType is ChatErrorType.InvalidConnReq -> {
alertManager.showAlertMsg("Invalid connection link",
AlertManager.shared.showAlertMsg("Invalid connection link",
"Please check that you used the correct link or ask your contact to send you another one."
)
return false
@@ -165,15 +167,14 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
is CR.ChatCmdError -> {
val e = r.chatError
if (e is ChatError.ChatErrorChat && e.errorType is ChatErrorType.ContactGroups) {
alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
"Can't delete contact!",
"Contact ${e.errorType.contact.displayName} cannot be deleted, it is a member of the group(s) ${e.errorType.groupNames}"
)
return false
}
}
else -> apiErrorAlert("apiDeleteChat", "Error deleting ${type.chatTypeName}", r)
}
apiErrorAlert("apiDeleteChat", "Error deleting ${type.chatTypeName}", r)
return false
}
@@ -234,7 +235,7 @@ open class ChatController(val ctrl: ChatCtrl, val alertManager: SimplexApp.Alert
fun apiErrorAlert(method: String, title: String, r: CR) {
val errMsg = "${r.responseType}: ${r.details}"
Log.e("SIMPLEX", "$method bad response: $errMsg")
alertManager.showAlertMsg(title, errMsg)
AlertManager.shared.showAlertMsg(title, errMsg)
}
fun processReceivedMsg(r: CR) {
@@ -1,17 +1,18 @@
package chat.simplex.app.views
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@Composable
fun SplashView() {
Box(modifier = Modifier
.fillMaxSize()
.background(color = Color.White)
Surface(
Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
// Image(
// painter = painterResource(R.drawable.logo),
@@ -1,8 +1,10 @@
package chat.simplex.app.views
import android.content.res.Configuration
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.*
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.*
@@ -15,19 +17,20 @@ 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 androidx.navigation.NavController
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.chat.SendMsgView
import chat.simplex.app.views.helpers.CloseSheetBar
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.newchat.ModalManager
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import kotlinx.coroutines.launch
@Composable
fun TerminalView(chatModel: ChatModel, nav: NavController) {
TerminalLayout(chatModel.terminalItems, nav::popBackStack, nav::navigate) { cmd ->
fun TerminalView(chatModel: ChatModel, close: () -> Unit) {
BackHandler(onBack = close)
TerminalLayout(chatModel.terminalItems, close) { cmd ->
withApi {
// show "in progress"
chatModel.controller.sendCmd(CC.Console(cmd))
@@ -37,39 +40,45 @@ fun TerminalView(chatModel: ChatModel, nav: NavController) {
}
@Composable
fun TerminalLayout(terminalItems: List<TerminalItem> , close: () -> Unit, navigate: (String) -> Unit,
sendCommand: (String) -> Unit) {
fun TerminalLayout(terminalItems: List<TerminalItem> , close: () -> Unit, sendCommand: (String) -> Unit) {
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
Scaffold(
topBar = { CloseSheetBar(close) },
bottomBar = { SendMsgView(sendCommand) },
modifier = Modifier.navigationBarsWithImePadding()
) { contentPadding ->
Box(
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth()
.background(MaterialTheme.colors.background)
) {
TerminalLog(terminalItems, navigate)
TerminalLog(terminalItems)
}
}
}
}
@Composable
fun TerminalLog(terminalItems: List<TerminalItem>, navigate: (String) -> Unit) {
fun TerminalLog(terminalItems: List<TerminalItem>) {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
LazyColumn(state = listState) {
items(terminalItems) { item ->
Text("${item.date.toString().subSequence(11, 19)} ${item.label}",
style = TextStyle(fontFamily = FontFamily.Monospace, fontSize = 18.sp, color = MaterialTheme.colors.primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 4.dp)
.clickable { navigate("details/${item.id}") })
Text("${item.date.toString().subSequence(11, 19)} ${item.label}",
style = TextStyle(fontFamily = FontFamily.Monospace, fontSize = 18.sp, color = MaterialTheme.colors.primary),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 4.dp)
.clickable {
ModalManager.shared.showModal {
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) {
Text(item.details)
}
}
}
)
}
val len = terminalItems.count()
if (len > 1) {
@@ -80,22 +89,6 @@ fun TerminalLog(terminalItems: List<TerminalItem>, navigate: (String) -> Unit) {
}
}
@Composable
fun DetailView(identifier: Long, terminalItems: List<TerminalItem>, nav: NavController){
Surface(
Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
Column {
CloseSheetBar(nav::popBackStack)
SelectionContainer(modifier = Modifier.verticalScroll(rememberScrollState())) {
Text((terminalItems.firstOrNull { it.id == identifier })?.details ?: "")
}
}
}
}
@Preview(showBackground = true)
@Preview(
uiMode = Configuration.UI_MODE_NIGHT_YES,
@@ -108,7 +101,6 @@ fun PreviewTerminalLayout() {
TerminalLayout(
terminalItems = TerminalItem.sampleData,
close = {},
navigate = {},
sendCommand = {}
)
}
@@ -1,5 +1,6 @@
package chat.simplex.app.views.chat
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -14,19 +15,19 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
@Composable
fun ChatInfoView(chatModel: ChatModel, nav: NavController) {
fun ChatInfoView(chatModel: ChatModel, close: () -> Unit) {
BackHandler(onBack = close)
val chat = chatModel.chats.firstOrNull { it.id == chatModel.chatId.value }
if (chat != null) {
ChatInfoLayout(chat,
close = nav::popBackStack,
close = close,
deleteContact = {
chatModel.alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
title = "Delete contact?",
text = "Contact and all messages will be deleted - this cannot be undone!",
confirmText = "Delete",
@@ -37,7 +38,7 @@ fun ChatInfoView(chatModel: ChatModel, nav: NavController) {
if (r) {
chatModel.removeChat(cInfo.id)
chatModel.chatId.value = null
nav.popBackStack()
close()
}
}
}
@@ -92,7 +93,7 @@ fun ChatInfoLayout(chat: Chat, close: () -> Unit, deleteContact: () -> Unit) {
Spacer(Modifier.weight(1F))
Box(Modifier.padding(24.dp)) {
Box(Modifier.padding(48.dp)) {
SimpleButton(
"Delete contact", icon = Icons.Outlined.Delete,
color = Color.Red,
@@ -18,13 +18,12 @@ 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.navigation.NavController
import chat.simplex.app.Pages
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.chat.item.ChatItemView
import chat.simplex.app.views.helpers.ChatInfoImage
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.newchat.ModalManager
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import kotlinx.coroutines.delay
@@ -32,7 +31,7 @@ import kotlinx.coroutines.launch
import kotlinx.datetime.Clock
@Composable
fun ChatView(chatModel: ChatModel, nav: NavController) {
fun ChatView(chatModel: ChatModel) {
val chat: Chat? = chatModel.chats.firstOrNull { chat -> chat.chatInfo.id == chatModel.chatId.value }
if (chat == null) {
chatModel.chatId.value = null
@@ -55,7 +54,7 @@ fun ChatView(chatModel: ChatModel, nav: NavController) {
}
ChatLayout(chat, chatModel.chatItems,
back = { chatModel.chatId.value = null },
info = { nav.navigate(Pages.ChatInfo.route) },
info = { ModalManager.shared.showCustomModal { close -> ChatInfoView(chatModel, close) } },
sendMessage = { msg ->
withApi {
// show "in progress"
@@ -86,9 +85,8 @@ fun ChatLayout(
bottomBar = { SendMsgView(sendMessage) },
modifier = Modifier.navigationBarsWithImePadding()
) { contentPadding ->
Box(
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth()
.background(MaterialTheme.colors.background)
) {
@@ -15,9 +15,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.SimpleXTheme
@Composable
@@ -33,6 +35,7 @@ fun SendMsgView(sendMessage: (String) -> Unit) {
autoCorrect = true
),
modifier = Modifier.padding(8.dp),
cursorBrush = SolidColor(HighOrLowlight),
decorationBox = { innerTextField ->
Surface(
shape = RoundedCornerShape(18.dp),
@@ -58,7 +58,7 @@ fun appendGroupMember(b: AnnotatedString.Builder, chatItem: ChatItem, groupMembe
@Composable
fun MarkdownText (
chatItem: ChatItem,
style: TextStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onBackground),
style: TextStyle = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.onSurface),
maxLines: Int = Int.MAX_VALUE,
overflow: TextOverflow = TextOverflow.Clip,
uriHandler: UriHandler? = null,
@@ -1,7 +1,6 @@
package chat.simplex.app.views.chat
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -18,35 +17,28 @@ import androidx.compose.ui.unit.dp
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.usersettings.simplexTeamUri
val bold = SpanStyle(fontWeight = FontWeight.Bold)
@Composable
fun ChatHelpView(addContact: () -> Unit, doAddContact: Boolean) {
fun ChatHelpView(addContact: (() -> Unit)? = null) {
Column(
Modifier
.fillMaxWidth()
.background(MaterialTheme.colors.background),
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
val uriHandler = LocalUriHandler.current
Text(
"Thank you for installing SimpleX Chat!",
color = MaterialTheme.colors.onBackground
)
Text("Thank you for installing SimpleX Chat!")
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append("You can ")
}
append("You can ")
withStyle(SpanStyle(color = MaterialTheme.colors.primary)) {
append("connect to SimpleX team")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(".")
}
append(".")
},
modifier = Modifier
.clickable(onClick = { uriHandler.openUri(simplexTeamUri) })
modifier = Modifier.clickable(onClick = {
uriHandler.openUri(simplexTeamUri)
})
)
Column(
@@ -56,46 +48,30 @@ fun ChatHelpView(addContact: () -> Unit, doAddContact: Boolean) {
) {
Text(
"To start a new chat",
color = MaterialTheme.colors.onBackground,
style = MaterialTheme.typography.h2
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
"Tap button",
color = MaterialTheme.colors.onBackground
)
Text("Tap button")
Icon(
Icons.Outlined.PersonAdd,
"Add Contact",
modifier = if (doAddContact) Modifier.clickable(onClick = addContact) else Modifier,
tint = MaterialTheme.colors.onBackground,
)
Text(
"above, then:",
color = MaterialTheme.colors.onBackground
modifier = if (addContact != null) Modifier.clickable(onClick = addContact) else Modifier,
)
Text("above, then:")
}
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)) {
append("Add new contact")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(": to create your one-time QR Code for your contact.")
}
withStyle(bold) { append("Add new contact") }
append(": to create your one-time QR Code for your contact.")
}
)
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)) {
append("Scan QR code")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(": to connect to your contact who shows QR code to you.")
}
withStyle(bold) { append("Scan QR code") }
append(": to connect to your contact who shows QR code to you.")
}
)
}
@@ -105,51 +81,22 @@ fun ChatHelpView(addContact: () -> Unit, doAddContact: Boolean) {
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(
"To connect via link",
color = MaterialTheme.colors.onBackground,
style = MaterialTheme.typography.h2
)
Text(
"If you received SimpleX Chat invitation link you can open it in your browser:",
color = MaterialTheme.colors.onBackground
)
Text("To connect via link", style = MaterialTheme.typography.h2)
Text("If you received SimpleX Chat invitation link you can open it in your browser:")
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append("\uD83D\uDCBB desktop: scan displayed QR code from the app, via ")
}
withStyle(
SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)
) {
append("Scan QR code")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(".")
}
append("\uD83D\uDCBB desktop: scan displayed QR code from the app, via ")
withStyle(bold) { append("Scan QR code") }
append(".")
}
)
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append("\uD83D\uDCF1 mobile: tap ")
}
withStyle(
SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)
) {
append("Open in mobile app")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(", then tap ")
}
withStyle(
SpanStyle(color = MaterialTheme.colors.onBackground, fontWeight = FontWeight.Bold)
) {
append("Connect")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(" in the app.")
}
append("\uD83D\uDCF1 mobile: tap ")
withStyle(bold) { append("Open in mobile app") }
append(", then tap ")
withStyle(bold) { append("Connect") }
append(" in the app.")
}
)
}
@@ -165,6 +112,6 @@ fun ChatHelpView(addContact: () -> Unit, doAddContact: Boolean) {
@Composable
fun PreviewChatHelpLayout() {
SimpleXTheme {
ChatHelpView({}, false)
ChatHelpView({})
}
}
@@ -11,20 +11,20 @@ import androidx.compose.ui.Alignment
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.helpers.AlertManager
import chat.simplex.app.views.helpers.withApi
import kotlinx.datetime.Clock
@Composable
fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel, nav: NavController) {
fun ChatListNavLinkView(chat: Chat, chatModel: ChatModel) {
ChatListNavLinkLayout(
chat = chat,
click = {
if (chat.chatInfo is ChatInfo.ContactRequest) {
contactRequestAlertDialog(chat.chatInfo, chatModel, nav)
contactRequestAlertDialog(chat.chatInfo, chatModel)
} else {
withApi { openChat(chatModel, chat.chatInfo) }
}
@@ -40,8 +40,8 @@ suspend fun openChat(chatModel: ChatModel, cInfo: ChatInfo) {
}
}
fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel, navController: NavController) {
chatModel.alertManager.showAlertDialog(
fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = "Accept connection request?",
text = "If you choose to reject sender will NOT be notified",
confirmText = "Accept",
@@ -8,15 +8,13 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.PersonAdd
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material.icons.outlined.*
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.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.simplex.app.model.ChatModel
import chat.simplex.app.views.chat.ChatHelpView
import chat.simplex.app.views.newchat.NewChatSheet
@@ -39,7 +37,7 @@ class ScaffoldController(val scope: CoroutineScope) {
}
fun toggleSheet() {
if (state.bottomSheetState.isExpanded ?: false) collapse() else expand()
if (state.bottomSheetState.isExpanded) collapse() else expand()
}
fun toggleDrawer() = scope.launch {
@@ -62,25 +60,24 @@ fun scaffoldController(): ScaffoldController {
}
@Composable
fun ChatListView(chatModel: ChatModel, nav: NavController) {
fun ChatListView(chatModel: ChatModel) {
val scaffoldCtrl = scaffoldController()
BottomSheetScaffold(
scaffoldState = scaffoldCtrl.state,
drawerContent = { SettingsView(chatModel, nav) },
drawerContent = { SettingsView(chatModel) },
sheetPeekHeight = 0.dp,
sheetContent = { NewChatSheet(chatModel, scaffoldCtrl, nav) },
sheetContent = { NewChatSheet(chatModel, scaffoldCtrl) },
sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp),
) {
Box {
Column(
modifier = Modifier
.padding(vertical = 8.dp)
.fillMaxSize()
.background(MaterialTheme.colors.background)
) {
ChatListToolbar(scaffoldCtrl)
if (chatModel.chats.isNotEmpty()) {
ChatList(chatModel, nav)
ChatList(chatModel)
} else {
val user = chatModel.currentUser.value
Help(scaffoldCtrl, displayName = user?.profile?.displayName)
@@ -111,7 +108,7 @@ fun Help(scaffoldCtrl: ScaffoldController, displayName: String?) {
style = MaterialTheme.typography.h1,
color = MaterialTheme.colors.onBackground
)
ChatHelpView({ scaffoldCtrl.toggleSheet() }, true)
ChatHelpView({ scaffoldCtrl.toggleSheet() })
Row(
Modifier.padding(top = 30.dp),
verticalAlignment = Alignment.CenterVertically,
@@ -143,7 +140,7 @@ fun ChatListToolbar(scaffoldCtrl: ScaffoldController) {
) {
IconButton(onClick = { scaffoldCtrl.toggleDrawer() }) {
Icon(
Icons.Outlined.Settings,
Icons.Outlined.Menu,
"Settings",
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
@@ -167,13 +164,13 @@ fun ChatListToolbar(scaffoldCtrl: ScaffoldController) {
}
@Composable
fun ChatList(chatModel: ChatModel, navController: NavController) {
fun ChatList(chatModel: ChatModel) {
Divider(Modifier.padding(horizontal = 8.dp))
LazyColumn(
modifier = Modifier.fillMaxWidth()
) {
items(chatModel.chats) { chat ->
ChatListNavLinkView(chat, chatModel, navController)
ChatListNavLinkView(chat, chatModel)
}
}
}
@@ -0,0 +1,81 @@
package chat.simplex.app.views.helpers
import android.util.Log
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
class AlertManager {
var alertView = mutableStateOf<(@Composable () -> Unit)?>(null)
var presentAlert = mutableStateOf<Boolean>(false)
fun showAlert(alert: @Composable () -> Unit) {
Log.d("SIMPLEX", "AlertManager.showAlert")
alertView.value = alert
presentAlert.value = true
}
fun hideAlert() {
presentAlert.value = false
alertView.value = 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(
onDismissRequest = this::hideAlert,
title = { Text(title) },
text = alertText,
confirmButton = {
Button(onClick = {
onConfirm?.invoke()
hideAlert()
}) { Text(confirmText) }
}
)
}
}
@Composable
fun showInView() {
if (presentAlert.value) alertView.value?.invoke()
}
companion object {
val shared = AlertManager()
}
}
@@ -0,0 +1,59 @@
package chat.simplex.app.views.newchat
import android.util.Log
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import chat.simplex.app.views.helpers.CloseSheetBar
@Composable
fun ModalView(close: () -> Unit, content: @Composable () -> Unit) {
BackHandler(onBack = close)
Surface(
Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
Column {
CloseSheetBar(close)
Box(Modifier.padding(horizontal = 16.dp)) { content() }
}
}
}
class ModalManager {
private val modalViews = arrayListOf<(@Composable (close: () -> Unit) -> Unit)?>()
private val modalCount = mutableStateOf(0)
fun showModal(content: @Composable () -> Unit) {
showCustomModal { close -> ModalView(close, content) }
}
fun showCustomModal(modal: @Composable (close: () -> Unit) -> Unit) {
Log.d("SIMPLEX", "ModalManager.showModal")
modalViews.add(modal)
modalCount.value = modalViews.count()
}
fun closeModal() {
if (!modalViews.isEmpty()) {
modalViews.removeAt(modalViews.count() - 1)
}
modalCount.value = modalViews.count()
}
@Composable
fun showInView() {
if (modalCount.value > 0) modalViews.lastOrNull()?.invoke(::closeModal)
}
companion object {
val shared = ModalManager()
}
}
@@ -1,7 +1,6 @@
package chat.simplex.app.views.newchat
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
@@ -16,60 +15,46 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
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.CloseSheetBar
import chat.simplex.app.views.helpers.shareText
@Composable
fun AddContactView(chatModel: ChatModel, nav: NavController) {
fun AddContactView(chatModel: ChatModel) {
val connReq = chatModel.connReqInvitation
if (connReq != null) {
val cxt = LocalContext.current
AddContactLayout(
connReq = connReq,
close = { nav.popBackStack() },
share = { shareText(cxt, connReq) }
)
}
}
@Composable
fun AddContactLayout(connReq: String, close: () -> Unit, share: () -> Unit) {
fun AddContactLayout(connReq: String, share: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.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,
color = MaterialTheme.colors.onBackground
)
Text(
"Show QR code to your contact\nto scan from the app",
style = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.onBackground
)
QRCode(connReq)
Text(
buildAnnotatedString {
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("If you cannot meet in person, you can ")
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
append("scan QR code in the video call")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
append(", or you can share the invitation link via any other channel.")
}
append(", or you can share the invitation link via any other channel.")
},
textAlign = TextAlign.Center,
style = MaterialTheme.typography.caption,
@@ -92,7 +77,6 @@ fun PreviewAddContactView() {
SimpleXTheme {
AddContactLayout(
connReq = "https://simplex.chat/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D",
close = {},
share = {}
)
}
@@ -2,7 +2,7 @@ package chat.simplex.app.views.newchat
import android.content.res.Configuration
import android.net.Uri
import androidx.compose.foundation.background
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.Composable
@@ -13,44 +13,41 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
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.SimpleXTheme
import chat.simplex.app.views.helpers.CloseSheetBar
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.withApi
@Composable
fun ConnectContactView(chatModel: ChatModel, nav: NavController) {
fun ConnectContactView(chatModel: ChatModel, close: () -> Unit) {
BackHandler(onBack = close)
ConnectContactLayout(
qrCodeScanner = {
QRCodeScanner { connReqUri ->
try {
val uri = Uri.parse(connReqUri)
withUriAction(chatModel, uri) { action ->
withUriAction(uri) { action ->
connectViaUri(chatModel, action, uri)
}
} catch (e: RuntimeException) {
chatModel.alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
title = "Invalid QR code",
text = "This QR code is not a link!"
)
}
nav.popBackStack()
close()
}
},
close = { nav.popBackStack() }
close = close
)
}
fun withUriAction(
chatModel: ChatModel, uri: Uri,
run: suspend (String) -> Unit
) {
fun withUriAction(uri: Uri, run: suspend (String) -> Unit) {
val action = uri.path?.drop(1)
if (action == "contact" || action == "invitation") {
withApi { run(action) }
} else {
chatModel.alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
title = "Invalid link!",
text = "This link is not a valid connection link!"
)
@@ -63,7 +60,7 @@ suspend fun connectViaUri(chatModel: ChatModel, action: String, uri: Uri) {
val whenConnected =
if (action == "contact") "your connection request is accepted"
else "your contact's device is online"
chatModel.alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
title = "Connection request sent!",
text = "You will be connected when $whenConnected, please wait or check later!"
)
@@ -72,50 +69,41 @@ suspend fun connectViaUri(chatModel: ChatModel, action: String, uri: Uri) {
@Composable
fun ConnectContactLayout(qrCodeScanner: @Composable () -> Unit, close: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.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,
color = MaterialTheme.colors.onBackground
)
Text(
"Your chat profile will be sent\nto your contact",
style = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.onBackground,
modifier = Modifier.padding(bottom = 4.dp)
)
Box(
Modifier
.fillMaxWidth()
.aspectRatio(ratio = 1F)
) { qrCodeScanner() }
Text(
buildAnnotatedString {
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
ModalView(close) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
"Scan QR code",
style = MaterialTheme.typography.h1,
)
Text(
"Your chat profile will be sent\nto your contact",
style = MaterialTheme.typography.h2,
textAlign = TextAlign.Center,
modifier = Modifier.padding(bottom = 4.dp)
)
Box(
Modifier
.fillMaxWidth()
.aspectRatio(ratio = 1F)
) { qrCodeScanner() }
Text(
buildAnnotatedString {
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")
}
withStyle(SpanStyle(color = MaterialTheme.colors.onBackground)) {
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
append("scan QR code in the video call")
}
append(", or you can create the invitation link.")
}
},
textAlign = TextAlign.Center,
style = MaterialTheme.typography.caption,
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(top = 4.dp)
)
},
textAlign = TextAlign.Center,
style = MaterialTheme.typography.caption,
modifier = Modifier
.padding(horizontal = 16.dp)
.padding(top = 4.dp)
)
}
}
}
@@ -14,8 +14,6 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
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.ChatModel
import chat.simplex.app.ui.theme.HighOrLowlight
import chat.simplex.app.ui.theme.SimpleXTheme
@@ -24,7 +22,7 @@ import chat.simplex.app.views.helpers.withApi
import com.google.accompanist.permissions.rememberPermissionState
@Composable
fun NewChatSheet(chatModel: ChatModel, newChatCtrl: ScaffoldController, nav: NavController) {
fun NewChatSheet(chatModel: ChatModel, newChatCtrl: ScaffoldController) {
val cameraPermissionState = rememberPermissionState(permission = Manifest.permission.CAMERA)
NewChatSheetLayout(
addContact = {
@@ -34,13 +32,13 @@ fun NewChatSheet(chatModel: ChatModel, newChatCtrl: ScaffoldController, nav: Nav
// hide spinner
if (chatModel.connReqInvitation != null) {
newChatCtrl.collapse()
nav.navigate(Pages.AddContact.route)
ModalManager.shared.showModal { AddContactView(chatModel) }
}
}
},
scanCode = {
newChatCtrl.collapse()
nav.navigate(Pages.Connect.route)
ModalManager.shared.showCustomModal { close -> ConnectContactView(chatModel, close) }
cameraPermissionState.launchPermissionRequest()
}
)
@@ -48,24 +46,34 @@ fun NewChatSheet(chatModel: ChatModel, newChatCtrl: ScaffoldController, nav: Nav
@Composable
fun NewChatSheetLayout(addContact: () -> Unit, scanCode: () -> Unit) {
Row(Modifier
Row(
Modifier
.fillMaxWidth()
.padding(horizontal = 8.dp, vertical = 48.dp),
horizontalArrangement = Arrangement.SpaceEvenly
) {
Box(Modifier.weight(1F).fillMaxWidth()) {
Box(
Modifier
.weight(1F)
.fillMaxWidth()) {
ActionButton(
"Add contact", "(create QR code\nor link)",
Icons.Outlined.PersonAdd, click = addContact
)
}
Box(Modifier.weight(1F).fillMaxWidth()) {
Box(
Modifier
.weight(1F)
.fillMaxWidth()) {
ActionButton(
"Scan QR code", "(in person or in video call)",
Icons.Outlined.QrCode, click = scanCode
)
}
Box(Modifier.weight(1F).fillMaxWidth()) {
Box(
Modifier
.weight(1F)
.fillMaxWidth()) {
ActionButton(
"Create Group", "(coming soon!)",
Icons.Outlined.GroupAdd, disabled = true
@@ -1,8 +1,8 @@
package chat.simplex.app.views.usersettings
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@@ -10,40 +10,27 @@ import androidx.compose.ui.Alignment
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.model.ChatModel
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.chat.ChatHelpView
import chat.simplex.app.views.helpers.CloseSheetBar
@Composable
fun HelpView(chatModel: ChatModel, nav: NavController) {
fun HelpView(chatModel: ChatModel) {
val user = chatModel.currentUser.value
if (user != null) {
HelpLayout(
displayName = user.profile.displayName,
back = nav::popBackStack
)
HelpLayout(displayName = user.profile.displayName)
}
}
@Composable
fun HelpLayout(displayName: String, back: () -> Unit) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
.padding(horizontal = 8.dp),
horizontalAlignment = Alignment.Start
) {
CloseSheetBar(back)
fun HelpLayout(displayName: String) {
Column(horizontalAlignment = Alignment.Start) {
Text(
"Welcome $displayName!",
Modifier.padding(bottom = 24.dp),
style = MaterialTheme.typography.h1,
color = MaterialTheme.colors.onBackground
)
ChatHelpView({}, false)
ChatHelpView()
}
}
@@ -56,9 +43,6 @@ fun HelpLayout(displayName: String, back: () -> Unit) {
@Composable
fun PreviewHelpView() {
SimpleXTheme {
HelpLayout(
displayName = "Alice",
back = {}
)
HelpLayout(displayName = "Alice")
}
}
@@ -1,69 +1,53 @@
package chat.simplex.app.views.usersettings
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.selection.SelectionContainer
import androidx.compose.material.*
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.*
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.simplex.app.model.Format
import chat.simplex.app.model.FormatColor
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.CloseSheetBar
@Composable
fun MarkdownHelpView(nav: NavController) {
MarkdownHelpLayout(nav::popBackStack)
}
@Composable
fun MarkdownHelpLayout(back: () -> Unit) {
Surface(
Modifier
.background(MaterialTheme.colors.background)
.fillMaxSize()
) {
Column {
CloseSheetBar(back)
Column(Modifier.padding(horizontal = 16.dp)) {
Text(
"How to use markdown",
style = MaterialTheme.typography.h1,
)
Text(
"You can use markdown to format messages:",
Modifier.padding(vertical = 16.dp)
)
MdFormat("*bold*", "bold text", Format.Bold())
MdFormat("_italic_", "italic text", Format.Italic())
MdFormat("~strike~", "strikethrough text", Format.StrikeThrough())
MdFormat("`code`", "a = b + c", Format.Snippet())
Row {
MdSyntax("!1 colored!")
Text(buildAnnotatedString {
withStyle(Format.Colored(FormatColor.red).style) { append("red text") }
append(" (")
appendColor(this, "1", FormatColor.red, ", ")
appendColor(this, "2", FormatColor.green, ", ")
appendColor(this, "3", FormatColor.blue, ", ")
appendColor(this, "4", FormatColor.yellow, ", ")
appendColor(this, "5", FormatColor.cyan, ", ")
appendColor(this, "6", FormatColor.magenta, ")")
})
}
Row {
MdSyntax("#secret#")
SelectionContainer {
Text(buildAnnotatedString {
withStyle(Format.Secret().style) { append("secret text") }
})
}
}
fun MarkdownHelpView() {
Column(Modifier.padding(horizontal = 16.dp)) {
Text(
"How to use markdown",
style = MaterialTheme.typography.h1,
)
Text(
"You can use markdown to format messages:",
Modifier.padding(vertical = 16.dp)
)
MdFormat("*bold*", "bold text", Format.Bold())
MdFormat("_italic_", "italic text", Format.Italic())
MdFormat("~strike~", "strikethrough text", Format.StrikeThrough())
MdFormat("`code`", "a = b + c", Format.Snippet())
Row {
MdSyntax("!1 colored!")
Text(buildAnnotatedString {
withStyle(Format.Colored(FormatColor.red).style) { append("red text") }
append(" (")
appendColor(this, "1", FormatColor.red, ", ")
appendColor(this, "2", FormatColor.green, ", ")
appendColor(this, "3", FormatColor.blue, ", ")
appendColor(this, "4", FormatColor.yellow, ", ")
appendColor(this, "5", FormatColor.cyan, ", ")
appendColor(this, "6", FormatColor.magenta, ")")
})
}
Row {
MdSyntax("#secret#")
SelectionContainer {
Text(buildAnnotatedString {
withStyle(Format.Secret().style) { append("secret text") }
})
}
}
}
@@ -102,6 +86,6 @@ fun appendColor(b: AnnotatedString.Builder, s: String, c: FormatColor, after: St
@Composable
fun PreviewMarkdownHelpView() {
SimpleXTheme {
MarkdownHelpLayout(back = {})
MarkdownHelpView()
}
}
@@ -17,20 +17,24 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
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.SimpleXTheme
import chat.simplex.app.views.TerminalView
import chat.simplex.app.views.newchat.ModalManager
@Composable
fun SettingsView(chatModel: ChatModel, nav: NavController) {
fun SettingsView(chatModel: ChatModel) {
val user = chatModel.currentUser.value
if (user != null) {
SettingsLayout(
profile = user.profile,
navigate = nav::navigate
// showModal = { modal -> ModalManager.shared.showModal { modal(chatModel) } },
showProfile = { ModalManager.shared.showModal { UserProfileView(chatModel) } },
showAddress = { ModalManager.shared.showModal { UserAddressView(chatModel) } },
showHelp = { ModalManager.shared.showModal { HelpView(chatModel) } },
showTerminal = { ModalManager.shared.showCustomModal { close -> TerminalView(chatModel, close) } }
)
}
}
@@ -41,7 +45,11 @@ val simplexTeamUri =
@Composable
fun SettingsLayout(
profile: Profile,
navigate: (String) -> Unit
// showModal: (modal: @Composable (ChatModel) -> Unit) -> Unit,
showProfile: () -> Unit,
showAddress: () -> Unit,
showHelp: () -> Unit,
showTerminal: () -> Unit
) {
val uriHandler = LocalUriHandler.current
Surface(
@@ -62,7 +70,7 @@ fun SettingsLayout(
)
Spacer(Modifier.height(30.dp))
SettingsSectionView({ navigate(Pages.UserProfile.route) }, 60.dp) {
SettingsSectionView(showProfile, 60.dp) {
Icon(
Icons.Outlined.AccountCircle,
contentDescription = "Avatar Placeholder",
@@ -78,7 +86,7 @@ fun SettingsLayout(
}
}
Divider(Modifier.padding(horizontal = 8.dp))
SettingsSectionView({ navigate(Pages.UserAddress.route) }) {
SettingsSectionView(showAddress) {
Icon(
Icons.Outlined.QrCode,
contentDescription = "Address",
@@ -88,7 +96,7 @@ fun SettingsLayout(
}
Spacer(Modifier.height(24.dp))
SettingsSectionView({ navigate(Pages.Help.route) }) {
SettingsSectionView(showHelp) {
Icon(
Icons.Outlined.HelpOutline,
contentDescription = "Chat help",
@@ -96,7 +104,7 @@ fun SettingsLayout(
Spacer(Modifier.padding(horizontal = 4.dp))
Text("How to use SimpleX Chat")
}
SettingsSectionView({ navigate(Pages.Markdown.route) }) {
SettingsSectionView({ ModalManager.shared.showModal { MarkdownHelpView() } }) {
Icon(
Icons.Outlined.TextFormat,
contentDescription = "Markdown help",
@@ -130,7 +138,7 @@ fun SettingsLayout(
}
Spacer(Modifier.height(24.dp))
SettingsSectionView({ navigate(Pages.Terminal.route) }) {
SettingsSectionView(showTerminal) {
Icon(
painter = painterResource(id = R.drawable.ic_outline_terminal),
contentDescription = "Chat console",
@@ -183,7 +191,10 @@ fun PreviewSettingsLayout() {
SimpleXTheme {
SettingsLayout(
profile = Profile.sampleData,
navigate = {}
showProfile = {},
showAddress = {},
showHelp = {},
showTerminal = {}
)
}
}
@@ -1,7 +1,6 @@
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
@@ -14,7 +13,6 @@ 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
@@ -22,11 +20,10 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
@Composable
fun UserAddressView(chatModel: ChatModel, nav: NavController) {
fun UserAddressView(chatModel: ChatModel) {
val cxt = LocalContext.current
UserAddressLayout(
userAddress = chatModel.userAddress.value,
back = { nav.popBackStack() },
createAddress = {
withApi {
chatModel.userAddress.value = chatModel.controller.apiCreateUserAddress()
@@ -34,7 +31,7 @@ fun UserAddressView(chatModel: ChatModel, nav: NavController) {
},
share = { userAddress: String -> shareText(cxt, userAddress) },
deleteAddress = {
chatModel.alertManager.showAlertMsg(
AlertManager.shared.showAlertMsg(
title = "Delete address?",
text = "All your contacts will remain connected",
confirmText = "Delete",
@@ -52,31 +49,23 @@ fun UserAddressView(chatModel: ChatModel, nav: NavController) {
@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
@@ -119,7 +108,6 @@ fun PreviewUserAddressLayoutNoAddress() {
SimpleXTheme {
UserAddressLayout(
userAddress = null,
back = {},
createAddress = {},
share = { _ -> },
deleteAddress = {},
@@ -138,7 +126,6 @@ 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 = {},
@@ -1,7 +1,6 @@
package chat.simplex.app.views.usersettings
import android.content.res.Configuration
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.BasicTextField
@@ -15,15 +14,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
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.model.Profile
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.CloseSheetBar
import chat.simplex.app.views.helpers.withApi
@Composable
fun UserProfileView(chatModel: ChatModel, nav: NavController) {
fun UserProfileView(chatModel: ChatModel) {
val user = chatModel.currentUser.value
if (user != null) {
var editProfile by remember { mutableStateOf(false) }
@@ -31,7 +28,6 @@ fun UserProfileView(chatModel: ChatModel, nav: NavController) {
UserProfileLayout(
editProfile = editProfile,
profile = profile,
back = { nav.popBackStack() },
editProfileOff = { editProfile = false },
editProfileOn = { editProfile = true },
saveProfile = { displayName: String, fullName: String ->
@@ -54,19 +50,11 @@ fun UserProfileView(chatModel: ChatModel, nav: NavController) {
fun UserProfileLayout(
editProfile: Boolean,
profile: Profile,
back: () -> Unit,
editProfileOff: () -> Unit,
editProfileOn: () -> Unit,
saveProfile: (String, String) -> Unit,
) {
Column(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.background)
.padding(horizontal = 8.dp),
horizontalAlignment = Alignment.Start
) {
CloseSheetBar(back)
Column(horizontalAlignment = Alignment.Start) {
Text(
"Your chat profile",
Modifier.padding(bottom = 24.dp),
@@ -185,7 +173,6 @@ fun PreviewUserProfileLayoutEditOff() {
UserProfileLayout(
profile = Profile.sampleData,
editProfile = false,
back = {},
editProfileOff = {},
editProfileOn = {},
saveProfile = { _, _ -> }
@@ -205,7 +192,6 @@ fun PreviewUserProfileLayoutEditOn() {
UserProfileLayout(
profile = Profile.sampleData,
editProfile = true,
back = {},
editProfileOff = {},
editProfileOn = {},
saveProfile = { _, _ -> }
+31 -30
View File
@@ -13,16 +13,6 @@
5C116CDD27AABE0400E66D01 /* ContactRequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */; };
5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C1A4C1F27A715B700EAD5AD /* ChatItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */; };
5C27D00827C7D8B500DD6182 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00327C7D8B500DD6182 /* libgmpxx.a */; };
5C27D00927C7D8B500DD6182 /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00327C7D8B500DD6182 /* libgmpxx.a */; };
5C27D00A27C7D8B500DD6182 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00427C7D8B500DD6182 /* libgmp.a */; };
5C27D00B27C7D8B500DD6182 /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00427C7D8B500DD6182 /* libgmp.a */; };
5C27D00C27C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00527C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a */; };
5C27D00D27C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00527C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a */; };
5C27D00E27C7D8B500DD6182 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00627C7D8B500DD6182 /* libffi.a */; };
5C27D00F27C7D8B500DD6182 /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00627C7D8B500DD6182 /* libffi.a */; };
5C27D01027C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00727C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a */; };
5C27D01127C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C27D00727C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a */; };
5C2E260727A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260827A2941F00F70299 /* SimpleXAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260627A2941F00F70299 /* SimpleXAPI.swift */; };
5C2E260B27A30CFA00F70299 /* ChatListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C2E260A27A30CFA00F70299 /* ChatListView.swift */; };
@@ -39,6 +29,16 @@
5C5346A927B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; };
5C577F7D27C83AA10006112D /* MarkdownHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C577F7C27C83AA10006112D /* MarkdownHelp.swift */; };
5C577F7E27C83AA10006112D /* MarkdownHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C577F7C27C83AA10006112D /* MarkdownHelp.swift */; };
5C67D2FA27CB9FA100E4261F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F527CB9FA100E4261F /* libgmp.a */; };
5C67D2FB27CB9FA100E4261F /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F527CB9FA100E4261F /* libgmp.a */; };
5C67D2FC27CB9FA100E4261F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F627CB9FA100E4261F /* libgmpxx.a */; };
5C67D2FD27CB9FA100E4261F /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F627CB9FA100E4261F /* libgmpxx.a */; };
5C67D2FE27CB9FA100E4261F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F727CB9FA100E4261F /* libffi.a */; };
5C67D2FF27CB9FA100E4261F /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F727CB9FA100E4261F /* libffi.a */; };
5C67D30027CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F827CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a */; };
5C67D30127CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F827CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a */; };
5C67D30227CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F927CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a */; };
5C67D30327CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5C67D2F927CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a */; };
5C6AD81327A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; };
5C6AD81427A834E300348BD7 /* NewChatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C6AD81227A834E300348BD7 /* NewChatButton.swift */; };
5C7505A227B65FDB00BE3227 /* CIMetaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C7505A127B65FDB00BE3227 /* CIMetaView.swift */; };
@@ -125,11 +125,6 @@
5C063D2627A4564100AEC577 /* ChatPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatPreviewView.swift; sourceTree = "<group>"; };
5C116CDB27AABE0400E66D01 /* ContactRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestView.swift; sourceTree = "<group>"; };
5C1A4C1D27A715B700EAD5AD /* ChatItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemView.swift; sourceTree = "<group>"; };
5C27D00327C7D8B500DD6182 /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C27D00427C7D8B500DD6182 /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C27D00527C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a"; sourceTree = "<group>"; };
5C27D00627C7D8B500DD6182 /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C27D00727C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a"; sourceTree = "<group>"; };
5C2E260627A2941F00F70299 /* SimpleXAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleXAPI.swift; sourceTree = "<group>"; };
5C2E260927A2C63500F70299 /* MyPlayground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = MyPlayground.playground; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
5C2E260A27A30CFA00F70299 /* ChatListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatListView.swift; sourceTree = "<group>"; };
@@ -140,6 +135,11 @@
5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = "<group>"; };
5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = "<group>"; };
5C577F7C27C83AA10006112D /* MarkdownHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MarkdownHelp.swift; sourceTree = "<group>"; };
5C67D2F527CB9FA100E4261F /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5C67D2F627CB9FA100E4261F /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5C67D2F727CB9FA100E4261F /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5C67D2F827CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a"; sourceTree = "<group>"; };
5C67D2F927CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a"; sourceTree = "<group>"; };
5C6AD81227A834E300348BD7 /* NewChatButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewChatButton.swift; sourceTree = "<group>"; };
5C7505A127B65FDB00BE3227 /* CIMetaView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIMetaView.swift; sourceTree = "<group>"; };
5C7505A427B679EE00BE3227 /* NavLinkPlain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavLinkPlain.swift; sourceTree = "<group>"; };
@@ -186,13 +186,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C27D00827C7D8B500DD6182 /* libgmpxx.a in Frameworks */,
5C27D01027C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a in Frameworks */,
5C27D00A27C7D8B500DD6182 /* libgmp.a in Frameworks */,
5C67D30227CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a in Frameworks */,
5C8F01CD27A6F0D8007D2C8D /* CodeScanner in Frameworks */,
5C67D2FE27CB9FA100E4261F /* libffi.a in Frameworks */,
5C67D2FC27CB9FA100E4261F /* libgmpxx.a in Frameworks */,
5C764E83279C748B000C6508 /* libz.tbd in Frameworks */,
5C27D00E27C7D8B500DD6182 /* libffi.a in Frameworks */,
5C27D00C27C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a in Frameworks */,
5C67D2FA27CB9FA100E4261F /* libgmp.a in Frameworks */,
5C67D30027CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a in Frameworks */,
5C764E82279C748B000C6508 /* libiconv.tbd in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -201,13 +201,13 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5C27D00927C7D8B500DD6182 /* libgmpxx.a in Frameworks */,
5C27D00F27C7D8B500DD6182 /* libffi.a in Frameworks */,
5C67D2FD27CB9FA100E4261F /* libgmpxx.a in Frameworks */,
5C764E85279C748C000C6508 /* libz.tbd in Frameworks */,
5C27D00B27C7D8B500DD6182 /* libgmp.a in Frameworks */,
5C27D01127C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a in Frameworks */,
5C27D00D27C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a in Frameworks */,
5C67D2FB27CB9FA100E4261F /* libgmp.a in Frameworks */,
5C67D2FF27CB9FA100E4261F /* libffi.a in Frameworks */,
5C764E84279C748C000C6508 /* libiconv.tbd in Frameworks */,
5C67D30127CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a in Frameworks */,
5C67D30327CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -259,11 +259,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
5C27D00627C7D8B500DD6182 /* libffi.a */,
5C27D00427C7D8B500DD6182 /* libgmp.a */,
5C27D00327C7D8B500DD6182 /* libgmpxx.a */,
5C27D00727C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY-ghc8.10.7.a */,
5C27D00527C7D8B500DD6182 /* libHSsimplex-chat-1.2.1-KSWVFEZPyZUBOUtDs8BKKY.a */,
5C67D2F727CB9FA100E4261F /* libffi.a */,
5C67D2F527CB9FA100E4261F /* libgmp.a */,
5C67D2F627CB9FA100E4261F /* libgmpxx.a */,
5C67D2F827CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM-ghc8.10.7.a */,
5C67D2F927CB9FA100E4261F /* libHSsimplex-chat-1.3.0-7NpjDBQ3CKKBWRdMwbLLzM.a */,
);
path = Libraries;
sourceTree = "<group>";
@@ -833,6 +833,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
LIBRARY_SEARCH_PATHS = "";
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = "$(PROJECT_DIR)/Libraries/ios";
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = "$(PROJECT_DIR)/Libraries/sim";
MARKETING_VERSION = 0.4;
+1 -4
View File
@@ -123,10 +123,7 @@ responseToView testView = \case
CRMemberSubError g c e -> [ttyGroup' g <> " member " <> ttyContact c <> " error: " <> sShow e]
CRMemberSubErrors summary -> viewErrorsSummary summary " group member errors"
CRGroupSubscribed g -> [ttyFullGroup g <> ": connected to server(s)"]
CRPendingSubSummary summary ->
(if null subscribed then [] else [sShow (length subscribed) <> " pending connections subscribed"]) <> viewErrorsSummary errors " connection errors"
where
(errors, subscribed) = partition (isJust . connError) summary
CRPendingSubSummary _ -> []
CRSndFileSubError SndFileTransfer {fileId, fileName} e ->
["sent file " <> sShow fileId <> " (" <> plain fileName <> ") error: " <> sShow e]
CRRcvFileSubError RcvFileTransfer {fileId, fileInvitation = FileInvitation {fileName}} e ->