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 000b037224..829839ec78 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 @@ -1,7 +1,7 @@ package chat.simplex.app import android.app.Application -import android.content.* +import android.content.Intent import android.net.Uri import android.os.Bundle import android.os.SystemClock.elapsedRealtime 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 a200f99cc3..73ecd073db 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 @@ -5,7 +5,8 @@ import android.net.LocalServerSocket import android.util.Log import androidx.lifecycle.* import chat.simplex.app.model.* -import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.helpers.getFilesDirectory +import chat.simplex.app.views.helpers.withApi import chat.simplex.app.views.onboarding.OnboardingStage import java.io.BufferedReader import java.io.InputStreamReader diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/NtfManager.kt b/apps/android/app/src/main/java/chat/simplex/app/model/NtfManager.kt index 404839d9db..dc9ebe5127 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/NtfManager.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/NtfManager.kt @@ -1,7 +1,6 @@ package chat.simplex.app.model import android.app.* -import android.app.Notification.VISIBILITY_PUBLIC import android.content.* import android.graphics.BitmapFactory import android.media.AudioAttributes 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 cb2ed9d2ca..f1f66fbeba 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 @@ -80,6 +80,7 @@ class AppPreferences(val context: Context) { val laNoticeShown = mkBoolPreference(SHARED_PREFS_LA_NOTICE_SHOWN, false) val privacyAcceptImages = mkBoolPreference(SHARED_PREFS_PRIVACY_ACCEPT_IMAGES, true) val privacyLinkPreviews = mkBoolPreference(SHARED_PREFS_PRIVACY_LINK_PREVIEWS, true) + val experimentalCalls = mkBoolPreference(SHARED_PREFS_EXPERIMENTAL_CALLS, false) private fun mkIntPreference(prefName: String, default: Int) = Preference( @@ -111,6 +112,8 @@ class AppPreferences(val context: Context) { private const val SHARED_PREFS_LA_NOTICE_SHOWN = "LANoticeShown" private const val SHARED_PREFS_PRIVACY_ACCEPT_IMAGES = "PrivacyAcceptImages" private const val SHARED_PREFS_PRIVACY_LINK_PREVIEWS = "PrivacyLinkPreviews" + private const val SHARED_PREFS_EXPERIMENTAL_CALLS = "ExperimentalCalls" + } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallManager.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallManager.kt index b0c8a442be..78f60ab1e8 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallManager.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallManager.kt @@ -13,6 +13,7 @@ class CallManager(val chatModel: ChatModel) { Log.d(TAG, "CallManager.reportNewIncomingCall") with (chatModel) { callInvitations[invitation.contact.id] = invitation + if (!chatModel.controller.appPrefs.experimentalCalls.get()) return if (Clock.System.now() - invitation.callTs <= 3.minutes) { activeCallInvitation.value = invitation controller.ntfManager.notifyCallInvitation(invitation) diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt index 340acd96c0..036228cb6a 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/CallView.kt @@ -31,7 +31,8 @@ import chat.simplex.app.R import chat.simplex.app.TAG import chat.simplex.app.model.* import chat.simplex.app.ui.theme.SimpleXTheme -import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.helpers.ProfileImage +import chat.simplex.app.views.helpers.withApi import com.google.accompanist.permissions.rememberMultiplePermissionsState import kotlinx.coroutines.delay import kotlinx.serialization.decodeFromString diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt index 1a185daca6..ff1b424f34 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallActivity.kt @@ -1,7 +1,8 @@ package chat.simplex.app.views.call import android.app.KeyguardManager -import android.content.* +import android.content.Context +import android.content.Intent import android.content.res.Configuration import android.os.Build import android.os.Bundle diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt index 703fea35bd..c0960220cf 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/call/IncomingCallAlertView.kt @@ -1,6 +1,5 @@ package chat.simplex.app.views.call -import androidx.annotation.StringRes import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt index 6d94fd8c74..b0d59c9030 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ChatView.kt @@ -45,6 +45,7 @@ fun ChatView(chatModel: ChatModel) { val chat: Chat? = chatModel.chats.firstOrNull { chat -> chat.chatInfo.id == chatModel.chatId.value } val user = chatModel.currentUser.value val useLinkPreviews = chatModel.controller.appPrefs.privacyLinkPreviews.get() + val enableCalls = chatModel.controller.appPrefs.experimentalCalls.get() val composeState = remember { mutableStateOf(ComposeState(useLinkPreviews = useLinkPreviews)) } val attachmentOption = remember { mutableStateOf(null) } val attachmentBottomSheetState = rememberModalBottomSheetState(initialValue = ModalBottomSheetValue.Hidden) @@ -85,6 +86,7 @@ fun ChatView(chatModel: ChatModel) { attachmentBottomSheetState, chatModel.chatItems, useLinkPreviews = useLinkPreviews, + enableCalls = enableCalls, back = { chatModel.chatId.value = null }, info = { ModalManager.shared.showCustomModal { close -> ChatInfoView(chatModel, close) } }, openDirectChat = { contactId -> @@ -139,6 +141,7 @@ fun ChatLayout( attachmentBottomSheetState: ModalBottomSheetState, chatItems: List, useLinkPreviews: Boolean, + enableCalls: Boolean = false, back: () -> Unit, info: () -> Unit, openDirectChat: (Long) -> Unit, @@ -166,7 +169,7 @@ fun ChatLayout( sheetShape = RoundedCornerShape(topStart = 18.dp, topEnd = 18.dp) ) { Scaffold( - topBar = { ChatInfoToolbar(chat, back, info, startCall) }, + topBar = { ChatInfoToolbar(chat, enableCalls, back, info, startCall) }, bottomBar = composeView, modifier = Modifier.navigationBarsWithImePadding() ) { contentPadding -> @@ -180,7 +183,7 @@ fun ChatLayout( } @Composable -fun ChatInfoToolbar(chat: Chat, back: () -> Unit, info: () -> Unit, startCall: (CallMediaType) -> Unit) { +fun ChatInfoToolbar(chat: Chat, enableCalls: Boolean, back: () -> Unit, info: () -> Unit, startCall: (CallMediaType) -> Unit) { @Composable fun toolbarButton(icon: ImageVector, @StringRes textId: Int, modifier: Modifier = Modifier.padding(0.dp), onClick: () -> Unit) { IconButton(onClick, modifier = modifier) { Icon(icon, stringResource(textId), tint = MaterialTheme.colors.primary) @@ -197,7 +200,7 @@ fun ChatInfoToolbar(chat: Chat, back: () -> Unit, info: () -> Unit, startCall: ( ) { val cInfo = chat.chatInfo toolbarButton(Icons.Outlined.ArrowBackIos, R.string.back, onClick = back) - if (cInfo is ChatInfo.Direct) { + if (cInfo is ChatInfo.Direct && enableCalls) { Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.CenterEnd) { Box(Modifier.width(85.dp), contentAlignment = Alignment.CenterStart) { toolbarButton(Icons.Outlined.Phone, R.string.icon_descr_audio_call) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt index c3852b38c1..6c254935a9 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/ComposeView.kt @@ -24,7 +24,7 @@ import androidx.compose.material.MaterialTheme import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.AttachFile import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.outlined.* +import androidx.compose.material.icons.outlined.Reply import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -40,7 +40,8 @@ import chat.simplex.app.R import chat.simplex.app.model.* import chat.simplex.app.views.chat.item.* import chat.simplex.app.views.helpers.* -import kotlinx.coroutines.* +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking import java.io.File sealed class ComposePreview { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt index 29becc9f0f..46051fed52 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/ImageFullScreenView.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.* import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.layout.ContentScale diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt index 2e6fb52c95..1f8e40c25b 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chat/item/IntegrityErrorItemView.kt @@ -10,7 +10,6 @@ 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.res.stringResource import androidx.compose.ui.text.* import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.tooling.preview.Preview @@ -18,7 +17,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import chat.simplex.app.R import chat.simplex.app.model.ChatItem -import chat.simplex.app.ui.theme.HighOrLowlight import chat.simplex.app.ui.theme.SimpleXTheme import chat.simplex.app.views.helpers.AlertManager import chat.simplex.app.views.helpers.generalGetString 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 index 10f0fa17e9..0fc8193047 100644 --- 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 @@ -11,7 +11,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.* +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* 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 c7252a5dae..a5ff2008aa 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 @@ -7,7 +7,8 @@ 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.* +import androidx.compose.material.icons.outlined.Menu +import androidx.compose.material.icons.outlined.PersonAdd import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -19,7 +20,6 @@ import chat.simplex.app.R import chat.simplex.app.model.ChatModel import chat.simplex.app.ui.theme.ToolbarDark import chat.simplex.app.ui.theme.ToolbarLight -import chat.simplex.app.views.helpers.ModalManager import chat.simplex.app.views.newchat.NewChatSheet import chat.simplex.app.views.onboarding.MakeConnection import chat.simplex.app.views.usersettings.SettingsView diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactConnectionView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactConnectionView.kt index 64f1107843..318f1a0093 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactConnectionView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/chatlist/ContactConnectionView.kt @@ -13,7 +13,6 @@ 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 androidx.compose.ui.unit.sp import chat.simplex.app.model.PendingContactConnection import chat.simplex.app.model.getTimestampText import chat.simplex.app.ui.theme.* diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt index 45b52ce276..6b1a50240a 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/GetImageView.kt @@ -18,7 +18,8 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.CallSuper import androidx.compose.foundation.layout.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.* +import androidx.compose.material.icons.outlined.Collections +import androidx.compose.material.icons.outlined.PhotoCamera import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.ui.Modifier diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt index b9ae1c1140..f101b7c916 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/helpers/LinkPreviews.kt @@ -11,7 +11,6 @@ import androidx.compose.material.icons.outlined.Close 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.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.stringResource diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt index 1b37f151bf..fac78c976c 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/CallSettings.kt @@ -5,10 +5,7 @@ import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import chat.simplex.app.R import chat.simplex.app.model.* @@ -62,17 +59,18 @@ fun CallSettingsLayout( @Composable fun SharedPreferenceToggle( text: String, - preference: Preference + preference: Preference, + preferenceState: MutableState? = null ) { - var preferenceState by remember { mutableStateOf(preference.get()) } + val prefState = preferenceState ?: remember { mutableStateOf(preference.get()) } Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Text(text, Modifier.padding(end = 24.dp)) Spacer(Modifier.fillMaxWidth().weight(1f)) Switch( - checked = preferenceState, + checked = prefState.value, onCheckedChange = { preference.set(it) - preferenceState = it + prefState.value = it }, colors = SwitchDefaults.colors( checkedThumbColor = MaterialTheme.colors.primary, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ExperimentalFeaturesView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ExperimentalFeaturesView.kt new file mode 100644 index 0000000000..81b753a6db --- /dev/null +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/ExperimentalFeaturesView.kt @@ -0,0 +1,32 @@ +package chat.simplex.app.views.usersettings + +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.Videocam +import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import chat.simplex.app.R +import chat.simplex.app.model.ChatModel + +@Composable +fun ExperimentalFeaturesView(chatModel: ChatModel, enableCalls: MutableState) { + Column( + Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.Start + ) { + Text( + stringResource(R.string.settings_experimental_features), + style = MaterialTheme.typography.h1, + modifier = Modifier.padding(start = 16.dp, bottom = 24.dp) + ) + SettingsSectionView("") { + SettingsPreferenceItem(Icons.Outlined.Videocam, stringResource(R.string.settings_audio_video_calls), chatModel.controller.appPrefs.experimentalCalls, enableCalls) + } + } +} \ No newline at end of file diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt index 0582eaa826..e2e2d1a56e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/PrivacySettings.kt @@ -1,21 +1,17 @@ package chat.simplex.app.views.usersettings -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.* -import androidx.compose.runtime.* +import androidx.compose.material.icons.outlined.Image +import androidx.compose.material.icons.outlined.TravelExplore +import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import chat.simplex.app.R -import chat.simplex.app.model.* -import chat.simplex.app.ui.theme.HighOrLowlight -import chat.simplex.app.ui.theme.SettingsBackgroundLight -import chat.simplex.app.views.helpers.ModalView +import chat.simplex.app.model.ChatModel @Composable fun PrivacySettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { @@ -35,37 +31,9 @@ fun PrivacySettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { Spacer(Modifier.height(30.dp)) SettingsSectionView(stringResource(R.string.settings_section_title_chats)) { - AutoAcceptImagesSection(chatModel.controller.appPrefs.privacyAcceptImages) + SettingsPreferenceItem(Icons.Outlined.Image, stringResource(R.string.auto_accept_images), chatModel.controller.appPrefs.privacyAcceptImages) divider() - LinkPreviewsSection(chatModel.controller.appPrefs.privacyLinkPreviews) + SettingsPreferenceItem(Icons.Outlined.TravelExplore, stringResource(R.string.send_link_previews), chatModel.controller.appPrefs.privacyLinkPreviews) } } } - -@Composable private fun AutoAcceptImagesSection(prefAcceptImages: Preference) { - SettingsItemView() { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - Icons.Outlined.Image, - contentDescription = stringResource(R.string.auto_accept_images), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - SharedPreferenceToggle(stringResource(R.string.auto_accept_images), prefAcceptImages) - } - } -} - -@Composable private fun LinkPreviewsSection(prefLinkPreviews: Preference) { - SettingsItemView() { - Row(verticalAlignment = Alignment.CenterVertically) { - Icon( - Icons.Outlined.TravelExplore, - contentDescription = stringResource(R.string.send_link_previews), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - SharedPreferenceToggle(stringResource(R.string.send_link_previews), prefLinkPreviews) - } - } -} \ No newline at end of file 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 f92b6a7715..505ada39ae 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 @@ -3,14 +3,14 @@ package chat.simplex.app.views.usersettings import android.content.res.Configuration import androidx.compose.foundation.* import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.* import androidx.compose.material.icons.Icons 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.* +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.UriHandler import androidx.compose.ui.res.painterResource @@ -45,6 +45,7 @@ fun SettingsView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit) { runServiceInBackground = chatModel.runServiceInBackground, setRunServiceInBackground = ::setRunServiceInBackground, setPerformLA = setPerformLA, + enableCalls = remember { mutableStateOf(chatModel.controller.appPrefs.experimentalCalls.get()) }, showModal = { modalView -> { ModalManager.shared.showModal { modalView(chatModel) } } }, showSettingsModal = { modalView -> { ModalManager.shared.showCustomModal { close -> ModalView(close = close, modifier = Modifier, @@ -68,6 +69,7 @@ fun SettingsLayout( runServiceInBackground: MutableState, setRunServiceInBackground: (Boolean) -> Unit, setPerformLA: (Boolean) -> Unit, + enableCalls: MutableState, showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), showCustomModal: (@Composable (ChatModel, () -> Unit) -> Unit) -> (() -> Unit), @@ -96,31 +98,33 @@ fun SettingsLayout( ProfilePreview(profile) } divider() - UserAddressSection(showModal) + SettingsActionItem(Icons.Outlined.QrCode, stringResource(R.string.your_simplex_contact_address), showModal { UserAddressView(it) }) } spacer() SettingsSectionView(stringResource(R.string.settings_section_title_settings)) { - CallSettingsItem(showSettingsModal) - divider() - PrivacySettingsItem(showSettingsModal, setPerformLA) + if (enableCalls.value) { + SettingsActionItem(Icons.Outlined.Videocam, stringResource(R.string.settings_audio_video_calls), showSettingsModal { CallSettingsView(it) }) + divider() + } + SettingsActionItem(Icons.Outlined.Lock, stringResource(R.string.privacy_and_security), showSettingsModal { PrivacySettingsView(it, setPerformLA) }) divider() PrivateNotificationsItem(runServiceInBackground, setRunServiceInBackground) divider() - SMPServersItem(showModal) + SettingsActionItem(Icons.Outlined.Dns, stringResource(R.string.smp_servers), showModal { SMPServersView(it) }) } spacer() SettingsSectionView(stringResource(R.string.settings_section_title_help)) { - HelpViewItem(showModal) + SettingsActionItem(Icons.Outlined.HelpOutline, stringResource(R.string.how_to_use_simplex_chat), showModal { HelpView(it) }) divider() - SimpleXInfoItem(showModal) + SettingsActionItem(Icons.Outlined.Info, stringResource(R.string.about_simplex_chat), showModal { SimpleXInfo(it, onboarding = false) }) divider() - MarkdownHelpItem(showModal) + SettingsActionItem(Icons.Outlined.TextFormat, stringResource(R.string.markdown_in_messages), showModal { MarkdownHelpView() }) divider() - ConnectToDevelopersItem(uriHandler) + SettingsActionItem(Icons.Outlined.Tag, stringResource(R.string.chat_with_the_founder), { uriHandler.openUri(simplexTeamUri) }, textColor = MaterialTheme.colors.primary) divider() - SendEmailItem(uriHandler) + SettingsActionItem(Icons.Outlined.Email, stringResource(R.string.send_us_an_email), { uriHandler.openUri("mailto:chat@simplex.chat") }, textColor = MaterialTheme.colors.primary) } spacer() @@ -129,6 +133,8 @@ fun SettingsLayout( divider() InstallTerminalAppItem(uriHandler) divider() + SettingsActionItem(Icons.Outlined.Science, stringResource(R.string.settings_experimental_features), showSettingsModal { ExperimentalFeaturesView(it, enableCalls) }) + divider() AppVersionItem() } } @@ -145,120 +151,6 @@ fun SettingsLayout( } } -@Composable private fun UserAddressSection(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showModal { UserAddressView(it) }) { - Icon( - Icons.Outlined.QrCode, - contentDescription = stringResource(R.string.icon_descr_address), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.your_simplex_contact_address)) - } -} - -@Composable private fun CallSettingsItem(showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showSettingsModal { CallSettingsView(it) }) { - Icon( - Icons.Outlined.Videocam, - contentDescription = stringResource(R.string.call_settings), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.call_settings)) - } -} - -@Composable private fun PrivacySettingsItem(showSettingsModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit), setPerformLA: (Boolean) -> Unit) { - SettingsItemView(showSettingsModal { PrivacySettingsView(it, setPerformLA) }) { - Icon( - Icons.Outlined.Lock, - contentDescription = stringResource(R.string.privacy_and_security), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.privacy_and_security)) - } -} - -@Composable private fun HelpViewItem(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showModal { HelpView(it) }) { - Icon( - Icons.Outlined.HelpOutline, - contentDescription = stringResource(R.string.icon_descr_help), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.how_to_use_simplex_chat)) - } -} - -@Composable private fun SimpleXInfoItem(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showModal { SimpleXInfo(it, onboarding = false) }) { - Icon( - Icons.Outlined.Info, - contentDescription = stringResource(R.string.icon_descr_help), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.about_simplex_chat)) - } -} - -@Composable private fun MarkdownHelpItem(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showModal { MarkdownHelpView() }) { - Icon( - Icons.Outlined.TextFormat, - contentDescription = stringResource(R.string.markdown_help), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.markdown_in_messages)) - } -} - -@Composable private fun ConnectToDevelopersItem(uriHandler: UriHandler) { - SettingsItemView({ uriHandler.openUri(simplexTeamUri) }) { - Icon( - Icons.Outlined.Tag, - contentDescription = stringResource(R.string.icon_descr_simplex_team), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text( - stringResource(R.string.chat_with_the_founder), - color = MaterialTheme.colors.primary - ) - } -} - -@Composable private fun SendEmailItem(uriHandler: UriHandler) { - SettingsItemView({ uriHandler.openUri("mailto:chat@simplex.chat") }) { - Icon( - Icons.Outlined.Email, - contentDescription = stringResource(R.string.icon_descr_email), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text( - stringResource(R.string.send_us_an_email), - color = MaterialTheme.colors.primary - ) - } -} - -@Composable private fun SMPServersItem(showModal: (@Composable (ChatModel) -> Unit) -> (() -> Unit)) { - SettingsItemView(showModal { SMPServersView(it) }) { - Icon( - Icons.Outlined.Dns, - contentDescription = stringResource(R.string.smp_servers), - tint = HighOrLowlight, - ) - Spacer(Modifier.padding(horizontal = 4.dp)) - Text(stringResource(R.string.smp_servers)) - } -} - @Composable private fun PrivateNotificationsItem( runServiceInBackground: MutableState, setRunServiceInBackground: (Boolean) -> Unit @@ -376,6 +268,26 @@ fun SettingsItemView(click: (() -> Unit)? = null, height: Dp = 46.dp, content: ( } } +@Composable +fun SettingsActionItem(icon: ImageVector, text: String, click: (() -> Unit)? = null, textColor: Color = Color.Unspecified) { + SettingsItemView(click) { + Icon(icon, text, tint = HighOrLowlight) + Spacer(Modifier.padding(horizontal = 4.dp)) + Text(text, color = textColor) + } +} + +@Composable +fun SettingsPreferenceItem(icon: ImageVector, text: String, pref: Preference, prefState: MutableState? = null) { + SettingsItemView() { + Row(verticalAlignment = Alignment.CenterVertically) { + Icon(icon, text, tint = HighOrLowlight) + Spacer(Modifier.padding(horizontal = 4.dp)) + SharedPreferenceToggle(text, pref, prefState) + } + } +} + @Preview(showBackground = true) @Preview( uiMode = Configuration.UI_MODE_NIGHT_YES, @@ -390,6 +302,7 @@ fun PreviewSettingsLayout() { runServiceInBackground = remember { mutableStateOf(true) }, setRunServiceInBackground = {}, setPerformLA = {}, + enableCalls = remember { mutableStateOf(true) }, showModal = { {} }, showSettingsModal = { {} }, showCustomModal = { {} }, diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index 7d546a2713..16269f27a7 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -379,7 +379,7 @@ аудиозвонок - Аудио- и видеозвонки + Аудио- и видеозвонки Ваши звонки Соединяться через сервер (relay) Звонки на экране блокировки: @@ -436,4 +436,5 @@ ДЛЯ РАЗРАБОТЧИКОВ УСТРОЙСТВО ЧАТЫ + Экспериментальные функции diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 8586c4d92e..284fd2ca86 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -381,7 +381,7 @@ audio call - Audio & video calls + Audio & video calls Your calls Connect via relay Calls on lock screen: @@ -438,4 +438,5 @@ DEVELOP DEVICE CHATS + Experimental features diff --git a/apps/ios/Shared/Views/Call/CallController.swift b/apps/ios/Shared/Views/Call/CallController.swift index 008db03e9f..ff8339b9b2 100644 --- a/apps/ios/Shared/Views/Call/CallController.swift +++ b/apps/ios/Shared/Views/Call/CallController.swift @@ -120,6 +120,7 @@ class CallController: NSObject, CXProviderDelegate, ObservableObject { func reportNewIncomingCall(invitation: CallInvitation, completion: @escaping (Error?) -> Void) { logger.debug("CallController.reportNewIncomingCall") + if !UserDefaults.standard.bool(forKey: DEFAULT_EXPERIMENTAL_CALLS) { return } if CallController.useCallKit, let uuid = invitation.callkitUUID { let update = CXCallUpdate() update.remoteHandle = CXHandle(type: .generic, value: invitation.contact.displayName) diff --git a/apps/ios/Shared/Views/Chat/ChatView.swift b/apps/ios/Shared/Views/Chat/ChatView.swift index 579069435a..48d581d2c8 100644 --- a/apps/ios/Shared/Views/Chat/ChatView.swift +++ b/apps/ios/Shared/Views/Chat/ChatView.swift @@ -13,6 +13,7 @@ private let memberImageSize: CGFloat = 34 struct ChatView: View { @EnvironmentObject var chatModel: ChatModel @Environment(\.colorScheme) var colorScheme + @AppStorage(DEFAULT_EXPERIMENTAL_CALLS) private var enableCalls = false @ObservedObject var chat: Chat @State private var composeState = ComposeState() @State private var deletingItem: ChatItem? = nil @@ -106,7 +107,7 @@ struct ChatView: View { } } ToolbarItem(placement: .navigationBarTrailing) { - if case let .direct(contact) = cInfo { + if enableCalls, case let .direct(contact) = cInfo { HStack { callButton(contact, .audio, imageName: "phone") callButton(contact, .video, imageName: "video") diff --git a/apps/ios/Shared/Views/UserSettings/ExperimentalFeaturesView.swift b/apps/ios/Shared/Views/UserSettings/ExperimentalFeaturesView.swift new file mode 100644 index 0000000000..0fa754ec20 --- /dev/null +++ b/apps/ios/Shared/Views/UserSettings/ExperimentalFeaturesView.swift @@ -0,0 +1,29 @@ +// +// ExperimentalFeaturesView.swift +// SimpleX (iOS) +// +// Created by Evgeny on 30/05/2022. +// Copyright © 2022 SimpleX Chat. All rights reserved. +// + +import SwiftUI + +struct ExperimentalFeaturesView: View { + @AppStorage(DEFAULT_EXPERIMENTAL_CALLS) private var enableCalls = false + + var body: some View { + List { + Section("") { + settingsRow("video") { + Toggle("Audio & video calls", isOn: $enableCalls) + } + } + } + } +} + +struct ExperimentalFeaturesView_Previews: PreviewProvider { + static var previews: some View { + ExperimentalFeaturesView() + } +} diff --git a/apps/ios/Shared/Views/UserSettings/SettingsView.swift b/apps/ios/Shared/Views/UserSettings/SettingsView.swift index ca1ec83e40..f531634c26 100644 --- a/apps/ios/Shared/Views/UserSettings/SettingsView.swift +++ b/apps/ios/Shared/Views/UserSettings/SettingsView.swift @@ -22,6 +22,7 @@ let DEFAULT_PENDING_CONNECTIONS = "pendingConnections" let DEFAULT_WEBRTC_POLICY_RELAY = "webrtcPolicyRelay" let DEFAULT_PRIVACY_ACCEPT_IMAGES = "privacyAcceptImages" let DEFAULT_PRIVACY_LINK_PREVIEWS = "privacyLinkPreviews" +let DEFAULT_EXPERIMENTAL_CALLS = "experimentalCalls" let appDefaults: [String: Any] = [ DEFAULT_SHOW_LA_NOTICE: false, @@ -31,7 +32,8 @@ let appDefaults: [String: Any] = [ DEFAULT_PENDING_CONNECTIONS: true, DEFAULT_WEBRTC_POLICY_RELAY: true, DEFAULT_PRIVACY_ACCEPT_IMAGES: true, - DEFAULT_PRIVACY_LINK_PREVIEWS: true + DEFAULT_PRIVACY_LINK_PREVIEWS: true, + DEFAULT_EXPERIMENTAL_CALLS: false ] private var indent: CGFloat = 36 @@ -42,6 +44,7 @@ struct SettingsView: View { @Binding var showSettings: Bool @AppStorage(DEFAULT_USE_NOTIFICATIONS) private var useNotifications = false @AppStorage(DEFAULT_PENDING_CONNECTIONS) private var pendingConnections = true + @AppStorage(DEFAULT_EXPERIMENTAL_CALLS) private var enableCalls = false @State var showNotificationsAlert: Bool = false @State var whichNotificationsAlert = NotificationAlert.enable @@ -67,11 +70,13 @@ struct SettingsView: View { } Section("Settings") { - NavigationLink { - CallSettings() - .navigationTitle("Your calls") - } label: { - settingsRow("video") { Text("Audio & video calls") } + if enableCalls { + NavigationLink { + CallSettings() + .navigationTitle("Your calls") + } label: { + settingsRow("video") { Text("Audio & video calls") } + } } NavigationLink { PrivacySettings() @@ -139,6 +144,12 @@ struct SettingsView: View { Text("Install [SimpleX Chat for terminal](https://github.com/simplex-chat/simplex-chat)") .padding(.leading, indent) } + NavigationLink { + ExperimentalFeaturesView() + .navigationTitle("Experimental features") + } label: { + settingsRow("gauge") { Text("Experimental features") } + } // if let token = chatModel.deviceToken { // HStack { // notificationsIcon() diff --git a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff index a752ee6555..5f1e5c140e 100644 --- a/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff +++ b/apps/ios/SimpleX Localizations/en.xcloc/Localized Contents/en.xliff @@ -531,6 +531,11 @@ Error: URL is invalid No comment provided by engineer. + + Experimental features + Experimental features + No comment provided by engineer. + File will be received when your contact is online, please wait or check later! File will be received when your contact is online, please wait or check later! @@ -746,6 +751,11 @@ We will be adding server redundancy to prevent lost messages. Paste No comment provided by engineer. + + Paste image + Paste image + No comment provided by engineer. + Paste received link Paste received link diff --git a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff index 716579010d..4dbb579d1c 100644 --- a/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff +++ b/apps/ios/SimpleX Localizations/ru.xcloc/Localized Contents/ru.xliff @@ -531,6 +531,11 @@ Ошибка: неверная ссылка No comment provided by engineer. + + Experimental features + Экспериментальные функции + No comment provided by engineer. + File will be received when your contact is online, please wait or check later! Файл будет принят, когда ваш контакт будет в сети, подождите или проверьте позже! @@ -746,6 +751,11 @@ We will be adding server redundancy to prevent lost messages. Вставить No comment provided by engineer. + + Paste image + Вставить изображение + No comment provided by engineer. + Paste received link Вставить полученную ссылку diff --git a/apps/ios/SimpleX.xcodeproj/project.pbxproj b/apps/ios/SimpleX.xcodeproj/project.pbxproj index 76f9cd852a..6fbfc9e0d6 100644 --- a/apps/ios/SimpleX.xcodeproj/project.pbxproj +++ b/apps/ios/SimpleX.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 5C3A88D127DF57800060F1C2 /* FramedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3A88D027DF57800060F1C2 /* FramedItemView.swift */; }; 5C3F1D562842B68D00EC8A82 /* IntegrityErrorItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */; }; 5C3F1D58284363C400EC8A82 /* PrivacySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */; }; + 5C3F1D5A2844B4DE00EC8A82 /* ExperimentalFeaturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C3F1D592844B4DE00EC8A82 /* ExperimentalFeaturesView.swift */; }; 5C5346A827B59A6A004DF848 /* ChatHelp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C5346A727B59A6A004DF848 /* ChatHelp.swift */; }; 5C55A91F283AD0E400C4E99E /* CallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A91E283AD0E400C4E99E /* CallManager.swift */; }; 5C55A921283CCCB700C4E99E /* IncomingCallView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C55A920283CCCB700C4E99E /* IncomingCallView.swift */; }; @@ -158,6 +159,7 @@ 5C3A88D027DF57800060F1C2 /* FramedItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FramedItemView.swift; sourceTree = ""; }; 5C3F1D552842B68D00EC8A82 /* IntegrityErrorItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntegrityErrorItemView.swift; sourceTree = ""; }; 5C3F1D57284363C400EC8A82 /* PrivacySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettings.swift; sourceTree = ""; }; + 5C3F1D592844B4DE00EC8A82 /* ExperimentalFeaturesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExperimentalFeaturesView.swift; sourceTree = ""; }; 5C422A7C27A9A6FA0097A1E1 /* SimpleX (iOS).entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "SimpleX (iOS).entitlements"; sourceTree = ""; }; 5C5346A727B59A6A004DF848 /* ChatHelp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatHelp.swift; sourceTree = ""; }; 5C55A91E283AD0E400C4E99E /* CallManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManager.swift; sourceTree = ""; }; @@ -469,6 +471,7 @@ 5CB924E027A867BA00ACCCDD /* UserProfile.swift */, 5C577F7C27C83AA10006112D /* MarkdownHelp.swift */, 640F50E227CF991C001E05C2 /* SMPServers.swift */, + 5C3F1D592844B4DE00EC8A82 /* ExperimentalFeaturesView.swift */, ); path = UserSettings; sourceTree = ""; @@ -762,6 +765,7 @@ 64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */, 5C029EA82837DBB3004A9677 /* CICallItemView.swift in Sources */, 5CE4407227ADB1D0007B033A /* Emoji.swift in Sources */, + 5C3F1D5A2844B4DE00EC8A82 /* ExperimentalFeaturesView.swift in Sources */, 5C1A4C1E27A715B700EAD5AD /* ChatItemView.swift in Sources */, 64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */, );