multiplatform: translations refactor (#2649)

* no xliff

* CDATA

* moved to MR.strings

* unused StringRes

* renamed resources package

* translation of search_verb

* optimization

* optimization

* translation of la_mode_off
This commit is contained in:
Stanislav Dmitrenko
2023-07-04 15:32:28 +03:00
committed by GitHub
parent be5e0d7f75
commit ebc5242932
140 changed files with 3140 additions and 2972 deletions
@@ -18,7 +18,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.*
@@ -30,7 +29,6 @@ import chat.simplex.app.views.SplashView
import chat.simplex.app.views.call.ActiveCallView
import chat.simplex.app.views.call.IncomingCallAlertView
import chat.simplex.app.views.chat.ChatView
import chat.simplex.app.views.chat.group.ProgressIndicator
import chat.simplex.app.views.chatlist.*
import chat.simplex.app.views.database.DatabaseErrorView
import chat.simplex.app.views.helpers.*
@@ -40,6 +38,8 @@ import chat.simplex.app.views.localauth.SetAppPasscodeView
import chat.simplex.app.views.newchat.*
import chat.simplex.app.views.onboarding.*
import chat.simplex.app.views.usersettings.LAMode
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.distinctUntilChanged
import java.lang.ref.WeakReference
@@ -94,7 +94,7 @@ class MainActivity: FragmentActivity() {
destroyedAfterBackPress,
::runAuthenticate,
::setPerformLA,
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown, this) }
showLANotice = { showLANotice(m.controller.appPrefs.laNoticeShown) }
)
}
}
@@ -175,13 +175,13 @@ class MainActivity: FragmentActivity() {
withContext(Dispatchers.Main) {
authenticate(
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_unlock)
generalGetString(MR.strings.auth_unlock)
else
generalGetString(R.string.la_enter_app_passcode),
generalGetString(MR.strings.la_enter_app_passcode),
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_log_in_using_credential)
generalGetString(MR.strings.auth_log_in_using_credential)
else
generalGetString(R.string.auth_unlock),
generalGetString(MR.strings.auth_unlock),
selfDestruct = true,
completed = { laResult ->
when (laResult) {
@@ -208,49 +208,49 @@ class MainActivity: FragmentActivity() {
}
}
private fun showLANotice(laNoticeShown: SharedPreference<Boolean>, activity: FragmentActivity) {
private fun showLANotice(laNoticeShown: SharedPreference<Boolean>) {
Log.d(TAG, "showLANotice")
if (!laNoticeShown.get()) {
laNoticeShown.set(true)
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.la_notice_title_simplex_lock),
text = generalGetString(R.string.la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled),
confirmText = generalGetString(R.string.la_notice_turn_on),
title = generalGetString(MR.strings.la_notice_title_simplex_lock),
text = generalGetString(MR.strings.la_notice_to_protect_your_information_turn_on_simplex_lock_you_will_be_prompted_to_complete_authentication_before_this_feature_is_enabled),
confirmText = generalGetString(MR.strings.la_notice_turn_on),
onConfirm = {
withBGApi { // to remove this call, change ordering of onConfirm call in AlertManager
showChooseLAMode(laNoticeShown, activity)
showChooseLAMode(laNoticeShown)
}
}
)
}
}
private fun showChooseLAMode(laNoticeShown: SharedPreference<Boolean>, activity: FragmentActivity) {
private fun showChooseLAMode(laNoticeShown: SharedPreference<Boolean>) {
Log.d(TAG, "showLANotice")
laNoticeShown.set(true)
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.la_lock_mode),
title = generalGetString(MR.strings.la_lock_mode),
text = null,
confirmText = generalGetString(R.string.la_lock_mode_passcode),
dismissText = generalGetString(R.string.la_lock_mode_system),
confirmText = generalGetString(MR.strings.la_lock_mode_passcode),
dismissText = generalGetString(MR.strings.la_lock_mode_system),
onConfirm = {
AlertManager.shared.hideAlert()
setPasscode()
},
onDismiss = {
AlertManager.shared.hideAlert()
initialEnableLA(activity)
initialEnableLA()
}
)
}
private fun initialEnableLA(activity: FragmentActivity) {
private fun initialEnableLA() {
val m = vm.chatModel
val appPrefs = m.controller.appPrefs
m.controller.appPrefs.laMode.set(LAMode.SYSTEM)
authenticate(
generalGetString(R.string.auth_enable_simplex_lock),
generalGetString(R.string.auth_confirm_credential),
generalGetString(MR.strings.auth_enable_simplex_lock),
generalGetString(MR.strings.auth_confirm_credential),
completed = { laResult ->
when (laResult) {
LAResult.Success -> {
@@ -297,24 +297,24 @@ class MainActivity: FragmentActivity() {
}
}
private fun setPerformLA(on: Boolean, activity: FragmentActivity) {
private fun setPerformLA(on: Boolean) {
vm.chatModel.controller.appPrefs.laNoticeShown.set(true)
if (on) {
enableLA(activity)
enableLA()
} else {
disableLA(activity)
disableLA()
}
}
private fun enableLA(activity: FragmentActivity) {
private fun enableLA() {
val m = vm.chatModel
authenticate(
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_enable_simplex_lock)
generalGetString(MR.strings.auth_enable_simplex_lock)
else
generalGetString(R.string.new_passcode),
generalGetString(MR.strings.new_passcode),
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_confirm_credential)
generalGetString(MR.strings.auth_confirm_credential)
else
"",
completed = { laResult ->
@@ -341,17 +341,17 @@ class MainActivity: FragmentActivity() {
)
}
private fun disableLA(activity: FragmentActivity) {
private fun disableLA() {
val m = vm.chatModel
authenticate(
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_disable_simplex_lock)
generalGetString(MR.strings.auth_disable_simplex_lock)
else
generalGetString(R.string.la_enter_app_passcode),
generalGetString(MR.strings.la_enter_app_passcode),
if (m.controller.appPrefs.laMode.get() == LAMode.SYSTEM)
generalGetString(R.string.auth_confirm_credential)
generalGetString(MR.strings.auth_confirm_credential)
else
generalGetString(R.string.auth_disable_simplex_lock),
generalGetString(MR.strings.auth_disable_simplex_lock),
completed = { laResult ->
val prefPerformLA = m.controller.appPrefs.performLA
val selfDestructPref = m.controller.appPrefs.selfDestruct
@@ -392,7 +392,7 @@ fun MainPage(
laFailed: MutableState<Boolean>,
destroyedAfterBackPress: MutableState<Boolean>,
runAuthenticate: () -> Unit,
setPerformLA: (Boolean, FragmentActivity) -> Unit,
setPerformLA: (Boolean) -> Unit,
showLANotice: () -> Unit
) {
var showChatDatabaseError by rememberSaveable {
@@ -434,7 +434,7 @@ fun MainPage(
contentAlignment = Alignment.Center
) {
SimpleButton(
stringResource(R.string.auth_unlock),
stringResource(MR.strings.auth_unlock),
icon = painterResource(R.drawable.ic_lock),
click = {
laFailed.value = false
@@ -561,7 +561,7 @@ private fun InitializationView() {
color = MaterialTheme.colors.secondary,
strokeWidth = 2.5.dp
)
Text(stringResource(R.string.opening_database))
Text(stringResource(MR.strings.opening_database))
}
}
}
@@ -602,7 +602,7 @@ fun processNotificationIntent(intent: Intent?, chatModel: ChatModel) {
chatModel.clearOverlays.value = true
val invitation = chatModel.callInvitations[chatId]
if (invitation == null) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.call_already_ended))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.call_already_ended))
} else {
chatModel.callManager.acceptIncomingCall(invitation = invitation)
}
@@ -674,17 +674,17 @@ fun connectIfOpenedViaUri(uri: Uri, chatModel: ChatModel) {
} else {
withUriAction(uri) { linkType ->
val title = when (linkType) {
ConnectionLinkType.CONTACT -> generalGetString(R.string.connect_via_contact_link)
ConnectionLinkType.INVITATION -> generalGetString(R.string.connect_via_invitation_link)
ConnectionLinkType.GROUP -> generalGetString(R.string.connect_via_group_link)
ConnectionLinkType.CONTACT -> generalGetString(MR.strings.connect_via_contact_link)
ConnectionLinkType.INVITATION -> generalGetString(MR.strings.connect_via_invitation_link)
ConnectionLinkType.GROUP -> generalGetString(MR.strings.connect_via_group_link)
}
AlertManager.shared.showAlertDialog(
title = title,
text = if (linkType == ConnectionLinkType.GROUP)
generalGetString(R.string.you_will_join_group)
generalGetString(MR.strings.you_will_join_group)
else
generalGetString(R.string.profile_will_be_sent_to_contact_sending_link),
confirmText = generalGetString(R.string.connect_via_link_verb),
generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link),
confirmText = generalGetString(MR.strings.connect_via_link_verb),
onConfirm = {
withApi {
Log.d(TAG, "connectIfOpenedViaUri: connecting")
@@ -11,6 +11,7 @@ import androidx.core.content.ContextCompat
import androidx.work.*
import chat.simplex.app.model.ChatController
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
// based on:
@@ -41,8 +42,8 @@ class SimplexService: Service() {
override fun onCreate() {
super.onCreate()
Log.d(TAG, "Simplex service created")
val title = getString(R.string.simplex_service_notification_title)
val text = getString(R.string.simplex_service_notification_text)
val title = generalGetString(MR.strings.simplex_service_notification_title)
val text = generalGetString(MR.strings.simplex_service_notification_text)
notificationManager = createNotificationChannel()
serviceNotification = createNotification(title, text)
startForeground(SIMPLEX_SERVICE_ID, serviceNotification)
@@ -142,7 +143,7 @@ class SimplexService: Service() {
setupIntent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
setupIntent.putExtra(Settings.EXTRA_CHANNEL_ID, NOTIFICATION_CHANNEL_ID)
val setup = PendingIntent.getActivity(this, 0, setupIntent, flags)
builder.addAction(0, getString(R.string.hide_notification), setup)
builder.addAction(0, generalGetString(MR.strings.hide_notification), setup)
}
return builder.build()
@@ -295,15 +296,15 @@ class SimplexService: Service() {
}
val title = when(chatDbStatus) {
is DBMigrationResult.ErrorNotADatabase -> generalGetString(R.string.enter_passphrase_notification_title)
is DBMigrationResult.ErrorNotADatabase -> generalGetString(MR.strings.enter_passphrase_notification_title)
is DBMigrationResult.OK -> return
else -> generalGetString(R.string.database_initialization_error_title)
else -> generalGetString(MR.strings.database_initialization_error_title)
}
val description = when(chatDbStatus) {
is DBMigrationResult.ErrorNotADatabase -> generalGetString(R.string.enter_passphrase_notification_desc)
is DBMigrationResult.ErrorNotADatabase -> generalGetString(MR.strings.enter_passphrase_notification_desc)
is DBMigrationResult.OK -> return
else -> generalGetString(R.string.database_initialization_error_desc)
else -> generalGetString(MR.strings.database_initialization_error_desc)
}
val builder = NotificationCompat.Builder(SimplexApp.context, NOTIFICATION_CHANNEL_ID)
@@ -15,6 +15,8 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.app.views.usersettings.NotificationPreviewMode
import chat.simplex.app.views.usersettings.NotificationsMode
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.*
import kotlinx.datetime.*
import kotlinx.datetime.TimeZone
@@ -693,7 +695,7 @@ sealed class ChatInfo: SomeChat, NamedChat {
override val localAlias get() = ""
companion object {
private val invalidChatName = generalGetString(R.string.invalid_chat)
private val invalidChatName = generalGetString(MR.strings.invalid_chat)
}
}
@@ -709,15 +711,15 @@ sealed class ChatInfo: SomeChat, NamedChat {
sealed class NetworkStatus {
val statusString: String get() =
when (this) {
is Connected -> generalGetString(R.string.server_connected)
is Error -> generalGetString(R.string.server_error)
else -> generalGetString(R.string.server_connecting)
is Connected -> generalGetString(MR.strings.server_connected)
is Error -> generalGetString(MR.strings.server_error)
else -> generalGetString(MR.strings.server_connecting)
}
val statusExplanation: String get() =
when (this) {
is Connected -> generalGetString(R.string.connected_to_server_to_receive_messages_from_contact)
is Error -> String.format(generalGetString(R.string.trying_to_connect_to_server_to_receive_messages_with_error), error)
else -> generalGetString(R.string.trying_to_connect_to_server_to_receive_messages)
is Connected -> generalGetString(MR.strings.connected_to_server_to_receive_messages_from_contact)
is Error -> String.format(generalGetString(MR.strings.trying_to_connect_to_server_to_receive_messages_with_error), error)
else -> generalGetString(MR.strings.trying_to_connect_to_server_to_receive_messages)
}
@Serializable @SerialName("unknown") class Unknown: NetworkStatus()
@@ -1062,10 +1064,10 @@ enum class GroupMemberRole(val memberRole: String) {
@SerialName("owner") Owner("owner");
val text: String get() = when (this) {
Observer -> generalGetString(R.string.group_member_role_observer)
Member -> generalGetString(R.string.group_member_role_member)
Admin -> generalGetString(R.string.group_member_role_admin)
Owner -> generalGetString(R.string.group_member_role_owner)
Observer -> generalGetString(MR.strings.group_member_role_observer)
Member -> generalGetString(MR.strings.group_member_role_member)
Admin -> generalGetString(MR.strings.group_member_role_admin)
Owner -> generalGetString(MR.strings.group_member_role_owner)
}
}
@@ -1093,31 +1095,31 @@ enum class GroupMemberStatus {
@SerialName("creator") MemCreator;
val text: String get() = when (this) {
MemRemoved -> generalGetString(R.string.group_member_status_removed)
MemLeft -> generalGetString(R.string.group_member_status_left)
MemGroupDeleted -> generalGetString(R.string.group_member_status_group_deleted)
MemInvited -> generalGetString(R.string.group_member_status_invited)
MemIntroduced -> generalGetString(R.string.group_member_status_introduced)
MemIntroInvited -> generalGetString(R.string.group_member_status_intro_invitation)
MemAccepted -> generalGetString(R.string.group_member_status_accepted)
MemAnnounced -> generalGetString(R.string.group_member_status_announced)
MemConnected -> generalGetString(R.string.group_member_status_connected)
MemComplete -> generalGetString(R.string.group_member_status_complete)
MemCreator -> generalGetString(R.string.group_member_status_creator)
MemRemoved -> generalGetString(MR.strings.group_member_status_removed)
MemLeft -> generalGetString(MR.strings.group_member_status_left)
MemGroupDeleted -> generalGetString(MR.strings.group_member_status_group_deleted)
MemInvited -> generalGetString(MR.strings.group_member_status_invited)
MemIntroduced -> generalGetString(MR.strings.group_member_status_introduced)
MemIntroInvited -> generalGetString(MR.strings.group_member_status_intro_invitation)
MemAccepted -> generalGetString(MR.strings.group_member_status_accepted)
MemAnnounced -> generalGetString(MR.strings.group_member_status_announced)
MemConnected -> generalGetString(MR.strings.group_member_status_connected)
MemComplete -> generalGetString(MR.strings.group_member_status_complete)
MemCreator -> generalGetString(MR.strings.group_member_status_creator)
}
val shortText: String get() = when (this) {
MemRemoved -> generalGetString(R.string.group_member_status_removed)
MemLeft -> generalGetString(R.string.group_member_status_left)
MemGroupDeleted -> generalGetString(R.string.group_member_status_group_deleted)
MemInvited -> generalGetString(R.string.group_member_status_invited)
MemIntroduced -> generalGetString(R.string.group_member_status_connecting)
MemIntroInvited -> generalGetString(R.string.group_member_status_connecting)
MemAccepted -> generalGetString(R.string.group_member_status_connecting)
MemAnnounced -> generalGetString(R.string.group_member_status_connecting)
MemConnected -> generalGetString(R.string.group_member_status_connected)
MemComplete -> generalGetString(R.string.group_member_status_complete)
MemCreator -> generalGetString(R.string.group_member_status_creator)
MemRemoved -> generalGetString(MR.strings.group_member_status_removed)
MemLeft -> generalGetString(MR.strings.group_member_status_left)
MemGroupDeleted -> generalGetString(MR.strings.group_member_status_group_deleted)
MemInvited -> generalGetString(MR.strings.group_member_status_invited)
MemIntroduced -> generalGetString(MR.strings.group_member_status_connecting)
MemIntroInvited -> generalGetString(MR.strings.group_member_status_connecting)
MemAccepted -> generalGetString(MR.strings.group_member_status_connecting)
MemAnnounced -> generalGetString(MR.strings.group_member_status_connecting)
MemConnected -> generalGetString(MR.strings.group_member_status_connected)
MemComplete -> generalGetString(MR.strings.group_member_status_complete)
MemCreator -> generalGetString(MR.strings.group_member_status_creator)
}
}
@@ -1206,17 +1208,17 @@ class PendingContactConnection(
override val incognito get() = customUserProfileId != null
override fun featureEnabled(feature: ChatFeature) = false
override val timedMessagesTTL: Int? get() = null
override val localDisplayName get() = String.format(generalGetString(R.string.connection_local_display_name), pccConnId)
override val localDisplayName get() = String.format(generalGetString(MR.strings.connection_local_display_name), pccConnId)
override val displayName: String get() {
if (localAlias.isNotEmpty()) return localAlias
val initiated = pccConnStatus.initiated
return if (initiated == null) {
// this should not be in the chat list
generalGetString(R.string.display_name_connection_established)
generalGetString(MR.strings.display_name_connection_established)
} else {
generalGetString(
if (initiated && !viaContactUri) R.string.display_name_invited_to_connect
else R.string.display_name_connecting
if (initiated && !viaContactUri) MR.strings.display_name_invited_to_connect
else MR.strings.display_name_connecting
)
}
}
@@ -1229,14 +1231,14 @@ class PendingContactConnection(
val initiated = pccConnStatus.initiated
return if (initiated == null) "" else generalGetString(
if (initiated && !viaContactUri)
if (incognito) R.string.description_you_shared_one_time_link_incognito else R.string.description_you_shared_one_time_link
if (incognito) MR.strings.description_you_shared_one_time_link_incognito else MR.strings.description_you_shared_one_time_link
else if (viaContactUri)
if (groupLinkId != null)
if (incognito) R.string.description_via_group_link_incognito else R.string.description_via_group_link
if (incognito) MR.strings.description_via_group_link_incognito else MR.strings.description_via_group_link
else
if (incognito) R.string.description_via_contact_address_link_incognito else R.string.description_via_contact_address_link
if (incognito) MR.strings.description_via_contact_address_link_incognito else MR.strings.description_via_contact_address_link
else
if (incognito) R.string.description_via_one_time_link_incognito else R.string.description_via_one_time_link
if (incognito) MR.strings.description_via_one_time_link_incognito else MR.strings.description_via_one_time_link
)
}
@@ -1312,7 +1314,7 @@ data class ChatItem (
val text: String get() {
val mc = content.msgContent
return when {
content.text == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(R.string.voice_message_with_duration), durationText(mc.duration))
content.text == "" && file != null && mc is MsgContent.MCVoice -> String.format(generalGetString(MR.strings.voice_message_with_duration), durationText(mc.duration))
content.text == "" && file != null -> file.fileName
else -> content.text
}
@@ -1491,7 +1493,7 @@ data class ChatItem (
meta = CIMeta(
itemId = TEMP_DELETED_CHAT_ITEM_ID,
itemTs = Clock.System.now(),
itemText = generalGetString(R.string.deleted_description),
itemText = generalGetString(MR.strings.deleted_description),
itemStatus = CIStatus.RcvRead(),
createdAt = Clock.System.now(),
updatedAt = Clock.System.now(),
@@ -1718,8 +1720,8 @@ sealed class CIContent: ItemContent {
override val text: String get() = when (this) {
is SndMsgContent -> msgContent.text
is RcvMsgContent -> msgContent.text
is SndDeleted -> generalGetString(R.string.deleted_description)
is RcvDeleted -> generalGetString(R.string.deleted_description)
is SndDeleted -> generalGetString(MR.strings.deleted_description)
is RcvDeleted -> generalGetString(MR.strings.deleted_description)
is SndCall -> status.text(duration)
is RcvCall -> status.text(duration)
is RcvIntegrityError -> msgError.text
@@ -1736,10 +1738,10 @@ sealed class CIContent: ItemContent {
is SndChatPreference -> preferenceText(feature, allowed, param)
is RcvGroupFeature -> featureText(groupFeature, preference.enable.text, param)
is SndGroupFeature -> featureText(groupFeature, preference.enable.text, param)
is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(R.string.feature_received_prohibited)}"
is SndModerated -> generalGetString(R.string.moderated_description)
is RcvModerated -> generalGetString(R.string.moderated_description)
is RcvChatFeatureRejected -> "${feature.text}: ${generalGetString(MR.strings.feature_received_prohibited)}"
is RcvGroupFeatureRejected -> "${groupFeature.text}: ${generalGetString(MR.strings.feature_received_prohibited)}"
is SndModerated -> generalGetString(MR.strings.moderated_description)
is RcvModerated -> generalGetString(MR.strings.moderated_description)
is InvalidJSON -> "invalid data"
}
@@ -1753,11 +1755,11 @@ sealed class CIContent: ItemContent {
fun preferenceText(feature: Feature, allowed: FeatureAllowed, param: Int?): String = when {
allowed != FeatureAllowed.NO && feature.hasParam && param != null ->
String.format(generalGetString(R.string.feature_offered_item_with_param), feature.text, timeText(param))
String.format(generalGetString(MR.strings.feature_offered_item_with_param), feature.text, timeText(param))
allowed != FeatureAllowed.NO ->
String.format(generalGetString(R.string.feature_offered_item), feature.text, timeText(param))
String.format(generalGetString(MR.strings.feature_offered_item), feature.text, timeText(param))
else ->
String.format(generalGetString(R.string.feature_cancelled_item), feature.text, timeText(param))
String.format(generalGetString(MR.strings.feature_cancelled_item), feature.text, timeText(param))
}
}
}
@@ -1768,8 +1770,8 @@ enum class MsgDecryptError {
@SerialName("tooManySkipped") TooManySkipped;
val text: String get() = when (this) {
RatchetHeader -> generalGetString(R.string.decryption_error)
TooManySkipped -> generalGetString(R.string.decryption_error)
RatchetHeader -> generalGetString(MR.strings.decryption_error)
TooManySkipped -> generalGetString(MR.strings.decryption_error)
}
}
@@ -1791,7 +1793,7 @@ class CIQuote (
fun sender(membership: GroupMember?): String? = when (chatDir) {
is CIDirection.DirectSnd -> generalGetString(R.string.sender_you_pronoun)
is CIDirection.DirectSnd -> generalGetString(MR.strings.sender_you_pronoun)
is CIDirection.DirectRcv -> null
is CIDirection.GroupSnd -> membership?.displayName
is CIDirection.GroupRcv -> chatDir.groupMember.displayName
@@ -1896,6 +1898,7 @@ class CIFile(
is CIFileStatus.RcvError -> false
}
@Transient
val cancelAction: CancelAction? = when (fileStatus) {
is CIFileStatus.SndStored -> sndCancelAction
is CIFileStatus.SndTransfer -> sndCancelAction
@@ -1927,41 +1930,39 @@ class CIFile(
}
}
@Serializable
class CancelAction(
val uiActionId: Int,
val uiActionId: StringResource,
val alert: AlertInfo
)
@Serializable
class AlertInfo(
val titleId: Int,
val messageId: Int,
val confirmId: Int
val titleId: StringResource,
val messageId: StringResource,
val confirmId: StringResource
)
private val sndCancelAction: CancelAction = CancelAction(
uiActionId = R.string.stop_file__action,
uiActionId = MR.strings.stop_file__action,
alert = AlertInfo(
titleId = R.string.stop_snd_file__title,
messageId = R.string.stop_snd_file__message,
confirmId = R.string.stop_file__confirm
titleId = MR.strings.stop_snd_file__title,
messageId = MR.strings.stop_snd_file__message,
confirmId = MR.strings.stop_file__confirm
)
)
private val revokeCancelAction: CancelAction = CancelAction(
uiActionId = R.string.revoke_file__action,
uiActionId = MR.strings.revoke_file__action,
alert = AlertInfo(
titleId = R.string.revoke_file__title,
messageId = R.string.revoke_file__message,
confirmId = R.string.revoke_file__confirm
titleId = MR.strings.revoke_file__title,
messageId = MR.strings.revoke_file__message,
confirmId = MR.strings.revoke_file__confirm
)
)
private val rcvCancelAction: CancelAction = CancelAction(
uiActionId = R.string.stop_file__action,
uiActionId = MR.strings.stop_file__action,
alert = AlertInfo(
titleId = R.string.stop_rcv_file__title,
messageId = R.string.stop_rcv_file__message,
confirmId = R.string.stop_file__confirm
titleId = MR.strings.stop_rcv_file__title,
messageId = MR.strings.stop_rcv_file__message,
confirmId = MR.strings.stop_file__confirm
)
)
@@ -2012,7 +2013,7 @@ class CIGroupInvitation (
val status: CIGroupInvitationStatus,
) {
val text: String get() = String.format(
generalGetString(R.string.group_invitation_item_description),
generalGetString(MR.strings.group_invitation_item_description),
groupProfile.displayName)
companion object {
@@ -2065,7 +2066,7 @@ object MsgContentSerializer : KSerializer<MsgContent> {
return if (json is JsonObject) {
if ("type" in json) {
val t = json["type"]?.jsonPrimitive?.content ?: ""
val text = json["text"]?.jsonPrimitive?.content ?: generalGetString(R.string.unknown_message_format)
val text = json["text"]?.jsonPrimitive?.content ?: generalGetString(MR.strings.unknown_message_format)
when (t) {
"text" -> MsgContent.MCText(text)
"link" -> {
@@ -2089,10 +2090,10 @@ object MsgContentSerializer : KSerializer<MsgContent> {
else -> MsgContent.MCUnknown(t, text, json)
}
} else {
MsgContent.MCUnknown(text = generalGetString(R.string.invalid_message_format), json = json)
MsgContent.MCUnknown(text = generalGetString(MR.strings.invalid_message_format), json = json)
}
} else {
MsgContent.MCUnknown(text = generalGetString(R.string.invalid_message_format), json = json)
MsgContent.MCUnknown(text = generalGetString(MR.strings.invalid_message_format), json = json)
}
}
@@ -2156,7 +2157,7 @@ class FormattedText(val text: String, val format: Format? = null) {
if (format is Format.SimplexLink && mode == SimplexLinkMode.DESCRIPTION) simplexLinkText(format.linkType, format.smpHosts) else text
fun simplexLinkText(linkType: SimplexLinkType, smpHosts: List<String>): String =
"${linkType.description} (${String.format(generalGetString(R.string.simplex_link_connection), smpHosts.firstOrNull() ?: "?")})"
"${linkType.description} (${String.format(generalGetString(MR.strings.simplex_link_connection), smpHosts.firstOrNull() ?: "?")})"
}
@Serializable
@@ -2197,9 +2198,9 @@ enum class SimplexLinkType(val linkType: String) {
group("group");
val description: String get() = generalGetString(when (this) {
contact -> R.string.simplex_link_contact
invitation -> R.string.simplex_link_invitation
group -> R.string.simplex_link_group
contact -> MR.strings.simplex_link_contact
invitation -> MR.strings.simplex_link_invitation
group -> MR.strings.simplex_link_group
})
}
@@ -2247,14 +2248,14 @@ enum class CICallStatus {
@SerialName("error") Error;
fun text(sec: Int): String = when (this) {
Pending -> generalGetString(R.string.callstatus_calling)
Missed -> generalGetString(R.string.callstatus_missed)
Rejected -> generalGetString(R.string.callstatus_rejected)
Accepted -> generalGetString(R.string.callstatus_accepted)
Negotiated -> generalGetString(R.string.callstatus_connecting)
Progress -> generalGetString(R.string.callstatus_in_progress)
Ended -> String.format(generalGetString(R.string.callstatus_ended), durationText(sec))
Error -> generalGetString(R.string.callstatus_error)
Pending -> generalGetString(MR.strings.callstatus_calling)
Missed -> generalGetString(MR.strings.callstatus_missed)
Rejected -> generalGetString(MR.strings.callstatus_rejected)
Accepted -> generalGetString(MR.strings.callstatus_accepted)
Negotiated -> generalGetString(MR.strings.callstatus_connecting)
Progress -> generalGetString(MR.strings.callstatus_in_progress)
Ended -> String.format(generalGetString(MR.strings.callstatus_ended), durationText(sec))
Error -> generalGetString(MR.strings.callstatus_error)
}
}
@@ -2272,10 +2273,10 @@ sealed class MsgErrorType() {
@Serializable @SerialName("msgDuplicate") class MsgDuplicate(): MsgErrorType()
val text: String get() = when (this) {
is MsgSkipped -> String.format(generalGetString(R.string.integrity_msg_skipped), toMsgId - fromMsgId + 1)
is MsgBadHash -> generalGetString(R.string.integrity_msg_bad_hash) // not used now
is MsgBadId -> generalGetString(R.string.integrity_msg_bad_id) // not used now
is MsgDuplicate -> generalGetString(R.string.integrity_msg_duplicate) // not used now
is MsgSkipped -> String.format(generalGetString(MR.strings.integrity_msg_skipped), toMsgId - fromMsgId + 1)
is MsgBadHash -> generalGetString(MR.strings.integrity_msg_bad_hash) // not used now
is MsgBadId -> generalGetString(MR.strings.integrity_msg_bad_id) // not used now
is MsgDuplicate -> generalGetString(MR.strings.integrity_msg_duplicate) // not used now
}
}
@@ -2293,16 +2294,16 @@ sealed class RcvGroupEvent() {
@Serializable @SerialName("invitedViaGroupLink") class InvitedViaGroupLink(): RcvGroupEvent()
val text: String get() = when (this) {
is MemberAdded -> String.format(generalGetString(R.string.rcv_group_event_member_added), profile.profileViewName)
is MemberConnected -> generalGetString(R.string.rcv_group_event_member_connected)
is MemberLeft -> generalGetString(R.string.rcv_group_event_member_left)
is MemberRole -> String.format(generalGetString(R.string.rcv_group_event_changed_member_role), profile.profileViewName, role.text)
is UserRole -> String.format(generalGetString(R.string.rcv_group_event_changed_your_role), role.text)
is MemberDeleted -> String.format(generalGetString(R.string.rcv_group_event_member_deleted), profile.profileViewName)
is UserDeleted -> generalGetString(R.string.rcv_group_event_user_deleted)
is GroupDeleted -> generalGetString(R.string.rcv_group_event_group_deleted)
is GroupUpdated -> generalGetString(R.string.rcv_group_event_updated_group_profile)
is InvitedViaGroupLink -> generalGetString(R.string.rcv_group_event_invited_via_your_group_link)
is MemberAdded -> String.format(generalGetString(MR.strings.rcv_group_event_member_added), profile.profileViewName)
is MemberConnected -> generalGetString(MR.strings.rcv_group_event_member_connected)
is MemberLeft -> generalGetString(MR.strings.rcv_group_event_member_left)
is MemberRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_member_role), profile.profileViewName, role.text)
is UserRole -> String.format(generalGetString(MR.strings.rcv_group_event_changed_your_role), role.text)
is MemberDeleted -> String.format(generalGetString(MR.strings.rcv_group_event_member_deleted), profile.profileViewName)
is UserDeleted -> generalGetString(MR.strings.rcv_group_event_user_deleted)
is GroupDeleted -> generalGetString(MR.strings.rcv_group_event_group_deleted)
is GroupUpdated -> generalGetString(MR.strings.rcv_group_event_updated_group_profile)
is InvitedViaGroupLink -> generalGetString(MR.strings.rcv_group_event_invited_via_your_group_link)
}
}
@@ -2315,11 +2316,11 @@ sealed class SndGroupEvent() {
@Serializable @SerialName("groupUpdated") class GroupUpdated(val groupProfile: GroupProfile): SndGroupEvent()
val text: String get() = when (this) {
is MemberRole -> String.format(generalGetString(R.string.snd_group_event_changed_member_role), profile.profileViewName, role.text)
is UserRole -> String.format(generalGetString(R.string.snd_group_event_changed_role_for_yourself), role.text)
is MemberDeleted -> String.format(generalGetString(R.string.snd_group_event_member_deleted), profile.profileViewName)
is UserLeft -> generalGetString(R.string.snd_group_event_user_left)
is GroupUpdated -> generalGetString(R.string.snd_group_event_group_profile_updated)
is MemberRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_member_role), profile.profileViewName, role.text)
is UserRole -> String.format(generalGetString(MR.strings.snd_group_event_changed_role_for_yourself), role.text)
is MemberDeleted -> String.format(generalGetString(MR.strings.snd_group_event_member_deleted), profile.profileViewName)
is UserLeft -> generalGetString(MR.strings.snd_group_event_user_left)
is GroupUpdated -> generalGetString(MR.strings.snd_group_event_group_profile_updated)
}
}
@@ -2329,8 +2330,8 @@ sealed class RcvConnEvent {
val text: String get() = when (this) {
is SwitchQueue -> when (phase) {
SwitchPhase.Completed -> generalGetString(R.string.rcv_conn_event_switch_queue_phase_completed)
else -> generalGetString(R.string.rcv_conn_event_switch_queue_phase_changing)
SwitchPhase.Completed -> generalGetString(MR.strings.rcv_conn_event_switch_queue_phase_completed)
else -> generalGetString(MR.strings.rcv_conn_event_switch_queue_phase_changing)
}
}
}
@@ -2344,13 +2345,13 @@ sealed class SndConnEvent {
is SwitchQueue -> {
member?.profile?.profileViewName?.let {
return when (phase) {
SwitchPhase.Completed -> String.format(generalGetString(R.string.snd_conn_event_switch_queue_phase_completed_for_member), it)
else -> String.format(generalGetString(R.string.snd_conn_event_switch_queue_phase_changing_for_member), it)
SwitchPhase.Completed -> String.format(generalGetString(MR.strings.snd_conn_event_switch_queue_phase_completed_for_member), it)
else -> String.format(generalGetString(MR.strings.snd_conn_event_switch_queue_phase_changing_for_member), it)
}
}
when (phase) {
SwitchPhase.Completed -> generalGetString(R.string.snd_conn_event_switch_queue_phase_completed)
else -> generalGetString(R.string.snd_conn_event_switch_queue_phase_changing)
SwitchPhase.Completed -> generalGetString(MR.strings.snd_conn_event_switch_queue_phase_completed)
else -> generalGetString(MR.strings.snd_conn_event_switch_queue_phase_changing)
}
}
}
@@ -17,6 +17,7 @@ import chat.simplex.app.views.call.*
import chat.simplex.app.views.chatlist.acceptContactRequest
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.NotificationPreviewMode
import chat.simplex.res.MR
import kotlinx.datetime.Clock
object NtfManager {
@@ -86,7 +87,7 @@ object NtfManager {
user = user,
chatId = cInfo.id,
displayName = cInfo.displayName,
msgText = generalGetString(R.string.notification_new_contact_request),
msgText = generalGetString(MR.strings.notification_new_contact_request),
image = cInfo.image,
listOf(NotificationAction.ACCEPT_CONTACT_REQUEST)
)
@@ -97,7 +98,7 @@ object NtfManager {
user = user,
chatId = contact.id,
displayName = contact.displayName,
msgText = generalGetString(R.string.notification_contact_connected)
msgText = generalGetString(MR.strings.notification_contact_connected)
)
}
@@ -113,8 +114,8 @@ object NtfManager {
val recentNotification = (now - prevNtfTime.getOrDefault(chatId, 0) < msgNtfTimeoutMs)
prevNtfTime[chatId] = now
val previewMode = appPreferences.notificationPreviewMode.get()
val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) generalGetString(R.string.notification_preview_somebody) else displayName
val content = if (previewMode != NotificationPreviewMode.MESSAGE.name) generalGetString(R.string.notification_preview_new_message) else msgText
val title = if (previewMode == NotificationPreviewMode.HIDDEN.name) generalGetString(MR.strings.notification_preview_somebody) else displayName
val content = if (previewMode != NotificationPreviewMode.MESSAGE.name) generalGetString(MR.strings.notification_preview_new_message) else msgText
val largeIcon = when {
actions.isEmpty() -> null
image == null || previewMode == NotificationPreviewMode.HIDDEN.name -> BitmapFactory.decodeResource(context.resources, R.drawable.icon)
@@ -142,7 +143,7 @@ object NtfManager {
actionIntent.putExtra(ChatIdKey, chatId)
val actionPendingIntent: PendingIntent = PendingIntent.getBroadcast(SimplexApp.context, 0, actionIntent, flags)
val actionButton = when (action) {
NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(R.string.accept)
NotificationAction.ACCEPT_CONTACT_REQUEST -> generalGetString(MR.strings.accept)
}
builder.addAction(0, actionButton, actionPendingIntent)
}
@@ -191,21 +192,21 @@ object NtfManager {
val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
NotificationCompat.Builder(context, CallChannel)
.setContentIntent(chatPendingIntent(OpenChatAction, invitation.user.userId, invitation.contact.id))
.addAction(R.drawable.ntf_icon, generalGetString(R.string.accept), chatPendingIntent(AcceptCallAction, invitation.user.userId, contactId))
.addAction(R.drawable.ntf_icon, generalGetString(R.string.reject), chatPendingIntent(RejectCallAction, invitation.user.userId, contactId, true))
.addAction(R.drawable.ntf_icon, generalGetString(MR.strings.accept), chatPendingIntent(AcceptCallAction, invitation.user.userId, contactId))
.addAction(R.drawable.ntf_icon, generalGetString(MR.strings.reject), chatPendingIntent(RejectCallAction, invitation.user.userId, contactId, true))
.setFullScreenIntent(fullScreenPendingIntent, true)
.setSound(soundUri)
}
val text = generalGetString(
if (invitation.callType.media == CallMediaType.Video) {
if (invitation.sharedKey == null) R.string.video_call_no_encryption else R.string.encrypted_video_call
if (invitation.sharedKey == null) MR.strings.video_call_no_encryption else MR.strings.encrypted_video_call
} else {
if (invitation.sharedKey == null) R.string.audio_call_no_encryption else R.string.encrypted_audio_call
if (invitation.sharedKey == null) MR.strings.audio_call_no_encryption else MR.strings.encrypted_audio_call
}
)
val previewMode = appPreferences.notificationPreviewMode.get()
val title = if (previewMode == NotificationPreviewMode.HIDDEN.name)
generalGetString(R.string.notification_preview_somebody)
generalGetString(MR.strings.notification_preview_somebody)
else
invitation.contact.displayName
val largeIcon = if (image == null || previewMode == NotificationPreviewMode.HIDDEN.name)
@@ -281,8 +282,8 @@ object NtfManager {
* old ones if needed
* */
fun createNtfChannelsMaybeShowAlert() {
manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(R.string.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH))
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(R.string.ntf_channel_calls)))
manager.createNotificationChannel(NotificationChannel(MessageChannel, generalGetString(MR.strings.ntf_channel_messages), NotificationManager.IMPORTANCE_HIGH))
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(MR.strings.ntf_channel_calls)))
// Remove old channels since they can't be edited
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION")
manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION")
@@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.simplex.app.*
@@ -27,6 +27,8 @@ import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.app.views.usersettings.*
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.*
import kotlinx.datetime.Clock
import kotlinx.datetime.Instant
@@ -357,7 +359,7 @@ object ChatController {
changeActiveUser_(toUserId, viewPwd)
} catch (e: Exception) {
Log.e(TAG, "Unable to set active user: ${e.stackTraceToString()}")
AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_active_user_title), e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_active_user_title), e.stackTraceToString())
}
}
@@ -450,9 +452,9 @@ object ChatController {
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore && r.chatError.storeError is StoreError.DuplicateName ||
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat && r.chatError.errorType is ChatErrorType.UserExists
) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_create_user_duplicate_title), generalGetString(R.string.failed_to_create_user_duplicate_desc))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_duplicate_title), generalGetString(MR.strings.failed_to_create_user_duplicate_desc))
} else {
AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_create_user_title), r.details)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_create_user_title), r.details)
}
Log.d(TAG, "apiCreateActiveUser: ${r.responseType} ${r.details}")
return null
@@ -568,7 +570,7 @@ object ChatController {
val r = sendCmd(CC.ApiGetChats(userId))
if (r is CR.ApiChats) return r.chats
Log.e(TAG, "failed getting the list of chats: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_parse_chats_title), generalGetString(R.string.contact_developers))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_parse_chats_title), generalGetString(MR.strings.contact_developers))
return emptyList()
}
@@ -576,7 +578,7 @@ object ChatController {
val r = sendCmd(CC.ApiGetChat(type, id, pagination, search))
if (r is CR.ApiChat) return r.chat
Log.e(TAG, "apiGetChat bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(generalGetString(R.string.failed_to_parse_chat_title), generalGetString(R.string.contact_developers))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.failed_to_parse_chat_title), generalGetString(MR.strings.contact_developers))
return null
}
@@ -587,7 +589,7 @@ object ChatController {
is CR.NewChatItem -> r.chatItem
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiSendMessage", generalGetString(R.string.error_sending_message), r)
apiErrorAlert("apiSendMessage", generalGetString(MR.strings.error_sending_message), r)
}
null
}
@@ -598,7 +600,7 @@ object ChatController {
return when (val r = sendCmd(CC.ApiGetChatItemInfo(type, id, itemId))) {
is CR.ApiChatItemInfo -> r.chatItemInfo
else -> {
apiErrorAlert("apiGetChatItemInfo", generalGetString(R.string.error_loading_details), r)
apiErrorAlert("apiGetChatItemInfo", generalGetString(MR.strings.error_loading_details), r)
null
}
}
@@ -639,7 +641,7 @@ object ChatController {
else {
Log.e(TAG, "getUserProtoServers bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(
generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.error_loading_smp_servers else R.string.error_loading_xftp_servers),
generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.error_loading_smp_servers else MR.strings.error_loading_xftp_servers),
"${r.responseType}: ${r.details}"
)
null
@@ -654,8 +656,8 @@ object ChatController {
else -> {
Log.e(TAG, "setUserProtoServers bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(
generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.error_saving_smp_servers else R.string.error_saving_xftp_servers),
generalGetString(if (serverProtocol == ServerProtocol.SMP) R.string.ensure_smp_server_address_are_correct_format_and_unique else R.string.ensure_xftp_server_address_are_correct_format_and_unique)
generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.error_saving_smp_servers else MR.strings.error_saving_xftp_servers),
generalGetString(if (serverProtocol == ServerProtocol.SMP) MR.strings.ensure_smp_server_address_are_correct_format_and_unique else MR.strings.ensure_xftp_server_address_are_correct_format_and_unique)
)
false
}
@@ -702,7 +704,7 @@ object ChatController {
else -> {
Log.e(TAG, "apiSetNetworkConfig bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(
generalGetString(R.string.error_setting_network_config),
generalGetString(MR.strings.error_setting_network_config),
"${r.responseType}: ${r.details}"
)
false
@@ -738,28 +740,28 @@ object ChatController {
suspend fun apiSwitchContact(contactId: Long): ConnectionStats? {
val r = sendCmd(CC.APISwitchContact(contactId))
if (r is CR.ContactSwitchStarted) return r.connectionStats
apiErrorAlert("apiSwitchContact", generalGetString(R.string.error_changing_address), r)
apiErrorAlert("apiSwitchContact", generalGetString(MR.strings.error_changing_address), r)
return null
}
suspend fun apiSwitchGroupMember(groupId: Long, groupMemberId: Long): ConnectionStats? {
val r = sendCmd(CC.APISwitchGroupMember(groupId, groupMemberId))
if (r is CR.GroupMemberSwitchStarted) return r.connectionStats
apiErrorAlert("apiSwitchGroupMember", generalGetString(R.string.error_changing_address), r)
apiErrorAlert("apiSwitchGroupMember", generalGetString(MR.strings.error_changing_address), r)
return null
}
suspend fun apiAbortSwitchContact(contactId: Long): ConnectionStats? {
val r = sendCmd(CC.APIAbortSwitchContact(contactId))
if (r is CR.ContactSwitchAborted) return r.connectionStats
apiErrorAlert("apiAbortSwitchContact", generalGetString(R.string.error_aborting_address_change), r)
apiErrorAlert("apiAbortSwitchContact", generalGetString(MR.strings.error_aborting_address_change), r)
return null
}
suspend fun apiAbortSwitchGroupMember(groupId: Long, groupMemberId: Long): ConnectionStats? {
val r = sendCmd(CC.APIAbortSwitchGroupMember(groupId, groupMemberId))
if (r is CR.GroupMemberSwitchAborted) return r.connectionStats
apiErrorAlert("apiAbortSwitchGroupMember", generalGetString(R.string.error_aborting_address_change), r)
apiErrorAlert("apiAbortSwitchGroupMember", generalGetString(MR.strings.error_aborting_address_change), r)
return null
}
@@ -801,7 +803,7 @@ object ChatController {
is CR.Invitation -> r.connReqInvitation
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiAddContact", generalGetString(R.string.connection_error), r)
apiErrorAlert("apiAddContact", generalGetString(MR.strings.connection_error), r)
}
null
}
@@ -818,16 +820,16 @@ object ChatController {
r is CR.SentConfirmation || r is CR.SentInvitation -> return true
r is CR.ContactAlreadyExists -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.contact_already_exists),
String.format(generalGetString(R.string.you_are_already_connected_to_vName_via_this_link), r.contact.displayName)
generalGetString(MR.strings.contact_already_exists),
String.format(generalGetString(MR.strings.you_are_already_connected_to_vName_via_this_link), r.contact.displayName)
)
return false
}
r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorChat
&& r.chatError.errorType is ChatErrorType.InvalidConnReq -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.invalid_connection_link),
generalGetString(R.string.please_check_correct_link_and_maybe_ask_for_a_new_one)
generalGetString(MR.strings.invalid_connection_link),
generalGetString(MR.strings.please_check_correct_link_and_maybe_ask_for_a_new_one)
)
return false
}
@@ -835,14 +837,14 @@ object ChatController {
&& r.chatError.agentError is AgentErrorType.SMP
&& r.chatError.agentError.smpErr is SMPErrorType.AUTH -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.connection_error_auth),
generalGetString(R.string.connection_error_auth_desc)
generalGetString(MR.strings.connection_error_auth),
generalGetString(MR.strings.connection_error_auth_desc)
)
return false
}
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiConnect", generalGetString(R.string.connection_error), r)
apiErrorAlert("apiConnect", generalGetString(MR.strings.connection_error), r)
}
return false
}
@@ -857,10 +859,10 @@ object ChatController {
r is CR.GroupDeletedUser && type == ChatType.Group -> return true
else -> {
val titleId = when (type) {
ChatType.Direct -> R.string.error_deleting_contact
ChatType.Group -> R.string.error_deleting_group
ChatType.ContactRequest -> R.string.error_deleting_contact_request
ChatType.ContactConnection -> R.string.error_deleting_pending_contact_connection
ChatType.Direct -> MR.strings.error_deleting_contact
ChatType.Group -> MR.strings.error_deleting_group
ChatType.ContactRequest -> MR.strings.error_deleting_contact_request
ChatType.ContactConnection -> MR.strings.error_deleting_pending_contact_connection
}
apiErrorAlert("apiDeleteChat", generalGetString(titleId), r)
}
@@ -929,7 +931,7 @@ object ChatController {
is CR.UserContactLinkCreated -> r.connReqContact
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiCreateUserAddress", generalGetString(R.string.error_creating_address), r)
apiErrorAlert("apiCreateUserAddress", generalGetString(MR.strings.error_creating_address), r)
}
null
}
@@ -976,14 +978,14 @@ object ChatController {
&& r.chatError.agentError is AgentErrorType.SMP
&& r.chatError.agentError.smpErr is SMPErrorType.AUTH -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.connection_error_auth),
generalGetString(R.string.sender_may_have_deleted_the_connection_request)
generalGetString(MR.strings.connection_error_auth),
generalGetString(MR.strings.sender_may_have_deleted_the_connection_request)
)
null
}
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiAcceptContactRequest", generalGetString(R.string.error_accepting_contact_request), r)
apiErrorAlert("apiAcceptContactRequest", generalGetString(MR.strings.error_accepting_contact_request), r)
}
null
}
@@ -1056,8 +1058,8 @@ object ChatController {
is CR.RcvFileAccepted -> r.chatItem
is CR.RcvFileAcceptedSndCancelled -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.cannot_receive_file),
generalGetString(R.string.sender_cancelled_file_transfer)
generalGetString(MR.strings.cannot_receive_file),
generalGetString(MR.strings.sender_cancelled_file_transfer)
)
null
}
@@ -1068,7 +1070,7 @@ object ChatController {
) {
Log.d(TAG, "apiReceiveFile ignoring FileAlreadyReceiving error")
} else {
apiErrorAlert("apiReceiveFile", generalGetString(R.string.error_receiving_file), r)
apiErrorAlert("apiReceiveFile", generalGetString(MR.strings.error_receiving_file), r)
}
}
null
@@ -1110,7 +1112,7 @@ object ChatController {
is CR.SentGroupInvitation -> r.member
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiAddMember", generalGetString(R.string.error_adding_members), r)
apiErrorAlert("apiAddMember", generalGetString(MR.strings.error_adding_members), r)
}
null
}
@@ -1127,15 +1129,15 @@ object ChatController {
suspend fun deleteGroup() { if (apiDeleteChat(ChatType.Group, groupId)) { chatModel.removeChat("#$groupId") } }
if (e is ChatError.ChatErrorAgent && e.agentError is AgentErrorType.SMP && e.agentError.smpErr is SMPErrorType.AUTH) {
deleteGroup()
AlertManager.shared.showAlertMsg(generalGetString(R.string.alert_title_group_invitation_expired), generalGetString(R.string.alert_message_group_invitation_expired))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.alert_title_group_invitation_expired), generalGetString(MR.strings.alert_message_group_invitation_expired))
} else if (e is ChatError.ChatErrorStore && e.storeError is StoreError.GroupNotFound) {
deleteGroup()
AlertManager.shared.showAlertMsg(generalGetString(R.string.alert_title_no_group), generalGetString(R.string.alert_message_no_group))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.alert_title_no_group), generalGetString(MR.strings.alert_message_no_group))
} else if (!(networkErrorAlert(r))) {
apiErrorAlert("apiJoinGroup", generalGetString(R.string.error_joining_group), r)
apiErrorAlert("apiJoinGroup", generalGetString(MR.strings.error_joining_group), r)
}
}
else -> apiErrorAlert("apiJoinGroup", generalGetString(R.string.error_joining_group), r)
else -> apiErrorAlert("apiJoinGroup", generalGetString(MR.strings.error_joining_group), r)
}
}
@@ -1144,7 +1146,7 @@ object ChatController {
is CR.UserDeletedMember -> r.member
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiRemoveMember", generalGetString(R.string.error_removing_member), r)
apiErrorAlert("apiRemoveMember", generalGetString(MR.strings.error_removing_member), r)
}
null
}
@@ -1155,7 +1157,7 @@ object ChatController {
is CR.MemberRoleUser -> r.member
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiMemberRole", generalGetString(R.string.error_changing_role), r)
apiErrorAlert("apiMemberRole", generalGetString(MR.strings.error_changing_role), r)
}
throw Exception("failed to change member role: ${r.responseType} ${r.details}")
}
@@ -1179,13 +1181,13 @@ object ChatController {
return when (val r = sendCmd(CC.ApiUpdateGroupProfile(groupId, groupProfile))) {
is CR.GroupUpdated -> r.toGroup
is CR.ChatCmdError -> {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_saving_group_profile), "$r.chatError")
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_saving_group_profile), "$r.chatError")
null
}
else -> {
Log.e(TAG, "apiUpdateGroup bad response: ${r.responseType} ${r.details}")
AlertManager.shared.showAlertMsg(
generalGetString(R.string.error_saving_group_profile),
generalGetString(MR.strings.error_saving_group_profile),
"${r.responseType}: ${r.details}"
)
null
@@ -1198,7 +1200,7 @@ object ChatController {
is CR.GroupLinkCreated -> r.connReqContact to r.memberRole
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiCreateGroupLink", generalGetString(R.string.error_creating_link_for_group), r)
apiErrorAlert("apiCreateGroupLink", generalGetString(MR.strings.error_creating_link_for_group), r)
}
null
}
@@ -1210,7 +1212,7 @@ object ChatController {
is CR.GroupLink -> r.connReqContact to r.memberRole
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiGroupLinkMemberRole", generalGetString(R.string.error_updating_link_for_group), r)
apiErrorAlert("apiGroupLinkMemberRole", generalGetString(MR.strings.error_updating_link_for_group), r)
}
null
}
@@ -1222,7 +1224,7 @@ object ChatController {
is CR.GroupLinkDeleted -> true
else -> {
if (!(networkErrorAlert(r))) {
apiErrorAlert("apiDeleteGroupLink", generalGetString(R.string.error_deleting_link_for_group), r)
apiErrorAlert("apiDeleteGroupLink", generalGetString(MR.strings.error_deleting_link_for_group), r)
}
false
}
@@ -1270,8 +1272,8 @@ object ChatController {
&& r.chatError.agentError is AgentErrorType.BROKER
&& r.chatError.agentError.brokerErr is BrokerErrorType.TIMEOUT -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.connection_timeout),
String.format(generalGetString(R.string.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress))
generalGetString(MR.strings.connection_timeout),
String.format(generalGetString(MR.strings.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress))
)
true
}
@@ -1279,8 +1281,8 @@ object ChatController {
&& r.chatError.agentError is AgentErrorType.BROKER
&& r.chatError.agentError.brokerErr is BrokerErrorType.NETWORK -> {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.connection_error),
String.format(generalGetString(R.string.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress))
generalGetString(MR.strings.connection_error),
String.format(generalGetString(MR.strings.network_error_desc), serverHostname(r.chatError.agentError.brokerAddress))
)
true
}
@@ -1429,7 +1431,7 @@ object ChatController {
r.user,
cInfo.id,
cInfo.displayName,
generalGetString(if (r.toChatItem != null) R.string.marked_deleted_description else R.string.deleted_description)
generalGetString(if (r.toChatItem != null) MR.strings.marked_deleted_description else MR.strings.deleted_description)
)
}
if (r.toChatItem == null) {
@@ -1707,10 +1709,10 @@ object ChatController {
Icon(
painterResource(R.drawable.ic_bolt),
contentDescription =
if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
)
Text(
if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
fontWeight = FontWeight.Bold
)
}
@@ -1718,16 +1720,16 @@ object ChatController {
text = {
Column {
Text(
if (mode == NotificationsMode.SERVICE) annotatedStringResource(R.string.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(R.string.periodic_notifications_desc),
if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc),
Modifier.padding(bottom = 8.dp)
)
Text(
annotatedStringResource(R.string.it_can_disabled_via_settings_notifications_still_shown)
annotatedStringResource(MR.strings.it_can_disabled_via_settings_notifications_still_shown)
)
}
},
confirmButton = {
TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(R.string.ok)) }
TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(MR.strings.ok)) }
}
)
}
@@ -1744,10 +1746,10 @@ object ChatController {
Icon(
painterResource(R.drawable.ic_bolt),
contentDescription =
if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
)
Text(
if (mode == NotificationsMode.SERVICE) stringResource(R.string.service_notifications) else stringResource(R.string.periodic_notifications),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications) else stringResource(MR.strings.periodic_notifications),
fontWeight = FontWeight.Bold
)
}
@@ -1755,14 +1757,14 @@ object ChatController {
text = {
Column {
Text(
if (mode == NotificationsMode.SERVICE) annotatedStringResource(R.string.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(R.string.periodic_notifications_desc),
if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc),
Modifier.padding(bottom = 8.dp)
)
Text(annotatedStringResource(R.string.turn_off_battery_optimization))
Text(annotatedStringResource(MR.strings.turn_off_battery_optimization))
}
},
confirmButton = {
TextButton(onClick = ignoreOptimization) { Text(stringResource(R.string.ok)) }
TextButton(onClick = ignoreOptimization) { Text(stringResource(MR.strings.ok)) }
}
)
}
@@ -1775,10 +1777,10 @@ object ChatController {
Icon(
painterResource(R.drawable.ic_bolt),
contentDescription =
if (mode == NotificationsMode.SERVICE) stringResource(R.string.icon_descr_instant_notifications) else stringResource(R.string.periodic_notifications),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
)
Text(
if (mode == NotificationsMode.SERVICE) stringResource(R.string.service_notifications_disabled) else stringResource(R.string.periodic_notifications_disabled),
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications_disabled) else stringResource(MR.strings.periodic_notifications_disabled),
fontWeight = FontWeight.Bold
)
}
@@ -1786,13 +1788,13 @@ object ChatController {
text = {
Column {
Text(
annotatedStringResource(R.string.turning_off_service_and_periodic),
annotatedStringResource(MR.strings.turning_off_service_and_periodic),
Modifier.padding(bottom = 8.dp)
)
}
},
confirmButton = {
TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(R.string.ok)) }
TextButton(onClick = AlertManager.shared::hideAlert) { Text(stringResource(MR.strings.ok)) }
}
)
}
@@ -2329,16 +2331,16 @@ enum class ProtocolTestStep {
@SerialName("deleteFile") DeleteFile;
val text: String get() = when (this) {
Connect -> generalGetString(R.string.smp_server_test_connect)
Disconnect -> generalGetString(R.string.smp_server_test_disconnect)
CreateQueue -> generalGetString(R.string.smp_server_test_create_queue)
SecureQueue -> generalGetString(R.string.smp_server_test_secure_queue)
DeleteQueue -> generalGetString(R.string.smp_server_test_delete_queue)
CreateFile -> generalGetString(R.string.smp_server_test_create_file)
UploadFile -> generalGetString(R.string.smp_server_test_upload_file)
DownloadFile -> generalGetString(R.string.smp_server_test_download_file)
CompareFile -> generalGetString(R.string.smp_server_test_compare_file)
DeleteFile -> generalGetString(R.string.smp_server_test_delete_file)
Connect -> generalGetString(MR.strings.smp_server_test_connect)
Disconnect -> generalGetString(MR.strings.smp_server_test_disconnect)
CreateQueue -> generalGetString(MR.strings.smp_server_test_create_queue)
SecureQueue -> generalGetString(MR.strings.smp_server_test_secure_queue)
DeleteQueue -> generalGetString(MR.strings.smp_server_test_delete_queue)
CreateFile -> generalGetString(MR.strings.smp_server_test_create_file)
UploadFile -> generalGetString(MR.strings.smp_server_test_upload_file)
DownloadFile -> generalGetString(MR.strings.smp_server_test_download_file)
CompareFile -> generalGetString(MR.strings.smp_server_test_compare_file)
DeleteFile -> generalGetString(MR.strings.smp_server_test_delete_file)
}
}
@@ -2357,14 +2359,14 @@ data class ProtocolTestFailure(
}
val localizedDescription: String get() {
val err = String.format(generalGetString(R.string.error_smp_test_failed_at_step), testStep.text)
val err = String.format(generalGetString(MR.strings.error_smp_test_failed_at_step), testStep.text)
return when {
testError is AgentErrorType.SMP && testError.smpErr is SMPErrorType.AUTH ->
err + " " + generalGetString(R.string.error_smp_test_server_auth)
err + " " + generalGetString(MR.strings.error_smp_test_server_auth)
testError is AgentErrorType.XFTP && testError.xftpErr is XFTPErrorType.AUTH ->
err + " " + generalGetString(R.string.error_xftp_test_server_auth)
err + " " + generalGetString(MR.strings.error_xftp_test_server_auth)
testError is AgentErrorType.BROKER && testError.brokerErr is BrokerErrorType.NETWORK ->
err + " " + generalGetString(R.string.error_smp_test_certificate)
err + " " + generalGetString(MR.strings.error_smp_test_certificate)
else -> err
}
}
@@ -2629,12 +2631,12 @@ sealed class CustomTimeUnit {
val text: String
get() =
when (this) {
Second -> generalGetString(R.string.custom_time_unit_seconds)
Minute -> generalGetString(R.string.custom_time_unit_minutes)
Hour -> generalGetString(R.string.custom_time_unit_hours)
Day -> generalGetString(R.string.custom_time_unit_days)
Week -> generalGetString(R.string.custom_time_unit_weeks)
Month -> generalGetString(R.string.custom_time_unit_months)
Second -> generalGetString(MR.strings.custom_time_unit_seconds)
Minute -> generalGetString(MR.strings.custom_time_unit_minutes)
Hour -> generalGetString(MR.strings.custom_time_unit_hours)
Day -> generalGetString(MR.strings.custom_time_unit_days)
Week -> generalGetString(MR.strings.custom_time_unit_weeks)
Month -> generalGetString(MR.strings.custom_time_unit_months)
}
companion object {
@@ -2657,24 +2659,24 @@ sealed class CustomTimeUnit {
fun toText(seconds: Int): String {
val (unit, value) = toTimeUnit(seconds)
return when (unit) {
Second -> String.format(generalGetString(R.string.ttl_sec), value)
Minute -> String.format(generalGetString(R.string.ttl_min), value)
Hour -> if (value == 1) String.format(generalGetString(R.string.ttl_hour), 1) else String.format(generalGetString(R.string.ttl_hours), value)
Day -> if (value == 1) String.format(generalGetString(R.string.ttl_day), 1) else String.format(generalGetString(R.string.ttl_days), value)
Week -> if (value == 1) String.format(generalGetString(R.string.ttl_week), 1) else String.format(generalGetString(R.string.ttl_weeks), value)
Month -> if (value == 1) String.format(generalGetString(R.string.ttl_month), 1) else String.format(generalGetString(R.string.ttl_months), value)
Second -> String.format(generalGetString(MR.strings.ttl_sec), value)
Minute -> String.format(generalGetString(MR.strings.ttl_min), value)
Hour -> if (value == 1) String.format(generalGetString(MR.strings.ttl_hour), 1) else String.format(generalGetString(MR.strings.ttl_hours), value)
Day -> if (value == 1) String.format(generalGetString(MR.strings.ttl_day), 1) else String.format(generalGetString(MR.strings.ttl_days), value)
Week -> if (value == 1) String.format(generalGetString(MR.strings.ttl_week), 1) else String.format(generalGetString(MR.strings.ttl_weeks), value)
Month -> if (value == 1) String.format(generalGetString(MR.strings.ttl_month), 1) else String.format(generalGetString(MR.strings.ttl_months), value)
}
}
fun toShortText(seconds: Int): String {
val (unit, value) = toTimeUnit(seconds)
return when (unit) {
Second -> String.format(generalGetString(R.string.ttl_s), value)
Minute -> String.format(generalGetString(R.string.ttl_m), value)
Hour -> String.format(generalGetString(R.string.ttl_h), value)
Day -> String.format(generalGetString(R.string.ttl_d), value)
Week -> String.format(generalGetString(R.string.ttl_w), value)
Month -> String.format(generalGetString(R.string.ttl_mth), value)
Second -> String.format(generalGetString(MR.strings.ttl_s), value)
Minute -> String.format(generalGetString(MR.strings.ttl_m), value)
Hour -> String.format(generalGetString(MR.strings.ttl_h), value)
Day -> String.format(generalGetString(MR.strings.ttl_d), value)
Week -> String.format(generalGetString(MR.strings.ttl_w), value)
Month -> String.format(generalGetString(MR.strings.ttl_mth), value)
}
}
}
@@ -2682,20 +2684,20 @@ sealed class CustomTimeUnit {
fun timeText(seconds: Int?): String {
if (seconds == null) {
return generalGetString(R.string.feature_off)
return generalGetString(MR.strings.feature_off)
}
if (seconds == 0) {
String.format(generalGetString(R.string.ttl_sec), 0)
String.format(generalGetString(MR.strings.ttl_sec), 0)
}
return CustomTimeUnit.toText(seconds)
}
fun shortTimeText(seconds: Int?): String {
if (seconds == null) {
return generalGetString(R.string.feature_off)
return generalGetString(MR.strings.feature_off)
}
if (seconds == 0) {
String.format(generalGetString(R.string.ttl_s), 0)
String.format(generalGetString(MR.strings.ttl_s), 0)
}
return CustomTimeUnit.toShortText(seconds)
}
@@ -2768,10 +2770,10 @@ data class FeatureEnabled(
) {
val text: String
get() = when {
forUser && forContact -> generalGetString(R.string.feature_enabled)
forUser -> generalGetString(R.string.feature_enabled_for_you)
forContact -> generalGetString(R.string.feature_enabled_for_contact)
else -> generalGetString(R.string.feature_off)
forUser && forContact -> generalGetString(MR.strings.feature_enabled)
forUser -> generalGetString(MR.strings.feature_enabled_for_you)
forContact -> generalGetString(MR.strings.feature_enabled_for_contact)
else -> generalGetString(MR.strings.feature_off)
}
val iconColor: Color
@@ -2845,11 +2847,11 @@ enum class ChatFeature: Feature {
override val text: String
get() = when(this) {
TimedMessages -> generalGetString(R.string.timed_messages)
FullDelete -> generalGetString(R.string.full_deletion)
Reactions -> generalGetString(R.string.message_reactions)
Voice -> generalGetString(R.string.voice_messages)
Calls -> generalGetString(R.string.audio_video_calls)
TimedMessages -> generalGetString(MR.strings.timed_messages)
FullDelete -> generalGetString(MR.strings.full_deletion)
Reactions -> generalGetString(MR.strings.message_reactions)
Voice -> generalGetString(MR.strings.voice_messages)
Calls -> generalGetString(MR.strings.audio_video_calls)
}
val icon: Painter
@@ -2873,63 +2875,63 @@ enum class ChatFeature: Feature {
fun allowDescription(allowed: FeatureAllowed): String =
when (this) {
TimedMessages -> when (allowed) {
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_disappearing_messages)
FeatureAllowed.YES -> generalGetString(R.string.allow_disappearing_messages_only_if)
FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_disappearing_messages)
FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_send_disappearing_messages)
FeatureAllowed.YES -> generalGetString(MR.strings.allow_disappearing_messages_only_if)
FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_sending_disappearing_messages)
}
FullDelete -> when (allowed) {
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_irreversibly_delete)
FeatureAllowed.YES -> generalGetString(R.string.allow_irreversible_message_deletion_only_if)
FeatureAllowed.NO -> generalGetString(R.string.contacts_can_mark_messages_for_deletion)
FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_irreversibly_delete)
FeatureAllowed.YES -> generalGetString(MR.strings.allow_irreversible_message_deletion_only_if)
FeatureAllowed.NO -> generalGetString(MR.strings.contacts_can_mark_messages_for_deletion)
}
Reactions -> when (allowed) {
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_adding_message_reactions)
FeatureAllowed.YES -> generalGetString(R.string.allow_message_reactions_only_if)
FeatureAllowed.NO -> generalGetString(R.string.prohibit_message_reactions)
FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_adding_message_reactions)
FeatureAllowed.YES -> generalGetString(MR.strings.allow_message_reactions_only_if)
FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_message_reactions)
}
Voice -> when (allowed) {
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_send_voice_messages)
FeatureAllowed.YES -> generalGetString(R.string.allow_voice_messages_only_if)
FeatureAllowed.NO -> generalGetString(R.string.prohibit_sending_voice_messages)
FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_send_voice_messages)
FeatureAllowed.YES -> generalGetString(MR.strings.allow_voice_messages_only_if)
FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_sending_voice_messages)
}
Calls -> when (allowed) {
FeatureAllowed.ALWAYS -> generalGetString(R.string.allow_your_contacts_to_call)
FeatureAllowed.YES -> generalGetString(R.string.allow_calls_only_if)
FeatureAllowed.NO -> generalGetString(R.string.prohibit_calls)
FeatureAllowed.ALWAYS -> generalGetString(MR.strings.allow_your_contacts_to_call)
FeatureAllowed.YES -> generalGetString(MR.strings.allow_calls_only_if)
FeatureAllowed.NO -> generalGetString(MR.strings.prohibit_calls)
}
}
fun enabledDescription(enabled: FeatureEnabled): String =
when (this) {
TimedMessages -> when {
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_disappearing)
enabled.forUser -> generalGetString(R.string.only_you_can_send_disappearing)
enabled.forContact -> generalGetString(R.string.only_your_contact_can_send_disappearing)
else -> generalGetString(R.string.disappearing_prohibited_in_this_chat)
enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_send_disappearing)
enabled.forUser -> generalGetString(MR.strings.only_you_can_send_disappearing)
enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_send_disappearing)
else -> generalGetString(MR.strings.disappearing_prohibited_in_this_chat)
}
FullDelete -> when {
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contacts_can_delete)
enabled.forUser -> generalGetString(R.string.only_you_can_delete_messages)
enabled.forContact -> generalGetString(R.string.only_your_contact_can_delete)
else -> generalGetString(R.string.message_deletion_prohibited)
enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contacts_can_delete)
enabled.forUser -> generalGetString(MR.strings.only_you_can_delete_messages)
enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_delete)
else -> generalGetString(MR.strings.message_deletion_prohibited)
}
Reactions -> when {
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_add_message_reactions)
enabled.forUser -> generalGetString(R.string.only_you_can_add_message_reactions)
enabled.forContact -> generalGetString(R.string.only_your_contact_can_add_message_reactions)
else -> generalGetString(R.string.message_reactions_prohibited_in_this_chat)
enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_add_message_reactions)
enabled.forUser -> generalGetString(MR.strings.only_you_can_add_message_reactions)
enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_add_message_reactions)
else -> generalGetString(MR.strings.message_reactions_prohibited_in_this_chat)
}
Voice -> when {
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_send_voice)
enabled.forUser -> generalGetString(R.string.only_you_can_send_voice)
enabled.forContact -> generalGetString(R.string.only_your_contact_can_send_voice)
else -> generalGetString(R.string.voice_prohibited_in_this_chat)
enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_send_voice)
enabled.forUser -> generalGetString(MR.strings.only_you_can_send_voice)
enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_send_voice)
else -> generalGetString(MR.strings.voice_prohibited_in_this_chat)
}
Calls -> when {
enabled.forUser && enabled.forContact -> generalGetString(R.string.both_you_and_your_contact_can_make_calls)
enabled.forUser -> generalGetString(R.string.only_you_can_make_calls)
enabled.forContact -> generalGetString(R.string.only_your_contact_can_make_calls)
else -> generalGetString(R.string.calls_prohibited_with_this_contact)
enabled.forUser && enabled.forContact -> generalGetString(MR.strings.both_you_and_your_contact_can_make_calls)
enabled.forUser -> generalGetString(MR.strings.only_you_can_make_calls)
enabled.forContact -> generalGetString(MR.strings.only_your_contact_can_make_calls)
else -> generalGetString(MR.strings.calls_prohibited_with_this_contact)
}
}
}
@@ -2950,12 +2952,12 @@ enum class GroupFeature: Feature {
override val text: String
get() = when(this) {
TimedMessages -> generalGetString(R.string.timed_messages)
DirectMessages -> generalGetString(R.string.direct_messages)
FullDelete -> generalGetString(R.string.full_deletion)
Reactions -> generalGetString(R.string.message_reactions)
Voice -> generalGetString(R.string.voice_messages)
Files -> generalGetString(R.string.files_and_media)
TimedMessages -> generalGetString(MR.strings.timed_messages)
DirectMessages -> generalGetString(MR.strings.direct_messages)
FullDelete -> generalGetString(MR.strings.full_deletion)
Reactions -> generalGetString(MR.strings.message_reactions)
Voice -> generalGetString(MR.strings.voice_messages)
Files -> generalGetString(MR.strings.files_and_media)
}
val icon: Painter
@@ -2982,55 +2984,55 @@ enum class GroupFeature: Feature {
if (canEdit) {
when(this) {
TimedMessages -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_disappearing)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_disappearing)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_disappearing)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_disappearing)
}
DirectMessages -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_direct_messages)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_direct_messages)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_direct_messages)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_direct_messages)
}
FullDelete -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_delete_messages)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_deletion)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_delete_messages)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_message_deletion)
}
Reactions -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_message_reactions)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_message_reactions_group)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_message_reactions)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_message_reactions_group)
}
Voice -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_voice)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_voice)
}
Files -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.allow_to_send_files)
GroupFeatureEnabled.OFF -> generalGetString(R.string.prohibit_sending_files)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.allow_to_send_files)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.prohibit_sending_files)
}
}
} else {
when(this) {
TimedMessages -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_disappearing)
GroupFeatureEnabled.OFF -> generalGetString(R.string.disappearing_messages_are_prohibited)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_disappearing)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.disappearing_messages_are_prohibited)
}
DirectMessages -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_dms)
GroupFeatureEnabled.OFF -> generalGetString(R.string.direct_messages_are_prohibited_in_chat)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_dms)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.direct_messages_are_prohibited_in_chat)
}
FullDelete -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_delete)
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_deletion_prohibited_in_chat)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_delete)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.message_deletion_prohibited_in_chat)
}
Reactions -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_add_message_reactions)
GroupFeatureEnabled.OFF -> generalGetString(R.string.message_reactions_are_prohibited)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_add_message_reactions)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.message_reactions_are_prohibited)
}
Voice -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(R.string.voice_messages_are_prohibited)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_voice)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.voice_messages_are_prohibited)
}
Files -> when(enabled) {
GroupFeatureEnabled.ON -> generalGetString(R.string.group_members_can_send_files)
GroupFeatureEnabled.OFF -> generalGetString(R.string.files_are_prohibited_in_group)
GroupFeatureEnabled.ON -> generalGetString(MR.strings.group_members_can_send_files)
GroupFeatureEnabled.OFF -> generalGetString(MR.strings.files_are_prohibited_in_group)
}
}
}
@@ -3056,10 +3058,10 @@ sealed class ContactFeatureAllowed {
}
val text: String
get() = when (this) {
is UserDefault -> String.format(generalGetString(R.string.chat_preferences_default), default.text)
is Always -> generalGetString(R.string.chat_preferences_always)
is Yes -> generalGetString(R.string.chat_preferences_yes)
is No -> generalGetString(R.string.chat_preferences_no)
is UserDefault -> String.format(generalGetString(MR.strings.chat_preferences_default), default.text)
is Always -> generalGetString(MR.strings.chat_preferences_always)
is Yes -> generalGetString(MR.strings.chat_preferences_yes)
is No -> generalGetString(MR.strings.chat_preferences_no)
}
}
@@ -3132,9 +3134,9 @@ enum class FeatureAllowed {
val text: String
get() = when(this) {
ALWAYS -> generalGetString(R.string.chat_preferences_always)
YES -> generalGetString(R.string.chat_preferences_yes)
NO -> generalGetString(R.string.chat_preferences_no)
ALWAYS -> generalGetString(MR.strings.chat_preferences_always)
YES -> generalGetString(MR.strings.chat_preferences_yes)
NO -> generalGetString(MR.strings.chat_preferences_no)
}
}
@@ -3212,8 +3214,8 @@ enum class GroupFeatureEnabled {
val text: String
get() = when (this) {
ON -> generalGetString(R.string.chat_preferences_on)
OFF -> generalGetString(R.string.chat_preferences_off)
ON -> generalGetString(MR.strings.chat_preferences_on)
OFF -> generalGetString(MR.strings.chat_preferences_off)
}
val iconColor: Color
@@ -3656,7 +3658,7 @@ sealed class CR {
is Invalid -> str
}
fun noDetails(): String ="${responseType}: " + generalGetString(R.string.no_details)
fun noDetails(): String ="${responseType}: " + generalGetString(MR.strings.no_details)
private fun withUser(u: User?, s: String): String = if (u != null) "userId: ${u.userId}\n$s" else s
}
@@ -13,6 +13,7 @@ import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -69,15 +70,15 @@ enum class ThemeColor {
val text: String
get() = when (this) {
PRIMARY -> generalGetString(R.string.color_primary)
PRIMARY_VARIANT -> generalGetString(R.string.color_primary_variant)
SECONDARY -> generalGetString(R.string.color_secondary)
SECONDARY_VARIANT -> generalGetString(R.string.color_secondary_variant)
BACKGROUND -> generalGetString(R.string.color_background)
SURFACE -> generalGetString(R.string.color_surface)
TITLE -> generalGetString(R.string.color_title)
SENT_MESSAGE -> generalGetString(R.string.color_sent_message)
RECEIVED_MESSAGE -> generalGetString(R.string.color_received_message)
PRIMARY -> generalGetString(MR.strings.color_primary)
PRIMARY_VARIANT -> generalGetString(MR.strings.color_primary_variant)
SECONDARY -> generalGetString(MR.strings.color_secondary)
SECONDARY_VARIANT -> generalGetString(MR.strings.color_secondary_variant)
BACKGROUND -> generalGetString(MR.strings.color_background)
SURFACE -> generalGetString(MR.strings.color_surface)
TITLE -> generalGetString(MR.strings.color_title)
SENT_MESSAGE -> generalGetString(MR.strings.color_sent_message)
RECEIVED_MESSAGE -> generalGetString(MR.strings.color_received_message)
}
}
@@ -7,6 +7,7 @@ import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.model.AppPreferences
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
object ThemeManager {
private val appPrefs: AppPreferences by lazy {
@@ -62,28 +63,28 @@ object ThemeManager {
Triple(
if (darkForSystemTheme) systemDarkThemeColors().first else LightColorPalette,
DefaultTheme.SYSTEM,
generalGetString(R.string.theme_system)
generalGetString(MR.strings.theme_system)
)
)
allThemes.add(
Triple(
LightColorPalette,
DefaultTheme.LIGHT,
generalGetString(R.string.theme_light)
generalGetString(MR.strings.theme_light)
)
)
allThemes.add(
Triple(
DarkColorPalette,
DefaultTheme.DARK,
generalGetString(R.string.theme_dark)
generalGetString(MR.strings.theme_dark)
)
)
allThemes.add(
Triple(
SimplexColorPalette,
DefaultTheme.SIMPLEX,
generalGetString(R.string.theme_simplex)
generalGetString(MR.strings.theme_simplex)
)
)
return allThemes
@@ -15,7 +15,7 @@ import androidx.compose.ui.focus.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -31,6 +31,8 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.app.views.onboarding.ReadableText
import com.google.accompanist.insets.navigationBarsWithImePadding
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -55,18 +57,18 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
}
})*/
Column(Modifier.padding(horizontal = DEFAULT_PADDING)) {
AppBarTitle(stringResource(R.string.create_profile), bottomPadding = DEFAULT_PADDING)
ReadableText(R.string.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1)
ReadableText(R.string.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1)
AppBarTitle(stringResource(MR.strings.create_profile), bottomPadding = DEFAULT_PADDING)
ReadableText(MR.strings.your_profile_is_stored_on_your_device, TextAlign.Center, padding = PaddingValues(), style = MaterialTheme.typography.body1)
ReadableText(MR.strings.profile_is_only_shared_with_your_contacts, TextAlign.Center, style = MaterialTheme.typography.body1)
Spacer(Modifier.height(DEFAULT_PADDING))
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(R.string.display_name),
stringResource(MR.strings.display_name),
fontSize = 16.sp
)
if (!isValidDisplayName(displayName.value)) {
Text(
stringResource(R.string.no_spaces),
stringResource(MR.strings.no_spaces),
fontSize = 16.sp,
color = Color.Red
)
@@ -75,7 +77,7 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(R.string.full_name_optional__prompt),
stringResource(MR.strings.full_name_optional__prompt),
fontSize = 16.sp,
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
)
@@ -85,7 +87,7 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
Row {
if (chatModel.users.isEmpty()) {
SimpleButtonDecorated(
text = stringResource(R.string.about_simplex),
text = stringResource(MR.strings.about_simplex),
icon = painterResource(R.drawable.ic_arrow_back_ios_new),
textDecoration = TextDecoration.None,
fontWeight = FontWeight.Medium
@@ -104,8 +106,8 @@ fun CreateProfilePanel(chatModel: ChatModel, close: () -> Unit) {
}
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = createColor)
Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = createColor)
}
}
}
@@ -13,7 +13,6 @@ import android.util.Log
import android.view.ViewGroup
import android.webkit.*
import androidx.activity.compose.BackHandler
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
@@ -25,7 +24,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -42,6 +41,8 @@ import chat.simplex.app.views.helpers.ProfileImage
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.usersettings.NotificationsMode
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@@ -272,14 +273,14 @@ private fun ActiveCallOverlayLayout(
ToggleAudioButton(call, toggleAudio)
Spacer(Modifier.size(40.dp))
IconButton(onClick = dismiss) {
Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(R.string.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp))
Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp))
}
if (call.videoEnabled) {
ControlButton(call, painterResource(R.drawable.ic_flip_camera_android_filled), R.string.icon_descr_flip_camera, flipCamera)
ControlButton(call, painterResource(R.drawable.ic_videocam_filled), R.string.icon_descr_video_off, toggleVideo)
ControlButton(call, painterResource(R.drawable.ic_flip_camera_android_filled), MR.strings.icon_descr_flip_camera, flipCamera)
ControlButton(call, painterResource(R.drawable.ic_videocam_filled), MR.strings.icon_descr_video_off, toggleVideo)
} else {
Spacer(Modifier.size(48.dp))
ControlButton(call, painterResource(R.drawable.ic_videocam_off), R.string.icon_descr_video_on, toggleVideo)
ControlButton(call, painterResource(R.drawable.ic_videocam_off), MR.strings.icon_descr_video_on, toggleVideo)
}
}
}
@@ -297,7 +298,7 @@ private fun ActiveCallOverlayLayout(
Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_BOTTOM_PADDING), contentAlignment = Alignment.CenterStart) {
Box(Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) {
IconButton(onClick = dismiss) {
Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(R.string.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp))
Icon(painterResource(R.drawable.ic_call_end_filled), stringResource(MR.strings.icon_descr_hang_up), tint = Color.Red, modifier = Modifier.size(64.dp))
}
}
Box(Modifier.padding(start = 32.dp)) {
@@ -315,7 +316,7 @@ private fun ActiveCallOverlayLayout(
}
@Composable
private fun ControlButton(call: Call, icon: Painter, @StringRes iconText: Int, action: () -> Unit, enabled: Boolean = true) {
private fun ControlButton(call: Call, icon: Painter, iconText: StringResource, action: () -> Unit, enabled: Boolean = true) {
if (call.hasMedia) {
IconButton(onClick = action, enabled = enabled) {
Icon(icon, stringResource(iconText), tint = if (enabled) Color(0xFFFFFFD8) else MaterialTheme.colors.secondary, modifier = Modifier.size(40.dp))
@@ -328,18 +329,18 @@ private fun ControlButton(call: Call, icon: Painter, @StringRes iconText: Int, a
@Composable
private fun ToggleAudioButton(call: Call, toggleAudio: () -> Unit) {
if (call.audioEnabled) {
ControlButton(call, painterResource(R.drawable.ic_mic), R.string.icon_descr_audio_off, toggleAudio)
ControlButton(call, painterResource(R.drawable.ic_mic), MR.strings.icon_descr_audio_off, toggleAudio)
} else {
ControlButton(call, painterResource(R.drawable.ic_mic_off), R.string.icon_descr_audio_on, toggleAudio)
ControlButton(call, painterResource(R.drawable.ic_mic_off), MR.strings.icon_descr_audio_on, toggleAudio)
}
}
@Composable
private fun ToggleSoundButton(call: Call, enabled: Boolean, toggleSound: () -> Unit) {
if (call.soundSpeaker) {
ControlButton(call, painterResource(R.drawable.ic_volume_up), R.string.icon_descr_speaker_off, toggleSound, enabled)
ControlButton(call, painterResource(R.drawable.ic_volume_up), MR.strings.icon_descr_speaker_off, toggleSound, enabled)
} else {
ControlButton(call, painterResource(R.drawable.ic_volume_down), R.string.icon_descr_speaker_on, toggleSound, enabled)
ControlButton(call, painterResource(R.drawable.ic_volume_down), MR.strings.icon_descr_speaker_on, toggleSound, enabled)
}
}
@@ -25,7 +25,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -36,6 +36,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.model.NtfManager.OpenChatAction
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.ProfileImage
import chat.simplex.res.MR
import kotlinx.datetime.Clock
class IncomingCallActivity: ComponentActivity() {
@@ -170,18 +171,18 @@ fun IncomingCallLockScreenAlertLayout(
Text(invitation.contact.chatViewName, style = MaterialTheme.typography.h2)
Spacer(Modifier.fillMaxHeight().weight(1f))
Row {
LockScreenCallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
LockScreenCallButton(stringResource(MR.strings.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
Spacer(Modifier.size(48.dp))
LockScreenCallButton(stringResource(R.string.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall)
LockScreenCallButton(stringResource(MR.strings.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall)
Spacer(Modifier.size(48.dp))
LockScreenCallButton(stringResource(R.string.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall)
LockScreenCallButton(stringResource(MR.strings.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall)
}
} else if (callOnLockScreen == CallOnLockScreen.SHOW) {
SimpleXLogo()
Text(stringResource(R.string.open_simplex_chat_to_accept_call), textAlign = TextAlign.Center, lineHeight = 22.sp)
Text(stringResource(R.string.allow_accepting_calls_from_lock_screen), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2, lineHeight = 22.sp)
Text(stringResource(MR.strings.open_simplex_chat_to_accept_call), textAlign = TextAlign.Center, lineHeight = 22.sp)
Text(stringResource(MR.strings.allow_accepting_calls_from_lock_screen), textAlign = TextAlign.Center, style = MaterialTheme.typography.body2, lineHeight = 22.sp)
Spacer(Modifier.fillMaxHeight().weight(1f))
SimpleButton(text = stringResource(R.string.open_verb), icon = painterResource(R.drawable.ic_check_filled), click = openApp)
SimpleButton(text = stringResource(MR.strings.open_verb), icon = painterResource(R.drawable.ic_check_filled), click = openApp)
}
}
}
@@ -190,7 +191,7 @@ fun IncomingCallLockScreenAlertLayout(
private fun SimpleXLogo() {
Image(
painter = painterResource(if (isInDarkTheme()) R.drawable.logo_light else R.drawable.logo),
contentDescription = stringResource(R.string.image_descr_simplex_logo),
contentDescription = stringResource(MR.strings.image_descr_simplex_logo),
modifier = Modifier
.padding(vertical = DEFAULT_PADDING)
.fillMaxWidth(0.80f)
@@ -12,7 +12,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
@@ -21,6 +21,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.ProfileImage
import chat.simplex.app.views.usersettings.ProfilePreview
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@Composable
@@ -59,9 +60,9 @@ fun IncomingCallAlertLayout(
ProfilePreview(profileOf = invitation.contact, size = 64.dp)
}
Row(verticalAlignment = Alignment.CenterVertically) {
CallButton(stringResource(R.string.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
CallButton(stringResource(R.string.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall)
CallButton(stringResource(R.string.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall)
CallButton(stringResource(MR.strings.reject), painterResource(R.drawable.ic_call_end_filled), Color.Red, rejectCall)
CallButton(stringResource(MR.strings.ignore), painterResource(R.drawable.ic_close), MaterialTheme.colors.primary, ignoreCall)
CallButton(stringResource(MR.strings.accept), painterResource(R.drawable.ic_check_filled), SimplexGreen, acceptCall)
}
}
}
@@ -75,8 +76,8 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) {
ProfileImage(size = 32.dp, image = invitation.user.profile.image, color = MaterialTheme.colors.secondaryVariant)
Spacer(Modifier.width(4.dp))
}
if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(R.string.icon_descr_video_call))
else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(R.string.icon_descr_audio_call))
if (invitation.callType.media == CallMediaType.Video) CallIcon(painterResource(R.drawable.ic_videocam_filled), stringResource(MR.strings.icon_descr_video_call))
else CallIcon(painterResource(R.drawable.ic_call_filled), stringResource(MR.strings.icon_descr_audio_call))
Spacer(Modifier.width(4.dp))
Text(invitation.callTypeText, color = MaterialTheme.colors.onBackground)
}
@@ -1,13 +1,12 @@
package chat.simplex.app.views.call
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.toUpperCase
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.*
import chat.simplex.app.model.Contact
import chat.simplex.app.model.User
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -33,9 +32,9 @@ data class Call(
val encryptionStatus: String @Composable get() = when(callState) {
CallState.WaitCapabilities -> ""
CallState.InvitationSent -> stringResource(if (localEncrypted) R.string.status_e2e_encrypted else R.string.status_no_e2e_encryption)
CallState.InvitationAccepted -> stringResource(if (sharedKey == null) R.string.status_contact_has_no_e2e_encryption else R.string.status_contact_has_e2e_encryption)
else -> stringResource(if (!localEncrypted) R.string.status_no_e2e_encryption else if (sharedKey == null) R.string.status_contact_has_no_e2e_encryption else R.string.status_e2e_encrypted)
CallState.InvitationSent -> stringResource(if (localEncrypted) MR.strings.status_e2e_encrypted else MR.strings.status_no_e2e_encryption)
CallState.InvitationAccepted -> stringResource(if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_contact_has_e2e_encryption)
else -> stringResource(if (!localEncrypted) MR.strings.status_no_e2e_encryption else if (sharedKey == null) MR.strings.status_contact_has_no_e2e_encryption else MR.strings.status_e2e_encrypted)
}
val hasMedia: Boolean get() = callState == CallState.OfferSent || callState == CallState.Negotiated || callState == CallState.Connected
@@ -53,15 +52,15 @@ enum class CallState {
Ended;
val text: String @Composable get() = when(this) {
WaitCapabilities -> stringResource(R.string.callstate_starting)
InvitationSent -> stringResource(R.string.callstate_waiting_for_answer)
InvitationAccepted -> stringResource(R.string.callstate_starting)
OfferSent -> stringResource(R.string.callstate_waiting_for_confirmation)
OfferReceived -> stringResource(R.string.callstate_received_answer)
AnswerReceived -> stringResource(R.string.callstate_received_confirmation)
Negotiated -> stringResource(R.string.callstate_connecting)
Connected -> stringResource(R.string.callstate_connected)
Ended -> stringResource(R.string.callstate_ended)
WaitCapabilities -> stringResource(MR.strings.callstate_starting)
InvitationSent -> stringResource(MR.strings.callstate_waiting_for_answer)
InvitationAccepted -> stringResource(MR.strings.callstate_starting)
OfferSent -> stringResource(MR.strings.callstate_waiting_for_confirmation)
OfferReceived -> stringResource(MR.strings.callstate_received_answer)
AnswerReceived -> stringResource(MR.strings.callstate_received_confirmation)
Negotiated -> stringResource(MR.strings.callstate_connecting)
Connected -> stringResource(MR.strings.callstate_connected)
Ended -> stringResource(MR.strings.callstate_ended)
}
}
@@ -99,12 +98,12 @@ sealed class WCallResponse {
@Serializable data class CallType(val media: CallMediaType, val capabilities: CallCapabilities)
@Serializable data class RcvCallInvitation(val user: User, val contact: Contact, val callType: CallType, val sharedKey: String? = null, val callTs: Instant) {
val callTypeText: String get() = generalGetString(when(callType.media) {
CallMediaType.Video -> if (sharedKey == null) R.string.video_call_no_encryption else R.string.encrypted_video_call
CallMediaType.Audio -> if (sharedKey == null) R.string.audio_call_no_encryption else R.string.encrypted_audio_call
CallMediaType.Video -> if (sharedKey == null) MR.strings.video_call_no_encryption else MR.strings.encrypted_video_call
CallMediaType.Audio -> if (sharedKey == null) MR.strings.audio_call_no_encryption else MR.strings.encrypted_audio_call
})
val callTitle: String get() = generalGetString(when(callType.media) {
CallMediaType.Video -> R.string.incoming_video_call
CallMediaType.Audio -> R.string.incoming_audio_call
CallMediaType.Video -> MR.strings.incoming_video_call
CallMediaType.Audio -> MR.strings.incoming_audio_call
})
}
@Serializable data class CallCapabilities(val encryption: Boolean)
@@ -114,9 +113,9 @@ sealed class WCallResponse {
val remote = remoteCandidate?.candidateType
return when {
local == RTCIceCandidateType.Host && remote == RTCIceCandidateType.Host ->
stringResource(R.string.call_connection_peer_to_peer)
stringResource(MR.strings.call_connection_peer_to_peer)
local == RTCIceCandidateType.Relay && remote == RTCIceCandidateType.Relay ->
stringResource(R.string.call_connection_via_relay)
stringResource(MR.strings.call_connection_via_relay)
else ->
"${local?.value ?: "unknown"} / ${remote?.value ?: "unknown"}"
}
@@ -21,7 +21,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
@@ -36,6 +36,7 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.app.views.usersettings.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.datetime.Clock
@@ -125,9 +126,9 @@ fun ChatInfoView(
fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_contact_question),
text = generalGetString(R.string.delete_contact_all_messages_deleted_cannot_undo_warning),
confirmText = generalGetString(R.string.delete_verb),
title = generalGetString(MR.strings.delete_contact_question),
text = generalGetString(MR.strings.delete_contact_all_messages_deleted_cannot_undo_warning),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
@@ -145,9 +146,9 @@ fun deleteContactDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() ->
fun clearChatDialog(chatInfo: ChatInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.clear_chat_question),
text = generalGetString(R.string.clear_chat_warning),
confirmText = generalGetString(R.string.clear_verb),
title = generalGetString(MR.strings.clear_chat_question),
text = generalGetString(MR.strings.clear_chat_warning),
confirmText = generalGetString(MR.strings.clear_verb),
onConfirm = {
withApi {
val updatedChatInfo = chatModel.controller.apiClearChat(chatInfo.chatType, chatInfo.apiId)
@@ -196,8 +197,8 @@ fun ChatInfoLayout(
LocalAliasEditor(localAlias, updateValue = onLocalAliasChanged)
SectionSpacer()
if (customUserProfile != null) {
SectionView(generalGetString(R.string.incognito).uppercase()) {
InfoRow(generalGetString(R.string.incognito_random_profile), customUserProfile.chatViewName)
SectionView(generalGetString(MR.strings.incognito).uppercase()) {
InfoRow(generalGetString(MR.strings.incognito_random_profile), customUserProfile.chatViewName)
}
SectionDividerSpaced()
}
@@ -211,18 +212,18 @@ fun ChatInfoLayout(
SectionDividerSpaced()
if (contact.contactLink != null) {
SectionView(stringResource(R.string.address_section_title).uppercase()) {
SectionView(stringResource(MR.strings.address_section_title).uppercase()) {
QRCode(contact.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { shareText(contact.contactLink) }
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(contact.displayName))
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(contact.displayName))
}
SectionDividerSpaced()
}
SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) {
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
SectionItemView({
AlertManager.shared.showAlertMsg(
generalGetString(R.string.network_status),
generalGetString(MR.strings.network_status),
contactNetworkStatus.statusExplanation
)}) {
NetworkStatusRow(contactNetworkStatus)
@@ -240,11 +241,11 @@ fun ChatInfoLayout(
}
val rcvServers = cStats.rcvQueuesInfo.map { it.rcvServer }
if (rcvServers.isNotEmpty()) {
SimplexServers(stringResource(R.string.receiving_via), rcvServers)
SimplexServers(stringResource(MR.strings.receiving_via), rcvServers)
}
val sndServers = cStats.sndQueuesInfo.map { it.sndServer }
if (sndServers.isNotEmpty()) {
SimplexServers(stringResource(R.string.sending_via), sndServers)
SimplexServers(stringResource(MR.strings.sending_via), sndServers)
}
}
}
@@ -256,9 +257,9 @@ fun ChatInfoLayout(
if (developerTools) {
SectionDividerSpaced()
SectionView(title = stringResource(R.string.section_title_for_console)) {
InfoRow(stringResource(R.string.info_row_local_name), chat.chatInfo.localDisplayName)
InfoRow(stringResource(R.string.info_row_database_id), chat.chatInfo.apiId.toString())
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
InfoRow(stringResource(MR.strings.info_row_local_name), chat.chatInfo.localDisplayName)
InfoRow(stringResource(MR.strings.info_row_database_id), chat.chatInfo.apiId.toString())
}
}
SectionBottomSpacer()
@@ -313,7 +314,7 @@ fun LocalAliasEditor(
value,
{
Text(
generalGetString(R.string.text_field_set_contact_placeholder),
generalGetString(MR.strings.text_field_set_contact_placeholder),
textAlign = if (center) TextAlign.Center else TextAlign.Start,
color = MaterialTheme.colors.secondary
)
@@ -354,10 +355,10 @@ private fun NetworkStatusRow(networkStatus: NetworkStatus) {
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {
Text(stringResource(R.string.network_status))
Text(stringResource(MR.strings.network_status))
Icon(
painterResource(R.drawable.ic_info),
stringResource(R.string.network_status),
stringResource(MR.strings.network_status),
tint = MaterialTheme.colors.primary
)
}
@@ -380,12 +381,12 @@ private fun ServerImage(networkStatus: NetworkStatus) {
Box(Modifier.size(18.dp)) {
when (networkStatus) {
is NetworkStatus.Connected ->
Icon(painterResource(R.drawable.ic_circle_filled), stringResource(R.string.icon_descr_server_status_connected), tint = Color.Green)
Icon(painterResource(R.drawable.ic_circle_filled), stringResource(MR.strings.icon_descr_server_status_connected), tint = Color.Green)
is NetworkStatus.Disconnected ->
Icon(painterResource(R.drawable.ic_pending_filled), stringResource(R.string.icon_descr_server_status_disconnected), tint = MaterialTheme.colors.secondary)
Icon(painterResource(R.drawable.ic_pending_filled), stringResource(MR.strings.icon_descr_server_status_disconnected), tint = MaterialTheme.colors.secondary)
is NetworkStatus.Error ->
Icon(painterResource(R.drawable.ic_error_filled), stringResource(R.string.icon_descr_server_status_error), tint = MaterialTheme.colors.secondary)
else -> Icon(painterResource(R.drawable.ic_circle), stringResource(R.string.icon_descr_server_status_pending), tint = MaterialTheme.colors.secondary)
Icon(painterResource(R.drawable.ic_error_filled), stringResource(MR.strings.icon_descr_server_status_error), tint = MaterialTheme.colors.secondary)
else -> Icon(painterResource(R.drawable.ic_circle), stringResource(MR.strings.icon_descr_server_status_pending), tint = MaterialTheme.colors.secondary)
}
}
}
@@ -396,7 +397,7 @@ fun SimplexServers(text: String, servers: List<String>) {
val clipboardManager: ClipboardManager = LocalClipboardManager.current
InfoRowEllipsis(text, info) {
clipboardManager.setText(AnnotatedString(servers.joinToString(separator = ",")))
Toast.makeText(SimplexApp.context, generalGetString(R.string.copied), Toast.LENGTH_SHORT).show()
Toast.makeText(SimplexApp.context, generalGetString(MR.strings.copied), Toast.LENGTH_SHORT).show()
}
}
@@ -404,7 +405,7 @@ fun SimplexServers(text: String, servers: List<String>) {
fun SwitchAddressButton(disabled: Boolean, switchAddress: () -> Unit) {
SectionItemView(switchAddress) {
Text(
stringResource(R.string.switch_receiving_address),
stringResource(MR.strings.switch_receiving_address),
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
@@ -414,7 +415,7 @@ fun SwitchAddressButton(disabled: Boolean, switchAddress: () -> Unit) {
fun AbortSwitchAddressButton(disabled: Boolean, abortSwitchAddress: () -> Unit) {
SectionItemView(abortSwitchAddress) {
Text(
stringResource(R.string.abort_switch_receiving_address),
stringResource(MR.strings.abort_switch_receiving_address),
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
@@ -424,7 +425,7 @@ fun AbortSwitchAddressButton(disabled: Boolean, abortSwitchAddress: () -> Unit)
fun VerifyCodeButton(contactVerified: Boolean, onClick: () -> Unit) {
SettingsActionItem(
if (contactVerified) painterResource(R.drawable.ic_verified_user) else painterResource(R.drawable.ic_shield),
stringResource(if (contactVerified) R.string.view_security_code else R.string.verify_security_code),
stringResource(if (contactVerified) MR.strings.view_security_code else MR.strings.verify_security_code),
click = onClick,
iconColor = MaterialTheme.colors.secondary,
)
@@ -434,7 +435,7 @@ fun VerifyCodeButton(contactVerified: Boolean, onClick: () -> Unit) {
private fun ContactPreferencesButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_toggle_on),
stringResource(R.string.contact_preferences),
stringResource(MR.strings.contact_preferences),
click = onClick
)
}
@@ -443,7 +444,7 @@ private fun ContactPreferencesButton(onClick: () -> Unit) {
fun ClearChatButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_settings_backup_restore),
stringResource(R.string.clear_chat_button),
stringResource(MR.strings.clear_chat_button),
click = onClick,
textColor = WarningOrange,
iconColor = WarningOrange,
@@ -454,7 +455,7 @@ fun ClearChatButton(onClick: () -> Unit) {
private fun DeleteContactButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.button_delete_contact),
stringResource(MR.strings.button_delete_contact),
click = onClick,
textColor = Color.Red,
iconColor = Color.Red,
@@ -465,7 +466,7 @@ private fun DeleteContactButton(onClick: () -> Unit) {
fun ShareAddressButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_share_filled),
stringResource(R.string.share_address),
stringResource(MR.strings.share_address),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
@@ -480,18 +481,18 @@ private fun setContactAlias(contactApiId: Long, localAlias: String, chatModel: C
fun showSwitchAddressAlert(switchAddress: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.switch_receiving_address_question),
text = generalGetString(R.string.switch_receiving_address_desc),
confirmText = generalGetString(R.string.change_verb),
title = generalGetString(MR.strings.switch_receiving_address_question),
text = generalGetString(MR.strings.switch_receiving_address_desc),
confirmText = generalGetString(MR.strings.change_verb),
onConfirm = switchAddress
)
}
fun showAbortSwitchAddressAlert(abortSwitchAddress: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.abort_switch_receiving_address_question),
text = generalGetString(R.string.abort_switch_receiving_address_desc),
confirmText = generalGetString(R.string.abort_switch_receiving_address_confirm),
title = generalGetString(MR.strings.abort_switch_receiving_address_question),
text = generalGetString(MR.strings.abort_switch_receiving_address_desc),
confirmText = generalGetString(MR.strings.abort_switch_receiving_address_confirm),
onConfirm = abortSwitchAddress,
destructive = true,
)
@@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -25,6 +25,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.chat.item.ItemAction
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
@@ -48,7 +49,7 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
)
} else {
Text(
generalGetString(R.string.item_info_no_text),
generalGetString(MR.strings.item_info_no_text),
style = MaterialTheme.typography.body1.copy(color = MaterialTheme.colors.secondary, lineHeight = 22.sp, fontStyle = FontStyle.Italic)
)
}
@@ -72,7 +73,7 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
)
if (current && ci.meta.itemDeleted == null) {
Text(
stringResource(R.string.item_info_current),
stringResource(MR.strings.item_info_current),
fontSize = 12.sp,
color = MaterialTheme.colors.secondary
)
@@ -80,11 +81,11 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
}
if (text != "") {
DefaultDropdownMenu(showMenu) {
ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = {
ItemAction(stringResource(MR.strings.share_verb), painterResource(R.drawable.ic_share), onClick = {
shareText(text)
showMenu.value = false
})
ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
ItemAction(stringResource(MR.strings.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
copyText(text)
showMenu.value = false
})
@@ -94,37 +95,37 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
}
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
AppBarTitle(stringResource(if (sent) R.string.sent_message else R.string.received_message))
AppBarTitle(stringResource(if (sent) MR.strings.sent_message else MR.strings.received_message))
SectionView {
InfoRow(stringResource(R.string.info_row_sent_at), localTimestamp(ci.meta.itemTs))
InfoRow(stringResource(MR.strings.info_row_sent_at), localTimestamp(ci.meta.itemTs))
if (!sent) {
InfoRow(stringResource(R.string.info_row_received_at), localTimestamp(ci.meta.createdAt))
InfoRow(stringResource(MR.strings.info_row_received_at), localTimestamp(ci.meta.createdAt))
}
when (val itemDeleted = ci.meta.itemDeleted) {
is CIDeleted.Deleted ->
if (itemDeleted.deletedTs != null) {
InfoRow(stringResource(R.string.info_row_deleted_at), localTimestamp(itemDeleted.deletedTs))
InfoRow(stringResource(MR.strings.info_row_deleted_at), localTimestamp(itemDeleted.deletedTs))
}
is CIDeleted.Moderated ->
if (itemDeleted.deletedTs != null) {
InfoRow(stringResource(R.string.info_row_moderated_at), localTimestamp(itemDeleted.deletedTs))
InfoRow(stringResource(MR.strings.info_row_moderated_at), localTimestamp(itemDeleted.deletedTs))
}
else -> {}
}
val deleteAt = ci.meta.itemTimed?.deleteAt
if (deleteAt != null) {
InfoRow(stringResource(R.string.info_row_disappears_at), localTimestamp(deleteAt))
InfoRow(stringResource(MR.strings.info_row_disappears_at), localTimestamp(deleteAt))
}
if (devTools) {
InfoRow(stringResource(R.string.info_row_database_id), ci.meta.itemId.toString())
InfoRow(stringResource(R.string.info_row_updated_at), localTimestamp(ci.meta.updatedAt))
InfoRow(stringResource(MR.strings.info_row_database_id), ci.meta.itemId.toString())
InfoRow(stringResource(MR.strings.info_row_updated_at), localTimestamp(ci.meta.updatedAt))
}
}
val versions = ciInfo.itemVersions
if (versions.isNotEmpty()) {
SectionDividerSpaced(maxTopPadding = false, maxBottomPadding = false)
SectionView(padding = PaddingValues(horizontal = DEFAULT_PADDING)) {
Text(stringResource(R.string.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
Text(stringResource(MR.strings.edit_history), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = DEFAULT_PADDING))
versions.forEachIndexed { i, ciVersion ->
ItemVersionView(ciVersion, current = i == 0)
}
@@ -137,47 +138,47 @@ fun ChatItemInfoView(ci: ChatItem, ciInfo: ChatItemInfo, devTools: Boolean) {
fun itemInfoShareText(ci: ChatItem, chatItemInfo: ChatItemInfo, devTools: Boolean): String {
val meta = ci.meta
val sent = ci.chatDir.sent
val shareText = mutableListOf<String>(generalGetString(if (sent) R.string.sent_message else R.string.received_message), "")
val shareText = mutableListOf<String>(generalGetString(if (sent) MR.strings.sent_message else MR.strings.received_message), "")
shareText.add(String.format(generalGetString(R.string.share_text_sent_at), localTimestamp(meta.itemTs)))
shareText.add(String.format(generalGetString(MR.strings.share_text_sent_at), localTimestamp(meta.itemTs)))
if (!ci.chatDir.sent) {
shareText.add(String.format(generalGetString(R.string.share_text_received_at), localTimestamp(meta.createdAt)))
shareText.add(String.format(generalGetString(MR.strings.share_text_received_at), localTimestamp(meta.createdAt)))
}
when (val itemDeleted = ci.meta.itemDeleted) {
is CIDeleted.Deleted ->
if (itemDeleted.deletedTs != null) {
shareText.add(String.format(generalGetString(R.string.share_text_deleted_at), localTimestamp(itemDeleted.deletedTs)))
shareText.add(String.format(generalGetString(MR.strings.share_text_deleted_at), localTimestamp(itemDeleted.deletedTs)))
}
is CIDeleted.Moderated ->
if (itemDeleted.deletedTs != null) {
shareText.add(String.format(generalGetString(R.string.share_text_moderated_at), localTimestamp(itemDeleted.deletedTs)))
shareText.add(String.format(generalGetString(MR.strings.share_text_moderated_at), localTimestamp(itemDeleted.deletedTs)))
}
else -> {}
}
val deleteAt = ci.meta.itemTimed?.deleteAt
if (deleteAt != null) {
shareText.add(String.format(generalGetString(R.string.share_text_disappears_at), localTimestamp(deleteAt)))
shareText.add(String.format(generalGetString(MR.strings.share_text_disappears_at), localTimestamp(deleteAt)))
}
if (devTools) {
shareText.add(String.format(generalGetString(R.string.share_text_database_id), meta.itemId))
shareText.add(String.format(generalGetString(R.string.share_text_updated_at), meta.updatedAt))
shareText.add(String.format(generalGetString(MR.strings.share_text_database_id), meta.itemId))
shareText.add(String.format(generalGetString(MR.strings.share_text_updated_at), meta.updatedAt))
}
val versions = chatItemInfo.itemVersions
if (versions.isNotEmpty()) {
shareText.add("")
shareText.add(generalGetString(R.string.edit_history))
shareText.add(generalGetString(MR.strings.edit_history))
versions.forEachIndexed { index, itemVersion ->
val ts = localTimestamp(itemVersion.itemVersionTs)
shareText.add("")
shareText.add(
if (index == 0 && ci.meta.itemDeleted == null) {
String.format(generalGetString(R.string.current_version_timestamp), ts)
String.format(generalGetString(MR.strings.current_version_timestamp), ts)
} else {
localTimestamp(itemVersion.itemVersionTs)
}
)
val t = itemVersion.msgContent.text
shareText.add(if (t != "") t else generalGetString(R.string.item_info_no_text))
shareText.add(if (t != "") t else generalGetString(MR.strings.item_info_no_text))
}
}
return shareText.joinToString(separator = "\n")
@@ -21,7 +21,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
@@ -41,6 +41,7 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.helpers.AppBarHeight
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import kotlinx.datetime.Clock
@@ -421,7 +422,7 @@ fun ChatInfoToolbar(
val barButtons = arrayListOf<@Composable RowScope.() -> Unit>()
val menuItems = arrayListOf<@Composable () -> Unit>()
menuItems.add {
ItemAction(stringResource(android.R.string.search_go).capitalize(Locale.current), painterResource(R.drawable.ic_search), onClick = {
ItemAction(stringResource(MR.strings.search_verb).capitalize(Locale.current), painterResource(R.drawable.ic_search), onClick = {
showMenu.value = false
showSearch = true
})
@@ -433,11 +434,11 @@ fun ChatInfoToolbar(
showMenu.value = false
startCall(CallMediaType.Audio)
}) {
Icon(painterResource(R.drawable.ic_call_500), stringResource(R.string.icon_descr_more_button), tint = MaterialTheme.colors.primary)
Icon(painterResource(R.drawable.ic_call_500), stringResource(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.primary)
}
}
menuItems.add {
ItemAction(stringResource(R.string.icon_descr_video_call).capitalize(Locale.current), painterResource(R.drawable.ic_videocam), onClick = {
ItemAction(stringResource(MR.strings.icon_descr_video_call).capitalize(Locale.current), painterResource(R.drawable.ic_videocam), onClick = {
showMenu.value = false
startCall(CallMediaType.Video)
})
@@ -448,14 +449,14 @@ fun ChatInfoToolbar(
showMenu.value = false
addMembers(chat.chatInfo.groupInfo)
}) {
Icon(painterResource(R.drawable.ic_person_add_500), stringResource(R.string.icon_descr_add_members), tint = MaterialTheme.colors.primary)
Icon(painterResource(R.drawable.ic_person_add_500), stringResource(MR.strings.icon_descr_add_members), tint = MaterialTheme.colors.primary)
}
}
}
val ntfsEnabled = remember { mutableStateOf(chat.chatInfo.ntfsEnabled) }
menuItems.add {
ItemAction(
if (ntfsEnabled.value) stringResource(R.string.mute_chat) else stringResource(R.string.unmute_chat),
if (ntfsEnabled.value) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat),
if (ntfsEnabled.value) painterResource(R.drawable.ic_notifications_off) else painterResource(R.drawable.ic_notifications),
onClick = {
showMenu.value = false
@@ -470,7 +471,7 @@ fun ChatInfoToolbar(
barButtons.add {
IconButton({ showMenu.value = true }) {
Icon(MoreVertFilled, stringResource(R.string.icon_descr_more_button), tint = MaterialTheme.colors.primary)
Icon(MoreVertFilled, stringResource(MR.strings.icon_descr_more_button), tint = MaterialTheme.colors.primary)
}
}
@@ -828,7 +829,7 @@ fun BoxWithConstraintsScope.FloatingButtons(
DefaultDropdownMenu(showDropDown, offset = DpOffset(maxWidth - DEFAULT_PADDING, 24.dp + fabSize)) {
ItemAction(
generalGetString(R.string.mark_read),
generalGetString(MR.strings.mark_read),
painterResource(R.drawable.ic_check),
onClick = {
markRead(
@@ -6,11 +6,12 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.res.MR
@Composable
fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boolean) {
@@ -25,7 +26,7 @@ fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boo
) {
Icon(
painterResource(R.drawable.ic_draft_filled),
stringResource(R.string.icon_descr_file),
stringResource(MR.strings.icon_descr_file),
Modifier
.padding(start = 4.dp, end = 2.dp)
.size(36.dp),
@@ -37,7 +38,7 @@ fun ComposeFileView(fileName: String, cancelFile: () -> Unit, cancelEnabled: Boo
IconButton(onClick = cancelFile, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_file_preview),
contentDescription = stringResource(MR.strings.icon_descr_cancel_file_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
@@ -12,12 +12,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.UploadContent
import chat.simplex.app.views.helpers.base64ToBitmap
import chat.simplex.res.MR
@Composable
fun ComposeImageView(media: ComposePreview.MediaPreview, cancelImages: () -> Unit, cancelEnabled: Boolean) {
@@ -65,7 +66,7 @@ fun ComposeImageView(media: ComposePreview.MediaPreview, cancelImages: () -> Uni
IconButton(onClick = cancelImages) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_image_preview),
contentDescription = stringResource(MR.strings.icon_descr_cancel_image_preview),
tint = MaterialTheme.colors.primary,
)
}
@@ -28,7 +28,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import chat.simplex.app.*
@@ -36,6 +36,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.views.chat.item.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.serialization.*
@@ -193,7 +194,7 @@ fun ComposeView(
if (isGranted) {
cameraLauncher.launchWithFallback()
} else {
Toast.makeText(context, generalGetString(R.string.toast_permission_denied), Toast.LENGTH_SHORT).show()
Toast.makeText(context, generalGetString(MR.strings.toast_permission_denied), Toast.LENGTH_SHORT).show()
}
}
val processPickedMedia = { uris: List<Uri>, text: String? ->
@@ -218,8 +219,8 @@ fun ComposeView(
} else {
bitmap = null
AlertManager.shared.showAlertMsg(
generalGetString(R.string.large_file),
String.format(generalGetString(R.string.maximum_supported_file_size), formatBytes(maxFileSize))
generalGetString(MR.strings.large_file),
String.format(generalGetString(MR.strings.maximum_supported_file_size), formatBytes(maxFileSize))
)
}
} else {
@@ -252,8 +253,8 @@ fun ComposeView(
}
} else {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.large_file),
String.format(generalGetString(R.string.maximum_supported_file_size), formatBytes(maxFileSize))
generalGetString(MR.strings.large_file),
String.format(generalGetString(MR.strings.maximum_supported_file_size), formatBytes(maxFileSize))
)
}
}
@@ -718,8 +719,8 @@ fun ComposeView(
val attachmentClicked = if (isGroupAndProhibitedFiles) {
{
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.files_and_media_prohibited),
text = generalGetString(R.string.only_owners_can_enable_files_and_media)
title = generalGetString(MR.strings.files_and_media_prohibited),
text = generalGetString(MR.strings.only_owners_can_enable_files_and_media)
)
}
} else {
@@ -728,7 +729,7 @@ fun ComposeView(
IconButton(attachmentClicked, enabled = !composeState.value.attachmentDisabled && rememberUpdatedState(chat.userCanSend).value) {
Icon(
painterResource(R.drawable.ic_attach_file_filled_500),
contentDescription = stringResource(R.string.attach),
contentDescription = stringResource(MR.strings.attach),
tint = if (!composeState.value.attachmentDisabled && userCanSend.value && !isGroupAndProhibitedFiles) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
modifier = Modifier
.size(28.dp)
@@ -860,7 +861,7 @@ class PickMultipleImagesFromGallery: ActivityResultContract<Int, List<Uri>>() {
if (uri != null) uris.add(uri)
}
if (itemCount > 10) {
AlertManager.shared.showAlertMsg(R.string.images_limit_title, R.string.images_limit_desc)
AlertManager.shared.showAlertMsg(MR.strings.images_limit_title, MR.strings.images_limit_desc)
}
uris
}
@@ -887,7 +888,7 @@ class PickMultipleVideosFromGallery: ActivityResultContract<Int, List<Uri>>() {
if (uri != null) uris.add(uri)
}
if (itemCount > 10) {
AlertManager.shared.showAlertMsg(R.string.videos_limit_title, R.string.videos_limit_desc)
AlertManager.shared.showAlertMsg(MR.strings.videos_limit_title, MR.strings.videos_limit_desc)
}
uris
}
@@ -11,7 +11,7 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -19,6 +19,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.durationText
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.distinctUntilChanged
@Composable
@@ -58,7 +59,7 @@ fun ComposeVoiceView(
) {
Icon(
if (audioPlaying.value) painterResource(R.drawable.ic_pause_filled) else painterResource(R.drawable.ic_play_arrow_filled),
stringResource(R.string.icon_descr_file),
stringResource(MR.strings.icon_descr_file),
Modifier
.padding(start = 4.dp, end = 2.dp)
.size(36.dp),
@@ -90,7 +91,7 @@ fun ComposeVoiceView(
) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_file_preview),
contentDescription = stringResource(MR.strings.icon_descr_cancel_file_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
@@ -14,12 +14,13 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.PreferenceToggle
import chat.simplex.res.MR
@Composable
fun ContactPreferencesView(
@@ -81,7 +82,7 @@ private fun ContactPreferencesLayout(
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.contact_preferences))
AppBarTitle(stringResource(MR.strings.contact_preferences))
val timedMessages: MutableState<Boolean> = remember(featuresAllowed) { mutableStateOf(featuresAllowed.timedMessagesAllowed) }
val onTTLUpdated = { ttl: Int? ->
applyPrefs(featuresAllowed.copy(timedMessagesTTL = ttl))
@@ -140,14 +141,14 @@ private fun FeatureSection(
leadingIcon = true,
) {
ExposedDropDownSettingRow(
generalGetString(R.string.chat_preferences_you_allow),
generalGetString(MR.strings.chat_preferences_you_allow),
ContactFeatureAllowed.values(userDefault).map { it to it.text },
allowFeature,
icon = null,
onSelected = onSelected
)
InfoRow(
generalGetString(R.string.chat_preferences_contact_allows),
generalGetString(MR.strings.chat_preferences_contact_allows),
pref.contactPreference.allow.text
)
}
@@ -175,13 +176,13 @@ private fun TimedMessagesFeatureSection(
leadingIcon = true,
) {
PreferenceToggle(
generalGetString(R.string.chat_preferences_you_allow),
generalGetString(MR.strings.chat_preferences_you_allow),
checked = allowFeature.value,
) { allow ->
onSelected(allow, if (allow) featuresAllowed.timedMessagesTTL ?: 86400 else null)
}
InfoRow(
generalGetString(R.string.chat_preferences_contact_allows),
generalGetString(MR.strings.chat_preferences_contact_allows),
pref.contactPreference.allow.text
)
if (featuresAllowed.timedMessagesAllowed) {
@@ -189,14 +190,14 @@ private fun TimedMessagesFeatureSection(
DropdownCustomTimePickerSettingRow(
selection = ttl,
propagateExternalSelectionUpdate = true, // for Reset
label = generalGetString(R.string.delete_after),
label = generalGetString(MR.strings.delete_after),
dropdownValues = TimedMessagesPreference.ttlValues,
customPickerTitle = generalGetString(R.string.delete_after),
customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select),
customPickerTitle = generalGetString(MR.strings.delete_after),
customPickerConfirmButtonText = generalGetString(MR.strings.custom_time_picker_select),
onSelected = onTTLUpdated
)
} else if (pref.contactPreference.allow == FeatureAllowed.YES || pref.contactPreference.allow == FeatureAllowed.ALWAYS) {
InfoRow(generalGetString(R.string.delete_after), timeText(pref.contactPreference.ttl))
InfoRow(generalGetString(MR.strings.delete_after), timeText(pref.contactPreference.ttl))
}
}
SectionTextFooter(ChatFeature.TimedMessages.enabledDescription(enabled))
@@ -206,19 +207,19 @@ private fun TimedMessagesFeatureSection(
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
SectionView {
SectionItemView(reset, disabled = disabled) {
Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
SectionItemView(save, disabled = disabled) {
Text(stringResource(R.string.save_and_notify_contact), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.save_and_notify_contact), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_preferences_question),
confirmText = generalGetString(R.string.save_and_notify_contact),
dismissText = generalGetString(R.string.exit_without_saving),
title = generalGetString(MR.strings.save_preferences_question),
confirmText = generalGetString(MR.strings.save_and_notify_contact),
dismissText = generalGetString(MR.strings.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)
@@ -9,13 +9,14 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.*
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@Composable
@@ -46,7 +47,7 @@ fun ContextItemView(
.padding(horizontal = 8.dp)
.height(20.dp)
.width(20.dp),
contentDescription = stringResource(R.string.icon_descr_context),
contentDescription = stringResource(MR.strings.icon_descr_context),
tint = MaterialTheme.colors.secondary,
)
MarkdownText(
@@ -59,7 +60,7 @@ fun ContextItemView(
IconButton(onClick = cancelContextItem) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.cancel_verb),
contentDescription = stringResource(MR.strings.cancel_verb),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
@@ -6,12 +6,13 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCodeScanner
import com.google.accompanist.permissions.rememberPermissionState
import chat.simplex.res.MR
@Composable
fun ScanCodeView(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit, close: () -> Unit) {
@@ -29,7 +30,7 @@ private fun ScanCodeLayout(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit,
.fillMaxSize()
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(R.string.scan_code), false)
AppBarTitle(stringResource(MR.strings.scan_code), false)
Box(
Modifier
.fillMaxWidth()
@@ -42,12 +43,12 @@ private fun ScanCodeLayout(verifyCode: (String?, cb: (Boolean) -> Unit) -> Unit,
close()
} else {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.incorrect_code)
title = generalGetString(MR.strings.incorrect_code)
)
}
}
}
}
Text(stringResource(R.string.scan_code_from_contacts_app))
Text(stringResource(MR.strings.scan_code_from_contacts_app))
}
}
@@ -48,6 +48,9 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.ItemAction
import chat.simplex.app.views.helpers.*
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.*
import java.lang.reflect.Field
@@ -96,8 +99,8 @@ fun SendMsgView(
.matchParentSize()
.clickable(enabled = !userCanSend, indication = null, interactionSource = remember { MutableInteractionSource() }, onClick = {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.observer_cant_send_message_title),
text = generalGetString(R.string.observer_cant_send_message_desc)
title = generalGetString(MR.strings.observer_cant_send_message_title),
text = generalGetString(MR.strings.observer_cant_send_message_desc)
)
})
)
@@ -175,7 +178,7 @@ fun SendMsgView(
) {
menuItems.add {
ItemAction(
generalGetString(R.string.send_live_message),
generalGetString(MR.strings.send_live_message),
BoltFilled,
onClick = {
startLiveMessage(scope, sendLiveMessage, updateLiveMessage, sendButtonSize, sendButtonAlpha, composeState, liveMessageAlertShown)
@@ -187,7 +190,7 @@ fun SendMsgView(
if (timedMessageAllowed) {
menuItems.add {
ItemAction(
generalGetString(R.string.disappearing_message),
generalGetString(MR.strings.disappearing_message),
painterResource(R.drawable.ic_timer),
onClick = {
showCustomDisappearingMessageDialog.value = true
@@ -230,8 +233,8 @@ private fun CustomDisappearingMessageDialog(
}
CustomTimePickerDialog(
selectedDisappearingMessageTime,
title = generalGetString(R.string.delete_after),
confirmButtonText = generalGetString(R.string.send_disappearing_message_send),
title = generalGetString(MR.strings.delete_after),
confirmButtonText = generalGetString(MR.strings.send_disappearing_message_send),
confirmButtonAction = { ttl ->
sendMessage(ttl)
customDisappearingMessageTimePref?.set?.invoke(ttl)
@@ -273,13 +276,13 @@ private fun CustomDisappearingMessageDialog(
) {
Text(" ") // centers title
Text(
generalGetString(R.string.send_disappearing_message),
generalGetString(MR.strings.send_disappearing_message),
fontSize = 16.sp,
color = MaterialTheme.colors.secondary
)
Icon(
painterResource(R.drawable.ic_close),
generalGetString(R.string.icon_descr_close_button),
generalGetString(MR.strings.icon_descr_close_button),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.size(25.dp)
@@ -287,19 +290,19 @@ private fun CustomDisappearingMessageDialog(
)
}
ChoiceButton(generalGetString(R.string.send_disappearing_message_30_seconds)) {
ChoiceButton(generalGetString(MR.strings.send_disappearing_message_30_seconds)) {
sendMessage(30)
setShowDialog(false)
}
ChoiceButton(generalGetString(R.string.send_disappearing_message_1_minute)) {
ChoiceButton(generalGetString(MR.strings.send_disappearing_message_1_minute)) {
sendMessage(60)
setShowDialog(false)
}
ChoiceButton(generalGetString(R.string.send_disappearing_message_5_minutes)) {
ChoiceButton(generalGetString(MR.strings.send_disappearing_message_5_minutes)) {
sendMessage(300)
setShowDialog(false)
}
ChoiceButton(generalGetString(R.string.send_disappearing_message_custom_time)) {
ChoiceButton(generalGetString(MR.strings.send_disappearing_message_custom_time)) {
showCustomTimePicker.value = true
}
}
@@ -411,14 +414,14 @@ private fun NativeKeyboard(
showDeleteTextButton.value = it.lineCount >= 4 && !cs.inProgress
}
if (composeState.value.preview is ComposePreview.VoicePreview) {
ComposeOverlay(R.string.voice_message_send_text, textStyle, padding)
ComposeOverlay(MR.strings.voice_message_send_text, textStyle, padding)
} else if (userIsObserver) {
ComposeOverlay(R.string.you_are_observer, textStyle, padding)
ComposeOverlay(MR.strings.you_are_observer, textStyle, padding)
}
}
@Composable
private fun ComposeOverlay(textId: Int, textStyle: MutableState<TextStyle>, padding: PaddingValues) {
private fun ComposeOverlay(textId: StringResource, textStyle: MutableState<TextStyle>, padding: PaddingValues) {
Text(
generalGetString(textId),
Modifier.padding(padding),
@@ -491,7 +494,7 @@ private fun DisallowedVoiceButton(enabled: Boolean, onClick: () -> Unit) {
IconButton(onClick, Modifier.size(36.dp), enabled = enabled) {
Icon(
painterResource(R.drawable.ic_keyboard_voice),
stringResource(R.string.icon_descr_record_voice_message),
stringResource(MR.strings.icon_descr_record_voice_message),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.size(36.dp)
@@ -505,7 +508,7 @@ private fun VoiceButtonWithoutPermission(onClick: () -> Unit) {
IconButton(onClick, Modifier.size(36.dp)) {
Icon(
painterResource(R.drawable.ic_keyboard_voice_filled),
stringResource(R.string.icon_descr_record_voice_message),
stringResource(MR.strings.icon_descr_record_voice_message),
tint = MaterialTheme.colors.primary,
modifier = Modifier
.size(34.dp)
@@ -537,7 +540,7 @@ private fun StopRecordButton(onClick: () -> Unit) {
IconButton(onClick, Modifier.size(36.dp)) {
Icon(
painterResource(R.drawable.ic_stop_filled),
stringResource(R.string.icon_descr_record_voice_message),
stringResource(MR.strings.icon_descr_record_voice_message),
tint = MaterialTheme.colors.primary,
modifier = Modifier
.size(36.dp)
@@ -551,7 +554,7 @@ private fun RecordVoiceButton(interactionSource: MutableInteractionSource) {
IconButton({}, Modifier.size(36.dp), interactionSource = interactionSource) {
Icon(
painterResource(R.drawable.ic_keyboard_voice_filled),
stringResource(R.string.icon_descr_record_voice_message),
stringResource(MR.strings.icon_descr_record_voice_message),
tint = MaterialTheme.colors.primary,
modifier = Modifier
.size(34.dp)
@@ -572,7 +575,7 @@ private fun CancelLiveMessageButton(
IconButton(onClick, Modifier.size(36.dp)) {
Icon(
painterResource(R.drawable.ic_close),
stringResource(R.string.icon_descr_cancel_live_message),
stringResource(MR.strings.icon_descr_cancel_live_message),
tint = MaterialTheme.colors.primary,
modifier = Modifier
.size(36.dp)
@@ -605,7 +608,7 @@ private fun SendMsgButton(
) {
Icon(
icon,
stringResource(R.string.icon_descr_send_message),
stringResource(MR.strings.icon_descr_send_message),
tint = Color.White,
modifier = Modifier
.size(sizeDp.value.dp)
@@ -634,7 +637,7 @@ private fun StartLiveMessageButton(enabled: Boolean, onClick: () -> Unit) {
) {
Icon(
BoltFilled,
stringResource(R.string.icon_descr_send_message),
stringResource(MR.strings.icon_descr_send_message),
tint = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
modifier = Modifier
.size(36.dp)
@@ -685,9 +688,9 @@ private fun startLiveMessage(
start()
} else {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.live_message),
text = generalGetString(R.string.send_live_message_desc),
confirmText = generalGetString(R.string.send_verb),
title = generalGetString(MR.strings.live_message),
text = generalGetString(MR.strings.send_live_message_desc),
confirmText = generalGetString(MR.strings.send_verb),
onConfirm = {
liveMessageAlertShown.set(true)
start()
@@ -697,22 +700,22 @@ private fun startLiveMessage(
private fun showNeedToAllowVoiceAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.allow_voice_messages_question),
text = generalGetString(R.string.you_need_to_allow_to_send_voice),
confirmText = generalGetString(R.string.allow_verb),
dismissText = generalGetString(R.string.cancel_verb),
title = generalGetString(MR.strings.allow_voice_messages_question),
text = generalGetString(MR.strings.you_need_to_allow_to_send_voice),
confirmText = generalGetString(MR.strings.allow_verb),
dismissText = generalGetString(MR.strings.cancel_verb),
onConfirm = onConfirm,
)
}
private fun showDisabledVoiceAlert(isDirectChat: Boolean) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.voice_messages_prohibited),
title = generalGetString(MR.strings.voice_messages_prohibited),
text = generalGetString(
if (isDirectChat)
R.string.ask_your_contact_to_enable_voice
MR.strings.ask_your_contact_to_enable_voice
else
R.string.only_group_owners_can_enable_voice
MR.strings.only_group_owners_can_enable_voice
)
)
}
@@ -11,7 +11,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -19,6 +19,7 @@ import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.res.MR
@Composable
fun VerifyCodeView(
@@ -60,14 +61,14 @@ private fun VerifyCodeLayout(
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(R.string.security_code), false)
AppBarTitle(stringResource(MR.strings.security_code), false)
val splitCode = splitToParts(connectionCode, 24)
Row(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), horizontalArrangement = Arrangement.Center) {
if (connectionVerified) {
Icon(painterResource(R.drawable.ic_verified_user), null, Modifier.padding(end = 4.dp).size(22.dp), tint = MaterialTheme.colors.secondary)
Text(String.format(stringResource(R.string.is_verified), displayName))
Text(String.format(stringResource(MR.strings.is_verified), displayName))
} else {
Text(String.format(stringResource(R.string.is_not_verified), displayName))
Text(String.format(stringResource(MR.strings.is_not_verified), displayName))
}
}
@@ -94,7 +95,7 @@ private fun VerifyCodeLayout(
}
Text(
generalGetString(R.string.to_verify_compare),
generalGetString(MR.strings.to_verify_compare),
Modifier.padding(bottom = DEFAULT_PADDING)
)
@@ -103,20 +104,20 @@ private fun VerifyCodeLayout(
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
if (connectionVerified) {
SimpleButton(generalGetString(R.string.clear_verification), painterResource(R.drawable.ic_shield)) {
SimpleButton(generalGetString(MR.strings.clear_verification), painterResource(R.drawable.ic_shield)) {
verifyCode(null) {}
}
} else {
SimpleButton(generalGetString(R.string.scan_code), painterResource(R.drawable.ic_qr_code)) {
SimpleButton(generalGetString(MR.strings.scan_code), painterResource(R.drawable.ic_qr_code)) {
ModalManager.shared.showModal {
ScanCodeView(verifyCode) { }
}
}
SimpleButton(generalGetString(R.string.mark_code_verified), painterResource(R.drawable.ic_verified_user)) {
SimpleButton(generalGetString(MR.strings.mark_code_verified), painterResource(R.drawable.ic_verified_user)) {
verifyCode(connectionCode) { verified ->
if (!verified) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.incorrect_code)
title = generalGetString(MR.strings.incorrect_code)
)
}
}
@@ -19,7 +19,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -32,6 +32,7 @@ import chat.simplex.app.views.chat.ChatInfoToolbarTitle
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.InfoAboutIncognito
import chat.simplex.app.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
@Composable
fun AddGroupMembersView(groupInfo: GroupInfo, creatingGroup: Boolean = false, chatModel: ChatModel, close: () -> Unit) {
@@ -112,12 +113,12 @@ fun AddGroupMembersLayout(
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.button_add_members))
AppBarTitle(stringResource(MR.strings.button_add_members))
InfoAboutIncognito(
chatModelIncognito,
false,
generalGetString(R.string.group_unsupported_incognito_main_profile_sent),
generalGetString(R.string.group_main_profile_sent),
generalGetString(MR.strings.group_unsupported_incognito_main_profile_sent),
generalGetString(MR.strings.group_main_profile_sent),
true
)
Spacer(Modifier.size(DEFAULT_PADDING))
@@ -139,7 +140,7 @@ fun AddGroupMembersLayout(
horizontalArrangement = Arrangement.Center
) {
Text(
stringResource(R.string.no_contacts_to_add),
stringResource(MR.strings.no_contacts_to_add),
Modifier.padding(),
color = MaterialTheme.colors.secondary
)
@@ -148,7 +149,7 @@ fun AddGroupMembersLayout(
SectionView {
if (creatingGroup) {
SectionItemView(openPreferences) {
Text(stringResource(R.string.set_group_preferences))
Text(stringResource(MR.strings.set_group_preferences))
}
}
RoleSelectionRow(groupInfo, selectedRole, allowModifyMembers)
@@ -162,7 +163,7 @@ fun AddGroupMembersLayout(
InviteSectionFooter(selectedContactsCount = selectedContacts.size, allowModifyMembers, clearSelection)
}
SectionDividerSpaced(maxTopPadding = true)
SectionView(stringResource(R.string.select_contacts)) {
SectionView(stringResource(MR.strings.select_contacts)) {
SectionItemView(padding = PaddingValues(start = DEFAULT_PADDING, end = DEFAULT_PADDING_HALF)) {
SearchRowView(searchText, selectedContacts.size)
}
@@ -179,7 +180,7 @@ private fun SearchRowView(
selectedContactsSize: Int
) {
Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) {
Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary)
Icon(painterResource(R.drawable.ic_search), stringResource(MR.strings.search_verb), tint = MaterialTheme.colors.secondary)
}
Spacer(Modifier.width(DEFAULT_SPACE_AFTER_ICON))
SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) {
@@ -201,7 +202,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<Gr
) {
val values = GroupMemberRole.values().filter { it <= groupInfo.membership.memberRole }.map { it to it.text }
ExposedDropDownSettingRow(
generalGetString(R.string.new_member_role),
generalGetString(MR.strings.new_member_role),
values,
selectedRole,
icon = null,
@@ -214,7 +215,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<Gr
fun InviteMembersButton(onClick: () -> Unit, disabled: Boolean) {
SettingsActionItem(
painterResource(R.drawable.ic_check),
stringResource(R.string.invite_to_group_button),
stringResource(MR.strings.invite_to_group_button),
click = onClick,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
@@ -226,7 +227,7 @@ fun InviteMembersButton(onClick: () -> Unit, disabled: Boolean) {
fun SkipInvitingButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_check),
stringResource(R.string.skip_inviting_button),
stringResource(MR.strings.skip_inviting_button),
click = onClick,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
@@ -242,7 +243,7 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec
) {
if (selectedContactsCount >= 1) {
Text(
String.format(generalGetString(R.string.num_contacts_selected), selectedContactsCount),
String.format(generalGetString(MR.strings.num_contacts_selected), selectedContactsCount),
color = MaterialTheme.colors.secondary,
fontSize = 12.sp
)
@@ -250,14 +251,14 @@ fun InviteSectionFooter(selectedContactsCount: Int, enabled: Boolean, clearSelec
Modifier.clickable { if (enabled) clearSelection() }
) {
Text(
stringResource(R.string.clear_contacts_selection_button),
stringResource(MR.strings.clear_contacts_selection_button),
color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
fontSize = 12.sp
)
}
} else {
Text(
stringResource(R.string.no_contacts_selected),
stringResource(MR.strings.no_contacts_selected),
color = MaterialTheme.colors.secondary,
fontSize = 12.sp
)
@@ -328,7 +329,7 @@ fun ContactCheckRow(
Spacer(Modifier.fillMaxWidth().weight(1f))
Icon(
icon,
contentDescription = stringResource(R.string.icon_descr_contact_checked),
contentDescription = stringResource(MR.strings.icon_descr_contact_checked),
tint = iconColor
)
}
@@ -336,9 +337,9 @@ fun ContactCheckRow(
fun showProhibitedToInviteIncognitoAlertDialog() {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.invite_prohibited),
text = generalGetString(R.string.invite_prohibited_description),
confirmText = generalGetString(R.string.ok),
title = generalGetString(MR.strings.invite_prohibited),
text = generalGetString(MR.strings.invite_prohibited_description),
confirmText = generalGetString(MR.strings.ok),
)
}
@@ -18,7 +18,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextOverflow
@@ -34,6 +34,7 @@ import chat.simplex.app.views.chatlist.cantInviteIncognitoAlert
import chat.simplex.app.views.chatlist.setGroupMembers
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.*
import chat.simplex.res.MR
@Composable
fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair<String?, GroupMemberRole?>) -> Unit, close: () -> Unit) {
@@ -108,12 +109,12 @@ fun GroupChatInfoView(chatModel: ChatModel, groupLink: String?, groupLinkMemberR
fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
val alertTextKey =
if (groupInfo.membership.memberCurrent) R.string.delete_group_for_all_members_cannot_undo_warning
else R.string.delete_group_for_self_cannot_undo_warning
if (groupInfo.membership.memberCurrent) MR.strings.delete_group_for_all_members_cannot_undo_warning
else MR.strings.delete_group_for_self_cannot_undo_warning
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_group_question),
title = generalGetString(MR.strings.delete_group_question),
text = generalGetString(alertTextKey),
confirmText = generalGetString(R.string.delete_verb),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
@@ -131,9 +132,9 @@ fun deleteGroupDialog(chatInfo: ChatInfo, groupInfo: GroupInfo, chatModel: ChatM
fun leaveGroupDialog(groupInfo: GroupInfo, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.leave_group_question),
text = generalGetString(R.string.you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved),
confirmText = generalGetString(R.string.leave_group_button),
title = generalGetString(MR.strings.leave_group_question),
text = generalGetString(MR.strings.you_will_stop_receiving_messages_from_this_group_chat_history_will_be_preserved),
confirmText = generalGetString(MR.strings.leave_group_button),
onConfirm = {
withApi {
chatModel.controller.leaveGroup(groupInfo.groupId)
@@ -183,10 +184,10 @@ fun GroupChatInfoLayout(
}
GroupPreferencesButton(openPreferences)
}
SectionTextFooter(stringResource(R.string.only_group_owners_can_change_prefs))
SectionTextFooter(stringResource(MR.strings.only_group_owners_can_change_prefs))
SectionDividerSpaced(maxTopPadding = true)
SectionView(title = String.format(generalGetString(R.string.group_info_section_title_num_members), members.count() + 1)) {
SectionView(title = String.format(generalGetString(MR.strings.group_info_section_title_num_members), members.count() + 1)) {
if (groupInfo.canAddMembers) {
if (groupLink == null) {
CreateGroupLinkButton(manageGroupLink)
@@ -199,7 +200,7 @@ fun GroupChatInfoLayout(
AddMembersButton(tint, onAddMembersClick)
}
val searchText = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
val filteredMembers = derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } }
val filteredMembers = remember { derivedStateOf { members.filter { it.chatViewName.lowercase().contains(searchText.value.text.trim()) } } }
if (members.size > 8) {
SectionItemView(padding = PaddingValues(start = 14.dp, end = DEFAULT_PADDING_HALF)) {
SearchRowView(searchText)
@@ -223,9 +224,9 @@ fun GroupChatInfoLayout(
if (developerTools) {
SectionDividerSpaced()
SectionView(title = stringResource(R.string.section_title_for_console)) {
InfoRow(stringResource(R.string.info_row_local_name), groupInfo.localDisplayName)
InfoRow(stringResource(R.string.info_row_database_id), groupInfo.apiId.toString())
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
InfoRow(stringResource(MR.strings.info_row_local_name), groupInfo.localDisplayName)
InfoRow(stringResource(MR.strings.info_row_database_id), groupInfo.apiId.toString())
}
}
SectionBottomSpacer()
@@ -260,7 +261,7 @@ private fun GroupChatInfoHeader(cInfo: ChatInfo) {
private fun GroupPreferencesButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_toggle_on),
stringResource(R.string.group_preferences),
stringResource(MR.strings.group_preferences),
click = onClick
)
}
@@ -269,7 +270,7 @@ private fun GroupPreferencesButton(onClick: () -> Unit) {
private fun AddMembersButton(tint: Color = MaterialTheme.colors.primary, onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_add),
stringResource(R.string.button_add_members),
stringResource(MR.strings.button_add_members),
onClick,
iconColor = tint,
textColor = tint
@@ -313,7 +314,7 @@ private fun MemberRow(member: GroupMember, user: Boolean = false) {
)
}
val s = member.memberStatus.shortText
val statusDescr = if (user) String.format(generalGetString(R.string.group_info_member_you), s) else s
val statusDescr = if (user) String.format(generalGetString(MR.strings.group_info_member_you), s) else s
Text(
statusDescr,
color = MaterialTheme.colors.secondary,
@@ -339,7 +340,7 @@ private fun MemberVerifiedShield() {
private fun GroupLinkButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_link),
stringResource(R.string.group_link),
stringResource(MR.strings.group_link),
onClick,
iconColor = MaterialTheme.colors.secondary
)
@@ -349,7 +350,7 @@ private fun GroupLinkButton(onClick: () -> Unit) {
private fun CreateGroupLinkButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_add_link),
stringResource(R.string.create_group_link),
stringResource(MR.strings.create_group_link),
onClick,
iconColor = MaterialTheme.colors.secondary
)
@@ -359,7 +360,7 @@ private fun CreateGroupLinkButton(onClick: () -> Unit) {
fun EditGroupProfileButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_edit),
stringResource(R.string.button_edit_group_profile),
stringResource(MR.strings.button_edit_group_profile),
onClick,
iconColor = MaterialTheme.colors.secondary
)
@@ -368,9 +369,9 @@ fun EditGroupProfileButton(onClick: () -> Unit) {
@Composable
private fun AddOrEditWelcomeMessage(welcomeMessage: String?, onClick: () -> Unit) {
val text = if (welcomeMessage == null) {
stringResource(R.string.button_add_welcome_message)
stringResource(MR.strings.button_add_welcome_message)
} else {
stringResource(R.string.button_welcome_message)
stringResource(MR.strings.button_welcome_message)
}
SettingsActionItem(
painterResource(R.drawable.ic_maps_ugc),
@@ -384,7 +385,7 @@ private fun AddOrEditWelcomeMessage(welcomeMessage: String?, onClick: () -> Unit
private fun LeaveGroupButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_logout),
stringResource(R.string.button_leave_group),
stringResource(MR.strings.button_leave_group),
onClick,
iconColor = Color.Red,
textColor = Color.Red
@@ -395,7 +396,7 @@ private fun LeaveGroupButton(onClick: () -> Unit) {
private fun DeleteGroupButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.button_delete_group),
stringResource(MR.strings.button_delete_group),
onClick,
iconColor = Color.Red,
textColor = Color.Red
@@ -407,7 +408,7 @@ private fun SearchRowView(
searchText: MutableState<TextFieldValue> = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue()) }
) {
Box(Modifier.width(36.dp), contentAlignment = Alignment.Center) {
Icon(painterResource(R.drawable.ic_search), stringResource(android.R.string.search_go), tint = MaterialTheme.colors.secondary)
Icon(painterResource(R.drawable.ic_search), stringResource(MR.strings.search_verb), tint = MaterialTheme.colors.secondary)
}
Spacer(Modifier.width(14.dp))
SearchTextField(Modifier.fillMaxWidth(), searchText = searchText, alwaysVisible = true) {
@@ -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.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
@@ -19,6 +19,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.res.MR
@Composable
fun GroupLinkView(chatModel: ChatModel, groupInfo: GroupInfo, connReqContact: String?, memberRole: GroupMemberRole?, onGroupLinkUpdated: (Pair<String?, GroupMemberRole?>) -> Unit) {
@@ -64,9 +65,9 @@ fun GroupLinkView(chatModel: ChatModel, groupInfo: GroupInfo, connReqContact: St
},
deleteLink = {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_link_question),
text = generalGetString(R.string.all_group_members_will_remain_connected),
confirmText = generalGetString(R.string.delete_verb),
title = generalGetString(MR.strings.delete_link_question),
text = generalGetString(MR.strings.all_group_members_will_remain_connected),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteGroupLink(groupInfo.groupId)
@@ -100,9 +101,9 @@ fun GroupLinkLayout(
Modifier
.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.group_link))
AppBarTitle(stringResource(MR.strings.group_link))
Text(
stringResource(R.string.you_can_share_group_link_anybody_will_be_able_to_connect),
stringResource(MR.strings.you_can_share_group_link_anybody_will_be_able_to_connect),
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = 12.dp),
lineHeight = 22.sp
)
@@ -112,7 +113,7 @@ fun GroupLinkLayout(
verticalArrangement = Arrangement.SpaceEvenly
) {
if (groupLink == null) {
SimpleButton(stringResource(R.string.button_create_group_link), icon = painterResource(R.drawable.ic_add_link), disabled = creatingLink, click = createLink)
SimpleButton(stringResource(MR.strings.button_create_group_link), icon = painterResource(R.drawable.ic_add_link), disabled = creatingLink, click = createLink)
} else {
RoleSelectionRow(groupInfo, groupLinkMemberRole)
var initialLaunch by remember { mutableStateOf(true) }
@@ -129,12 +130,12 @@ fun GroupLinkLayout(
modifier = Modifier.padding(horizontal = DEFAULT_PADDING, vertical = 10.dp)
) {
SimpleButton(
stringResource(R.string.share_link),
stringResource(MR.strings.share_link),
icon = painterResource(R.drawable.ic_share),
click = share
)
SimpleButton(
stringResource(R.string.delete_link),
stringResource(MR.strings.delete_link),
icon = painterResource(R.drawable.ic_delete),
color = Color.Red,
click = deleteLink
@@ -155,7 +156,7 @@ private fun RoleSelectionRow(groupInfo: GroupInfo, selectedRole: MutableState<Gr
) {
val values = listOf(GroupMemberRole.Member, GroupMemberRole.Observer).map { it to it.text }
ExposedDropDownSettingRow(
generalGetString(R.string.initial_member_role),
generalGetString(MR.strings.initial_member_role),
values,
selectedRole,
icon = null,
@@ -18,7 +18,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -31,6 +31,7 @@ import chat.simplex.app.views.chat.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.*
import chat.simplex.app.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@Composable
@@ -144,9 +145,9 @@ fun GroupMemberInfoView(
fun removeMemberDialog(groupInfo: GroupInfo, member: GroupMember, chatModel: ChatModel, close: (() -> Unit)? = null) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.button_remove_member),
text = generalGetString(R.string.member_will_be_removed_from_group_cannot_be_undone),
confirmText = generalGetString(R.string.remove_member_confirmation),
title = generalGetString(MR.strings.button_remove_member),
text = generalGetString(MR.strings.member_will_be_removed_from_group_cannot_be_undone),
confirmText = generalGetString(MR.strings.remove_member_confirmation),
onConfirm = {
withApi {
val removedMember = chatModel.controller.apiRemoveMember(member.groupId, member.groupMemberId)
@@ -218,7 +219,7 @@ fun GroupMemberInfoLayout(
if (member.contactLink != null) {
val context = LocalContext.current
SectionView(stringResource(R.string.address_section_title).uppercase()) {
SectionView(stringResource(MR.strings.address_section_title).uppercase()) {
QRCode(member.contactLink, Modifier.padding(horizontal = DEFAULT_PADDING, vertical = DEFAULT_PADDING_HALF).aspectRatio(1f))
ShareAddressButton { shareText(member.contactLink) }
if (contactId != null) {
@@ -228,30 +229,30 @@ fun GroupMemberInfoLayout(
} else {
ConnectViaAddressButton(onClick = { connectViaAddress(member.contactLink) })
}
SectionTextFooter(stringResource(R.string.you_can_share_this_address_with_your_contacts).format(member.displayName))
SectionTextFooter(stringResource(MR.strings.you_can_share_this_address_with_your_contacts).format(member.displayName))
}
SectionDividerSpaced()
}
SectionView(title = stringResource(R.string.member_info_section_title_member)) {
InfoRow(stringResource(R.string.info_row_group), groupInfo.displayName)
SectionView(title = stringResource(MR.strings.member_info_section_title_member)) {
InfoRow(stringResource(MR.strings.info_row_group), groupInfo.displayName)
val roles = remember { member.canChangeRoleTo(groupInfo) }
if (roles != null) {
RoleSelectionRow(roles, newRole, onRoleSelected)
} else {
InfoRow(stringResource(R.string.role_in_group), member.memberRole.text)
InfoRow(stringResource(MR.strings.role_in_group), member.memberRole.text)
}
val conn = member.activeConn
if (conn != null) {
val connLevelDesc =
if (conn.connLevel == 0) stringResource(R.string.conn_level_desc_direct)
else String.format(generalGetString(R.string.conn_level_desc_indirect), conn.connLevel)
InfoRow(stringResource(R.string.info_row_connection), connLevelDesc)
if (conn.connLevel == 0) stringResource(MR.strings.conn_level_desc_direct)
else String.format(generalGetString(MR.strings.conn_level_desc_indirect), conn.connLevel)
InfoRow(stringResource(MR.strings.info_row_connection), connLevelDesc)
}
}
if (cStats != null) {
SectionDividerSpaced()
SectionView(title = stringResource(R.string.conn_stats_section_title_servers)) {
SectionView(title = stringResource(MR.strings.conn_stats_section_title_servers)) {
SwitchAddressButton(
disabled = cStats.rcvQueuesInfo.any { it.rcvSwitchStatus != null },
switchAddress = switchMemberAddress
@@ -264,11 +265,11 @@ fun GroupMemberInfoLayout(
}
val rcvServers = cStats.rcvQueuesInfo.map { it.rcvServer }
if (rcvServers.isNotEmpty()) {
SimplexServers(stringResource(R.string.receiving_via), rcvServers)
SimplexServers(stringResource(MR.strings.receiving_via), rcvServers)
}
val sndServers = cStats.sndQueuesInfo.map { it.sndServer }
if (sndServers.isNotEmpty()) {
SimplexServers(stringResource(R.string.sending_via), sndServers)
SimplexServers(stringResource(MR.strings.sending_via), sndServers)
}
}
}
@@ -282,9 +283,9 @@ fun GroupMemberInfoLayout(
if (developerTools) {
SectionDividerSpaced()
SectionView(title = stringResource(R.string.section_title_for_console)) {
InfoRow(stringResource(R.string.info_row_local_name), member.localDisplayName)
InfoRow(stringResource(R.string.info_row_database_id), member.groupMemberId.toString())
SectionView(title = stringResource(MR.strings.section_title_for_console)) {
InfoRow(stringResource(MR.strings.info_row_local_name), member.localDisplayName)
InfoRow(stringResource(MR.strings.info_row_database_id), member.groupMemberId.toString())
}
}
SectionBottomSpacer()
@@ -324,7 +325,7 @@ fun GroupMemberInfoHeader(member: GroupMember) {
fun RemoveMemberButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.button_remove_member),
stringResource(MR.strings.button_remove_member),
click = onClick,
textColor = Color.Red,
iconColor = Color.Red,
@@ -335,7 +336,7 @@ fun RemoveMemberButton(onClick: () -> Unit) {
fun OpenChatButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_chat),
stringResource(R.string.button_send_direct_message),
stringResource(MR.strings.button_send_direct_message),
click = onClick,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
@@ -346,7 +347,7 @@ fun OpenChatButton(onClick: () -> Unit) {
fun ConnectViaAddressButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_link),
stringResource(R.string.connect_button),
stringResource(MR.strings.connect_button),
click = onClick,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
@@ -366,7 +367,7 @@ private fun RoleSelectionRow(
) {
val values = remember { roles.map { it to it.text } }
ExposedDropDownSettingRow(
generalGetString(R.string.change_role),
generalGetString(MR.strings.change_role),
values,
selectedRole,
icon = null,
@@ -383,12 +384,12 @@ private fun updateMemberRoleDialog(
onConfirm: () -> Unit
) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.change_member_role_question),
title = generalGetString(MR.strings.change_member_role_question),
text = if (member.memberCurrent)
String.format(generalGetString(R.string.member_role_will_be_changed_with_notification), newRole.text)
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_notification), newRole.text)
else
String.format(generalGetString(R.string.member_role_will_be_changed_with_invitation), newRole.text),
confirmText = generalGetString(R.string.change_verb),
String.format(generalGetString(MR.strings.member_role_will_be_changed_with_invitation), newRole.text),
confirmText = generalGetString(MR.strings.change_verb),
onDismiss = onDismiss,
onConfirm = onConfirm,
onDismissRequest = onDismiss
@@ -13,12 +13,13 @@ import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.PreferenceToggleWithIcon
import chat.simplex.res.MR
@Composable
fun GroupPreferencesView(m: ChatModel, chatId: String, close: () -> Unit,) {
@@ -71,7 +72,7 @@ private fun GroupPreferencesLayout(
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.group_preferences))
AppBarTitle(stringResource(MR.strings.group_preferences))
val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.enable) }
val onTTLUpdated = { ttl: Int? ->
applyPrefs(preferences.copy(timedMessages = preferences.timedMessages.copy(ttl = ttl)))
@@ -149,10 +150,10 @@ private fun FeatureSection(
DropdownCustomTimePickerSettingRow(
selection = ttl,
propagateExternalSelectionUpdate = true, // for Reset
label = generalGetString(R.string.delete_after),
label = generalGetString(MR.strings.delete_after),
dropdownValues = TimedMessagesPreference.ttlValues,
customPickerTitle = generalGetString(R.string.delete_after),
customPickerConfirmButtonText = generalGetString(R.string.custom_time_picker_select),
customPickerTitle = generalGetString(MR.strings.delete_after),
customPickerConfirmButtonText = generalGetString(MR.strings.custom_time_picker_select),
onSelected = onTTLUpdated
)
}
@@ -164,7 +165,7 @@ private fun FeatureSection(
iconTint = iconTint,
)
if (timedOn) {
InfoRow(generalGetString(R.string.delete_after), timeText(preferences.timedMessages.ttl))
InfoRow(generalGetString(MR.strings.delete_after), timeText(preferences.timedMessages.ttl))
}
}
}
@@ -175,19 +176,19 @@ private fun FeatureSection(
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
SectionView {
SectionItemView(reset, disabled = disabled) {
Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
SectionItemView(save, disabled = disabled) {
Text(stringResource(R.string.save_and_notify_group_members), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.save_and_notify_group_members), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_preferences_question),
confirmText = generalGetString(R.string.save_and_notify_group_members),
dismissText = generalGetString(R.string.exit_without_saving),
title = generalGetString(MR.strings.save_preferences_question),
confirmText = generalGetString(MR.strings.save_and_notify_group_members),
dismissText = generalGetString(MR.strings.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)
@@ -13,7 +13,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -28,6 +28,7 @@ import chat.simplex.app.views.onboarding.ReadableText
import chat.simplex.app.views.usersettings.*
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -105,7 +106,7 @@ fun GroupProfileLayout(
Modifier.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING)
) {
ReadableText(R.string.group_profile_is_stored_on_members_devices, TextAlign.Center)
ReadableText(MR.strings.group_profile_is_stored_on_members_devices, TextAlign.Center)
Box(
Modifier
.fillMaxWidth()
@@ -124,13 +125,13 @@ fun GroupProfileLayout(
}
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(R.string.group_display_name_field),
stringResource(MR.strings.group_display_name_field),
fontSize = 16.sp
)
if (!isValidDisplayName(displayName.value)) {
Spacer(Modifier.size(DEFAULT_PADDING_HALF))
Text(
stringResource(R.string.no_spaces),
stringResource(MR.strings.no_spaces),
fontSize = 16.sp,
color = Color.Red
)
@@ -139,7 +140,7 @@ fun GroupProfileLayout(
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(R.string.group_full_name_field),
stringResource(MR.strings.group_full_name_field),
fontSize = 16.sp,
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
)
@@ -148,7 +149,7 @@ fun GroupProfileLayout(
val enabled = !dataUnchanged && displayName.value.isNotEmpty() && isValidDisplayName(displayName.value)
if (enabled) {
Text(
stringResource(R.string.save_group_profile),
stringResource(MR.strings.save_group_profile),
modifier = Modifier.clickable {
saveProfile(
groupProfile.copy(
@@ -162,7 +163,7 @@ fun GroupProfileLayout(
)
} else {
Text(
stringResource(R.string.save_group_profile),
stringResource(MR.strings.save_group_profile),
color = MaterialTheme.colors.secondary
)
}
@@ -182,9 +183,9 @@ fun GroupProfileLayout(
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_preferences_question),
confirmText = generalGetString(R.string.save_and_notify_group_members),
dismissText = generalGetString(R.string.exit_without_saving),
title = generalGetString(MR.strings.save_preferences_question),
confirmText = generalGetString(MR.strings.save_and_notify_group_members),
dismissText = generalGetString(MR.strings.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)
@@ -15,7 +15,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.*
@@ -24,6 +24,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@Composable
@@ -74,14 +75,14 @@ private fun GroupWelcomeLayout(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
val editMode = remember { mutableStateOf(true) }
AppBarTitle(stringResource(R.string.group_welcome_title))
AppBarTitle(stringResource(MR.strings.group_welcome_title))
val wt = rememberSaveable { welcomeText }
if (groupInfo.canEdit) {
if (editMode.value) {
val focusRequester = remember { FocusRequester() }
TextEditor(
wt,
Modifier.height(140.dp), stringResource(R.string.enter_welcome_message),
Modifier.height(140.dp), stringResource(MR.strings.enter_welcome_message),
focusRequester = focusRequester
)
LaunchedEffect(Unit) {
@@ -131,7 +132,7 @@ private fun TextPreview(text: String, linkMode: SimplexLinkMode, markdown: Boole
private fun SaveButton(save: () -> Unit, disabled: Boolean) {
SectionView {
SectionItemView(save, disabled = disabled) {
Text(stringResource(R.string.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.save_and_update_group_profile), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
}
@@ -141,12 +142,12 @@ private fun ChangeModeButton(editMode: Boolean, click: () -> Unit, disabled: Boo
SectionItemView(click, disabled = disabled) {
Icon(
painterResource(if (editMode) R.drawable.ic_visibility else R.drawable.ic_edit),
contentDescription = generalGetString(R.string.edit_verb),
contentDescription = generalGetString(MR.strings.edit_verb),
tint = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary,
)
TextIconSpaced()
Text(
stringResource(if (editMode) R.string.group_welcome_preview else R.string.edit_verb),
stringResource(if (editMode) MR.strings.group_welcome_preview else MR.strings.edit_verb),
color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
)
}
@@ -157,19 +158,19 @@ private fun CopyTextButton(click: () -> Unit) {
SectionItemView(click) {
Icon(
painterResource(R.drawable.ic_content_copy),
contentDescription = generalGetString(R.string.copy_verb),
contentDescription = generalGetString(MR.strings.copy_verb),
tint = MaterialTheme.colors.primary,
)
TextIconSpaced()
Text(stringResource(R.string.copy_verb), color = MaterialTheme.colors.primary)
Text(stringResource(MR.strings.copy_verb), color = MaterialTheme.colors.primary)
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_welcome_message_question),
confirmText = generalGetString(R.string.save_and_update_group_profile),
dismissText = generalGetString(R.string.exit_without_saving),
title = generalGetString(MR.strings.save_welcome_message_question),
confirmText = generalGetString(MR.strings.save_and_update_group_profile),
dismissText = generalGetString(MR.strings.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)
@@ -7,12 +7,13 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.res.MR
@Composable
fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, duration: Int, acceptCall: (Contact) -> Unit) {
@@ -21,20 +22,20 @@ fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, durat
Modifier
.padding(horizontal = 4.dp)
.padding(bottom = 8.dp), horizontalAlignment = Alignment.CenterHorizontally) {
@Composable fun ConnectingCallIcon() = Icon(painterResource(R.drawable.ic_settings_phone), stringResource(R.string.icon_descr_call_connecting), tint = SimplexGreen)
@Composable fun ConnectingCallIcon() = Icon(painterResource(R.drawable.ic_settings_phone), stringResource(MR.strings.icon_descr_call_connecting), tint = SimplexGreen)
when (status) {
CICallStatus.Pending -> if (sent) {
Icon(painterResource(R.drawable.ic_call), stringResource(R.string.icon_descr_call_pending_sent))
Icon(painterResource(R.drawable.ic_call), stringResource(MR.strings.icon_descr_call_pending_sent))
} else {
AcceptCallButton(cInfo, acceptCall)
}
CICallStatus.Missed -> Icon(painterResource(R.drawable.ic_call), stringResource(R.string.icon_descr_call_missed), tint = Color.Red)
CICallStatus.Rejected -> Icon(painterResource(R.drawable.ic_call_end), stringResource(R.string.icon_descr_call_rejected), tint = Color.Red)
CICallStatus.Missed -> Icon(painterResource(R.drawable.ic_call), stringResource(MR.strings.icon_descr_call_missed), tint = Color.Red)
CICallStatus.Rejected -> Icon(painterResource(R.drawable.ic_call_end), stringResource(MR.strings.icon_descr_call_rejected), tint = Color.Red)
CICallStatus.Accepted -> ConnectingCallIcon()
CICallStatus.Negotiated -> ConnectingCallIcon()
CICallStatus.Progress -> Icon(painterResource(R.drawable.ic_phone_in_talk_filled), stringResource(R.string.icon_descr_call_progress), tint = SimplexGreen)
CICallStatus.Progress -> Icon(painterResource(R.drawable.ic_phone_in_talk_filled), stringResource(MR.strings.icon_descr_call_progress), tint = SimplexGreen)
CICallStatus.Ended -> Row {
Icon(painterResource(R.drawable.ic_call_end), stringResource(R.string.icon_descr_call_ended), tint = MaterialTheme.colors.secondary, modifier = Modifier.padding(end = 4.dp))
Icon(painterResource(R.drawable.ic_call_end), stringResource(MR.strings.icon_descr_call_ended), tint = MaterialTheme.colors.secondary, modifier = Modifier.padding(end = 4.dp))
Text(durationText(duration), color = MaterialTheme.colors.secondary)
}
CICallStatus.Error -> {}
@@ -52,9 +53,9 @@ fun CICallItemView(cInfo: ChatInfo, cItem: ChatItem, status: CICallStatus, durat
@Composable
fun AcceptCallButton(cInfo: ChatInfo, acceptCall: (Contact) -> Unit) {
if (cInfo is ChatInfo.Direct) {
SimpleButton(stringResource(R.string.answer_call), painterResource(R.drawable.ic_ring_volume)) { acceptCall(cInfo.contact) }
SimpleButton(stringResource(MR.strings.answer_call), painterResource(R.drawable.ic_ring_volume)) { acceptCall(cInfo.contact) }
} else {
Icon(painterResource(R.drawable.ic_ring_volume), stringResource(R.string.answer_call), tint = MaterialTheme.colors.secondary)
Icon(painterResource(R.drawable.ic_ring_volume), stringResource(MR.strings.answer_call), tint = MaterialTheme.colors.secondary)
}
// if case let .direct(contact) = chatInfo {
// Button {
@@ -12,6 +12,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
@Composable
fun CIFeaturePreferenceView(
@@ -30,7 +31,7 @@ fun CIFeaturePreferenceView(
if (contact != null && allowed != FeatureAllowed.NO && contact.allowsFeature(feature) && !contact.userAllowsFeature(feature)) {
val acceptStyle = SpanStyle(color = MaterialTheme.colors.primary, fontSize = 12.sp)
val setParam = feature == ChatFeature.TimedMessages && contact.mergedPreferences.timedMessages.userPreference.pref.ttl == null
val acceptTextId = if (setParam) R.string.accept_feature_set_1_day else R.string.accept_feature
val acceptTextId = if (setParam) MR.strings.accept_feature_set_1_day else MR.strings.accept_feature
val param = if (setParam) 86400 else null
val annotatedText = buildAnnotatedString {
withStyle(chatEventStyle) { append(chatItem.content.text + " ") }
@@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.*
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -23,6 +23,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@Composable
@@ -44,14 +45,14 @@ fun CIFileView(
) {
Icon(
painterResource(R.drawable.ic_draft_filled),
stringResource(R.string.icon_descr_file),
stringResource(MR.strings.icon_descr_file),
Modifier.fillMaxSize(),
tint = color
)
if (innerIcon != null) {
Icon(
innerIcon,
stringResource(R.string.icon_descr_file),
stringResource(MR.strings.icon_descr_file),
Modifier
.size(32.dp)
.padding(top = 12.dp),
@@ -76,8 +77,8 @@ fun CIFileView(
receiveFile(file.fileId)
} else {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.large_file),
String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
generalGetString(MR.strings.large_file),
String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
)
}
}
@@ -85,13 +86,13 @@ fun CIFileView(
when (file.fileProtocol) {
FileProtocol.XFTP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_file),
generalGetString(R.string.file_will_be_received_when_contact_completes_uploading)
generalGetString(MR.strings.waiting_for_file),
generalGetString(MR.strings.file_will_be_received_when_contact_completes_uploading)
)
FileProtocol.SMP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_file),
generalGetString(R.string.file_will_be_received_when_contact_is_online)
generalGetString(MR.strings.waiting_for_file),
generalGetString(MR.strings.file_will_be_received_when_contact_is_online)
)
}
is CIFileStatus.RcvComplete -> {
@@ -99,7 +100,7 @@ fun CIFileView(
if (filePath != null) {
saveFileLauncher.launch(file.fileName)
} else {
Toast.makeText(context, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show()
Toast.makeText(context, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show()
}
}
else -> {}
@@ -8,7 +8,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.*
@@ -18,6 +18,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun CIGroupInvitationView(
@@ -60,11 +61,11 @@ fun CIGroupInvitationView(
@Composable
fun groupInvitationText() {
when {
sent -> Text(stringResource(R.string.you_sent_group_invitation))
!sent && groupInvitation.status == CIGroupInvitationStatus.Pending -> Text(stringResource(R.string.you_are_invited_to_group))
!sent && groupInvitation.status == CIGroupInvitationStatus.Accepted -> Text(stringResource(R.string.you_joined_this_group))
!sent && groupInvitation.status == CIGroupInvitationStatus.Rejected -> Text(stringResource(R.string.you_rejected_group_invitation))
!sent && groupInvitation.status == CIGroupInvitationStatus.Expired -> Text(stringResource(R.string.group_invitation_expired))
sent -> Text(stringResource(MR.strings.you_sent_group_invitation))
!sent && groupInvitation.status == CIGroupInvitationStatus.Pending -> Text(stringResource(MR.strings.you_are_invited_to_group))
!sent && groupInvitation.status == CIGroupInvitationStatus.Accepted -> Text(stringResource(MR.strings.you_joined_this_group))
!sent && groupInvitation.status == CIGroupInvitationStatus.Rejected -> Text(stringResource(MR.strings.you_rejected_group_invitation))
!sent && groupInvitation.status == CIGroupInvitationStatus.Expired -> Text(stringResource(MR.strings.group_invitation_expired))
}
}
@@ -95,7 +96,7 @@ fun CIGroupInvitationView(
if (action) {
groupInvitationText()
Text(stringResource(
if (chatIncognito) R.string.group_invitation_tap_to_join_incognito else R.string.group_invitation_tap_to_join),
if (chatIncognito) MR.strings.group_invitation_tap_to_join_incognito else MR.strings.group_invitation_tap_to_join),
color = if (chatIncognito) Indigo else MaterialTheme.colors.primary)
} else {
Box(Modifier.padding(end = 48.dp)) {
@@ -2,7 +2,6 @@ package chat.simplex.app.views.chat.item
import android.graphics.Bitmap
import android.os.Build.VERSION.SDK_INT
import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.*
@@ -19,7 +18,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.core.content.FileProvider
@@ -32,6 +31,8 @@ import coil.compose.rememberAsyncImagePainter
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.request.ImageRequest
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import java.io.File
@Composable
@@ -52,7 +53,7 @@ fun CIImageView(
}
@Composable
fun fileIcon(icon: Painter, @StringRes stringId: Int) {
fun fileIcon(icon: Painter, stringId: StringResource) {
Icon(
icon,
stringResource(stringId),
@@ -77,14 +78,14 @@ fun CIImageView(
FileProtocol.SMP -> {}
}
is CIFileStatus.SndTransfer -> progressIndicator()
is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), R.string.icon_descr_image_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), R.string.icon_descr_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), R.string.icon_descr_waiting_for_image)
is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), MR.strings.icon_descr_image_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), MR.strings.icon_descr_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), MR.strings.icon_descr_waiting_for_image)
is CIFileStatus.RcvTransfer -> progressIndicator()
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
else -> {}
}
}
@@ -101,7 +102,7 @@ fun CIImageView(
fun imageView(imageBitmap: Bitmap, onClick: () -> Unit) {
Image(
imageBitmap.asImageBitmap(),
contentDescription = stringResource(R.string.image_descr),
contentDescription = stringResource(MR.strings.image_descr),
// .width(1000.dp) is a hack for image to increase IntrinsicSize of FramedItemView
// if text is short and take all available width if text is long
modifier = Modifier
@@ -118,7 +119,7 @@ fun CIImageView(
fun imageView(painter: Painter, onClick: () -> Unit) {
Image(
painter,
contentDescription = stringResource(R.string.image_descr),
contentDescription = stringResource(MR.strings.image_descr),
// .width(1000.dp) is a hack for image to increase IntrinsicSize of FramedItemView
// if text is short and take all available width if text is long
modifier = Modifier
@@ -175,21 +176,21 @@ fun CIImageView(
receiveFile(file.fileId)
} else {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.large_file),
String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
generalGetString(MR.strings.large_file),
String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
)
}
CIFileStatus.RcvAccepted ->
when (file.fileProtocol) {
FileProtocol.XFTP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_image),
generalGetString(R.string.image_will_be_received_when_contact_completes_uploading)
generalGetString(MR.strings.waiting_for_image),
generalGetString(MR.strings.image_will_be_received_when_contact_completes_uploading)
)
FileProtocol.SMP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_image),
generalGetString(R.string.image_will_be_received_when_contact_is_online)
generalGetString(MR.strings.waiting_for_image),
generalGetString(MR.strings.image_will_be_received_when_contact_is_online)
)
}
CIFileStatus.RcvTransfer(rcvProgress = 7, rcvTotal = 10) -> {} // ?
@@ -8,13 +8,14 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
@Composable
fun CIInvalidJSONView(json: String) {
@@ -22,7 +23,7 @@ fun CIInvalidJSONView(json: String) {
.clickable { ModalManager.shared.showModal(true) { InvalidJSONView(json) } }
.padding(horizontal = 10.dp, vertical = 6.dp)
) {
Text(stringResource(R.string.invalid_data), color = Color.Red, fontStyle = FontStyle.Italic)
Text(stringResource(MR.strings.invalid_data), color = Color.Red, fontStyle = FontStyle.Italic)
}
}
@@ -31,7 +32,7 @@ fun InvalidJSONView(json: String) {
Column {
Spacer(Modifier.height(DEFAULT_PADDING))
SectionView {
SettingsActionItem(painterResource(R.drawable.ic_share), generalGetString(R.string.share_verb), click = {
SettingsActionItem(painterResource(R.drawable.ic_share), generalGetString(MR.strings.share_verb), click = {
shareText(json)
})
}
@@ -5,19 +5,20 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
@Composable
fun CIRcvDecryptionError(msgDecryptError: MsgDecryptError, msgCount: UInt, ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean) {
CIMsgError(ci, timedMessagesTTL, showMember) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.decryption_error),
title = generalGetString(MR.strings.decryption_error),
text = when (msgDecryptError) {
MsgDecryptError.RatchetHeader -> String.format(generalGetString(R.string.alert_text_decryption_error_header), msgCount.toLong()) + "\n" +
generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(R.string.alert_text_fragment_permanent_error_reconnect)
MsgDecryptError.TooManySkipped -> String.format(generalGetString(R.string.alert_text_decryption_error_too_many_skipped), msgCount.toLong()) + "\n" +
generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(R.string.alert_text_fragment_permanent_error_reconnect)
MsgDecryptError.RatchetHeader -> String.format(generalGetString(MR.strings.alert_text_decryption_error_header), msgCount.toLong()) + "\n" +
generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(MR.strings.alert_text_fragment_permanent_error_reconnect)
MsgDecryptError.TooManySkipped -> String.format(generalGetString(MR.strings.alert_text_decryption_error_too_many_skipped), msgCount.toLong()) + "\n" +
generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(MR.strings.alert_text_fragment_permanent_error_reconnect)
}
)
}
@@ -3,7 +3,6 @@ package chat.simplex.app.views.chat.item
import android.graphics.Bitmap
import android.graphics.Rect
import android.net.Uri
import androidx.annotation.StringRes
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CornerSize
@@ -18,7 +17,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.*
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.*
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.FileProvider
@@ -30,6 +29,8 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH
import com.google.android.exoplayer2.ui.StyledPlayerView
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import java.io.File
@Composable
@@ -68,14 +69,14 @@ fun CIVideoView(
when (file.fileProtocol) {
FileProtocol.XFTP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_video),
generalGetString(R.string.video_will_be_received_when_contact_completes_uploading)
generalGetString(MR.strings.waiting_for_video),
generalGetString(MR.strings.video_will_be_received_when_contact_completes_uploading)
)
FileProtocol.SMP ->
AlertManager.shared.showAlertMsg(
generalGetString(R.string.waiting_for_video),
generalGetString(R.string.video_will_be_received_when_contact_is_online)
generalGetString(MR.strings.waiting_for_video),
generalGetString(MR.strings.video_will_be_received_when_contact_is_online)
)
}
CIFileStatus.RcvTransfer(rcvProgress = 7, rcvTotal = 10) -> {} // ?
@@ -220,7 +221,7 @@ private fun ImageView(preview: Bitmap, showMenu: MutableState<Boolean>, onClick:
val width = remember(preview) { if (preview.width * 0.97 <= preview.height) videoViewFullWidth(windowWidth) * 0.75f else 1000.dp }
Image(
preview.asImageBitmap(),
contentDescription = stringResource(R.string.video_descr),
contentDescription = stringResource(MR.strings.video_descr),
modifier = Modifier
.width(width)
.combinedClickable(
@@ -252,7 +253,7 @@ private fun progressIndicator() {
}
@Composable
private fun fileIcon(icon: Painter, @StringRes stringId: Int) {
private fun fileIcon(icon: Painter, stringId: StringResource) {
Icon(
icon,
stringResource(stringId),
@@ -295,19 +296,19 @@ private fun loadingIndicator(file: CIFile?) {
FileProtocol.XFTP -> progressCircle(file.fileStatus.sndProgress, file.fileStatus.sndTotal)
FileProtocol.SMP -> progressIndicator()
}
is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), R.string.icon_descr_video_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), R.string.icon_descr_video_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), R.string.icon_descr_waiting_for_video)
is CIFileStatus.SndComplete -> fileIcon(painterResource(R.drawable.ic_check_filled), MR.strings.icon_descr_video_snd_complete)
is CIFileStatus.SndCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.SndError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvInvitation -> fileIcon(painterResource(R.drawable.ic_arrow_downward), MR.strings.icon_descr_video_asked_to_receive)
is CIFileStatus.RcvAccepted -> fileIcon(painterResource(R.drawable.ic_more_horiz), MR.strings.icon_descr_waiting_for_video)
is CIFileStatus.RcvTransfer ->
if (file.fileProtocol == FileProtocol.XFTP && file.fileStatus.rcvProgress < file.fileStatus.rcvTotal) {
progressCircle(file.fileStatus.rcvProgress, file.fileStatus.rcvTotal)
} else {
progressIndicator()
}
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), R.string.icon_descr_file)
is CIFileStatus.RcvCancelled -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
is CIFileStatus.RcvError -> fileIcon(painterResource(R.drawable.ic_close), MR.strings.icon_descr_file)
else -> {}
}
}
@@ -326,8 +327,8 @@ private fun receiveFileIfValidSize(file: CIFile, receiveFile: (Long) -> Unit) {
receiveFile(file.fileId)
} else {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.large_file),
String.format(generalGetString(R.string.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
generalGetString(MR.strings.large_file),
String.format(generalGetString(MR.strings.contact_sent_large_file), formatBytes(getMaxFileSize(file.fileProtocol)))
)
}
}
@@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -26,6 +26,7 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.*
import chat.simplex.app.views.helpers.*
import com.google.accompanist.permissions.rememberPermissionState
import chat.simplex.res.MR
import kotlinx.datetime.Clock
// TODO refactor so that FramedItemView can show all CIContent items if they're deleted (see Swift code)
@@ -69,10 +70,10 @@ fun ChatItemView(
val onClick = {
when (cItem.meta.itemStatus) {
is CIStatus.SndErrorAuth -> {
showMsgDeliveryErrorAlert(generalGetString(R.string.message_delivery_error_desc))
showMsgDeliveryErrorAlert(generalGetString(MR.strings.message_delivery_error_desc))
}
is CIStatus.SndError -> {
showMsgDeliveryErrorAlert(generalGetString(R.string.unknown_error) + ": ${cItem.meta.itemStatus.agentError}")
showMsgDeliveryErrorAlert(generalGetString(MR.strings.unknown_error) + ": ${cItem.meta.itemStatus.agentError}")
}
else -> {}
}
@@ -116,17 +117,17 @@ fun ChatItemView(
fun deleteMessageQuestionText(): String {
return if (fullDeleteAllowed) {
generalGetString(R.string.delete_message_cannot_be_undone_warning)
generalGetString(MR.strings.delete_message_cannot_be_undone_warning)
} else {
generalGetString(R.string.delete_message_mark_deleted_warning)
generalGetString(MR.strings.delete_message_mark_deleted_warning)
}
}
fun moderateMessageQuestionText(): String {
return if (fullDeleteAllowed) {
generalGetString(R.string.moderate_message_will_be_deleted_warning)
generalGetString(MR.strings.moderate_message_will_be_deleted_warning)
} else {
generalGetString(R.string.moderate_message_will_be_marked_warning)
generalGetString(MR.strings.moderate_message_will_be_marked_warning)
}
}
@@ -163,7 +164,7 @@ fun ChatItemView(
MsgReactionsMenu()
}
if (cItem.meta.itemDeleted == null && !live) {
ItemAction(stringResource(R.string.reply_verb), painterResource(R.drawable.ic_reply), onClick = {
ItemAction(stringResource(MR.strings.reply_verb), painterResource(R.drawable.ic_reply), onClick = {
if (composeState.value.editing) {
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
} else {
@@ -172,7 +173,7 @@ fun ChatItemView(
showMenu.value = false
})
}
ItemAction(stringResource(R.string.share_verb), painterResource(R.drawable.ic_share), onClick = {
ItemAction(stringResource(MR.strings.share_verb), painterResource(R.drawable.ic_share), onClick = {
val filePath = getLoadedFilePath(cItem.file)
when {
filePath != null -> shareFile(cItem.text, filePath)
@@ -180,7 +181,7 @@ fun ChatItemView(
}
showMenu.value = false
})
ItemAction(stringResource(R.string.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
ItemAction(stringResource(MR.strings.copy_verb), painterResource(R.drawable.ic_content_copy), onClick = {
copyText(cItem.content.text)
showMenu.value = false
})
@@ -188,7 +189,7 @@ fun ChatItemView(
val filePath = getLoadedFilePath(cItem.file)
if (filePath != null) {
val writePermissionState = rememberPermissionState(permission = Manifest.permission.WRITE_EXTERNAL_STORAGE)
ItemAction(stringResource(R.string.save_verb), painterResource(R.drawable.ic_download), onClick = {
ItemAction(stringResource(MR.strings.save_verb), painterResource(R.drawable.ic_download), onClick = {
when (cItem.content.msgContent) {
is MsgContent.MCImage -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R || writePermissionState.hasPermission) {
@@ -205,14 +206,14 @@ fun ChatItemView(
}
}
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
ItemAction(stringResource(R.string.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = {
ItemAction(stringResource(MR.strings.edit_verb), painterResource(R.drawable.ic_edit_filled), onClick = {
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
showMenu.value = false
})
}
if (cItem.meta.itemDeleted != null && revealed.value) {
ItemAction(
stringResource(R.string.hide_verb),
stringResource(MR.strings.hide_verb),
painterResource(R.drawable.ic_visibility_off),
onClick = {
revealed.value = false
@@ -239,7 +240,7 @@ fun ChatItemView(
DefaultDropdownMenu(showMenu) {
if (!cItem.isDeletedContent) {
ItemAction(
stringResource(R.string.reveal_verb),
stringResource(MR.strings.reveal_verb),
painterResource(R.drawable.ic_visibility),
onClick = {
revealed.value = true
@@ -289,7 +290,7 @@ fun ChatItemView(
fun ModeratedItem() {
MarkedDeletedItemView(cItem, cInfo.timedMessagesTTL, showMember = showMember)
DefaultDropdownMenu(showMenu) {
DeleteItemAction(cItem, showMenu, questionText = generalGetString(R.string.delete_message_cannot_be_undone_warning), deleteMessage)
DeleteItemAction(cItem, showMenu, questionText = generalGetString(MR.strings.delete_message_cannot_be_undone_warning), deleteMessage)
}
}
@@ -358,7 +359,7 @@ fun ItemInfoAction(
showMenu: MutableState<Boolean>
) {
ItemAction(
stringResource(R.string.info_menu),
stringResource(MR.strings.info_menu),
painterResource(R.drawable.ic_info),
onClick = {
showItemDetails(cInfo, cItem)
@@ -376,7 +377,7 @@ fun DeleteItemAction(
deleteMessage: (Long, CIDeleteMode) -> Unit
) {
ItemAction(
stringResource(R.string.delete_verb),
stringResource(MR.strings.delete_verb),
painterResource(R.drawable.ic_delete),
onClick = {
showMenu.value = false
@@ -394,7 +395,7 @@ fun ModerateItemAction(
deleteMessage: (Long, CIDeleteMode) -> Unit
) {
ItemAction(
stringResource(R.string.moderate_verb),
stringResource(MR.strings.moderate_verb),
painterResource(R.drawable.ic_flag),
onClick = {
showMenu.value = false
@@ -458,7 +459,7 @@ fun cancelFileAlertDialog(fileId: Long, cancelFile: (Long) -> Unit, cancelAction
fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMessage: (Long, CIDeleteMode) -> Unit) {
AlertManager.shared.showAlertDialogButtons(
title = generalGetString(R.string.delete_message__question),
title = generalGetString(MR.strings.delete_message__question),
text = questionText,
buttons = {
Row(
@@ -470,13 +471,13 @@ fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMes
TextButton(onClick = {
deleteMessage(chatItem.id, CIDeleteMode.cidmInternal)
AlertManager.shared.hideAlert()
}) { Text(stringResource(R.string.for_me_only), color = MaterialTheme.colors.error) }
}) { Text(stringResource(MR.strings.for_me_only), color = MaterialTheme.colors.error) }
if (chatItem.meta.editable) {
Spacer(Modifier.padding(horizontal = 4.dp))
TextButton(onClick = {
deleteMessage(chatItem.id, CIDeleteMode.cidmBroadcast)
AlertManager.shared.hideAlert()
}) { Text(stringResource(R.string.for_everybody), color = MaterialTheme.colors.error) }
}) { Text(stringResource(MR.strings.for_everybody), color = MaterialTheme.colors.error) }
}
}
}
@@ -485,9 +486,9 @@ fun deleteMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMes
fun moderateMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteMessage: (Long, CIDeleteMode) -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_member_message__question),
title = generalGetString(MR.strings.delete_member_message__question),
text = questionText,
confirmText = generalGetString(R.string.delete_verb),
confirmText = generalGetString(MR.strings.delete_verb),
destructive = true,
onConfirm = {
deleteMessage(chatItem.id, CIDeleteMode.cidmBroadcast)
@@ -497,7 +498,7 @@ fun moderateMessageAlertDialog(chatItem: ChatItem, questionText: String, deleteM
private fun showMsgDeliveryErrorAlert(description: String) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.message_delivery_error_title),
title = generalGetString(MR.strings.message_delivery_error_title),
text = description,
)
}
@@ -15,7 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.*
import androidx.compose.ui.platform.UriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextOverflow
@@ -25,6 +25,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.datetime.Clock
import kotlin.math.min
@@ -118,7 +119,7 @@ fun FramedItemView(
val imageBitmap = base64ToBitmap(qi.content.image).asImageBitmap()
Image(
imageBitmap,
contentDescription = stringResource(R.string.image_descr),
contentDescription = stringResource(MR.strings.image_descr),
contentScale = ContentScale.Crop,
modifier = Modifier.size(68.dp).clipToBounds()
)
@@ -130,7 +131,7 @@ fun FramedItemView(
val imageBitmap = base64ToBitmap(qi.content.image).asImageBitmap()
Image(
imageBitmap,
contentDescription = stringResource(R.string.video_descr),
contentDescription = stringResource(MR.strings.video_descr),
contentScale = ContentScale.Crop,
modifier = Modifier.size(68.dp).clipToBounds()
)
@@ -141,7 +142,7 @@ fun FramedItemView(
}
Icon(
if (qi.content is MsgContent.MCFile) painterResource(R.drawable.ic_draft_filled) else painterResource(R.drawable.ic_mic_filled),
if (qi.content is MsgContent.MCFile) stringResource(R.string.icon_descr_file) else stringResource(R.string.voice_message),
if (qi.content is MsgContent.MCFile) stringResource(MR.strings.icon_descr_file) else stringResource(MR.strings.voice_message),
Modifier
.padding(top = 6.dp, end = 4.dp)
.size(22.dp),
@@ -181,12 +182,12 @@ fun FramedItemView(
PriorityLayout(Modifier, CHAT_IMAGE_LAYOUT_ID) {
if (ci.meta.itemDeleted != null) {
if (ci.meta.itemDeleted is CIDeleted.Moderated) {
FramedItemHeader(String.format(stringResource(R.string.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName), true, painterResource(R.drawable.ic_flag))
FramedItemHeader(String.format(stringResource(MR.strings.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName), true, painterResource(R.drawable.ic_flag))
} else {
FramedItemHeader(stringResource(R.string.marked_deleted_description), true, painterResource(R.drawable.ic_delete))
FramedItemHeader(stringResource(MR.strings.marked_deleted_description), true, painterResource(R.drawable.ic_delete))
}
} else if (ci.meta.isLive) {
FramedItemHeader(stringResource(R.string.live), false)
FramedItemHeader(stringResource(MR.strings.live), false)
}
ci.quotedItem?.let { ciQuoteView(it) }
if (ci.file == null && ci.formattedText == null && !ci.meta.isLive && isShortEmoji(ci.content.text)) {
@@ -19,7 +19,7 @@ import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.*
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isVisible
@@ -35,6 +35,7 @@ import coil.size.Size
import com.google.accompanist.pager.*
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
import com.google.android.exoplayer2.ui.StyledPlayerView
import chat.simplex.res.MR
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import kotlin.math.absoluteValue
@@ -159,7 +160,7 @@ fun ImageFullScreenView(imageProvider: () -> ImageGalleryProvider, close: () ->
placeholder = BitmapPainter(imageBitmap.asImageBitmap()), // show original image while it's still loading by coil
imageLoader = imageLoader
),
contentDescription = stringResource(R.string.image_descr),
contentDescription = stringResource(MR.strings.image_descr),
contentScale = ContentScale.Fit,
modifier = modifier,
)
@@ -23,6 +23,7 @@ import chat.simplex.app.ui.theme.CurrentColors
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
@Composable
fun IntegrityErrorItemView(msgError: MsgErrorType, ci: ChatItem, timedMessagesTTL: Int?, showMember: Boolean = false) {
@@ -30,21 +31,21 @@ fun IntegrityErrorItemView(msgError: MsgErrorType, ci: ChatItem, timedMessagesTT
when (msgError) {
is MsgErrorType.MsgSkipped ->
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.alert_title_skipped_messages),
text = generalGetString(R.string.alert_text_skipped_messages_it_can_happen_when)
title = generalGetString(MR.strings.alert_title_skipped_messages),
text = generalGetString(MR.strings.alert_text_skipped_messages_it_can_happen_when)
)
is MsgErrorType.MsgBadHash ->
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.alert_title_msg_bad_hash),
text = generalGetString(R.string.alert_text_msg_bad_hash) + "\n" +
generalGetString(R.string.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(R.string.alert_text_fragment_please_report_to_developers)
title = generalGetString(MR.strings.alert_title_msg_bad_hash),
text = generalGetString(MR.strings.alert_text_msg_bad_hash) + "\n" +
generalGetString(MR.strings.alert_text_fragment_encryption_out_of_sync_old_database) + "\n" +
generalGetString(MR.strings.alert_text_fragment_please_report_to_developers)
)
is MsgErrorType.MsgBadId, is MsgErrorType.MsgDuplicate ->
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.alert_title_msg_bad_id),
text = generalGetString(R.string.alert_text_msg_bad_id) + "\n" +
generalGetString(R.string.alert_text_fragment_please_report_to_developers)
title = generalGetString(MR.strings.alert_title_msg_bad_id),
text = generalGetString(MR.strings.alert_text_msg_bad_id) + "\n" +
generalGetString(MR.strings.alert_text_fragment_please_report_to_developers)
)
}
}
@@ -19,6 +19,7 @@ import chat.simplex.app.model.CIDeleted
import chat.simplex.app.model.ChatItem
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
import kotlinx.datetime.Clock
@Composable
@@ -35,9 +36,9 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, showMember: Bool
) {
Box(Modifier.weight(1f, false)) {
if (ci.meta.itemDeleted is CIDeleted.Moderated) {
MarkedDeletedText(String.format(generalGetString(R.string.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName))
MarkedDeletedText(String.format(generalGetString(MR.strings.moderated_item_description), ci.meta.itemDeleted.byGroupMember.chatViewName))
} else {
MarkedDeletedText(generalGetString(R.string.marked_deleted_description))
MarkedDeletedText(generalGetString(MR.strings.marked_deleted_description))
}
}
CIMetaView(ci, timedMessagesTTL)
@@ -8,7 +8,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
@@ -20,6 +20,7 @@ import chat.simplex.app.views.helpers.annotatedStringResource
import chat.simplex.app.views.onboarding.ReadableTextWithLink
import chat.simplex.app.views.usersettings.MarkdownHelpView
import chat.simplex.app.views.usersettings.simplexTeamUri
import chat.simplex.res.MR
val bold = SpanStyle(fontWeight = FontWeight.Bold)
@@ -28,14 +29,14 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) {
Column(
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(stringResource(R.string.thank_you_for_installing_simplex), lineHeight = 22.sp)
ReadableTextWithLink(R.string.you_can_connect_to_simplex_chat_founder, simplexTeamUri)
Text(stringResource(MR.strings.thank_you_for_installing_simplex), lineHeight = 22.sp)
ReadableTextWithLink(MR.strings.you_can_connect_to_simplex_chat_founder, simplexTeamUri)
Column(
Modifier.padding(top = 24.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(
stringResource(R.string.to_start_a_new_chat_help_header),
stringResource(MR.strings.to_start_a_new_chat_help_header),
style = MaterialTheme.typography.h2,
lineHeight = 22.sp
)
@@ -43,33 +44,33 @@ fun ChatHelpView(addContact: (() -> Unit)? = null) {
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(stringResource(R.string.chat_help_tap_button))
Text(stringResource(MR.strings.chat_help_tap_button))
Icon(
painterResource(R.drawable.ic_person_add),
stringResource(R.string.add_contact),
stringResource(MR.strings.add_contact),
modifier = if (addContact != null) Modifier.clickable(onClick = addContact) else Modifier,
)
Text(stringResource(R.string.above_then_preposition_continuation))
Text(stringResource(MR.strings.above_then_preposition_continuation))
}
Text(annotatedStringResource(R.string.add_new_contact_to_create_one_time_QR_code), lineHeight = 22.sp)
Text(annotatedStringResource(R.string.scan_QR_code_to_connect_to_contact_who_shows_QR_code), lineHeight = 22.sp)
Text(annotatedStringResource(MR.strings.add_new_contact_to_create_one_time_QR_code), lineHeight = 22.sp)
Text(annotatedStringResource(MR.strings.scan_QR_code_to_connect_to_contact_who_shows_QR_code), lineHeight = 22.sp)
}
Column(
Modifier.padding(top = 24.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(stringResource(R.string.to_connect_via_link_title), style = MaterialTheme.typography.h2)
Text(stringResource(R.string.if_you_received_simplex_invitation_link_you_can_open_in_browser), lineHeight = 22.sp)
Text(annotatedStringResource(R.string.desktop_scan_QR_code_from_app_via_scan_QR_code), lineHeight = 22.sp)
Text(annotatedStringResource(R.string.mobile_tap_open_in_mobile_app_then_tap_connect_in_app), lineHeight = 22.sp)
Text(stringResource(MR.strings.to_connect_via_link_title), style = MaterialTheme.typography.h2)
Text(stringResource(MR.strings.if_you_received_simplex_invitation_link_you_can_open_in_browser), lineHeight = 22.sp)
Text(annotatedStringResource(MR.strings.desktop_scan_QR_code_from_app_via_scan_QR_code), lineHeight = 22.sp)
Text(annotatedStringResource(MR.strings.mobile_tap_open_in_mobile_app_then_tap_connect_in_app), lineHeight = 22.sp)
}
Column(
Modifier.padding(vertical = 24.dp),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
Text(stringResource(R.string.markdown_in_messages), style = MaterialTheme.typography.h2)
Text(stringResource(MR.strings.markdown_in_messages), style = MaterialTheme.typography.h2)
MarkdownHelpView()
}
}
@@ -10,7 +10,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -26,6 +26,7 @@ import chat.simplex.app.views.chat.item.InvalidJSONView
import chat.simplex.app.views.chat.item.ItemAction
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.ContactConnectionInfoView
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.datetime.Clock
@@ -190,7 +191,7 @@ fun GroupMenuItems(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showM
@Composable
fun MarkReadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.mark_read),
stringResource(MR.strings.mark_read),
painterResource(R.drawable.ic_check),
onClick = {
markChatRead(chat, chatModel)
@@ -203,7 +204,7 @@ fun MarkReadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<
@Composable
fun MarkUnreadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.mark_unread),
stringResource(MR.strings.mark_unread),
painterResource(R.drawable.ic_mark_chat_unread),
onClick = {
markChatUnread(chat, chatModel)
@@ -215,7 +216,7 @@ fun MarkUnreadChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableStat
@Composable
fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolean, showMenu: MutableState<Boolean>) {
ItemAction(
if (favorite) stringResource(R.string.unfavorite_chat) else stringResource(R.string.favorite_chat),
if (favorite) stringResource(MR.strings.unfavorite_chat) else stringResource(MR.strings.favorite_chat),
if (favorite) painterResource(R.drawable.ic_star_off) else painterResource(R.drawable.ic_star),
onClick = {
toggleChatFavorite(chat, !favorite, chatModel)
@@ -227,7 +228,7 @@ fun ToggleFavoritesChatAction(chat: Chat, chatModel: ChatModel, favorite: Boolea
@Composable
fun ToggleNotificationsChatAction(chat: Chat, chatModel: ChatModel, ntfsEnabled: Boolean, showMenu: MutableState<Boolean>) {
ItemAction(
if (ntfsEnabled) stringResource(R.string.mute_chat) else stringResource(R.string.unmute_chat),
if (ntfsEnabled) stringResource(MR.strings.mute_chat) else stringResource(MR.strings.unmute_chat),
if (ntfsEnabled) painterResource(R.drawable.ic_notifications_off) else painterResource(R.drawable.ic_notifications),
onClick = {
toggleNotifications(chat, !ntfsEnabled, chatModel)
@@ -239,7 +240,7 @@ fun ToggleNotificationsChatAction(chat: Chat, chatModel: ChatModel, ntfsEnabled:
@Composable
fun ClearChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.clear_chat_menu_action),
stringResource(MR.strings.clear_chat_menu_action),
painterResource(R.drawable.ic_settings_backup_restore),
onClick = {
clearChatDialog(chat.chatInfo, chatModel)
@@ -252,7 +253,7 @@ fun ClearChatAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boo
@Composable
fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.delete_contact_menu_action),
stringResource(MR.strings.delete_contact_menu_action),
painterResource(R.drawable.ic_delete),
onClick = {
deleteContactDialog(chat.chatInfo, chatModel)
@@ -265,7 +266,7 @@ fun DeleteContactAction(chat: Chat, chatModel: ChatModel, showMenu: MutableState
@Composable
fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.delete_group_menu_action),
stringResource(MR.strings.delete_group_menu_action),
painterResource(R.drawable.ic_delete),
onClick = {
deleteGroupDialog(chat.chatInfo, groupInfo, chatModel)
@@ -279,7 +280,7 @@ fun DeleteGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, sh
fun JoinGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
val joinGroup: () -> Unit = { withApi { chatModel.controller.apiJoinGroup(groupInfo.groupId) } }
ItemAction(
if (chat.chatInfo.incognito) stringResource(R.string.join_group_incognito_button) else stringResource(R.string.join_group_button),
if (chat.chatInfo.incognito) stringResource(MR.strings.join_group_incognito_button) else stringResource(MR.strings.join_group_button),
if (chat.chatInfo.incognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_login),
color = if (chat.chatInfo.incognito) Indigo else MaterialTheme.colors.onBackground,
onClick = {
@@ -292,7 +293,7 @@ fun JoinGroupAction(chat: Chat, groupInfo: GroupInfo, chatModel: ChatModel, show
@Composable
fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.leave_group_button),
stringResource(MR.strings.leave_group_button),
painterResource(R.drawable.ic_logout),
onClick = {
leaveGroupDialog(groupInfo, chatModel)
@@ -305,7 +306,7 @@ fun LeaveGroupAction(groupInfo: GroupInfo, chatModel: ChatModel, showMenu: Mutab
@Composable
fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
if (chatModel.incognito.value) stringResource(R.string.accept_contact_incognito_button) else stringResource(R.string.accept_contact_button),
if (chatModel.incognito.value) stringResource(MR.strings.accept_contact_incognito_button) else stringResource(MR.strings.accept_contact_button),
if (chatModel.incognito.value) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_check),
color = if (chatModel.incognito.value) Indigo else MaterialTheme.colors.onBackground,
onClick = {
@@ -314,7 +315,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo
}
)
ItemAction(
stringResource(R.string.reject_contact_button),
stringResource(MR.strings.reject_contact_button),
painterResource(R.drawable.ic_close),
onClick = {
rejectContactRequest(chatInfo, chatModel)
@@ -327,7 +328,7 @@ fun ContactRequestMenuItems(chatInfo: ChatInfo.ContactRequest, chatModel: ChatMo
@Composable
fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel: ChatModel, showMenu: MutableState<Boolean>) {
ItemAction(
stringResource(R.string.set_contact_name),
stringResource(MR.strings.set_contact_name),
painterResource(R.drawable.ic_edit),
onClick = {
ModalManager.shared.showModalCloseable(true) { close ->
@@ -337,7 +338,7 @@ fun ContactConnectionMenuItems(chatInfo: ChatInfo.ContactConnection, chatModel:
},
)
ItemAction(
stringResource(R.string.delete_verb),
stringResource(MR.strings.delete_verb),
painterResource(R.drawable.ic_delete),
onClick = {
deleteContactConnectionAlert(chatInfo.contactConnection, chatModel) {}
@@ -357,7 +358,7 @@ private fun InvalidDataView() {
.weight(1F)
) {
Text(
stringResource(R.string.invalid_data),
stringResource(MR.strings.invalid_data),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = MaterialTheme.typography.h3,
@@ -414,11 +415,11 @@ fun markChatUnread(chat: Chat, chatModel: ChatModel) {
fun contactRequestAlertDialog(contactRequest: ChatInfo.ContactRequest, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.accept_connection_request__question),
text = generalGetString(R.string.if_you_choose_to_reject_the_sender_will_not_be_notified),
confirmText = if (chatModel.incognito.value) generalGetString(R.string.accept_contact_incognito_button) else generalGetString(R.string.accept_contact_button),
title = generalGetString(MR.strings.accept_connection_request__question),
text = generalGetString(MR.strings.if_you_choose_to_reject_the_sender_will_not_be_notified),
confirmText = if (chatModel.incognito.value) generalGetString(MR.strings.accept_contact_incognito_button) else generalGetString(MR.strings.accept_contact_button),
onConfirm = { acceptContactRequest(contactRequest.apiId, contactRequest, true, chatModel) },
dismissText = generalGetString(R.string.reject_contact_button),
dismissText = generalGetString(MR.strings.reject_contact_button),
onDismiss = { rejectContactRequest(contactRequest, chatModel) }
)
}
@@ -443,12 +444,12 @@ fun rejectContactRequest(contactRequest: ChatInfo.ContactRequest, chatModel: Cha
fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel: ChatModel) {
AlertManager.shared.showAlertDialogButtons(
title = generalGetString(
if (connection.initiated) R.string.you_invited_your_contact
else R.string.you_accepted_connection
if (connection.initiated) MR.strings.you_invited_your_contact
else MR.strings.you_accepted_connection
),
text = generalGetString(
if (connection.viaContactUri) R.string.you_will_be_connected_when_your_connection_request_is_accepted
else R.string.you_will_be_connected_when_your_contacts_device_is_online
if (connection.viaContactUri) MR.strings.you_will_be_connected_when_your_connection_request_is_accepted
else MR.strings.you_will_be_connected_when_your_contacts_device_is_online
),
buttons = {
Row(
@@ -461,11 +462,11 @@ fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel
AlertManager.shared.hideAlert()
deleteContactConnectionAlert(connection, chatModel) {}
}) {
Text(stringResource(R.string.delete_verb))
Text(stringResource(MR.strings.delete_verb))
}
Spacer(Modifier.padding(horizontal = 4.dp))
TextButton(onClick = { AlertManager.shared.hideAlert() }) {
Text(stringResource(R.string.ok))
Text(stringResource(MR.strings.ok))
}
}
}
@@ -474,12 +475,12 @@ fun contactConnectionAlertDialog(connection: PendingContactConnection, chatModel
fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel: ChatModel, onSuccess: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_pending_connection__question),
title = generalGetString(MR.strings.delete_pending_connection__question),
text = generalGetString(
if (connection.initiated) R.string.contact_you_shared_link_with_wont_be_able_to_connect
else R.string.connection_you_accepted_will_be_cancelled
if (connection.initiated) MR.strings.contact_you_shared_link_with_wont_be_able_to_connect
else MR.strings.connection_you_accepted_will_be_cancelled
),
confirmText = generalGetString(R.string.delete_verb),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
withApi {
AlertManager.shared.hideAlert()
@@ -495,9 +496,9 @@ fun deleteContactConnectionAlert(connection: PendingContactConnection, chatModel
fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.alert_title_contact_connection_pending),
text = generalGetString(R.string.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry),
confirmText = generalGetString(R.string.button_delete_contact),
title = generalGetString(MR.strings.alert_title_contact_connection_pending),
text = generalGetString(MR.strings.alert_text_connection_pending_they_need_to_be_online_can_delete_and_retry),
confirmText = generalGetString(MR.strings.button_delete_contact),
onConfirm = {
withApi {
val r = chatModel.controller.apiDeleteChat(chatInfo.chatType, chatInfo.apiId)
@@ -508,26 +509,26 @@ fun pendingContactAlertDialog(chatInfo: ChatInfo, chatModel: ChatModel) {
}
},
destructive = true,
dismissText = generalGetString(R.string.cancel_verb),
dismissText = generalGetString(MR.strings.cancel_verb),
)
}
fun acceptGroupInvitationAlertDialog(groupInfo: GroupInfo, chatModel: ChatModel) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.join_group_question),
text = generalGetString(R.string.you_are_invited_to_group_join_to_connect_with_group_members),
confirmText = if (groupInfo.membership.memberIncognito) generalGetString(R.string.join_group_incognito_button) else generalGetString(R.string.join_group_button),
title = generalGetString(MR.strings.join_group_question),
text = generalGetString(MR.strings.you_are_invited_to_group_join_to_connect_with_group_members),
confirmText = if (groupInfo.membership.memberIncognito) generalGetString(MR.strings.join_group_incognito_button) else generalGetString(MR.strings.join_group_button),
onConfirm = { withApi { chatModel.controller.apiJoinGroup(groupInfo.groupId) } },
dismissText = generalGetString(R.string.delete_verb),
dismissText = generalGetString(MR.strings.delete_verb),
onDismiss = { deleteGroup(groupInfo, chatModel) }
)
}
fun cantInviteIncognitoAlert() {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.alert_title_cant_invite_contacts),
text = generalGetString(R.string.alert_title_cant_invite_contacts_descr),
confirmText = generalGetString(R.string.ok),
title = generalGetString(MR.strings.alert_title_cant_invite_contacts),
text = generalGetString(MR.strings.alert_title_cant_invite_contacts_descr),
confirmText = generalGetString(MR.strings.ok),
)
}
@@ -544,8 +545,8 @@ fun deleteGroup(groupInfo: GroupInfo, chatModel: ChatModel) {
fun groupInvitationAcceptedAlert() {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.joining_group),
generalGetString(R.string.youve_accepted_group_invitation_connecting_to_inviting_group_member)
generalGetString(MR.strings.joining_group),
generalGetString(MR.strings.youve_accepted_group_invitation_connecting_to_inviting_group_member)
)
}
@@ -14,7 +14,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
@@ -31,12 +31,13 @@ import chat.simplex.app.views.onboarding.WhatsNewView
import chat.simplex.app.views.onboarding.shouldShowWhatsNew
import chat.simplex.app.views.usersettings.SettingsView
import chat.simplex.app.views.usersettings.simplexTeamUri
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
@Composable
fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity) -> Unit, stopped: Boolean) {
fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean) -> Unit, stopped: Boolean) {
val newChatSheetState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val userPickerState by rememberSaveable(stateSaver = AnimatedViewState.saver()) { mutableStateOf(MutableStateFlow(AnimatedViewState.GONE)) }
val showNewChatSheet = {
@@ -88,7 +89,7 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity)
backgroundColor = if (!stopped) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
contentColor = Color.White
) {
Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(R.drawable.ic_edit_filled) else painterResource(R.drawable.ic_close), stringResource(R.string.add_contact_or_create_group))
Icon(if (!newChatSheetState.collectAsState().value.isVisible()) painterResource(R.drawable.ic_edit_filled) else painterResource(R.drawable.ic_close), stringResource(MR.strings.add_contact_or_create_group))
}
}
}
@@ -105,7 +106,7 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity)
if (!stopped && !newChatSheetState.collectAsState().value.isVisible()) {
OnboardingButtons(showNewChatSheet)
}
Text(stringResource(R.string.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary)
Text(stringResource(MR.strings.you_have_no_chats), Modifier.align(Alignment.Center), color = MaterialTheme.colors.secondary)
}
}
}
@@ -131,11 +132,11 @@ fun ChatListView(chatModel: ChatModel, setPerformLA: (Boolean, FragmentActivity)
private fun OnboardingButtons(openNewChatSheet: () -> Unit) {
Column(Modifier.fillMaxSize().padding(DEFAULT_PADDING), horizontalAlignment = Alignment.End, verticalArrangement = Arrangement.Bottom) {
val uriHandler = LocalUriHandler.current
ConnectButton(generalGetString(R.string.chat_with_developers)) {
ConnectButton(generalGetString(MR.strings.chat_with_developers)) {
uriHandler.openUriCatching(simplexTeamUri)
}
Spacer(Modifier.height(DEFAULT_PADDING))
ConnectButton(generalGetString(R.string.tap_to_start_new_chat), openNewChatSheet)
ConnectButton(generalGetString(MR.strings.tap_to_start_new_chat), openNewChatSheet)
val color = MaterialTheme.colors.primaryVariant
Canvas(modifier = Modifier.width(40.dp).height(10.dp), onDraw = {
val trianglePath = Path().apply {
@@ -180,7 +181,7 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
if (chatModel.chats.size > 0) {
barButtons.add {
IconButton({ showSearch = true }) {
Icon(painterResource(R.drawable.ic_search_500), stringResource(android.R.string.search_go).capitalize(Locale.current), tint = MaterialTheme.colors.primary)
Icon(painterResource(R.drawable.ic_search_500), stringResource(MR.strings.search_verb).capitalize(Locale.current), tint = MaterialTheme.colors.primary)
}
}
}
@@ -188,13 +189,13 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
barButtons.add {
IconButton(onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.chat_is_stopped_indication),
generalGetString(R.string.you_can_start_chat_via_setting_or_by_restarting_the_app)
generalGetString(MR.strings.chat_is_stopped_indication),
generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app)
)
}) {
Icon(
painterResource(R.drawable.ic_report_filled),
generalGetString(R.string.chat_is_stopped_indication),
generalGetString(MR.strings.chat_is_stopped_indication),
tint = Color.Red,
)
}
@@ -226,13 +227,13 @@ private fun ChatListToolbar(chatModel: ChatModel, drawerState: DrawerState, user
if (chatModel.incognito.value) {
Icon(
painterResource(R.drawable.ic_theater_comedy_filled),
stringResource(R.string.incognito),
stringResource(MR.strings.incognito),
tint = Indigo,
modifier = Modifier.padding(10.dp).size(26.dp)
)
}
Text(
stringResource(R.string.your_chats),
stringResource(MR.strings.your_chats),
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
)
@@ -328,7 +329,7 @@ private fun ChatList(chatModel: ChatModel, search: String) {
}
if (chats.isEmpty() && !chatModel.chats.isEmpty()) {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(generalGetString(R.string.no_filtered_chats), color = MaterialTheme.colors.secondary)
Text(generalGetString(MR.strings.no_filtered_chats), color = MaterialTheme.colors.secondary)
}
}
}
@@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
@@ -26,6 +26,7 @@ import chat.simplex.app.views.chat.ComposePreview
import chat.simplex.app.views.chat.ComposeState
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun ChatPreviewView(
@@ -44,7 +45,7 @@ fun ChatPreviewView(
fun groupInactiveIcon() {
Icon(
painterResource(R.drawable.ic_cancel_filled),
stringResource(R.string.icon_descr_group_inactive),
stringResource(MR.strings.icon_descr_group_inactive),
Modifier.size(18.dp).background(MaterialTheme.colors.background, CircleShape),
tint = MaterialTheme.colors.secondary
)
@@ -143,7 +144,7 @@ fun ChatPreviewView(
val (text: CharSequence, inlineTextContent) = when {
chatModelDraftChatId == chat.id && chatModelDraft != null -> remember(chatModelDraft) { messageDraft(chatModelDraft) }
ci.meta.itemDeleted == null -> ci.text to null
else -> generalGetString(R.string.marked_deleted_description) to null
else -> generalGetString(MR.strings.marked_deleted_description) to null
}
val formattedText = when {
chatModelDraftChatId == chat.id && chatModelDraft != null -> null
@@ -170,12 +171,12 @@ fun ChatPreviewView(
when (cInfo) {
is ChatInfo.Direct ->
if (!cInfo.ready) {
Text(stringResource(R.string.contact_connection_pending), color = MaterialTheme.colors.secondary)
Text(stringResource(MR.strings.contact_connection_pending), color = MaterialTheme.colors.secondary)
}
is ChatInfo.Group ->
when (cInfo.groupInfo.membership.memberStatus) {
GroupMemberStatus.MemInvited -> Text(groupInvitationPreviewText(chatModelIncognito, currentUserProfileDisplayName, cInfo.groupInfo))
GroupMemberStatus.MemAccepted -> Text(stringResource(R.string.group_connection_pending), color = MaterialTheme.colors.secondary)
GroupMemberStatus.MemAccepted -> Text(stringResource(MR.strings.group_connection_pending), color = MaterialTheme.colors.secondary)
else -> {}
}
else -> {}
@@ -237,7 +238,7 @@ fun ChatPreviewView(
) {
Icon(
painterResource(R.drawable.ic_notifications_off_filled),
contentDescription = generalGetString(R.string.notifications),
contentDescription = generalGetString(MR.strings.notifications),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.padding(horizontal = 3.dp)
@@ -252,7 +253,7 @@ fun ChatPreviewView(
) {
Icon(
painterResource(R.drawable.ic_star_filled),
contentDescription = generalGetString(R.string.favorite_chat),
contentDescription = generalGetString(MR.strings.favorite_chat),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.padding(horizontal = 3.dp)
@@ -276,16 +277,16 @@ fun ChatPreviewView(
@Composable
private fun groupInvitationPreviewText(chatModelIncognito: Boolean, currentUserProfileDisplayName: String?, groupInfo: GroupInfo): String {
return if (groupInfo.membership.memberIncognito)
String.format(stringResource(R.string.group_preview_join_as), groupInfo.membership.memberProfile.displayName)
String.format(stringResource(MR.strings.group_preview_join_as), groupInfo.membership.memberProfile.displayName)
else if (chatModelIncognito)
String.format(stringResource(R.string.group_preview_join_as), currentUserProfileDisplayName ?: "")
String.format(stringResource(MR.strings.group_preview_join_as), currentUserProfileDisplayName ?: "")
else
stringResource(R.string.group_preview_you_are_invited)
stringResource(MR.strings.group_preview_you_are_invited)
}
@Composable
fun unreadCountStr(n: Int): String {
return if (n < 1000) "$n" else "${n / 1000}" + stringResource(R.string.thousand_abbreviation)
return if (n < 1000) "$n" else "${n / 1000}" + stringResource(MR.strings.thousand_abbreviation)
}
@Composable
@@ -6,7 +6,7 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -15,6 +15,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.ChatInfoImage
import chat.simplex.res.MR
@Composable
fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.ContactRequest) {
@@ -34,7 +35,7 @@ fun ContactRequestView(chatModelIncognito: Boolean, contactRequest: ChatInfo.Con
color = if (chatModelIncognito) Indigo else MaterialTheme.colors.primary
)
val height = with(LocalDensity.current) { 46.sp.toDp() }
Text(stringResource(R.string.contact_wants_to_connect_with_you), Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight)
Text(stringResource(MR.strings.contact_wants_to_connect_with_you), Modifier.heightIn(min = height), maxLines = 2, color = if (isInDarkTheme()) MessagePreviewDark else MessagePreviewLight)
}
val ts = getTimestampText(contactRequest.contactRequest.updatedAt)
Column(
@@ -12,7 +12,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.intl.Locale
@@ -21,6 +21,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow
@Composable
@@ -52,7 +53,7 @@ fun ShareListView(chatModel: ChatModel, stopped: Boolean) {
@Composable
private fun EmptyList() {
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(stringResource(R.string.you_have_no_chats), color = MaterialTheme.colors.secondary)
Text(stringResource(MR.strings.you_have_no_chats), color = MaterialTheme.colors.secondary)
}
}
@@ -82,7 +83,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
if (chatModel.chats.size >= 8) {
barButtons.add {
IconButton({ showSearch = true }) {
Icon(painterResource(R.drawable.ic_search_500), stringResource(android.R.string.search_go).capitalize(Locale.current), tint = MaterialTheme.colors.primary)
Icon(painterResource(R.drawable.ic_search_500), stringResource(MR.strings.search_verb).capitalize(Locale.current), tint = MaterialTheme.colors.primary)
}
}
}
@@ -90,13 +91,13 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
barButtons.add {
IconButton(onClick = {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.chat_is_stopped_indication),
generalGetString(R.string.you_can_start_chat_via_setting_or_by_restarting_the_app)
generalGetString(MR.strings.chat_is_stopped_indication),
generalGetString(MR.strings.you_can_start_chat_via_setting_or_by_restarting_the_app)
)
}) {
Icon(
painterResource(R.drawable.ic_report_filled),
generalGetString(R.string.chat_is_stopped_indication),
generalGetString(MR.strings.chat_is_stopped_indication),
tint = Color.Red,
)
}
@@ -109,10 +110,10 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
when (chatModel.sharedContent.value) {
is SharedContent.Text -> stringResource(R.string.share_message)
is SharedContent.Media -> stringResource(R.string.share_image)
is SharedContent.File -> stringResource(R.string.share_file)
else -> stringResource(R.string.share_message)
is SharedContent.Text -> stringResource(MR.strings.share_message)
is SharedContent.Media -> stringResource(MR.strings.share_image)
is SharedContent.File -> stringResource(MR.strings.share_file)
else -> stringResource(MR.strings.share_message)
},
color = MaterialTheme.colors.onBackground,
fontWeight = FontWeight.SemiBold,
@@ -120,7 +121,7 @@ private fun ShareListToolbar(chatModel: ChatModel, userPickerState: MutableState
if (chatModel.incognito.value) {
Icon(
painterResource(R.drawable.ic_theater_comedy_filled),
stringResource(R.string.incognito),
stringResource(MR.strings.incognito),
tint = Indigo,
modifier = Modifier.padding(10.dp).size(26.dp)
)
@@ -26,6 +26,7 @@ import chat.simplex.app.TAG
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
@@ -217,7 +218,7 @@ fun UserProfileRow(u: User) {
@Composable
private fun SettingsPickerItem(onClick: () -> Unit) {
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
val text = generalGetString(R.string.settings_section_title_settings).lowercase().capitalize(Locale.current)
val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current)
Icon(painterResource(R.drawable.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(
@@ -230,7 +231,7 @@ private fun SettingsPickerItem(onClick: () -> Unit) {
@Composable
private fun CancelPickerItem(onClick: () -> Unit) {
SectionItemView(onClick, padding = PaddingValues(start = DEFAULT_PADDING + 7.dp, end = DEFAULT_PADDING), minHeight = 68.dp) {
val text = generalGetString(R.string.cancel_verb)
val text = generalGetString(MR.strings.cancel_verb)
Icon(painterResource(R.drawable.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(
@@ -18,7 +18,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import chat.simplex.app.*
import chat.simplex.app.R
@@ -26,6 +26,7 @@ import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.*
import chat.simplex.res.MR
import kotlinx.datetime.*
import java.io.BufferedOutputStream
import java.io.File
@@ -56,17 +57,17 @@ fun ChatArchiveLayout(
Modifier.fillMaxWidth(),
) {
AppBarTitle(title)
SectionView(stringResource(R.string.chat_archive_section)) {
SectionView(stringResource(MR.strings.chat_archive_section)) {
SettingsActionItem(
painterResource(R.drawable.ic_ios_share),
stringResource(R.string.save_archive),
stringResource(MR.strings.save_archive),
saveArchive,
textColor = MaterialTheme.colors.primary,
iconColor = MaterialTheme.colors.primary,
)
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.delete_archive),
stringResource(MR.strings.delete_archive),
deleteArchiveAlert,
textColor = Color.Red,
iconColor = Color.Red,
@@ -74,7 +75,7 @@ fun ChatArchiveLayout(
}
val archiveTs = SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.US).format(Date.from(archiveTime.toJavaInstant()))
SectionTextFooter(
String.format(generalGetString(R.string.archive_created_on_ts), archiveTs)
String.format(generalGetString(MR.strings.archive_created_on_ts), archiveTs)
)
SectionBottomSpacer()
}
@@ -93,11 +94,11 @@ private fun rememberSaveArchiveLauncher(chatArchivePath: String): ManagedActivit
val outputStream = BufferedOutputStream(stream)
File(chatArchivePath).inputStream().use { it.copyTo(outputStream) }
outputStream.close()
Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show()
}
}
} catch (e: Error) {
Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show()
Log.e(TAG, "rememberSaveArchiveLauncher error saving archive $e")
}
}
@@ -105,8 +106,8 @@ private fun rememberSaveArchiveLauncher(chatArchivePath: String): ManagedActivit
private fun deleteArchiveAlert(m: ChatModel, archivePath: String) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_chat_archive_question),
confirmText = generalGetString(R.string.delete_verb),
title = generalGetString(MR.strings.delete_chat_archive_question),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = {
val fileDeleted = File(archivePath).delete()
if (fileDeleted) {
@@ -19,7 +19,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.*
@@ -30,6 +30,7 @@ import chat.simplex.app.SimplexApp
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.datetime.Clock
import kotlin.math.log2
@@ -71,14 +72,14 @@ fun DatabaseEncryptionView(m: ChatModel) {
sqliteError is SQLiteError.ErrorNotADatabase -> {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(
generalGetString(R.string.wrong_passphrase_title),
generalGetString(R.string.enter_correct_current_passphrase)
generalGetString(MR.strings.wrong_passphrase_title),
generalGetString(MR.strings.enter_correct_current_passphrase)
)
}
}
error != null -> {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_encrypting_database),
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database),
"failed to set storage encryption: ${error.responseType} ${error.details}"
)
}
@@ -91,13 +92,13 @@ fun DatabaseEncryptionView(m: ChatModel) {
}
resetFormAfterEncryption(m, initialRandomDBPassphrase, currentKey, newKey, confirmNewKey, storedKey, useKeychain.value)
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.database_encrypted))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_encrypted))
}
}
}
} catch (e: Exception) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_encrypting_database), e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_encrypting_database), e.stackTraceToString())
}
}
}
@@ -136,16 +137,16 @@ fun DatabaseEncryptionLayout(
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.database_passphrase))
AppBarTitle(stringResource(MR.strings.database_passphrase))
SectionView(null) {
SavePassphraseSetting(useKeychain.value, initialRandomDBPassphrase.value, storedKey.value, progressIndicator.value) { checked ->
if (checked) {
setUseKeychain(true, useKeychain, prefs)
} else if (storedKey.value) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.remove_passphrase_from_keychain),
text = generalGetString(R.string.notifications_will_be_hidden) + "\n" + storeSecurelyDanger(),
confirmText = generalGetString(R.string.remove_passphrase),
title = generalGetString(MR.strings.remove_passphrase_from_keychain),
text = generalGetString(MR.strings.notifications_will_be_hidden) + "\n" + storeSecurelyDanger(),
confirmText = generalGetString(MR.strings.remove_passphrase),
onConfirm = {
DatabaseUtils.ksDatabasePassword.remove()
setUseKeychain(false, useKeychain, prefs)
@@ -161,7 +162,7 @@ fun DatabaseEncryptionLayout(
if (!initialRandomDBPassphrase.value && chatDbEncrypted == true) {
PassphraseField(
currentKey,
generalGetString(R.string.current_passphrase),
generalGetString(MR.strings.current_passphrase),
modifier = Modifier.padding(horizontal = DEFAULT_PADDING),
isValid = ::validKey,
keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }),
@@ -170,7 +171,7 @@ fun DatabaseEncryptionLayout(
PassphraseField(
newKey,
generalGetString(R.string.new_passphrase),
generalGetString(MR.strings.new_passphrase),
modifier = Modifier.padding(horizontal = DEFAULT_PADDING),
showStrength = true,
isValid = ::validKey,
@@ -201,7 +202,7 @@ fun DatabaseEncryptionLayout(
PassphraseField(
confirmNewKey,
generalGetString(R.string.confirm_new_passphrase),
generalGetString(MR.strings.confirm_new_passphrase),
modifier = Modifier.padding(horizontal = DEFAULT_PADDING),
isValid = { confirmNewKey.value == "" || newKey.value == confirmNewKey.value },
keyboardActions = KeyboardActions(onDone = {
@@ -211,27 +212,27 @@ fun DatabaseEncryptionLayout(
)
SectionItemViewSpaceBetween(onClickUpdate, disabled = disabled, minHeight = TextFieldDefaults.MinHeight) {
Text(generalGetString(R.string.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(generalGetString(MR.strings.update_database_passphrase), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
Column {
if (chatDbEncrypted == false) {
SectionTextFooter(generalGetString(R.string.database_is_not_encrypted))
SectionTextFooter(generalGetString(MR.strings.database_is_not_encrypted))
} else if (useKeychain.value) {
if (storedKey.value) {
SectionTextFooter(generalGetString(R.string.keychain_is_storing_securely))
SectionTextFooter(generalGetString(MR.strings.keychain_is_storing_securely))
if (initialRandomDBPassphrase.value) {
SectionTextFooter(generalGetString(R.string.encrypted_with_random_passphrase))
SectionTextFooter(generalGetString(MR.strings.encrypted_with_random_passphrase))
} else {
SectionTextFooter(generalGetString(R.string.impossible_to_recover_passphrase))
SectionTextFooter(generalGetString(MR.strings.impossible_to_recover_passphrase))
}
} else {
SectionTextFooter(generalGetString(R.string.keychain_allows_to_receive_ntfs))
SectionTextFooter(generalGetString(MR.strings.keychain_allows_to_receive_ntfs))
}
} else {
SectionTextFooter(generalGetString(R.string.you_have_to_enter_passphrase_every_time))
SectionTextFooter(generalGetString(R.string.impossible_to_recover_passphrase))
SectionTextFooter(generalGetString(MR.strings.you_have_to_enter_passphrase_every_time))
SectionTextFooter(generalGetString(MR.strings.impossible_to_recover_passphrase))
}
}
SectionBottomSpacer()
@@ -240,9 +241,9 @@ fun DatabaseEncryptionLayout(
fun encryptDatabaseSavedAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.encrypt_database_question),
text = generalGetString(R.string.database_will_be_encrypted_and_passphrase_stored) + "\n" + storeSecurelySaved(),
confirmText = generalGetString(R.string.encrypt_database),
title = generalGetString(MR.strings.encrypt_database_question),
text = generalGetString(MR.strings.database_will_be_encrypted_and_passphrase_stored) + "\n" + storeSecurelySaved(),
confirmText = generalGetString(MR.strings.encrypt_database),
onConfirm = onConfirm,
destructive = true,
)
@@ -250,9 +251,9 @@ fun encryptDatabaseSavedAlert(onConfirm: () -> Unit) {
fun encryptDatabaseAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.encrypt_database_question),
text = generalGetString(R.string.database_will_be_encrypted) +"\n" + storeSecurelyDanger(),
confirmText = generalGetString(R.string.encrypt_database),
title = generalGetString(MR.strings.encrypt_database_question),
text = generalGetString(MR.strings.database_will_be_encrypted) +"\n" + storeSecurelyDanger(),
confirmText = generalGetString(MR.strings.encrypt_database),
onConfirm = onConfirm,
destructive = true,
)
@@ -260,9 +261,9 @@ fun encryptDatabaseAlert(onConfirm: () -> Unit) {
fun changeDatabaseKeySavedAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.change_database_passphrase_question),
text = generalGetString(R.string.database_encryption_will_be_updated) + "\n" + storeSecurelySaved(),
confirmText = generalGetString(R.string.update_database),
title = generalGetString(MR.strings.change_database_passphrase_question),
text = generalGetString(MR.strings.database_encryption_will_be_updated) + "\n" + storeSecurelySaved(),
confirmText = generalGetString(MR.strings.update_database),
onConfirm = onConfirm,
destructive = false,
)
@@ -270,9 +271,9 @@ fun changeDatabaseKeySavedAlert(onConfirm: () -> Unit) {
fun changeDatabaseKeyAlert(onConfirm: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.change_database_passphrase_question),
text = generalGetString(R.string.database_passphrase_will_be_updated) + "\n" + storeSecurelyDanger(),
confirmText = generalGetString(R.string.update_database),
title = generalGetString(MR.strings.change_database_passphrase_question),
text = generalGetString(MR.strings.database_passphrase_will_be_updated) + "\n" + storeSecurelyDanger(),
confirmText = generalGetString(MR.strings.update_database),
onConfirm = onConfirm,
destructive = true,
)
@@ -291,12 +292,12 @@ fun SavePassphraseSetting(
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
if (storedKey) painterResource(R.drawable.ic_vpn_key_filled) else painterResource(R.drawable.ic_vpn_key_off_filled),
stringResource(R.string.save_passphrase_in_keychain),
stringResource(MR.strings.save_passphrase_in_keychain),
tint = if (storedKey) SimplexGreen else MaterialTheme.colors.secondary
)
Spacer(Modifier.padding(horizontal = 4.dp))
Text(
stringResource(R.string.save_passphrase_in_keychain),
stringResource(MR.strings.save_passphrase_in_keychain),
Modifier.padding(end = 24.dp),
color = Color.Unspecified
)
@@ -333,9 +334,9 @@ fun setUseKeychain(value: Boolean, useKeychain: MutableState<Boolean>, prefs: Ap
prefs.storeDBPassphrase.set(value)
}
fun storeSecurelySaved() = generalGetString(R.string.store_passphrase_securely)
fun storeSecurelySaved() = generalGetString(MR.strings.store_passphrase_securely)
fun storeSecurelyDanger() = generalGetString(R.string.store_passphrase_securely_without_recover)
fun storeSecurelyDanger() = generalGetString(MR.strings.store_passphrase_securely_without_recover)
private fun operationEnded(m: ChatModel, progressIndicator: MutableState<Boolean>, alert: () -> Unit) {
m.chatDbChanged.value = true
@@ -5,7 +5,6 @@ import SectionSpacer
import SectionView
import android.content.Context
import android.util.Log
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
@@ -25,6 +24,8 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.AppVersionText
import chat.simplex.app.views.usersettings.NotificationsMode
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.*
import kotlinx.datetime.Clock
import java.io.File
@@ -59,7 +60,7 @@ fun DatabaseErrorView(
}
@Composable
fun DatabaseErrorDetails(@StringRes title: Int, content: @Composable ColumnScope.() -> Unit) {
fun DatabaseErrorDetails(title: StringResource, content: @Composable ColumnScope.() -> Unit) {
Text(
generalGetString(title),
Modifier.padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING, bottom = DEFAULT_PADDING),
@@ -70,12 +71,12 @@ fun DatabaseErrorView(
@Composable
fun FileNameText(dbFile: String) {
Text(String.format(generalGetString(R.string.file_with_path), dbFile.split("/").lastOrNull() ?: dbFile))
Text(String.format(generalGetString(MR.strings.file_with_path), dbFile.split("/").lastOrNull() ?: dbFile))
}
@Composable
fun MigrationsText(ms: List<String>) {
Text(String.format(generalGetString(R.string.database_migrations), ms.joinToString(", ")))
Text(String.format(generalGetString(MR.strings.database_migrations), ms.joinToString(", ")))
}
Column(
@@ -86,8 +87,8 @@ fun DatabaseErrorView(
when (val status = chatDbStatus.value) {
is DBMigrationResult.ErrorNotADatabase ->
if (useKeychain && !storedDBKey.isNullOrEmpty()) {
DatabaseErrorDetails(R.string.wrong_passphrase) {
Text(generalGetString(R.string.passphrase_is_different))
DatabaseErrorDetails(MR.strings.wrong_passphrase) {
Text(generalGetString(MR.strings.passphrase_is_different))
DatabaseKeyField(dbKey, buttonEnabled) {
saveAndRunChatOnClick()
}
@@ -96,8 +97,8 @@ fun DatabaseErrorView(
FileNameText(status.dbFile)
}
} else {
DatabaseErrorDetails(R.string.encrypted_database) {
Text(generalGetString(R.string.database_passphrase_is_required))
DatabaseErrorDetails(MR.strings.encrypted_database) {
Text(generalGetString(MR.strings.database_passphrase_is_required))
if (useKeychain) {
DatabaseKeyField(dbKey, buttonEnabled, ::saveAndRunChatOnClick)
SaveAndOpenButton(buttonEnabled, ::saveAndRunChatOnClick)
@@ -109,9 +110,9 @@ fun DatabaseErrorView(
}
is DBMigrationResult.ErrorMigration -> when (val err = status.migrationError) {
is MigrationError.Upgrade ->
DatabaseErrorDetails(R.string.database_upgrade) {
DatabaseErrorDetails(MR.strings.database_upgrade) {
TextButton({ callRunChat(confirmMigrations = MigrationConfirmation.YesUp) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) {
Text(generalGetString(R.string.upgrade_and_open_chat))
Text(generalGetString(MR.strings.upgrade_and_open_chat))
}
Spacer(Modifier.height(20.dp))
FileNameText(status.dbFile)
@@ -119,51 +120,51 @@ fun DatabaseErrorView(
AppVersionText()
}
is MigrationError.Downgrade ->
DatabaseErrorDetails(R.string.database_downgrade) {
DatabaseErrorDetails(MR.strings.database_downgrade) {
TextButton({ callRunChat(confirmMigrations = MigrationConfirmation.YesUpDown) }, Modifier.align(Alignment.CenterHorizontally), enabled = !progressIndicator.value) {
Text(generalGetString(R.string.downgrade_and_open_chat))
Text(generalGetString(MR.strings.downgrade_and_open_chat))
}
Spacer(Modifier.height(20.dp))
Text(generalGetString(R.string.database_downgrade_warning), fontWeight = FontWeight.Bold)
Text(generalGetString(MR.strings.database_downgrade_warning), fontWeight = FontWeight.Bold)
FileNameText(status.dbFile)
MigrationsText(err.downMigrations)
AppVersionText()
}
is MigrationError.Error ->
DatabaseErrorDetails(R.string.incompatible_database_version) {
DatabaseErrorDetails(MR.strings.incompatible_database_version) {
FileNameText(status.dbFile)
Text(String.format(generalGetString(R.string.error_with_info), mtrErrorDescription(err.mtrError)))
Text(String.format(generalGetString(MR.strings.error_with_info), mtrErrorDescription(err.mtrError)))
}
}
is DBMigrationResult.ErrorSQL ->
DatabaseErrorDetails(R.string.database_error) {
DatabaseErrorDetails(MR.strings.database_error) {
FileNameText(status.dbFile)
Text(String.format(generalGetString(R.string.error_with_info), status.migrationSQLError))
Text(String.format(generalGetString(MR.strings.error_with_info), status.migrationSQLError))
}
is DBMigrationResult.ErrorKeychain ->
DatabaseErrorDetails(R.string.keychain_error) {
Text(generalGetString(R.string.cannot_access_keychain))
DatabaseErrorDetails(MR.strings.keychain_error) {
Text(generalGetString(MR.strings.cannot_access_keychain))
}
is DBMigrationResult.InvalidConfirmation ->
DatabaseErrorDetails(R.string.invalid_migration_confirmation) {
DatabaseErrorDetails(MR.strings.invalid_migration_confirmation) {
// this can only happen if incorrect parameter is passed
}
is DBMigrationResult.Unknown ->
DatabaseErrorDetails(R.string.database_error) {
Text(String.format(generalGetString(R.string.unknown_database_error_with_info), status.json))
DatabaseErrorDetails(MR.strings.database_error) {
Text(String.format(generalGetString(MR.strings.unknown_database_error_with_info), status.json))
}
is DBMigrationResult.OK -> {}
null -> {}
}
if (restoreDbFromBackup.value) {
SectionSpacer()
Text(generalGetString(R.string.database_backup_can_be_restored))
Text(generalGetString(MR.strings.database_backup_can_be_restored))
Spacer(Modifier.size(DEFAULT_PADDING))
RestoreDbButton {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.restore_database_alert_title),
text = generalGetString(R.string.restore_database_alert_desc),
confirmText = generalGetString(R.string.restore_database_alert_confirm),
title = generalGetString(MR.strings.restore_database_alert_title),
text = generalGetString(MR.strings.restore_database_alert_desc),
confirmText = generalGetString(MR.strings.restore_database_alert_confirm),
onConfirm = { restoreDb(restoreDbFromBackup, appPreferences) },
destructive = true,
)
@@ -212,15 +213,15 @@ private fun runChat(
}
}
is DBMigrationResult.ErrorNotADatabase ->
AlertManager.shared.showAlertMsg(generalGetString(R.string.wrong_passphrase_title), generalGetString(R.string.enter_correct_passphrase))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.wrong_passphrase_title), generalGetString(MR.strings.enter_correct_passphrase))
is DBMigrationResult.ErrorSQL ->
AlertManager.shared.showAlertMsg(generalGetString(R.string.database_error), status.migrationSQLError)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_error), status.migrationSQLError)
is DBMigrationResult.ErrorKeychain ->
AlertManager.shared.showAlertMsg(generalGetString(R.string.keychain_error))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.keychain_error))
is DBMigrationResult.Unknown ->
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), status.json)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), status.json)
is DBMigrationResult.InvalidConfirmation ->
AlertManager.shared.showAlertMsg(generalGetString(R.string.invalid_migration_confirmation))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.invalid_migration_confirmation))
is DBMigrationResult.ErrorMigration -> {}
null -> {}
}
@@ -249,23 +250,23 @@ private fun restoreDb(restoreDbFromBackup: MutableState<Boolean>, prefs: AppPref
restoreDbFromBackup.value = false
prefs.encryptionStartedAt.set(null)
} catch (e: Exception) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.database_restore_error), e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.database_restore_error), e.stackTraceToString())
}
}
private fun mtrErrorDescription(err: MTRError): String =
when (err) {
is MTRError.NoDown ->
String.format(generalGetString(R.string.mtr_error_no_down_migration), err.dbMigrations.joinToString(", "))
String.format(generalGetString(MR.strings.mtr_error_no_down_migration), err.dbMigrations.joinToString(", "))
is MTRError.Different ->
String.format(generalGetString(R.string.mtr_error_different), err.appMigration, err.dbMigration)
String.format(generalGetString(MR.strings.mtr_error_different), err.appMigration, err.dbMigration)
}
@Composable
private fun DatabaseKeyField(text: MutableState<String>, enabled: Boolean, onClick: (() -> Unit)? = null) {
PassphraseField(
text,
generalGetString(R.string.enter_passphrase),
generalGetString(MR.strings.enter_passphrase),
isValid = ::validKey,
keyboardActions = KeyboardActions(onDone = if (enabled) {
{ onClick?.invoke() }
@@ -277,21 +278,21 @@ private fun DatabaseKeyField(text: MutableState<String>, enabled: Boolean, onCli
@Composable
private fun ColumnScope.SaveAndOpenButton(enabled: Boolean, onClick: () -> Unit) {
TextButton(onClick, Modifier.align(Alignment.CenterHorizontally), enabled = enabled) {
Text(generalGetString(R.string.save_passphrase_and_open_chat))
Text(generalGetString(MR.strings.save_passphrase_and_open_chat))
}
}
@Composable
private fun ColumnScope.OpenChatButton(enabled: Boolean, onClick: () -> Unit) {
TextButton(onClick, Modifier.align(Alignment.CenterHorizontally), enabled = enabled) {
Text(generalGetString(R.string.open_chat))
Text(generalGetString(MR.strings.open_chat))
}
}
@Composable
private fun ColumnScope.RestoreDbButton(onClick: () -> Unit) {
TextButton(onClick, Modifier.align(Alignment.CenterHorizontally)) {
Text(generalGetString(R.string.restore_database), color = MaterialTheme.colors.error)
Text(generalGetString(MR.strings.restore_database), color = MaterialTheme.colors.error)
}
}
@@ -23,7 +23,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
@@ -35,6 +35,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlinx.datetime.*
import org.apache.commons.io.IOUtils
@@ -151,15 +152,15 @@ fun DatabaseLayout(
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.your_chat_database))
AppBarTitle(stringResource(MR.strings.your_chat_database))
SectionView(stringResource(R.string.messages_section_title).uppercase()) {
SectionView(stringResource(MR.strings.messages_section_title).uppercase()) {
TtlOptions(chatItemTTL, enabled = rememberUpdatedState(!stopped && !progressIndicator), onChatItemTTLSelected)
}
SectionTextFooter(
remember(currentUser?.displayName) {
buildAnnotatedString {
append(generalGetString(R.string.messages_section_description) + " ")
append(generalGetString(MR.strings.messages_section_description) + " ")
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
append(currentUser?.displayName ?: "")
}
@@ -169,17 +170,17 @@ fun DatabaseLayout(
)
SectionDividerSpaced(maxTopPadding = true)
SectionView(stringResource(R.string.run_chat_section)) {
SectionView(stringResource(MR.strings.run_chat_section)) {
RunChatSetting(runChat, stopped, startChat, stopChatAlert)
}
SectionDividerSpaced()
SectionView(stringResource(R.string.chat_database_section)) {
SectionView(stringResource(MR.strings.chat_database_section)) {
val unencrypted = chatDbEncrypted == false
SettingsActionItem(
if (unencrypted) painterResource(R.drawable.ic_lock_open) else if (useKeyChain) painterResource(R.drawable.ic_vpn_key_filled)
else painterResource(R.drawable.ic_lock),
stringResource(R.string.database_passphrase),
stringResource(MR.strings.database_passphrase),
click = showSettingsModal() { DatabaseEncryptionView(it) },
iconColor = if (unencrypted) WarningOrange else MaterialTheme.colors.secondary,
disabled = operationsDisabled
@@ -188,7 +189,7 @@ fun DatabaseLayout(
SectionDividerSpaced(maxBottomPadding = false)
SettingsActionItem(
painterResource(R.drawable.ic_ios_share),
stringResource(R.string.export_database),
stringResource(MR.strings.export_database),
click = {
if (initialRandomDBPassphrase.get()) {
exportProhibitedAlert()
@@ -202,7 +203,7 @@ fun DatabaseLayout(
)
SettingsActionItem(
painterResource(R.drawable.ic_download),
stringResource(R.string.import_database),
stringResource(MR.strings.import_database),
{ importArchiveLauncher.launch("application/zip") },
textColor = Color.Red,
iconColor = Color.Red,
@@ -222,7 +223,7 @@ fun DatabaseLayout(
}
SettingsActionItem(
painterResource(R.drawable.ic_delete_forever),
stringResource(R.string.delete_database),
stringResource(MR.strings.delete_database),
deleteChatAlert,
textColor = Color.Red,
iconColor = Color.Red,
@@ -231,21 +232,21 @@ fun DatabaseLayout(
}
SectionTextFooter(
if (stopped) {
stringResource(R.string.you_must_use_the_most_recent_version_of_database)
stringResource(MR.strings.you_must_use_the_most_recent_version_of_database)
} else {
stringResource(R.string.stop_chat_to_enable_database_actions)
stringResource(MR.strings.stop_chat_to_enable_database_actions)
}
)
SectionDividerSpaced(maxTopPadding = true)
SectionView(stringResource(R.string.files_and_media_section).uppercase()) {
SectionView(stringResource(MR.strings.files_and_media_section).uppercase()) {
val deleteFilesDisabled = operationsDisabled || appFilesCountAndSize.value.first == 0
SectionItemView(
deleteAppFilesAndMedia,
disabled = deleteFilesDisabled
) {
Text(
stringResource(if (users.size > 1) R.string.delete_files_and_media_for_all_users else R.string.delete_files_and_media_all),
stringResource(if (users.size > 1) MR.strings.delete_files_and_media_for_all_users else MR.strings.delete_files_and_media_all),
color = if (deleteFilesDisabled) MaterialTheme.colors.secondary else Color.Red
)
}
@@ -253,9 +254,9 @@ fun DatabaseLayout(
val (count, size) = appFilesCountAndSize.value
SectionTextFooter(
if (count == 0) {
stringResource(R.string.no_received_app_files)
stringResource(MR.strings.no_received_app_files)
} else {
String.format(stringResource(R.string.total_files_count_and_size), count, formatBytes(size))
String.format(stringResource(MR.strings.total_files_count_and_size), count, formatBytes(size))
}
)
SectionBottomSpacer()
@@ -268,7 +269,7 @@ private fun AppDataBackupPreference(privacyFullBackup: SharedPreference<Boolean>
painterResource(R.drawable.ic_backup),
iconColor = MaterialTheme.colors.secondary,
pref = privacyFullBackup,
text = stringResource(R.string.full_backup)
text = stringResource(MR.strings.full_backup)
) {
if (initialRandomDBPassphrase.get()) {
exportProhibitedAlert()
@@ -285,9 +286,9 @@ private fun setChatItemTTLAlert(
appFilesCountAndSize: MutableState<Pair<Int, Long>>,
) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.enable_automatic_deletion_question),
text = generalGetString(R.string.enable_automatic_deletion_message),
confirmText = generalGetString(R.string.delete_messages),
title = generalGetString(MR.strings.enable_automatic_deletion_question),
text = generalGetString(MR.strings.enable_automatic_deletion_message),
confirmText = generalGetString(MR.strings.delete_messages),
onConfirm = { setCiTTL(m, selectedChatItemTTL, progressIndicator, appFilesCountAndSize) },
onDismiss = { selectedChatItemTTL.value = m.chatItemTTL.value },
destructive = true,
@@ -303,16 +304,16 @@ private fun TtlOptions(current: State<ChatItemTTL>, enabled: State<Boolean>, onS
}
all.map {
when (it) {
is ChatItemTTL.None -> it to generalGetString(R.string.chat_item_ttl_none)
is ChatItemTTL.Day -> it to generalGetString(R.string.chat_item_ttl_day)
is ChatItemTTL.Week -> it to generalGetString(R.string.chat_item_ttl_week)
is ChatItemTTL.Month -> it to generalGetString(R.string.chat_item_ttl_month)
is ChatItemTTL.Seconds -> it to String.format(generalGetString(R.string.chat_item_ttl_seconds), it.secs)
is ChatItemTTL.None -> it to generalGetString(MR.strings.chat_item_ttl_none)
is ChatItemTTL.Day -> it to generalGetString(MR.strings.chat_item_ttl_day)
is ChatItemTTL.Week -> it to generalGetString(MR.strings.chat_item_ttl_week)
is ChatItemTTL.Month -> it to generalGetString(MR.strings.chat_item_ttl_month)
is ChatItemTTL.Seconds -> it to String.format(generalGetString(MR.strings.chat_item_ttl_seconds), it.secs)
}
}
}
ExposedDropDownSettingRow(
generalGetString(R.string.delete_messages_after),
generalGetString(MR.strings.delete_messages_after),
values,
current,
icon = null,
@@ -328,7 +329,7 @@ fun RunChatSetting(
startChat: () -> Unit,
stopChatAlert: () -> Unit
) {
val chatRunningText = if (stopped) stringResource(R.string.chat_is_stopped) else stringResource(R.string.chat_is_running)
val chatRunningText = if (stopped) stringResource(MR.strings.chat_is_stopped) else stringResource(MR.strings.chat_is_running)
SettingsActionItemWithContent(
icon = if (stopped) painterResource(R.drawable.ic_report_filled) else painterResource(R.drawable.ic_play_arrow_filled),
text = chatRunningText,
@@ -349,7 +350,7 @@ fun RunChatSetting(
@Composable
fun chatArchiveTitle(chatArchiveTime: Instant, chatLastStart: Instant): String {
return stringResource(if (chatArchiveTime < chatLastStart) R.string.old_database_archive else R.string.new_database_archive)
return stringResource(if (chatArchiveTime < chatLastStart) MR.strings.old_database_archive else MR.strings.new_database_archive)
}
private fun startChat(m: ChatModel, runChat: MutableState<Boolean?>, chatLastStart: MutableState<Instant?>, chatDbChanged: MutableState<Boolean>) {
@@ -381,16 +382,16 @@ private fun startChat(m: ChatModel, runChat: MutableState<Boolean?>, chatLastSta
}
} catch (e: Error) {
runChat.value = false
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_starting_chat), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_starting_chat), e.toString())
}
}
}
private fun stopChatAlert(m: ChatModel, runChat: MutableState<Boolean?>) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.stop_chat_question),
text = generalGetString(R.string.stop_chat_to_export_import_or_delete_chat_database),
confirmText = generalGetString(R.string.stop_chat_confirmation),
title = generalGetString(MR.strings.stop_chat_question),
text = generalGetString(MR.strings.stop_chat_to_export_import_or_delete_chat_database),
confirmText = generalGetString(MR.strings.stop_chat_confirmation),
onConfirm = { authStopChat(m, runChat) },
onDismiss = { runChat.value = true }
)
@@ -398,16 +399,16 @@ private fun stopChatAlert(m: ChatModel, runChat: MutableState<Boolean?>) {
private fun exportProhibitedAlert() {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.set_password_to_export),
text = generalGetString(R.string.set_password_to_export_desc),
title = generalGetString(MR.strings.set_password_to_export),
text = generalGetString(MR.strings.set_password_to_export_desc),
)
}
private fun authStopChat(m: ChatModel, runChat: MutableState<Boolean?>) {
if (m.controller.appPrefs.performLA.get()) {
authenticate(
generalGetString(R.string.auth_stop_chat),
generalGetString(R.string.auth_log_in_using_credential),
generalGetString(MR.strings.auth_stop_chat),
generalGetString(MR.strings.auth_log_in_using_credential),
completed = { laResult ->
when (laResult) {
LAResult.Success, is LAResult.Unavailable -> {
@@ -436,7 +437,7 @@ private fun stopChat(m: ChatModel, runChat: MutableState<Boolean?>) {
MessagesFetcherWorker.cancelAll()
} catch (e: Error) {
runChat.value = true
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_stopping_chat), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_stopping_chat), e.toString())
}
}
}
@@ -468,7 +469,7 @@ private fun exportArchive(
saveArchiveLauncher.launch(archiveFile.substringAfterLast("/"))
progressIndicator.value = false
} catch (e: Error) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_exporting_chat_database), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_exporting_chat_database), e.toString())
progressIndicator.value = false
}
}
@@ -524,14 +525,14 @@ private fun rememberSaveArchiveLauncher(chatArchiveFile: MutableState<String?>):
val outputStream = BufferedOutputStream(stream)
File(filePath).inputStream().use { it.copyTo(outputStream) }
outputStream.close()
Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(cxt, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show()
}
}
} catch (e: Error) {
Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show()
Log.e(TAG, "rememberSaveArchiveLauncher error saving archive $e")
} finally {
chatArchiveFile.value = null
@@ -546,9 +547,9 @@ private fun importArchiveAlert(
progressIndicator: MutableState<Boolean>
) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.import_database_question),
text = generalGetString(R.string.your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one),
confirmText = generalGetString(R.string.import_database_confirmation),
title = generalGetString(MR.strings.import_database_question),
text = generalGetString(MR.strings.your_current_chat_database_will_be_deleted_and_replaced_with_the_imported_one),
confirmText = generalGetString(MR.strings.import_database_confirmation),
onConfirm = { importArchive(m, importedArchiveUri, appFilesCountAndSize, progressIndicator) },
destructive = true,
)
@@ -573,21 +574,21 @@ private fun importArchive(
appFilesCountAndSize.value = directoryFileCountAndSize(getAppFilesDirectory())
if (archiveErrors.isEmpty()) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database))
}
} else {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_imported), text = generalGetString(R.string.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(R.string.non_fatal_errors_occured_during_import))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_imported), text = generalGetString(MR.strings.restart_the_app_to_use_imported_chat_database) + "\n" + generalGetString(MR.strings.non_fatal_errors_occured_during_import))
}
}
} catch (e: Error) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_importing_database), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_importing_database), e.toString())
}
}
} catch (e: Error) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_database), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_deleting_database), e.toString())
}
} finally {
File(archivePath).delete()
@@ -617,9 +618,9 @@ private fun saveArchiveFromUri(importedArchiveUri: Uri): String? {
private fun deleteChatAlert(m: ChatModel, progressIndicator: MutableState<Boolean>) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_chat_profile_question),
text = generalGetString(R.string.delete_chat_profile_action_cannot_be_undone_warning),
confirmText = generalGetString(R.string.delete_verb),
title = generalGetString(MR.strings.delete_chat_profile_question),
text = generalGetString(MR.strings.delete_chat_profile_action_cannot_be_undone_warning),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = { deleteChat(m, progressIndicator) },
destructive = true,
)
@@ -631,11 +632,11 @@ private fun deleteChat(m: ChatModel, progressIndicator: MutableState<Boolean>) {
try {
deleteChatAsync(m)
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.chat_database_deleted), generalGetString(R.string.restart_the_app_to_create_a_new_chat_profile))
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.chat_database_deleted), generalGetString(MR.strings.restart_the_app_to_create_a_new_chat_profile))
}
} catch (e: Error) {
operationEnded(m, progressIndicator) {
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_deleting_database), e.toString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_deleting_database), e.toString())
}
}
}
@@ -659,7 +660,7 @@ private fun setCiTTL(
// Rollback to model's value
chatItemTTL.value = m.chatItemTTL.value
afterSetCiTTL(m, progressIndicator, appFilesCountAndSize)
AlertManager.shared.showAlertMsg(generalGetString(R.string.error_changing_message_deletion), e.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.error_changing_message_deletion), e.stackTraceToString())
}
}
}
@@ -683,9 +684,9 @@ private fun afterSetCiTTL(
private fun deleteFilesAndMediaAlert(appFilesCountAndSize: MutableState<Pair<Int, Long>>) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.delete_files_and_media_question),
text = generalGetString(R.string.delete_files_and_media_desc),
confirmText = generalGetString(R.string.delete_verb),
title = generalGetString(MR.strings.delete_files_and_media_question),
text = generalGetString(MR.strings.delete_files_and_media_desc),
confirmText = generalGetString(MR.strings.delete_verb),
onConfirm = { deleteFiles(appFilesCountAndSize) },
destructive = true
)
@@ -17,6 +17,8 @@ import androidx.compose.ui.window.Dialog
import chat.simplex.app.R
import chat.simplex.app.TAG
import chat.simplex.app.ui.theme.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
class AlertManager {
var alertViews = mutableStateListOf<(@Composable () -> Unit)>()
@@ -78,9 +80,9 @@ class AlertManager {
fun showAlertDialog(
title: String,
text: String? = null,
confirmText: String = generalGetString(R.string.ok),
confirmText: String = generalGetString(MR.strings.ok),
onConfirm: (() -> Unit)? = null,
dismissText: String = generalGetString(R.string.cancel_verb),
dismissText: String = generalGetString(MR.strings.cancel_verb),
onDismiss: (() -> Unit)? = null,
onDismissRequest: (() -> Unit)? = null,
destructive: Boolean = false
@@ -113,9 +115,9 @@ class AlertManager {
fun showAlertDialogStacked(
title: String,
text: String? = null,
confirmText: String = generalGetString(R.string.ok),
confirmText: String = generalGetString(MR.strings.ok),
onConfirm: (() -> Unit)? = null,
dismissText: String = generalGetString(R.string.cancel_verb),
dismissText: String = generalGetString(MR.strings.cancel_verb),
onDismiss: (() -> Unit)? = null,
onDismissRequest: (() -> Unit)? = null,
destructive: Boolean = false
@@ -147,7 +149,7 @@ class AlertManager {
fun showAlertMsg(
title: String, text: String? = null,
confirmText: String = generalGetString(R.string.ok)
confirmText: String = generalGetString(MR.strings.ok)
) {
showAlert {
AlertDialog(
@@ -169,9 +171,9 @@ class AlertManager {
}
}
fun showAlertMsg(
title: Int,
text: Int? = null,
confirmText: Int = R.string.ok,
title: StringResource,
text: StringResource? = null,
confirmText: StringResource = MR.strings.ok,
) = showAlertMsg(generalGetString(title), if (text != null) generalGetString(text) else null, generalGetString(confirmText))
@Composable
@@ -11,13 +11,14 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.*
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.model.ChatInfo
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.res.MR
@Composable
fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = MaterialTheme.colors.secondaryVariant) {
@@ -31,7 +32,7 @@ fun ChatInfoImage(chatInfo: ChatInfo, size: Dp, iconColor: Color = MaterialTheme
fun IncognitoImage(size: Dp, iconColor: Color = MaterialTheme.colors.secondaryVariant) {
Box(Modifier.size(size)) {
Icon(
painterResource(R.drawable.ic_theater_comedy_filled), stringResource(R.string.incognito),
painterResource(R.drawable.ic_theater_comedy_filled), stringResource(MR.strings.incognito),
modifier = Modifier.size(size).padding(size / 12),
iconColor
)
@@ -55,14 +56,14 @@ fun ProfileImage(
if (iconToReplace != null) {
Icon(
iconToReplace,
contentDescription = stringResource(R.string.icon_descr_profile_image_placeholder),
contentDescription = stringResource(MR.strings.icon_descr_profile_image_placeholder),
tint = color,
modifier = Modifier.fillMaxSize()
)
} else {
Icon(
painterResource(icon),
contentDescription = stringResource(R.string.icon_descr_profile_image_placeholder),
contentDescription = stringResource(MR.strings.icon_descr_profile_image_placeholder),
tint = color,
modifier = Modifier.fillMaxSize()
)
@@ -71,7 +72,7 @@ fun ProfileImage(
val imageBitmap = base64ToBitmap(image).asImageBitmap()
Image(
imageBitmap,
stringResource(R.string.image_descr_profile_image),
stringResource(MR.strings.image_descr_profile_image),
contentScale = ContentScale.Crop,
modifier = Modifier.size(size).padding(size / 12).clip(CircleShape)
)
@@ -9,10 +9,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.views.newchat.ActionButton
import chat.simplex.res.MR
sealed class AttachmentOption {
object CameraPhoto: AttachmentOption()
@@ -40,19 +41,19 @@ fun ChooseAttachmentView(
.padding(horizontal = 8.dp, vertical = 30.dp),
horizontalArrangement = Arrangement.SpaceEvenly
) {
ActionButton(Modifier.fillMaxWidth(0.25f), null, stringResource(R.string.use_camera_button), icon = painterResource(R.drawable.ic_camera_enhance)) {
ActionButton(Modifier.fillMaxWidth(0.25f), null, stringResource(MR.strings.use_camera_button), icon = painterResource(R.drawable.ic_camera_enhance)) {
attachmentOption.value = AttachmentOption.CameraPhoto
hide()
}
ActionButton(Modifier.fillMaxWidth(0.33f), null, stringResource(R.string.gallery_image_button), icon = painterResource(R.drawable.ic_add_photo)) {
ActionButton(Modifier.fillMaxWidth(0.33f), null, stringResource(MR.strings.gallery_image_button), icon = painterResource(R.drawable.ic_add_photo)) {
attachmentOption.value = AttachmentOption.GalleryImage
hide()
}
ActionButton(Modifier.fillMaxWidth(0.50f), null, stringResource(R.string.gallery_video_button), icon = painterResource(R.drawable.ic_smart_display)) {
ActionButton(Modifier.fillMaxWidth(0.50f), null, stringResource(MR.strings.gallery_video_button), icon = painterResource(R.drawable.ic_smart_display)) {
attachmentOption.value = AttachmentOption.GalleryVideo
hide()
}
ActionButton(Modifier.fillMaxWidth(1f), null, stringResource(R.string.choose_file), icon = painterResource(R.drawable.ic_note_add)) {
ActionButton(Modifier.fillMaxWidth(1f), null, stringResource(MR.strings.choose_file), icon = painterResource(R.drawable.ic_note_add)) {
attachmentOption.value = AttachmentOption.File
hide()
}
@@ -15,6 +15,7 @@ import androidx.compose.ui.window.Dialog
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.res.MR
import com.sd.lib.compose.wheel_picker.*
@Composable
@@ -174,7 +175,7 @@ fun CustomTimePickerDialog(
)
Icon(
painterResource(R.drawable.ic_close),
generalGetString(R.string.icon_descr_close_button),
generalGetString(MR.strings.icon_descr_close_button),
tint = MaterialTheme.colors.secondary,
modifier = Modifier
.size(25.dp)
@@ -238,7 +239,7 @@ fun DropdownCustomTimePickerSettingRow(
values.value.map { sel: DropdownSelection ->
when (sel) {
is DropdownSelection.DropdownValue -> sel to timeText(sel.value)
DropdownSelection.Custom -> sel to generalGetString(R.string.custom_time_picker_custom)
DropdownSelection.Custom -> sel to generalGetString(MR.strings.custom_time_picker_custom)
}
},
dropdownSelection,
@@ -9,9 +9,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.ui.theme.*
import chat.simplex.res.MR
@Composable
fun DefaultTopAppBar(
@@ -47,7 +48,7 @@ fun DefaultTopAppBar(
fun NavigationButtonBack(onButtonClicked: (() -> Unit)?) {
IconButton(onButtonClicked ?: {}, enabled = onButtonClicked != null) {
Icon(
painterResource(R.drawable.ic_arrow_back_ios_new), stringResource(R.string.back), tint = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
painterResource(R.drawable.ic_arrow_back_ios_new), stringResource(MR.strings.back), tint = if (onButtonClicked != null) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
)
}
}
@@ -56,7 +57,7 @@ fun NavigationButtonBack(onButtonClicked: (() -> Unit)?) {
fun ShareButton(onButtonClicked: () -> Unit) {
IconButton(onButtonClicked) {
Icon(
painterResource(R.drawable.ic_share), stringResource(R.string.share_verb), tint = MaterialTheme.colors.primary
painterResource(R.drawable.ic_share), stringResource(MR.strings.share_verb), tint = MaterialTheme.colors.primary
)
}
}
@@ -66,7 +67,7 @@ fun NavigationButtonMenu(onButtonClicked: () -> Unit) {
IconButton(onClick = onButtonClicked) {
Icon(
painterResource(R.drawable.ic_menu),
stringResource(R.string.icon_descr_settings),
stringResource(MR.strings.icon_descr_settings),
tint = MaterialTheme.colors.primary,
)
}
@@ -15,6 +15,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.usersettings.SettingsActionItemWithContent
import chat.simplex.res.MR
@Composable
fun <T> ExposedDropDownSettingRow(
@@ -51,7 +52,7 @@ fun <T> ExposedDropDownSettingRow(
Spacer(Modifier.size(12.dp))
Icon(
if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less),
generalGetString(R.string.icon_descr_more_button),
generalGetString(MR.strings.icon_descr_more_button),
tint = MaterialTheme.colors.secondary
)
}
@@ -24,7 +24,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@@ -33,6 +33,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.json
import chat.simplex.app.views.chat.PickFromGallery
import chat.simplex.app.views.newchat.ActionButton
import chat.simplex.res.MR
import kotlinx.serialization.builtins.*
import java.io.ByteArrayOutputStream
import java.io.File
@@ -228,7 +229,7 @@ fun GetImageBottomSheet(
cameraLauncher.launchWithFallback()
hideBottomSheet()
} else {
Toast.makeText(context, generalGetString(R.string.toast_permission_denied), Toast.LENGTH_SHORT).show()
Toast.makeText(context, generalGetString(MR.strings.toast_permission_denied), Toast.LENGTH_SHORT).show()
}
}
@@ -246,7 +247,7 @@ fun GetImageBottomSheet(
.padding(horizontal = 8.dp, vertical = 30.dp),
horizontalArrangement = Arrangement.SpaceEvenly
) {
ActionButton(null, stringResource(R.string.use_camera_button), icon = painterResource(R.drawable.ic_photo_camera)) {
ActionButton(null, stringResource(MR.strings.use_camera_button), icon = painterResource(R.drawable.ic_photo_camera)) {
when (PackageManager.PERMISSION_GRANTED) {
ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) -> {
cameraLauncher.launchWithFallback()
@@ -257,7 +258,7 @@ fun GetImageBottomSheet(
}
}
}
ActionButton(null, stringResource(R.string.from_gallery_button), icon = painterResource(R.drawable.ic_image)) {
ActionButton(null, stringResource(MR.strings.from_gallery_button), icon = painterResource(R.drawable.ic_image)) {
try {
galleryLauncher.launch(0)
} catch (e: ActivityNotFoundException) {
@@ -13,7 +13,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -21,6 +21,7 @@ import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.LinkPreview
import chat.simplex.app.ui.theme.*
import chat.simplex.res.MR
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.jsoup.Jsoup
@@ -98,7 +99,7 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancel
val imageBitmap = base64ToBitmap(linkPreview.image).asImageBitmap()
Image(
imageBitmap,
stringResource(R.string.image_descr_link_preview),
stringResource(MR.strings.image_descr_link_preview),
modifier = Modifier.width(80.dp).height(60.dp).padding(end = 8.dp)
)
Column(Modifier.fillMaxWidth().weight(1F)) {
@@ -113,7 +114,7 @@ fun ComposeLinkView(linkPreview: LinkPreview?, cancelPreview: () -> Unit, cancel
IconButton(onClick = cancelPreview, modifier = Modifier.padding(0.dp)) {
Icon(
painterResource(R.drawable.ic_close),
contentDescription = stringResource(R.string.icon_descr_cancel_link_preview),
contentDescription = stringResource(MR.strings.icon_descr_cancel_link_preview),
tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(10.dp)
)
@@ -127,7 +128,7 @@ fun ChatItemLinkView(linkPreview: LinkPreview) {
Column {
Image(
base64ToBitmap(linkPreview.image).asImageBitmap(),
stringResource(R.string.image_descr_link_preview),
stringResource(MR.strings.image_descr_link_preview),
modifier = Modifier.fillMaxWidth(),
contentScale = ContentScale.FillWidth,
)
@@ -16,6 +16,7 @@ import chat.simplex.app.SimplexApp
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
import chat.simplex.app.views.localauth.LocalAuthView
import chat.simplex.app.views.usersettings.LAMode
import chat.simplex.res.MR
sealed class LAResult {
object Success: LAResult()
@@ -32,7 +33,7 @@ data class LocalAuthRequest (
val completed: (LAResult) -> Unit
) {
companion object {
val sample = LocalAuthRequest(generalGetString(R.string.la_enter_app_passcode), generalGetString(R.string.la_authenticate), "", selfDestruct = false) { }
val sample = LocalAuthRequest(generalGetString(MR.strings.la_enter_app_passcode), generalGetString(MR.strings.la_authenticate), "", selfDestruct = false) { }
}
}
@@ -54,11 +55,11 @@ fun authenticate(
else -> completed(LAResult.Unavailable())
}
LAMode.PASSCODE -> {
val password = ksAppPassword.get() ?: return completed(LAResult.Unavailable(generalGetString(R.string.la_no_app_password)))
val password = ksAppPassword.get() ?: return completed(LAResult.Unavailable(generalGetString(MR.strings.la_no_app_password)))
ModalManager.shared.showPasscodeCustomModal { close ->
BackHandler {
close()
completed(LAResult.Error(generalGetString(R.string.authentication_cancelled)))
completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled)))
}
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
LocalAuthView(SimplexApp.context.chatModel, LocalAuthRequest(promptTitle, promptSubtitle, password, selfDestruct && SimplexApp.context.chatModel.controller.appPrefs.selfDestruct.get()) {
@@ -120,28 +121,28 @@ private fun authenticateWithBiometricManager(
}
fun laTurnedOnAlert() = AlertManager.shared.showAlertMsg(
generalGetString(R.string.auth_simplex_lock_turned_on),
generalGetString(R.string.auth_you_will_be_required_to_authenticate_when_you_start_or_resume)
generalGetString(MR.strings.auth_simplex_lock_turned_on),
generalGetString(MR.strings.auth_you_will_be_required_to_authenticate_when_you_start_or_resume)
)
fun laPasscodeNotSetAlert() = AlertManager.shared.showAlertMsg(
generalGetString(R.string.lock_not_enabled),
generalGetString(R.string.you_can_turn_on_lock)
generalGetString(MR.strings.lock_not_enabled),
generalGetString(MR.strings.you_can_turn_on_lock)
)
fun laFailedAlert() {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.la_auth_failed),
text = generalGetString(R.string.la_could_not_be_verified)
title = generalGetString(MR.strings.la_auth_failed),
text = generalGetString(MR.strings.la_could_not_be_verified)
)
}
fun laUnavailableInstructionAlert() = AlertManager.shared.showAlertMsg(
generalGetString(R.string.auth_unavailable),
generalGetString(R.string.auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled)
generalGetString(MR.strings.auth_unavailable),
generalGetString(MR.strings.auth_device_authentication_is_not_enabled_you_can_turn_on_in_settings_once_enabled)
)
fun laUnavailableTurningOffAlert() = AlertManager.shared.showAlertMsg(
generalGetString(R.string.auth_unavailable),
generalGetString(R.string.auth_device_authentication_is_disabled_turning_off)
generalGetString(MR.strings.auth_unavailable),
generalGetString(MR.strings.auth_device_authentication_is_disabled_turning_off)
)
@@ -13,7 +13,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.intl.Locale
import chat.simplex.app.TAG
@@ -13,6 +13,7 @@ import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.ChatItem
import chat.simplex.app.views.helpers.AudioPlayer.duration
import chat.simplex.res.MR
import kotlinx.coroutines.*
import java.io.*
@@ -162,13 +163,13 @@ object AudioPlayer {
player.setDataSource(filePath)
}.onFailure {
Log.e(TAG, it.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message)
return null
}
runCatching { player.prepare() }.onFailure {
// Can happen when audio file is broken
Log.e(TAG, it.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message)
return null
}
}
@@ -18,13 +18,14 @@ import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.*
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@OptIn(ExperimentalComposeUiApi::class)
@@ -33,7 +34,7 @@ fun SearchTextField(
modifier: Modifier,
alwaysVisible: Boolean,
searchText: MutableState<TextFieldValue> = rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) },
placeholder: String = stringResource(android.R.string.search_go),
placeholder: String = stringResource(MR.strings.search_verb),
onValueChange: (String) -> Unit
) {
val focusRequester = remember { FocusRequester() }
@@ -103,7 +104,7 @@ fun SearchTextField(
searchText.value = TextFieldValue("");
onValueChange("")
}) {
Icon(painterResource(R.drawable.ic_close), stringResource(R.string.icon_descr_close_button), tint = MaterialTheme.colors.primary,)
Icon(painterResource(R.drawable.ic_close), stringResource(MR.strings.icon_descr_close_button), tint = MaterialTheme.colors.primary,)
}
}} else null,
singleLine = true,
@@ -15,6 +15,7 @@ import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import chat.simplex.app.*
import chat.simplex.app.model.CIFile
import chat.simplex.res.MR
import java.io.BufferedOutputStream
import java.io.File
@@ -80,10 +81,10 @@ fun rememberSaveFileLauncher(ciFile: CIFile?): ManagedActivityResultLauncher<Str
val outputStream = BufferedOutputStream(stream)
File(filePath).inputStream().use { it.copyTo(outputStream) }
outputStream.close()
Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show()
}
} else {
Toast.makeText(cxt, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show()
}
}
}
@@ -118,10 +119,10 @@ fun saveImage(ciFile: CIFile?) {
val outputStream = BufferedOutputStream(stream)
File(filePath).inputStream().use { it.copyTo(outputStream) }
outputStream.close()
Toast.makeText(cxt, generalGetString(R.string.image_saved), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.image_saved), Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(cxt, generalGetString(R.string.file_not_found), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_not_found), Toast.LENGTH_SHORT).show()
}
}
@@ -22,8 +22,6 @@ import android.util.Log
import android.view.View
import android.view.ViewTreeObserver
import android.view.inputmethod.InputMethodManager
import androidx.annotation.StringRes
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.Saver
import androidx.compose.ui.graphics.Color
@@ -38,10 +36,11 @@ import androidx.core.content.FileProvider
import androidx.core.graphics.ColorUtils
import androidx.core.text.HtmlCompat
import chat.simplex.app.*
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.ThemeOverrides
import com.charleskorn.kaml.decodeFromStream
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import kotlinx.coroutines.*
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
@@ -94,9 +93,9 @@ fun hideKeyboard(view: View) =
// Resource to annotated string from
// https://stackoverflow.com/questions/68549248/android-jetpack-compose-how-to-show-styled-text-from-string-resources
fun generalGetString(id: Int): String {
fun generalGetString(id: StringResource): String {
// prefer stringResource in Composable items to retain preview abilities
return SimplexApp.context.getString(id)
return id.getString(SimplexApp.context)
}
@Composable
@@ -111,7 +110,7 @@ fun Spanned.toHtmlWithoutParagraphs(): String {
.substringAfter("<p dir=\"ltr\">").substringBeforeLast("</p>")
}
fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence {
fun Resources.getText(id: StringResource, vararg args: Any): CharSequence {
val escapedArgs = args.map {
if (it is Spanned) it.toHtmlWithoutParagraphs() else it
}.toTypedArray()
@@ -121,13 +120,16 @@ fun Resources.getText(@StringRes id: Int, vararg args: Any): CharSequence {
return HtmlCompat.fromHtml(formattedHtml, HtmlCompat.FROM_HTML_MODE_LEGACY)
}
fun escapedHtmlToAnnotatedString(text: String, density: Density): AnnotatedString {
return spannableStringToAnnotatedString(HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_LEGACY), density)
}
@Composable
fun annotatedStringResource(@StringRes id: Int): AnnotatedString {
val resources = resources()
fun annotatedStringResource(id: StringResource): AnnotatedString {
val density = LocalDensity.current
return remember(id) {
val text = resources.getText(id)
spannableStringToAnnotatedString(text, density)
val text = id.getString(SimplexApp.context)
escapedHtmlToAnnotatedString(text, density)
}
}
@@ -362,8 +364,8 @@ fun getBitmapFromUri(uri: Uri, withAlertOnException: Boolean = true): Bitmap? {
Log.e(TAG, "Unable to decode the image: ${e.stackTraceToString()}")
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.image_decoding_exception_title),
text = generalGetString(R.string.image_decoding_exception_desc)
title = generalGetString(MR.strings.image_decoding_exception_title),
text = generalGetString(MR.strings.image_decoding_exception_desc)
)
}
null
@@ -381,8 +383,8 @@ fun getDrawableFromUri(uri: Uri, withAlertOnException: Boolean = true): Drawable
} catch (e: android.graphics.ImageDecoder.DecodeException) {
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.image_decoding_exception_title),
text = generalGetString(R.string.image_decoding_exception_desc)
title = generalGetString(MR.strings.image_decoding_exception_title),
text = generalGetString(MR.strings.image_decoding_exception_desc)
)
}
Log.e(TAG, "Error while decoding drawable: ${e.stackTraceToString()}")
@@ -400,8 +402,8 @@ fun getThemeFromUri(uri: Uri, withAlertOnException: Boolean = true): ThemeOverri
}.onFailure {
if (withAlertOnException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.import_theme_error),
text = generalGetString(R.string.import_theme_error_desc),
title = generalGetString(MR.strings.import_theme_error),
text = generalGetString(MR.strings.import_theme_error_desc),
)
}
}
@@ -15,6 +15,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes
import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.upstream.DefaultDataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import chat.simplex.res.MR
import kotlinx.coroutines.*
import java.io.File
@@ -125,7 +126,7 @@ class VideoPlayer private constructor(
player.setMediaSource(source, seek ?: 0L)
}.onFailure {
Log.e(TAG, it.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message)
brokenVideo.value = true
return false
}
@@ -134,7 +135,7 @@ class VideoPlayer private constructor(
runCatching { player.prepare() }.onFailure {
// Can happen when video file is broken
Log.e(TAG, it.stackTraceToString())
AlertManager.shared.showAlertMsg(generalGetString(R.string.unknown_error), it.message)
AlertManager.shared.showAlertMsg(generalGetString(MR.strings.unknown_error), it.message)
brokenVideo.value = true
return false
}
@@ -4,7 +4,7 @@ import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.*
import chat.simplex.app.model.*
import chat.simplex.app.views.database.deleteChatAsync
@@ -13,12 +13,13 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.helpers.DatabaseUtils.ksSelfDestructPassword
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
import chat.simplex.app.views.onboarding.OnboardingStage
import chat.simplex.res.MR
import kotlinx.coroutines.delay
@Composable
fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) {
val passcode = rememberSaveable { mutableStateOf("") }
PasscodeView(passcode, authRequest.title ?: stringResource(R.string.la_enter_app_passcode), authRequest.reason, stringResource(R.string.submit_passcode),
PasscodeView(passcode, authRequest.title ?: stringResource(MR.strings.la_enter_app_passcode), authRequest.reason, stringResource(MR.strings.submit_passcode),
submit = {
val sdPassword = ksSelfDestructPassword.get()
if (sdPassword == passcode.value && authRequest.selfDestruct) {
@@ -26,12 +27,12 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) {
authRequest.completed(r)
}
} else {
val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(R.string.incorrect_passcode))
val r: LAResult = if (passcode.value == authRequest.password) LAResult.Success else LAResult.Error(generalGetString(MR.strings.incorrect_passcode))
authRequest.completed(r)
}
},
cancel = {
authRequest.completed(LAResult.Error(generalGetString(R.string.authentication_cancelled)))
authRequest.completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled)))
})
}
@@ -74,7 +75,7 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (
AlertManager.shared.hideAlert()
completed(LAResult.Success)
} catch (e: Exception) {
completed(LAResult.Error(generalGetString(R.string.incorrect_passcode)))
completed(LAResult.Error(generalGetString(MR.strings.incorrect_passcode)))
}
}
}
@@ -14,6 +14,7 @@ import chat.simplex.app.R
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.ui.theme.SimpleButton
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun PasscodeView(
@@ -39,7 +40,7 @@ fun PasscodeView(
}
PasscodeEntry(passcode, true)
Row {
SimpleButton(generalGetString(R.string.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel)
SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel)
Spacer(Modifier.size(20.dp))
SimpleButton(submitLabel, icon = painterResource(R.drawable.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit)
}
@@ -82,7 +83,7 @@ fun PasscodeView(
Modifier.padding(start = 30.dp).height(s * 3),
verticalArrangement = Arrangement.SpaceEvenly
) {
SimpleButton(generalGetString(R.string.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel)
SimpleButton(generalGetString(MR.strings.cancel_verb), icon = painterResource(R.drawable.ic_close), click = cancel)
SimpleButton(submitLabel, icon = painterResource(R.drawable.ic_done_filled), disabled = submitEnabled?.invoke(passcode.value) == false || passcode.value.length < 4, click = submit)
}
}
@@ -7,11 +7,12 @@ import chat.simplex.app.R
import chat.simplex.app.views.helpers.DatabaseUtils
import chat.simplex.app.views.helpers.DatabaseUtils.ksAppPassword
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
@Composable
fun SetAppPasscodeView(
passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword,
title: String = generalGetString(R.string.new_passcode),
title: String = generalGetString(MR.strings.new_passcode),
reason: String? = null,
submit: () -> Unit,
cancel: () -> Unit,
@@ -35,8 +36,8 @@ fun SetAppPasscodeView(
if (confirming) {
SetPasswordView(
generalGetString(R.string.confirm_passcode),
generalGetString(R.string.confirm_verb),
generalGetString(MR.strings.confirm_passcode),
generalGetString(MR.strings.confirm_verb),
submitEnabled = { pwd -> pwd == enteredPassword }
) {
if (passcode.value == enteredPassword) {
@@ -48,7 +49,7 @@ fun SetAppPasscodeView(
}
}
} else {
SetPasswordView(title, generalGetString(R.string.save_verb)) {
SetPasswordView(title, generalGetString(MR.strings.save_verb)) {
enteredPassword = passcode.value
passcode.value = ""
confirming = true
@@ -4,20 +4,21 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.layout.Column
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.views.helpers.AppBarTitle
import chat.simplex.app.views.onboarding.ReadableText
import chat.simplex.app.views.onboarding.ReadableTextWithLink
import chat.simplex.res.MR
@Composable
fun AddContactLearnMore() {
Column(
Modifier.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.one_time_link))
ReadableText(R.string.scan_qr_to_connect_to_contact)
ReadableText(R.string.if_you_cant_meet_in_person)
ReadableTextWithLink(R.string.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends")
AppBarTitle(stringResource(MR.strings.one_time_link))
ReadableText(MR.strings.scan_qr_to_connect_to_contact)
ReadableText(MR.strings.if_you_cant_meet_in_person)
ReadableTextWithLink(MR.strings.read_more_in_user_guide_with_link, "https://simplex.chat/docs/guide/readme.html#connect-to-friends")
}
}
@@ -12,7 +12,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -20,6 +20,7 @@ import chat.simplex.app.R
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
@Composable
fun AddContactView(connReqInvitation: String, connIncognito: Boolean) {
@@ -49,11 +50,11 @@ fun AddContactLayout(connReq: String, connIncognito: Boolean, share: () -> Unit,
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.SpaceBetween,
) {
AppBarTitle(stringResource(R.string.add_contact))
AppBarTitle(stringResource(MR.strings.add_contact))
OneTimeLinkProfileText(connIncognito)
SectionSpacer()
SectionView(stringResource(R.string.one_time_link_short).uppercase()) {
SectionView(stringResource(MR.strings.one_time_link_short).uppercase()) {
OneTimeLinkSection(connReq, share, learnMore)
}
SectionBottomSpacer()
@@ -66,8 +67,8 @@ fun OneTimeLinkProfileText(connIncognito: Boolean) {
InfoAboutIncognito(
connIncognito,
true,
generalGetString(R.string.incognito_random_profile_description),
generalGetString(R.string.your_profile_will_be_sent)
generalGetString(MR.strings.incognito_random_profile_description),
generalGetString(MR.strings.your_profile_will_be_sent)
)
}
}
@@ -98,7 +99,7 @@ fun ColumnScope.OneTimeLinkSection(connReq: String, share: () -> Unit, learnMore
fun ShareLinkButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_share),
stringResource(R.string.share_invitation_link),
stringResource(MR.strings.share_invitation_link),
onClick,
iconColor = MaterialTheme.colors.primary,
textColor = MaterialTheme.colors.primary,
@@ -109,7 +110,7 @@ fun ShareLinkButton(onClick: () -> Unit) {
fun OneTimeLinkLearnMoreButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_info),
stringResource(R.string.learn_more),
stringResource(MR.strings.learn_more),
onClick,
)
}
@@ -126,7 +127,7 @@ fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean
) {
Icon(
if (supportedIncognito) painterResource(R.drawable.ic_theater_comedy_filled) else painterResource(R.drawable.ic_info),
stringResource(R.string.incognito),
stringResource(MR.strings.incognito),
tint = if (supportedIncognito) Indigo else WarningOrange,
modifier = Modifier.padding(end = 10.dp).size(20.dp)
)
@@ -142,7 +143,7 @@ fun InfoAboutIncognito(chatModelIncognito: Boolean, supportedIncognito: Boolean
) {
Icon(
painterResource(R.drawable.ic_info),
stringResource(R.string.incognito),
stringResource(MR.strings.incognito),
tint = MaterialTheme.colors.secondary,
modifier = Modifier.padding(end = 10.dp).size(20.dp)
)
@@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -31,6 +31,7 @@ import chat.simplex.app.views.usersettings.DeleteImageButton
import chat.simplex.app.views.usersettings.EditImageButton
import com.google.accompanist.insets.ProvideWindowInsets
import com.google.accompanist.insets.navigationBarsWithImePadding
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -88,8 +89,8 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) {
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING)
) {
AppBarTitle(stringResource(R.string.create_secret_group_title))
ReadableText(R.string.group_is_decentralized, TextAlign.Center)
AppBarTitle(stringResource(MR.strings.create_secret_group_title))
ReadableText(MR.strings.group_is_decentralized, TextAlign.Center)
Box(
Modifier
.fillMaxWidth()
@@ -108,13 +109,13 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) {
}
Row(Modifier.padding(bottom = DEFAULT_PADDING_HALF).fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween) {
Text(
stringResource(R.string.group_display_name_field),
stringResource(MR.strings.group_display_name_field),
fontSize = 16.sp
)
if (!isValidDisplayName(displayName.value)) {
Spacer(Modifier.size(DEFAULT_PADDING_HALF))
Text(
stringResource(R.string.no_spaces),
stringResource(MR.strings.no_spaces),
fontSize = 16.sp,
color = Color.Red
)
@@ -123,7 +124,7 @@ fun AddGroupLayout(createGroup: (GroupProfile) -> Unit, close: () -> Unit) {
ProfileNameField(displayName, "", ::isValidDisplayName, focusRequester)
Spacer(Modifier.height(DEFAULT_PADDING))
Text(
stringResource(R.string.group_full_name_field),
stringResource(MR.strings.group_full_name_field),
fontSize = 16.sp,
modifier = Modifier.padding(bottom = DEFAULT_PADDING_HALF)
)
@@ -161,8 +162,8 @@ fun CreateGroupButton(color: Color, modifier: Modifier) {
) {
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
Row(modifier, verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(R.string.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(R.string.create_profile_button), tint = color)
Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = color, fontWeight = FontWeight.Bold)
Icon(painterResource(R.drawable.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = color)
}
}
}
@@ -6,10 +6,11 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.res.MR
enum class ConnectViaLinkTab {
SCAN, PASTE
@@ -24,8 +25,8 @@ fun ConnectViaLinkView(m: ChatModel, close: () -> Unit) {
}
val tabTitles = ConnectViaLinkTab.values().map {
when (it) {
ConnectViaLinkTab.SCAN -> stringResource(R.string.scan_QR_code)
ConnectViaLinkTab.PASTE -> stringResource(R.string.paste_the_link_you_received)
ConnectViaLinkTab.SCAN -> stringResource(MR.strings.scan_QR_code)
ConnectViaLinkTab.PASTE -> stringResource(MR.strings.paste_the_link_you_received)
}
}
Column(
@@ -12,7 +12,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import chat.simplex.app.R
import chat.simplex.app.model.*
@@ -21,6 +21,7 @@ import chat.simplex.app.views.chat.LocalAliasEditor
import chat.simplex.app.views.chatlist.deleteContactConnectionAlert
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.SettingsActionItem
import chat.simplex.res.MR
@Composable
fun ContactConnectionInfoView(
@@ -84,16 +85,16 @@ private fun ContactConnectionInfoLayout(
) {
AppBarTitle(
stringResource(
if (contactConnection.initiated) R.string.you_invited_your_contact
else R.string.you_accepted_connection
if (contactConnection.initiated) MR.strings.you_invited_your_contact
else MR.strings.you_accepted_connection
)
)
Text(
stringResource(
if (contactConnection.viaContactUri)
if (contactConnection.groupLinkId != null) R.string.you_will_be_connected_when_group_host_device_is_online
else R.string.you_will_be_connected_when_your_connection_request_is_accepted
else R.string.you_will_be_connected_when_your_contacts_device_is_online
if (contactConnection.groupLinkId != null) MR.strings.you_will_be_connected_when_group_host_device_is_online
else MR.strings.you_will_be_connected_when_your_connection_request_is_accepted
else MR.strings.you_will_be_connected_when_your_contacts_device_is_online
),
Modifier.padding(start = DEFAULT_PADDING, end = DEFAULT_PADDING, bottom = DEFAULT_PADDING)
)
@@ -123,7 +124,7 @@ private fun ContactConnectionInfoLayout(
fun DeleteButton(onClick: () -> Unit) {
SettingsActionItem(
painterResource(R.drawable.ic_delete),
stringResource(R.string.delete_verb),
stringResource(MR.strings.delete_verb),
click = onClick,
textColor = Color.Red,
iconColor = Color.Red,
@@ -7,7 +7,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
@@ -15,6 +15,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.helpers.ModalManager
import chat.simplex.app.views.helpers.withApi
import chat.simplex.app.views.usersettings.UserAddressView
import chat.simplex.res.MR
enum class CreateLinkTab {
ONE_TIME, LONG_TERM
@@ -43,9 +44,9 @@ fun CreateLinkView(m: ChatModel, initialSelection: CreateLinkTab) {
}
val tabTitles = CreateLinkTab.values().map {
when {
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(R.string.create_one_time_link)
it == CreateLinkTab.ONE_TIME -> stringResource(R.string.one_time_link)
it == CreateLinkTab.LONG_TERM -> stringResource(R.string.your_simplex_contact_address)
it == CreateLinkTab.ONE_TIME && connReqInvitation.value.isNullOrEmpty() -> stringResource(MR.strings.create_one_time_link)
it == CreateLinkTab.ONE_TIME -> stringResource(MR.strings.one_time_link)
it == CreateLinkTab.LONG_TERM -> stringResource(MR.strings.your_simplex_contact_address)
else -> ""
}
}
@@ -17,7 +17,7 @@ import androidx.compose.ui.graphics.*
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -28,6 +28,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@@ -55,7 +56,7 @@ fun NewChatSheet(chatModel: ChatModel, newChatSheetState: StateFlow<AnimatedView
)
}
private val titles = listOf(R.string.share_one_time_link, R.string.connect_via_link_or_qr, R.string.create_group)
private val titles = listOf(MR.strings.share_one_time_link, MR.strings.connect_via_link_or_qr, MR.strings.create_group)
private val icons = listOf(R.drawable.ic_add_link, R.drawable.ic_qr_code, R.drawable.ic_group)
@Composable
@@ -154,11 +155,11 @@ private fun NewChatSheetLayout(
contentColor = Color.White
) {
Icon(
painterResource(R.drawable.ic_edit_filled), stringResource(R.string.add_contact_or_create_group),
painterResource(R.drawable.ic_edit_filled), stringResource(MR.strings.add_contact_or_create_group),
Modifier.graphicsLayer { alpha = 1 - animatedFloat.value }
)
Icon(
painterResource(R.drawable.ic_close), stringResource(R.string.add_contact_or_create_group),
painterResource(R.drawable.ic_close), stringResource(MR.strings.add_contact_or_create_group),
Modifier.graphicsLayer { alpha = animatedFloat.value }
)
}
@@ -13,7 +13,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat.getSystemService
@@ -22,6 +22,7 @@ import chat.simplex.app.TAG
import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun PasteToConnectView(chatModel: ChatModel, close: () -> Unit) {
@@ -46,17 +47,17 @@ fun PasteToConnectView(chatModel: ChatModel, close: () -> Unit) {
}
if (linkType == ConnectionLinkType.GROUP) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.connect_via_group_link),
text = generalGetString(R.string.you_will_join_group),
confirmText = generalGetString(R.string.connect_via_link_verb),
title = generalGetString(MR.strings.connect_via_group_link),
text = generalGetString(MR.strings.you_will_join_group),
confirmText = generalGetString(MR.strings.connect_via_link_verb),
onConfirm = { withApi { action() } }
)
} else action()
}
} catch (e: RuntimeException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.invalid_connection_link),
text = generalGetString(R.string.this_string_is_not_a_connection_link)
title = generalGetString(MR.strings.invalid_connection_link),
text = generalGetString(MR.strings.this_string_is_not_a_connection_link)
)
}
},
@@ -74,14 +75,14 @@ fun PasteToConnectLayout(
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.SpaceBetween,
) {
AppBarTitle(stringResource(R.string.connect_via_link), false)
Text(stringResource(R.string.paste_connection_link_below_to_connect))
AppBarTitle(stringResource(MR.strings.connect_via_link), false)
Text(stringResource(MR.strings.paste_connection_link_below_to_connect))
InfoAboutIncognito(
chatModelIncognito,
true,
generalGetString(R.string.incognito_random_profile_from_contact_description),
generalGetString(R.string.profile_will_be_sent_to_contact_sending_link)
generalGetString(MR.strings.incognito_random_profile_from_contact_description),
generalGetString(MR.strings.profile_will_be_sent_to_contact_sending_link)
)
Box(Modifier.padding(top = DEFAULT_PADDING, bottom = 6.dp)) {
@@ -93,21 +94,21 @@ fun PasteToConnectLayout(
horizontalArrangement = Arrangement.Start,
) {
if (connectionLink.value == "") {
SimpleButton(text = stringResource(R.string.paste_button), icon = painterResource(R.drawable.ic_content_paste)) {
SimpleButton(text = stringResource(MR.strings.paste_button), icon = painterResource(R.drawable.ic_content_paste)) {
pasteFromClipboard()
}
} else {
SimpleButton(text = stringResource(R.string.clear_verb), icon = painterResource(R.drawable.ic_close)) {
SimpleButton(text = stringResource(MR.strings.clear_verb), icon = painterResource(R.drawable.ic_close)) {
connectionLink.value = ""
}
}
Spacer(Modifier.weight(1f).fillMaxWidth())
SimpleButton(text = stringResource(R.string.connect_button), icon = painterResource(R.drawable.ic_link)) {
SimpleButton(text = stringResource(MR.strings.connect_button), icon = painterResource(R.drawable.ic_link)) {
connectViaLink(connectionLink.value)
}
}
Text(annotatedStringResource(R.string.you_can_also_connect_by_clicking_the_link))
Text(annotatedStringResource(MR.strings.you_can_also_connect_by_clicking_the_link))
SectionBottomSpacer()
}
}
@@ -7,7 +7,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.*
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.graphics.*
import androidx.core.graphics.drawable.toBitmap
@@ -18,6 +18,7 @@ import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.launch
@Composable
@@ -38,7 +39,7 @@ fun QRCode(
}
Image(
bitmap = qr,
contentDescription = stringResource(R.string.image_descr_qr_code),
contentDescription = stringResource(MR.strings.image_descr_qr_code),
modifier
.clickable {
scope.launch {
@@ -12,7 +12,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -25,6 +25,7 @@ import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.helpers.*
import com.google.accompanist.permissions.rememberPermissionState
import chat.simplex.res.MR
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@@ -49,17 +50,17 @@ fun ScanToConnectView(chatModel: ChatModel, close: () -> Unit) {
}
if (linkType == ConnectionLinkType.GROUP) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.connect_via_group_link),
text = generalGetString(R.string.you_will_join_group),
confirmText = generalGetString(R.string.connect_via_link_verb),
title = generalGetString(MR.strings.connect_via_group_link),
text = generalGetString(MR.strings.you_will_join_group),
confirmText = generalGetString(MR.strings.connect_via_link_verb),
onConfirm = { withApi { action() } }
)
} else action()
}
} catch (e: RuntimeException) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.invalid_QR_code),
text = generalGetString(R.string.this_QR_code_is_not_a_link)
title = generalGetString(MR.strings.invalid_QR_code),
text = generalGetString(MR.strings.this_QR_code_is_not_a_link)
)
}
}
@@ -97,8 +98,8 @@ fun withUriAction(uri: Uri, run: suspend (ConnectionLinkType) -> Unit) {
withApi { run(type) }
} else {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.invalid_contact_link),
text = generalGetString(R.string.this_link_is_not_a_valid_connection_link)
title = generalGetString(MR.strings.invalid_contact_link),
text = generalGetString(MR.strings.this_link_is_not_a_valid_connection_link)
)
}
}
@@ -107,12 +108,12 @@ suspend fun connectViaUri(chatModel: ChatModel, action: ConnectionLinkType, uri:
val r = chatModel.controller.apiConnect(uri.toString())
if (r) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.connection_request_sent),
title = generalGetString(MR.strings.connection_request_sent),
text =
when (action) {
ConnectionLinkType.CONTACT -> generalGetString(R.string.you_will_be_connected_when_your_connection_request_is_accepted)
ConnectionLinkType.INVITATION -> generalGetString(R.string.you_will_be_connected_when_your_contacts_device_is_online)
ConnectionLinkType.GROUP -> generalGetString(R.string.you_will_be_connected_when_group_host_device_is_online)
ConnectionLinkType.CONTACT -> generalGetString(MR.strings.you_will_be_connected_when_your_connection_request_is_accepted)
ConnectionLinkType.INVITATION -> generalGetString(MR.strings.you_will_be_connected_when_your_contacts_device_is_online)
ConnectionLinkType.GROUP -> generalGetString(MR.strings.you_will_be_connected_when_group_host_device_is_online)
}
)
}
@@ -125,12 +126,12 @@ fun ConnectContactLayout(chatModelIncognito: Boolean, qrCodeScanner: @Composable
Modifier.verticalScroll(rememberScrollState()).padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
AppBarTitle(stringResource(R.string.scan_QR_code), false)
AppBarTitle(stringResource(MR.strings.scan_QR_code), false)
InfoAboutIncognito(
chatModelIncognito,
true,
generalGetString(R.string.incognito_random_profile_description),
generalGetString(R.string.your_profile_will_be_sent)
generalGetString(MR.strings.incognito_random_profile_description),
generalGetString(MR.strings.your_profile_will_be_sent)
)
Box(
Modifier
@@ -139,7 +140,7 @@ fun ConnectContactLayout(chatModelIncognito: Boolean, qrCodeScanner: @Composable
.padding(bottom = 12.dp)
) { qrCodeScanner() }
Text(
annotatedStringResource(R.string.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link),
annotatedStringResource(MR.strings.if_you_cannot_meet_in_person_scan_QR_in_video_call_or_ask_for_invitation_link),
lineHeight = 22.sp
)
SectionBottomSpacer()
@@ -10,7 +10,7 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import chat.simplex.app.*
@@ -20,6 +20,7 @@ import chat.simplex.app.model.UserContactLinkRec
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.newchat.QRCode
import chat.simplex.res.MR
@Composable
fun CreateSimpleXAddress(m: ChatModel) {
@@ -31,8 +32,8 @@ fun CreateSimpleXAddress(m: ChatModel) {
share = { address: String -> shareText(address) },
sendEmail = { address ->
sendEmail(
generalGetString(R.string.email_invite_subject),
generalGetString(R.string.email_invite_body).format(address.connReqContact)
generalGetString(MR.strings.email_invite_subject),
generalGetString(MR.strings.email_invite_body).format(address.connReqContact)
)
},
createAddress = {
@@ -76,7 +77,7 @@ private fun CreateSimpleXAddressLayout(
Modifier.fillMaxSize().verticalScroll(rememberScrollState()).padding(top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally,
) {
AppBarTitle(stringResource(R.string.simplex_address))
AppBarTitle(stringResource(MR.strings.simplex_address))
Spacer(Modifier.weight(1f))
@@ -89,7 +90,7 @@ private fun CreateSimpleXAddressLayout(
ContinueButton(nextStep)
} else {
CreateAddressButton(createAddress)
TextBelowButton(stringResource(R.string.your_contacts_will_see_it))
TextBelowButton(stringResource(MR.strings.your_contacts_will_see_it))
Spacer(Modifier.weight(1f))
SkipButton(nextStep)
}
@@ -100,7 +101,7 @@ private fun CreateSimpleXAddressLayout(
@Composable
private fun CreateAddressButton(onClick: () -> Unit) {
TextButton(onClick) {
Text(stringResource(R.string.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary)
Text(stringResource(MR.strings.create_simplex_address), style = MaterialTheme.typography.h2, color = MaterialTheme.colors.primary)
}
}
@@ -108,10 +109,10 @@ private fun CreateAddressButton(onClick: () -> Unit) {
fun ShareAddressButton(onClick: () -> Unit) {
SimpleButtonFrame(onClick) {
Icon(
painterResource(R.drawable.ic_share_filled), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
painterResource(R.drawable.ic_share_filled), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(end = 8.dp).size(18.dp)
)
Text(stringResource(R.string.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary)
Text(stringResource(MR.strings.share_verb), style = MaterialTheme.typography.caption, color = MaterialTheme.colors.primary)
}
}
@@ -119,22 +120,22 @@ fun ShareAddressButton(onClick: () -> Unit) {
fun ShareViaEmailButton(onClick: () -> Unit) {
SimpleButtonFrame(onClick) {
Icon(
painterResource(R.drawable.ic_mail), generalGetString(R.string.share_verb), tint = MaterialTheme.colors.primary,
painterResource(R.drawable.ic_mail), generalGetString(MR.strings.share_verb), tint = MaterialTheme.colors.primary,
modifier = Modifier.padding(end = 8.dp).size(30.dp)
)
Text(stringResource(R.string.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary)
Text(stringResource(MR.strings.invite_friends), style = MaterialTheme.typography.h6, color = MaterialTheme.colors.primary)
}
}
@Composable
private fun ContinueButton(onClick: () -> Unit) {
SimpleButtonIconEnded(stringResource(R.string.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick)
SimpleButtonIconEnded(stringResource(MR.strings.continue_to_next_step), painterResource(R.drawable.ic_chevron_right), click = onClick)
}
@Composable
private fun SkipButton(onClick: () -> Unit) {
SimpleButtonIconEnded(stringResource(R.string.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick)
TextBelowButton(stringResource(R.string.you_can_create_it_later))
SimpleButtonIconEnded(stringResource(MR.strings.dont_create_address), painterResource(R.drawable.ic_chevron_right), click = onClick)
TextBelowButton(stringResource(MR.strings.you_can_create_it_later))
}
@Composable
@@ -1,7 +1,6 @@
package chat.simplex.app.views.onboarding
import android.content.res.Configuration
import androidx.annotation.StringRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
@@ -9,18 +8,19 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.app.R
import chat.simplex.app.SimplexApp
import chat.simplex.app.model.User
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.MarkdownText
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
import dev.icerock.moko.resources.compose.stringResource
@Composable
fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = null) {
@@ -28,15 +28,15 @@ fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = n
.fillMaxWidth()
.padding(horizontal = DEFAULT_PADDING),
) {
AppBarTitle(stringResource(R.string.how_simplex_works), false)
ReadableText(R.string.many_people_asked_how_can_it_deliver)
ReadableText(R.string.to_protect_privacy_simplex_has_ids_for_queues)
ReadableText(R.string.you_control_servers_to_receive_your_contacts_to_send)
ReadableText(R.string.only_client_devices_store_contacts_groups_e2e_encrypted_messages)
AppBarTitle(stringResource(MR.strings.how_simplex_works), false)
ReadableText(MR.strings.many_people_asked_how_can_it_deliver)
ReadableText(MR.strings.to_protect_privacy_simplex_has_ids_for_queues)
ReadableText(MR.strings.you_control_servers_to_receive_your_contacts_to_send)
ReadableText(MR.strings.only_client_devices_store_contacts_groups_e2e_encrypted_messages)
if (onboardingStage == null) {
ReadableTextWithLink(R.string.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme")
ReadableTextWithLink(MR.strings.read_more_in_github_with_link, "https://github.com/simplex-chat/simplex-chat#readme")
} else {
ReadableText(R.string.read_more_in_github)
ReadableText(MR.strings.read_more_in_github)
}
Spacer(Modifier.fillMaxHeight().weight(1f))
@@ -51,12 +51,12 @@ fun HowItWorks(user: User?, onboardingStage: MutableState<OnboardingStage?>? = n
}
@Composable
fun ReadableText(@StringRes stringResId: Int, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp), style: TextStyle = LocalTextStyle.current) {
fun ReadableText(stringResId: StringResource, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp), style: TextStyle = LocalTextStyle.current) {
Text(annotatedStringResource(stringResId), modifier = Modifier.padding(padding), textAlign = textAlign, lineHeight = 22.sp, style = style)
}
@Composable
fun ReadableTextWithLink(@StringRes stringResId: Int, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
fun ReadableTextWithLink(stringResId: StringResource, link: String, textAlign: TextAlign = TextAlign.Start, padding: PaddingValues = PaddingValues(bottom = 12.dp)) {
val annotated = annotatedStringResource(stringResId)
val primary = MaterialTheme.colors.primary
// This replaces links in text highlighted with specific color, e.g. SimplexBlue
@@ -2,7 +2,6 @@ package chat.simplex.app.views.onboarding
import android.Manifest
import android.os.Build
import androidx.annotation.StringRes
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -11,7 +10,7 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -25,6 +24,8 @@ import chat.simplex.app.views.helpers.*
import chat.simplex.app.views.usersettings.NotificationsMode
import chat.simplex.app.views.usersettings.changeNotificationsMode
import com.google.accompanist.permissions.rememberPermissionState
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
@Composable
fun SetNotificationsMode(m: ChatModel) {
@@ -35,18 +36,18 @@ fun SetNotificationsMode(m: ChatModel) {
.padding(vertical = 14.dp)
) {
//CloseSheetBar(null)
AppBarTitle(stringResource(R.string.onboarding_notifications_mode_title))
AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title))
val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) }
Column(Modifier.padding(horizontal = DEFAULT_PADDING * 1f)) {
Text(stringResource(R.string.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
Text(stringResource(MR.strings.onboarding_notifications_mode_subtitle), Modifier.fillMaxWidth(), textAlign = TextAlign.Center)
Spacer(Modifier.height(DEFAULT_PADDING * 2f))
NotificationButton(currentMode, NotificationsMode.OFF, R.string.onboarding_notifications_mode_off, R.string.onboarding_notifications_mode_off_desc)
NotificationButton(currentMode, NotificationsMode.PERIODIC, R.string.onboarding_notifications_mode_periodic, R.string.onboarding_notifications_mode_periodic_desc)
NotificationButton(currentMode, NotificationsMode.SERVICE, R.string.onboarding_notifications_mode_service, R.string.onboarding_notifications_mode_service_desc)
NotificationButton(currentMode, NotificationsMode.OFF, MR.strings.onboarding_notifications_mode_off, MR.strings.onboarding_notifications_mode_off_desc)
NotificationButton(currentMode, NotificationsMode.PERIODIC, MR.strings.onboarding_notifications_mode_periodic, MR.strings.onboarding_notifications_mode_periodic_desc)
NotificationButton(currentMode, NotificationsMode.SERVICE, MR.strings.onboarding_notifications_mode_service, MR.strings.onboarding_notifications_mode_service_desc)
}
Spacer(Modifier.fillMaxHeight().weight(1f))
Box(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING_HALF), contentAlignment = Alignment.Center) {
OnboardingActionButton(R.string.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) {
OnboardingActionButton(MR.strings.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage, false) {
changeNotificationsMode(currentMode.value, m)
}
}
@@ -74,7 +75,7 @@ fun SetNotificationsModeAdditions() {
}
@Composable
private fun NotificationButton(currentMode: MutableState<NotificationsMode>, mode: NotificationsMode, @StringRes title: Int, @StringRes description: Int) {
private fun NotificationButton(currentMode: MutableState<NotificationsMode>, mode: NotificationsMode, title: StringResource, description: StringResource) {
TextButton(
onClick = { currentMode.value = mode },
border = BorderStroke(1.dp, color = if (currentMode.value == mode) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)),
@@ -1,7 +1,6 @@
package chat.simplex.app.views.onboarding
import android.content.res.Configuration
import androidx.annotation.StringRes
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -12,7 +11,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
@@ -23,6 +22,8 @@ import chat.simplex.app.model.ChatModel
import chat.simplex.app.model.User
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.ModalManager
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
@Composable
fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) {
@@ -49,11 +50,11 @@ fun SimpleXInfoLayout(
SimpleXLogo()
}
Text(stringResource(R.string.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center)
Text(stringResource(MR.strings.next_generation_of_private_messaging), style = MaterialTheme.typography.h2, modifier = Modifier.padding(bottom = 48.dp).padding(horizontal = 36.dp), textAlign = TextAlign.Center)
InfoRow(painterResource(R.drawable.privacy), R.string.privacy_redefined, R.string.first_platform_without_user_ids, width = 80.dp)
InfoRow(painterResource(R.drawable.shield), R.string.immune_to_spam_and_abuse, R.string.people_can_connect_only_via_links_you_share)
InfoRow(painterResource(if (isInDarkTheme()) R.drawable.decentralized_light else R.drawable.decentralized), R.string.decentralized, R.string.opensource_protocol_and_code_anybody_can_run_servers)
InfoRow(painterResource(R.drawable.privacy), MR.strings.privacy_redefined, MR.strings.first_platform_without_user_ids, width = 80.dp)
InfoRow(painterResource(R.drawable.shield), MR.strings.immune_to_spam_and_abuse, MR.strings.people_can_connect_only_via_links_you_share)
InfoRow(painterResource(if (isInDarkTheme()) R.drawable.decentralized_light else R.drawable.decentralized), MR.strings.decentralized, MR.strings.opensource_protocol_and_code_anybody_can_run_servers)
Spacer(Modifier.fillMaxHeight().weight(1f))
@@ -69,7 +70,7 @@ fun SimpleXInfoLayout(
.fillMaxWidth()
.padding(bottom = DEFAULT_PADDING.times(1.5f), top = DEFAULT_PADDING), contentAlignment = Alignment.Center
) {
SimpleButtonDecorated(text = stringResource(R.string.how_it_works), icon = painterResource(R.drawable.ic_info),
SimpleButtonDecorated(text = stringResource(MR.strings.how_it_works), icon = painterResource(R.drawable.ic_info),
click = showModal { HowItWorks(user, onboardingStage) })
}
}
@@ -79,7 +80,7 @@ fun SimpleXInfoLayout(
fun SimpleXLogo() {
Image(
painter = painterResource(if (isInDarkTheme()) R.drawable.logo_light else R.drawable.logo),
contentDescription = stringResource(R.string.image_descr_simplex_logo),
contentDescription = stringResource(MR.strings.image_descr_simplex_logo),
modifier = Modifier
.padding(vertical = DEFAULT_PADDING)
.fillMaxWidth(0.60f)
@@ -87,7 +88,7 @@ fun SimpleXLogo() {
}
@Composable
private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: Int, width: Dp = 76.dp) {
private fun InfoRow(icon: Painter, titleId: StringResource, textId: StringResource, width: Dp = 76.dp) {
Row(Modifier.padding(bottom = 27.dp), verticalAlignment = Alignment.Top) {
Image(icon, contentDescription = null, modifier = Modifier
.width(width)
@@ -102,15 +103,15 @@ private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: I
@Composable
fun OnboardingActionButton(user: User?, onboardingStage: MutableState<OnboardingStage?>, onclick: (() -> Unit)? = null) {
if (user == null) {
OnboardingActionButton(R.string.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, true, onclick)
OnboardingActionButton(MR.strings.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, true, onclick)
} else {
OnboardingActionButton(R.string.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, true, onclick)
OnboardingActionButton(MR.strings.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, true, onclick)
}
}
@Composable
fun OnboardingActionButton(
@StringRes labelId: Int,
labelId: StringResource,
onboarding: OnboardingStage?,
onboardingStage: MutableState<OnboardingStage?>,
border: Boolean,
@@ -15,6 +15,7 @@ import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@@ -26,13 +27,15 @@ import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import dev.icerock.moko.resources.StringResource
@Composable
fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
val currentVersion = remember { mutableStateOf(versionDescriptions.lastIndex) }
@Composable
fun featureDescription(icon: Painter, titleId: Int, descrId: Int, link: String?) {
fun featureDescription(icon: Painter, titleId: StringResource, descrId: StringResource, link: String?) {
@Composable
fun linkButton(link: String) {
val uriHandler = LocalUriHandler.current
@@ -115,7 +118,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
.verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(DEFAULT_PADDING.times(0.75f))
) {
AppBarTitle(String.format(generalGetString(R.string.new_in_version), v.version), bottomPadding = DEFAULT_PADDING)
AppBarTitle(String.format(generalGetString(MR.strings.new_in_version), v.version), bottomPadding = DEFAULT_PADDING)
v.features.forEach { feature ->
featureDescription(painterResource(feature.icon), feature.titleId, feature.descrId, feature.link)
@@ -124,9 +127,9 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
val uriHandler = LocalUriHandler.current
if (v.post != null) {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.padding(top = DEFAULT_PADDING.div(4))) {
Text(stringResource(R.string.whats_new_read_more), color = MaterialTheme.colors.primary,
Text(stringResource(MR.strings.whats_new_read_more), color = MaterialTheme.colors.primary,
modifier = Modifier.clickable { uriHandler.openUriCatching(v.post) })
Icon(painterResource(R.drawable.ic_open_in_new), stringResource(R.string.whats_new_read_more), tint = MaterialTheme.colors.primary)
Icon(painterResource(R.drawable.ic_open_in_new), stringResource(MR.strings.whats_new_read_more), tint = MaterialTheme.colors.primary)
}
}
@@ -136,7 +139,7 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
Modifier.fillMaxWidth(), contentAlignment = Alignment.Center
) {
Text(
generalGetString(R.string.ok),
generalGetString(MR.strings.ok),
modifier = Modifier.clickable(onClick = close),
style = MaterialTheme.typography.h3,
color = MaterialTheme.colors.primary
@@ -154,8 +157,8 @@ fun WhatsNewView(viaSettings: Boolean = false, close: () -> Unit) {
private data class FeatureDescription(
val icon: Int,
val titleId: Int,
val descrId: Int,
val titleId: StringResource,
val descrId: StringResource,
val link: String? = null
)
@@ -172,19 +175,19 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_verified_user,
titleId = R.string.v4_2_security_assessment,
descrId = R.string.v4_2_security_assessment_desc,
titleId = MR.strings.v4_2_security_assessment,
descrId = MR.strings.v4_2_security_assessment_desc,
link = "https://simplex.chat/blog/20221108-simplex-chat-v4.2-security-audit-new-website.html"
),
FeatureDescription(
icon = R.drawable.ic_group,
titleId = R.string.v4_2_group_links,
descrId = R.string.v4_2_group_links_desc
titleId = MR.strings.v4_2_group_links,
descrId = MR.strings.v4_2_group_links_desc
),
FeatureDescription(
icon = R.drawable.ic_check,
titleId = R.string.v4_2_auto_accept_contact_requests,
descrId = R.string.v4_2_auto_accept_contact_requests_desc
titleId = MR.strings.v4_2_auto_accept_contact_requests,
descrId = MR.strings.v4_2_auto_accept_contact_requests_desc
),
)
),
@@ -194,23 +197,23 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_mic,
titleId = R.string.v4_3_voice_messages,
descrId = R.string.v4_3_voice_messages_desc
titleId = MR.strings.v4_3_voice_messages,
descrId = MR.strings.v4_3_voice_messages_desc
),
FeatureDescription(
icon = R.drawable.ic_delete_forever,
titleId = R.string.v4_3_irreversible_message_deletion,
descrId = R.string.v4_3_irreversible_message_deletion_desc
titleId = MR.strings.v4_3_irreversible_message_deletion,
descrId = MR.strings.v4_3_irreversible_message_deletion_desc
),
FeatureDescription(
icon = R.drawable.ic_wifi_tethering,
titleId = R.string.v4_3_improved_server_configuration,
descrId = R.string.v4_3_improved_server_configuration_desc
titleId = MR.strings.v4_3_improved_server_configuration,
descrId = MR.strings.v4_3_improved_server_configuration_desc
),
FeatureDescription(
icon = R.drawable.ic_visibility_off,
titleId = R.string.v4_3_improved_privacy_and_security,
descrId = R.string.v4_3_improved_privacy_and_security_desc
titleId = MR.strings.v4_3_improved_privacy_and_security,
descrId = MR.strings.v4_3_improved_privacy_and_security_desc
),
)
),
@@ -220,23 +223,23 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_timer,
titleId = R.string.v4_4_disappearing_messages,
descrId = R.string.v4_4_disappearing_messages_desc
titleId = MR.strings.v4_4_disappearing_messages,
descrId = MR.strings.v4_4_disappearing_messages_desc
),
FeatureDescription(
icon = R.drawable.ic_pending,
titleId = R.string.v4_4_live_messages,
descrId = R.string.v4_4_live_messages_desc
titleId = MR.strings.v4_4_live_messages,
descrId = MR.strings.v4_4_live_messages_desc
),
FeatureDescription(
icon = R.drawable.ic_verified_user,
titleId = R.string.v4_4_verify_connection_security,
descrId = R.string.v4_4_verify_connection_security_desc
titleId = MR.strings.v4_4_verify_connection_security,
descrId = MR.strings.v4_4_verify_connection_security_desc
),
FeatureDescription(
icon = R.drawable.ic_translate,
titleId = R.string.v4_4_french_interface,
descrId = R.string.v4_4_french_interface_descr
titleId = MR.strings.v4_4_french_interface,
descrId = MR.strings.v4_4_french_interface_descr
)
)
),
@@ -246,34 +249,34 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_manage_accounts,
titleId = R.string.v4_5_multiple_chat_profiles,
descrId = R.string.v4_5_multiple_chat_profiles_descr
titleId = MR.strings.v4_5_multiple_chat_profiles,
descrId = MR.strings.v4_5_multiple_chat_profiles_descr
),
FeatureDescription(
icon = R.drawable.ic_edit_note,
titleId = R.string.v4_5_message_draft,
descrId = R.string.v4_5_message_draft_descr
titleId = MR.strings.v4_5_message_draft,
descrId = MR.strings.v4_5_message_draft_descr
),
FeatureDescription(
icon = R.drawable.ic_safety_divider,
titleId = R.string.v4_5_transport_isolation,
descrId = R.string.v4_5_transport_isolation_descr,
titleId = MR.strings.v4_5_transport_isolation,
descrId = MR.strings.v4_5_transport_isolation_descr,
link = "https://simplex.chat/blog/20230204-simplex-chat-v4-5-user-chat-profiles.html#transport-isolation"
),
FeatureDescription(
icon = R.drawable.ic_task,
titleId = R.string.v4_5_private_filenames,
descrId = R.string.v4_5_private_filenames_descr
titleId = MR.strings.v4_5_private_filenames,
descrId = MR.strings.v4_5_private_filenames_descr
),
FeatureDescription(
icon = R.drawable.ic_battery_2_bar,
titleId = R.string.v4_5_reduced_battery_usage,
descrId = R.string.v4_5_reduced_battery_usage_descr
titleId = MR.strings.v4_5_reduced_battery_usage,
descrId = MR.strings.v4_5_reduced_battery_usage_descr
),
FeatureDescription(
icon = R.drawable.ic_translate,
titleId = R.string.v4_5_italian_interface,
descrId = R.string.v4_5_italian_interface_descr,
titleId = MR.strings.v4_5_italian_interface,
descrId = MR.strings.v4_5_italian_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
)
)
@@ -284,33 +287,33 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_lock,
titleId = R.string.v4_6_hidden_chat_profiles,
descrId = R.string.v4_6_hidden_chat_profiles_descr
titleId = MR.strings.v4_6_hidden_chat_profiles,
descrId = MR.strings.v4_6_hidden_chat_profiles_descr
),
FeatureDescription(
icon = R.drawable.ic_flag,
titleId = R.string.v4_6_group_moderation,
descrId = R.string.v4_6_group_moderation_descr
titleId = MR.strings.v4_6_group_moderation,
descrId = MR.strings.v4_6_group_moderation_descr
),
FeatureDescription(
icon = R.drawable.ic_maps_ugc,
titleId = R.string.v4_6_group_welcome_message,
descrId = R.string.v4_6_group_welcome_message_descr
titleId = MR.strings.v4_6_group_welcome_message,
descrId = MR.strings.v4_6_group_welcome_message_descr
),
FeatureDescription(
icon = R.drawable.ic_call,
titleId = R.string.v4_6_audio_video_calls,
descrId = R.string.v4_6_audio_video_calls_descr
titleId = MR.strings.v4_6_audio_video_calls,
descrId = MR.strings.v4_6_audio_video_calls_descr
),
FeatureDescription(
icon = R.drawable.ic_battery_3_bar,
titleId = R.string.v4_6_reduced_battery_usage,
descrId = R.string.v4_6_reduced_battery_usage_descr
titleId = MR.strings.v4_6_reduced_battery_usage,
descrId = MR.strings.v4_6_reduced_battery_usage_descr
),
FeatureDescription(
icon = R.drawable.ic_translate,
titleId = R.string.v4_6_chinese_spanish_interface,
descrId = R.string.v4_6_chinese_spanish_interface_descr,
titleId = MR.strings.v4_6_chinese_spanish_interface,
descrId = MR.strings.v4_6_chinese_spanish_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
)
)
@@ -321,18 +324,18 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_upload_file,
titleId = R.string.v5_0_large_files_support,
descrId = R.string.v5_0_large_files_support_descr
titleId = MR.strings.v5_0_large_files_support,
descrId = MR.strings.v5_0_large_files_support_descr
),
FeatureDescription(
icon = R.drawable.ic_lock,
titleId = R.string.v5_0_app_passcode,
descrId = R.string.v5_0_app_passcode_descr
titleId = MR.strings.v5_0_app_passcode,
descrId = MR.strings.v5_0_app_passcode_descr
),
FeatureDescription(
icon = R.drawable.ic_translate,
titleId = R.string.v5_0_polish_interface,
descrId = R.string.v5_0_polish_interface_descr,
titleId = MR.strings.v5_0_polish_interface,
descrId = MR.strings.v5_0_polish_interface_descr,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
)
)
@@ -349,28 +352,28 @@ private val versionDescriptions: List<VersionDescription> = listOf(
features = listOf(
FeatureDescription(
icon = R.drawable.ic_add_reaction,
titleId = R.string.v5_1_message_reactions,
descrId = R.string.v5_1_message_reactions_descr
titleId = MR.strings.v5_1_message_reactions,
descrId = MR.strings.v5_1_message_reactions_descr
),
FeatureDescription(
icon = R.drawable.ic_chat,
titleId = R.string.v5_1_better_messages,
descrId = R.string.v5_1_better_messages_descr
titleId = MR.strings.v5_1_better_messages,
descrId = MR.strings.v5_1_better_messages_descr
),
FeatureDescription(
icon = R.drawable.ic_light_mode,
titleId = R.string.v5_1_custom_themes,
descrId = R.string.v5_1_custom_themes_descr
titleId = MR.strings.v5_1_custom_themes,
descrId = MR.strings.v5_1_custom_themes_descr
),
FeatureDescription(
icon = R.drawable.ic_lock,
titleId = R.string.v5_1_self_destruct_passcode,
descrId = R.string.v5_1_self_destruct_passcode_descr
titleId = MR.strings.v5_1_self_destruct_passcode,
descrId = MR.strings.v5_1_self_destruct_passcode_descr
),
FeatureDescription(
icon = R.drawable.ic_translate,
titleId = R.string.v5_1_japanese_portuguese_interface,
descrId = R.string.whats_new_thanks_to_users_contribute_weblate,
titleId = MR.strings.v5_1_japanese_portuguese_interface,
descrId = MR.strings.whats_new_thanks_to_users_contribute_weblate,
link = "https://github.com/simplex-chat/simplex-chat/tree/stable#help-translating-simplex-chat"
)
)
@@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -23,6 +23,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import java.text.DecimalFormat
@Composable
@@ -138,45 +139,45 @@ fun AdvancedNetworkSettingsView(chatModel: ChatModel) {
revert: () -> Unit,
save: () -> Unit
) {
val secondsLabel = stringResource(R.string.network_option_seconds_label)
val secondsLabel = stringResource(MR.strings.network_option_seconds_label)
Column(
Modifier
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.network_settings_title))
AppBarTitle(stringResource(MR.strings.network_settings_title))
SectionView {
SectionItemView {
ResetToDefaultsButton(reset, disabled = resetDisabled)
}
SectionItemView {
TimeoutSettingRow(
stringResource(R.string.network_option_tcp_connection_timeout), networkTCPConnectTimeout,
stringResource(MR.strings.network_option_tcp_connection_timeout), networkTCPConnectTimeout,
listOf(2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000), secondsLabel
)
}
SectionItemView {
TimeoutSettingRow(
stringResource(R.string.network_option_protocol_timeout), networkTCPTimeout,
stringResource(MR.strings.network_option_protocol_timeout), networkTCPTimeout,
listOf(1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000), secondsLabel
)
}
SectionItemView {
TimeoutSettingRow(
stringResource(R.string.network_option_protocol_timeout_per_kb), networkTCPTimeoutPerKb,
stringResource(MR.strings.network_option_protocol_timeout_per_kb), networkTCPTimeoutPerKb,
listOf(5_000, 10_000, 20_000, 40_000), secondsLabel
)
}
SectionItemView {
TimeoutSettingRow(
stringResource(R.string.network_option_ping_interval), networkSMPPingInterval,
stringResource(MR.strings.network_option_ping_interval), networkSMPPingInterval,
listOf(120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000), secondsLabel
)
}
SectionItemView {
IntSettingRow(
stringResource(R.string.network_option_ping_count), networkSMPPingCount,
stringResource(MR.strings.network_option_ping_count), networkSMPPingCount,
listOf(1, 2, 3, 5, 8), ""
)
}
@@ -220,7 +221,7 @@ fun ResetToDefaultsButton(reset: () -> Unit, disabled: Boolean) {
verticalAlignment = Alignment.CenterVertically
) {
val color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
Text(stringResource(R.string.network_options_reset_to_defaults), color = color)
Text(stringResource(MR.strings.network_options_reset_to_defaults), color = color)
}
}
@@ -233,7 +234,7 @@ fun EnableKeepAliveSwitch(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(stringResource(R.string.network_option_enable_tcp_keep_alive))
Text(stringResource(MR.strings.network_option_enable_tcp_keep_alive))
DefaultSwitch(
checked = networkEnableKeepAlive.value,
onCheckedChange = { networkEnableKeepAlive.value = it },
@@ -272,7 +273,7 @@ fun IntSettingRow(title: String, selection: MutableState<Int>, values: List<Int>
Spacer(Modifier.size(4.dp))
Icon(
if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less),
generalGetString(R.string.invite_to_group_button),
generalGetString(MR.strings.invite_to_group_button),
modifier = Modifier.padding(start = 8.dp),
tint = MaterialTheme.colors.secondary
)
@@ -333,7 +334,7 @@ fun TimeoutSettingRow(title: String, selection: MutableState<Long>, values: List
Spacer(Modifier.size(4.dp))
Icon(
if (!expanded.value) painterResource(R.drawable.ic_expand_more) else painterResource(R.drawable.ic_expand_less),
generalGetString(R.string.invite_to_group_button),
generalGetString(MR.strings.invite_to_group_button),
modifier = Modifier.padding(start = 8.dp),
tint = MaterialTheme.colors.secondary
)
@@ -368,8 +369,8 @@ fun SettingsSectionFooter(revert: () -> Unit, save: () -> Unit, disabled: Boolea
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.network_options_revert), revert, disabled)
FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.network_options_save), save, disabled)
FooterButton(painterResource(R.drawable.ic_replay), stringResource(MR.strings.network_options_revert), revert, disabled)
FooterButton(painterResource(R.drawable.ic_check), stringResource(MR.strings.network_options_save), save, disabled)
}
}
@@ -399,9 +400,9 @@ fun FooterButton(icon: Painter, title: String, action: () -> Unit, disabled: Boo
fun showUpdateNetworkSettingsDialog(action: () -> Unit) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.update_network_settings_question),
text = generalGetString(R.string.updating_settings_will_reconnect_client_to_all_servers),
confirmText = generalGetString(R.string.update_network_settings_confirmation),
title = generalGetString(MR.strings.update_network_settings_question),
text = generalGetString(MR.strings.updating_settings_will_reconnect_client_to_all_servers),
confirmText = generalGetString(MR.strings.update_network_settings_confirmation),
onConfirm = action
)
}
@@ -32,7 +32,7 @@ import androidx.compose.ui.graphics.*
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
@@ -43,6 +43,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import com.godaddy.android.colorpicker.*
import chat.simplex.res.MR
import kotlinx.coroutines.delay
import kotlinx.serialization.encodeToString
import java.io.BufferedOutputStream
@@ -100,14 +101,14 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) ->
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.appearance_settings))
SectionView(stringResource(R.string.settings_section_title_language), padding = PaddingValues()) {
AppBarTitle(stringResource(MR.strings.appearance_settings))
SectionView(stringResource(MR.strings.settings_section_title_language), padding = PaddingValues()) {
val context = LocalContext.current
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// SectionItemWithValue(
// generalGetString(R.string.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() },
// generalGetString(MR.strings.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() },
// remember { mutableStateOf("system") },
// listOf(ValueTitleDesc("system", generalGetString(R.string.change_verb), "")),
// listOf(ValueTitleDesc("system", generalGetString(MR.strings.change_verb), "")),
// onSelected = { openSystemLangPicker(context as? Activity ?: return@SectionItemWithValue) }
// )
// } else {
@@ -130,7 +131,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) ->
}
SectionDividerSpaced()
SectionView(stringResource(R.string.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) {
SectionView(stringResource(MR.strings.settings_section_title_icon), padding = PaddingValues(horizontal = DEFAULT_PADDING_HALF)) {
LazyRow {
items(AppIcon.values().size, { index -> AppIcon.values()[index] }) { index ->
val item = AppIcon.values()[index]
@@ -155,7 +156,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) ->
SectionDividerSpaced(maxTopPadding = true)
val currentTheme by CurrentColors.collectAsState()
SectionView(stringResource(R.string.settings_section_title_themes)) {
SectionView(stringResource(MR.strings.settings_section_title_themes)) {
val darkTheme = isSystemInDarkTheme()
val state = remember { derivedStateOf { currentTheme.name } }
ThemeSelector(state) {
@@ -167,7 +168,7 @@ fun AppearanceView(m: ChatModel, showSettingsModal: (@Composable (ChatModel) ->
}
}
}
SectionItemView(showSettingsModal { _ -> CustomizeThemeView(editColor) }) { Text(stringResource(R.string.customize_theme_title)) }
SectionItemView(showSettingsModal { _ -> CustomizeThemeView(editColor) }) { Text(stringResource(MR.strings.customize_theme_title)) }
SectionBottomSpacer()
}
}
@@ -179,51 +180,51 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
) {
val currentTheme by CurrentColors.collectAsState()
AppBarTitle(stringResource(R.string.customize_theme_title))
AppBarTitle(stringResource(MR.strings.customize_theme_title))
SectionView(stringResource(R.string.theme_colors_section_title)) {
SectionView(stringResource(MR.strings.theme_colors_section_title)) {
SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY, currentTheme.colors.primary) }) {
val title = generalGetString(R.string.color_primary)
val title = generalGetString(MR.strings.color_primary)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primary)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.PRIMARY_VARIANT, currentTheme.colors.primaryVariant) }) {
val title = generalGetString(R.string.color_primary_variant)
val title = generalGetString(MR.strings.color_primary_variant)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.primaryVariant)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY, currentTheme.colors.secondary) }) {
val title = generalGetString(R.string.color_secondary)
val title = generalGetString(MR.strings.color_secondary)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondary)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SECONDARY_VARIANT, currentTheme.colors.secondaryVariant) }) {
val title = generalGetString(R.string.color_secondary_variant)
val title = generalGetString(MR.strings.color_secondary_variant)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.secondaryVariant)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.BACKGROUND, currentTheme.colors.background) }) {
val title = generalGetString(R.string.color_background)
val title = generalGetString(MR.strings.color_background)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.background)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SURFACE, currentTheme.colors.surface) }) {
val title = generalGetString(R.string.color_surface)
val title = generalGetString(MR.strings.color_surface)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = colors.surface)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.TITLE, currentTheme.appColors.title) }) {
val title = generalGetString(R.string.color_title)
val title = generalGetString(MR.strings.color_title)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.title)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.SENT_MESSAGE, currentTheme.appColors.sentMessage) }) {
val title = generalGetString(R.string.color_sent_message)
val title = generalGetString(MR.strings.color_sent_message)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.sentMessage)
}
SectionItemViewSpaceBetween({ editColor(ThemeColor.RECEIVED_MESSAGE, currentTheme.appColors.receivedMessage) }) {
val title = generalGetString(R.string.color_received_message)
val title = generalGetString(MR.strings.color_received_message)
Text(title)
Icon(painterResource(R.drawable.ic_circle_filled), title, tint = currentTheme.appColors.receivedMessage)
}
@@ -231,7 +232,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
val isInDarkTheme = isInDarkTheme()
if (currentTheme.base.hasChangedAnyColor(currentTheme.colors, currentTheme.appColors)) {
SectionItemView({ ThemeManager.resetAllThemeColors(darkForSystemTheme = isInDarkTheme) }) {
Text(generalGetString(R.string.reset_color), color = colors.primary)
Text(generalGetString(MR.strings.reset_color), color = colors.primary)
}
}
SectionSpacer()
@@ -243,7 +244,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
theme.value = yaml.encodeToString<ThemeOverrides>(overrides)
exportThemeLauncher.launch("simplex.theme")
}) {
Text(generalGetString(R.string.export_theme), color = colors.primary)
Text(generalGetString(MR.strings.export_theme), color = colors.primary)
}
val importThemeLauncher = rememberGetContentLauncher { uri: Uri? ->
@@ -256,7 +257,7 @@ fun CustomizeThemeView(editColor: (ThemeColor, Color) -> Unit) {
}
// Can not limit to YAML mime type since it's unsupported by Android
SectionItemView({ importThemeLauncher.launch("*/*") }) {
Text(generalGetString(R.string.import_theme), color = colors.primary)
Text(generalGetString(MR.strings.import_theme), color = colors.primary)
}
}
SectionBottomSpacer()
@@ -289,7 +290,7 @@ fun ColorEditor(
Modifier.align(Alignment.CenterHorizontally),
colors = ButtonDefaults.textButtonColors(contentColor = currentColor)
) {
Text(generalGetString(R.string.save_color))
Text(generalGetString(MR.strings.save_color))
}
}
}
@@ -312,7 +313,7 @@ fun ColorPicker(initialColor: Color, onColorChanged: (Color) -> Unit) {
private fun LangSelector(state: State<String>, onSelected: (String) -> Unit) {
// Should be the same as in app/build.gradle's `android.defaultConfig.resConfigs`
val supportedLanguages = mapOf(
"system" to generalGetString(R.string.language_system),
"system" to generalGetString(MR.strings.language_system),
"en" to "English",
"cs" to "Čeština",
"de" to "Deutsch",
@@ -328,7 +329,7 @@ private fun LangSelector(state: State<String>, onSelected: (String) -> Unit) {
)
val values by remember { mutableStateOf(supportedLanguages.map { it.key to it.value }) }
ExposedDropDownSettingRow(
generalGetString(R.string.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() },
generalGetString(MR.strings.settings_section_title_language).lowercase().replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() },
values,
state,
icon = null,
@@ -342,7 +343,7 @@ private fun ThemeSelector(state: State<String>, onSelected: (String) -> Unit) {
val darkTheme = isSystemInDarkTheme()
val values by remember { mutableStateOf(ThemeManager.allThemes(darkTheme).map { it.second.name to it.third }) }
ExposedDropDownSettingRow(
generalGetString(R.string.theme),
generalGetString(MR.strings.theme),
values,
state,
icon = null,
@@ -355,12 +356,12 @@ private fun ThemeSelector(state: State<String>, onSelected: (String) -> Unit) {
private fun DarkThemeSelector(state: State<String?>, onSelected: (String) -> Unit) {
val values by remember {
val darkThemes = ArrayList<Pair<String, String>>()
darkThemes.add(DefaultTheme.DARK.name to generalGetString(R.string.theme_dark))
darkThemes.add(DefaultTheme.SIMPLEX.name to generalGetString(R.string.theme_simplex))
darkThemes.add(DefaultTheme.DARK.name to generalGetString(MR.strings.theme_dark))
darkThemes.add(DefaultTheme.SIMPLEX.name to generalGetString(MR.strings.theme_simplex))
mutableStateOf(darkThemes.toList())
}
ExposedDropDownSettingRow(
generalGetString(R.string.dark_theme),
generalGetString(MR.strings.dark_theme),
values,
state,
icon = null,
@@ -388,12 +389,12 @@ private fun rememberSaveThemeLauncher(theme: MutableState<String?>): ManagedActi
BufferedOutputStream(stream).use { outputStream ->
theme.byteInputStream().use { it.copyTo(outputStream) }
}
Toast.makeText(cxt, generalGetString(R.string.file_saved), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.file_saved), Toast.LENGTH_SHORT).show()
}
}
}
} catch (e: Error) {
Toast.makeText(cxt, generalGetString(R.string.error_saving_file), Toast.LENGTH_SHORT).show()
Toast.makeText(cxt, generalGetString(MR.strings.error_saving_file), Toast.LENGTH_SHORT).show()
Log.e(TAG, "rememberSaveThemeLauncher error saving theme $e")
} finally {
theme.value = null
@@ -12,11 +12,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun CallSettingsView(m: ChatModel,
@@ -39,20 +40,20 @@ fun CallSettingsLayout(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
AppBarTitle(stringResource(R.string.your_calls))
AppBarTitle(stringResource(MR.strings.your_calls))
val lockCallState = remember { mutableStateOf(callOnLockScreen.get()) }
SectionView(stringResource(R.string.settings_section_title_settings)) {
SectionItemView(editIceServers) { Text(stringResource(R.string.webrtc_ice_servers)) }
SectionView(stringResource(MR.strings.settings_section_title_settings)) {
SectionItemView(editIceServers) { Text(stringResource(MR.strings.webrtc_ice_servers)) }
val enabled = remember { mutableStateOf(true) }
LockscreenOpts(lockCallState, enabled, onSelected = { callOnLockScreen.set(it); lockCallState.value = it })
SettingsPreferenceItem(null, stringResource(R.string.always_use_relay), webrtcPolicyRelay)
SettingsPreferenceItem(null, stringResource(MR.strings.always_use_relay), webrtcPolicyRelay)
}
SectionTextFooter(
if (remember { webrtcPolicyRelay.state }.value) {
generalGetString(R.string.relay_server_protects_ip)
generalGetString(MR.strings.relay_server_protects_ip)
} else {
generalGetString(R.string.relay_server_if_necessary)
generalGetString(MR.strings.relay_server_if_necessary)
}
)
SectionBottomSpacer()
@@ -64,14 +65,14 @@ private fun LockscreenOpts(lockscreenOpts: State<CallOnLockScreen>, enabled: Sta
val values = remember {
CallOnLockScreen.values().map {
when (it) {
CallOnLockScreen.DISABLE -> it to generalGetString(R.string.no_call_on_lock_screen)
CallOnLockScreen.SHOW -> it to generalGetString(R.string.show_call_on_lock_screen)
CallOnLockScreen.ACCEPT -> it to generalGetString(R.string.accept_call_on_lock_screen)
CallOnLockScreen.DISABLE -> it to generalGetString(MR.strings.no_call_on_lock_screen)
CallOnLockScreen.SHOW -> it to generalGetString(MR.strings.show_call_on_lock_screen)
CallOnLockScreen.ACCEPT -> it to generalGetString(MR.strings.accept_call_on_lock_screen)
}
}
}
ExposedDropDownSettingRow(
generalGetString(R.string.call_on_lock_screen),
generalGetString(MR.strings.call_on_lock_screen),
values,
lockscreenOpts,
icon = null,
@@ -8,6 +8,7 @@ import chat.simplex.app.R
import chat.simplex.app.TAG
import chat.simplex.app.views.helpers.AlertManager
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
import java.security.KeyStore
import javax.crypto.*
import javax.crypto.spec.GCMParameterSpec
@@ -24,8 +25,8 @@ internal class Cryptor {
// Repeated calls will not show the alert again
warningShown = true
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.wrong_passphrase),
text = generalGetString(R.string.restore_passphrase_not_found_desc)
title = generalGetString(MR.strings.wrong_passphrase),
text = generalGetString(MR.strings.restore_passphrase_not_found_desc)
)
}
return null
@@ -11,11 +11,12 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.views.TerminalView
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun DeveloperView(
@@ -25,18 +26,18 @@ fun DeveloperView(
) {
Column(Modifier.fillMaxWidth().verticalScroll(rememberScrollState())) {
val uriHandler = LocalUriHandler.current
AppBarTitle(stringResource(R.string.settings_developer_tools))
AppBarTitle(stringResource(MR.strings.settings_developer_tools))
val developerTools = m.controller.appPrefs.developerTools
val devTools = remember { developerTools.state }
SectionView() {
InstallTerminalAppItem(uriHandler)
ChatConsoleItem { withAuth(generalGetString(R.string.auth_open_chat_console), generalGetString(R.string.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) })}
SettingsPreferenceItem(painterResource(R.drawable.ic_drive_folder_upload), stringResource(R.string.confirm_database_upgrades), m.controller.appPrefs.confirmDBUpgrades)
SettingsPreferenceItem(painterResource(R.drawable.ic_code), stringResource(R.string.show_developer_options), developerTools)
ChatConsoleItem { withAuth(generalGetString(MR.strings.auth_open_chat_console), generalGetString(MR.strings.auth_log_in_using_credential), showCustomModal { it, close -> TerminalView(it, close) })}
SettingsPreferenceItem(painterResource(R.drawable.ic_drive_folder_upload), stringResource(MR.strings.confirm_database_upgrades), m.controller.appPrefs.confirmDBUpgrades)
SettingsPreferenceItem(painterResource(R.drawable.ic_code), stringResource(MR.strings.show_developer_options), developerTools)
}
SectionTextFooter(
generalGetString(if (devTools.value) R.string.show_dev_options else R.string.hide_dev_options) + " " +
generalGetString(R.string.developer_options)
generalGetString(if (devTools.value) MR.strings.show_dev_options else MR.strings.hide_dev_options) + " " +
generalGetString(MR.strings.developer_options)
)
SectionBottomSpacer()
}
@@ -7,13 +7,14 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.tooling.preview.Preview
import chat.simplex.app.R
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.app.views.chatlist.ChatHelpView
import chat.simplex.app.views.helpers.AppBarTitle
import chat.simplex.res.MR
@Composable
fun HelpView(userDisplayName: String) {
@@ -28,7 +29,7 @@ fun HelpLayout(userDisplayName: String) {
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING),
){
AppBarTitle(String.format(stringResource(R.string.personal_welcome), userDisplayName), false)
AppBarTitle(String.format(stringResource(MR.strings.personal_welcome), userDisplayName), false)
ChatHelpView()
}
}
@@ -13,7 +13,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
@@ -22,6 +22,7 @@ import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chatlist.UserProfileRow
import chat.simplex.app.views.database.PassphraseField
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun HiddenProfileView(
@@ -39,7 +40,7 @@ fun HiddenProfileView(
close()
} catch (e: Exception) {
AlertManager.shared.showAlertMsg(
title = generalGetString(R.string.error_saving_user_password),
title = generalGetString(MR.strings.error_saving_user_password),
text = e.stackTraceToString()
)
}
@@ -58,7 +59,7 @@ private fun HiddenProfileLayout(
.fillMaxWidth()
.verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.hide_profile))
AppBarTitle(stringResource(MR.strings.hide_profile))
SectionView(padding = PaddingValues(start = 8.dp, end = DEFAULT_PADDING)) {
UserProfileRow(user)
}
@@ -69,18 +70,18 @@ private fun HiddenProfileLayout(
val passwordValid by remember { derivedStateOf { hidePassword.value == hidePassword.value.trim() } }
val confirmValid by remember { derivedStateOf { confirmHidePassword.value == "" || hidePassword.value == confirmHidePassword.value } }
val saveDisabled by remember { derivedStateOf { hidePassword.value == "" || !passwordValid || confirmHidePassword.value == "" || !confirmValid } }
SectionView(stringResource(R.string.hidden_profile_password).uppercase()) {
SectionView(stringResource(MR.strings.hidden_profile_password).uppercase()) {
SectionItemView {
PassphraseField(hidePassword, generalGetString(R.string.password_to_show), isValid = { passwordValid }, showStrength = true)
PassphraseField(hidePassword, generalGetString(MR.strings.password_to_show), isValid = { passwordValid }, showStrength = true)
}
SectionItemView {
PassphraseField(confirmHidePassword, stringResource(R.string.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword)
PassphraseField(confirmHidePassword, stringResource(MR.strings.confirm_password), isValid = { confirmValid }, dependsOn = hidePassword)
}
SectionItemViewSpaceBetween({ saveProfilePassword(hidePassword.value) }, disabled = saveDisabled, minHeight = TextFieldDefaults.MinHeight) {
Text(generalGetString(R.string.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(generalGetString(MR.strings.save_profile_password), color = if (saveDisabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
SectionTextFooter(stringResource(R.string.to_reveal_profile_enter_password))
SectionTextFooter(stringResource(MR.strings.to_reveal_profile_enter_password))
SectionBottomSpacer()
}
}
@@ -6,12 +6,13 @@ import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp
import chat.simplex.app.R
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.views.helpers.AppBarTitle
import chat.simplex.app.views.helpers.generalGetString
import chat.simplex.res.MR
@Composable
fun IncognitoView() {
@@ -21,17 +22,17 @@ fun IncognitoView() {
@Composable
fun IncognitoLayout() {
Column {
AppBarTitle(stringResource(R.string.settings_section_title_incognito))
AppBarTitle(stringResource(MR.strings.settings_section_title_incognito))
Column(
Modifier
.verticalScroll(rememberScrollState())
.padding(horizontal = DEFAULT_PADDING),
verticalArrangement = Arrangement.spacedBy(20.dp)
) {
Text(generalGetString(R.string.incognito_info_protects))
Text(generalGetString(R.string.incognito_info_allows))
Text(generalGetString(R.string.incognito_info_share))
Text(generalGetString(R.string.incognito_info_find))
Text(generalGetString(MR.strings.incognito_info_protects))
Text(generalGetString(MR.strings.incognito_info_allows))
Text(generalGetString(MR.strings.incognito_info_share))
Text(generalGetString(MR.strings.incognito_info_find))
SectionBottomSpacer()
}
}
@@ -9,7 +9,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -18,6 +18,7 @@ import chat.simplex.app.model.Format
import chat.simplex.app.model.FormatColor
import chat.simplex.app.ui.theme.DEFAULT_PADDING
import chat.simplex.app.ui.theme.SimpleXTheme
import chat.simplex.res.MR
@Composable
fun MarkdownHelpView() {
@@ -25,14 +26,14 @@ fun MarkdownHelpView() {
Modifier
.fillMaxWidth()
) {
Text(stringResource(R.string.you_can_use_markdown_to_format_messages__prompt))
Text(stringResource(MR.strings.you_can_use_markdown_to_format_messages__prompt))
Spacer(Modifier.height(DEFAULT_PADDING))
val bold = stringResource(R.string.bold)
val italic = stringResource(R.string.italic)
val strikethrough = stringResource(R.string.strikethrough)
val equation = stringResource(R.string.a_plus_b)
val colored = stringResource(R.string.colored)
val secret = stringResource(R.string.secret)
val bold = stringResource(MR.strings.bold_text)
val italic = stringResource(MR.strings.italic_text)
val strikethrough = stringResource(MR.strings.strikethrough_text)
val equation = stringResource(MR.strings.a_plus_b)
val colored = stringResource(MR.strings.colored_text)
val secret = stringResource(MR.strings.secret_text)
MdFormat("*$bold*", bold, Format.Bold())
MdFormat("_${italic}_", italic, Format.Italic())
@@ -16,7 +16,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.*
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
@@ -29,6 +29,7 @@ import chat.simplex.app.model.*
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.chat.item.ClickableText
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun NetworkAndServersView(
@@ -61,9 +62,9 @@ fun NetworkAndServersView(
toggleSocksProxy = { enable ->
if (enable) {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.network_enable_socks),
text = generalGetString(R.string.network_enable_socks_info).format(proxyPort.value),
confirmText = generalGetString(R.string.confirm_verb),
title = generalGetString(MR.strings.network_enable_socks),
text = generalGetString(MR.strings.network_enable_socks_info).format(proxyPort.value),
confirmText = generalGetString(MR.strings.confirm_verb),
onConfirm = {
withApi {
val conf = NetCfg.proxyDefaults.withHostPort(chatModel.controller.appPrefs.networkProxyHostPort.get())
@@ -76,9 +77,9 @@ fun NetworkAndServersView(
)
} else {
AlertManager.shared.showAlertDialog(
title = generalGetString(R.string.network_disable_socks),
text = generalGetString(R.string.network_disable_socks_info),
confirmText = generalGetString(R.string.confirm_verb),
title = generalGetString(MR.strings.network_disable_socks),
text = generalGetString(MR.strings.network_disable_socks_info),
confirmText = generalGetString(MR.strings.confirm_verb),
onConfirm = {
withApi {
val conf = NetCfg.defaults
@@ -96,12 +97,12 @@ fun NetworkAndServersView(
val prevValue = onionHosts.value
onionHosts.value = it
val startsWith = when (it) {
OnionHosts.NEVER -> generalGetString(R.string.network_use_onion_hosts_no_desc_in_alert)
OnionHosts.PREFER -> generalGetString(R.string.network_use_onion_hosts_prefer_desc_in_alert)
OnionHosts.REQUIRED -> generalGetString(R.string.network_use_onion_hosts_required_desc_in_alert)
OnionHosts.NEVER -> generalGetString(MR.strings.network_use_onion_hosts_no_desc_in_alert)
OnionHosts.PREFER -> generalGetString(MR.strings.network_use_onion_hosts_prefer_desc_in_alert)
OnionHosts.REQUIRED -> generalGetString(MR.strings.network_use_onion_hosts_required_desc_in_alert)
}
showUpdateNetworkSettingsDialog(
title = generalGetString(R.string.update_onion_hosts_settings_question),
title = generalGetString(MR.strings.update_onion_hosts_settings_question),
startsWith,
onDismiss = {
onionHosts.value = prevValue
@@ -124,11 +125,11 @@ fun NetworkAndServersView(
val prevValue = sessionMode.value
sessionMode.value = it
val startsWith = when (it) {
TransportSessionMode.User -> generalGetString(R.string.network_session_mode_user_description)
TransportSessionMode.Entity -> generalGetString(R.string.network_session_mode_entity_description)
TransportSessionMode.User -> generalGetString(MR.strings.network_session_mode_user_description)
TransportSessionMode.Entity -> generalGetString(MR.strings.network_session_mode_entity_description)
}
showUpdateNetworkSettingsDialog(
title = generalGetString(R.string.update_network_session_mode_question),
title = generalGetString(MR.strings.update_network_session_mode_question),
startsWith,
onDismiss = { sessionMode.value = prevValue }
) {
@@ -164,28 +165,28 @@ fun NetworkAndServersView(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
AppBarTitle(stringResource(R.string.network_and_servers))
SectionView(generalGetString(R.string.settings_section_title_messages)) {
SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(R.string.smp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.SMP, close) })
AppBarTitle(stringResource(MR.strings.network_and_servers))
SectionView(generalGetString(MR.strings.settings_section_title_messages)) {
SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(MR.strings.smp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.SMP, close) })
SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(R.string.xftp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.XFTP, close) })
SettingsActionItem(painterResource(R.drawable.ic_dns), stringResource(MR.strings.xftp_servers), showCustomModal { m, close -> ProtocolServersView(m, ServerProtocol.XFTP, close) })
UseSocksProxySwitch(networkUseSocksProxy, proxyPort, toggleSocksProxy, showSettingsModal)
UseOnionHosts(onionHosts, networkUseSocksProxy, showSettingsModal, useOnion)
if (developerTools) {
SessionModePicker(sessionMode, showSettingsModal, updateSessionMode)
}
SettingsActionItem(painterResource(R.drawable.ic_cable), stringResource(R.string.network_settings), showSettingsModal { AdvancedNetworkSettingsView(it) })
SettingsActionItem(painterResource(R.drawable.ic_cable), stringResource(MR.strings.network_settings), showSettingsModal { AdvancedNetworkSettingsView(it) })
}
if (networkUseSocksProxy.value) {
SectionCustomFooter { Text(annotatedStringResource(R.string.disable_onion_hosts_when_not_supported)) }
SectionCustomFooter { Text(annotatedStringResource(MR.strings.disable_onion_hosts_when_not_supported)) }
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 32.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
} else {
Divider(Modifier.padding(start = DEFAULT_PADDING_HALF, top = 24.dp, end = DEFAULT_PADDING_HALF, bottom = 30.dp))
}
SectionView(generalGetString(R.string.settings_section_title_calls)) {
SettingsActionItem(painterResource(R.drawable.ic_electrical_services), stringResource(R.string.webrtc_ice_servers), showModal { RTCServersView(it) })
SectionView(generalGetString(MR.strings.settings_section_title_calls)) {
SettingsActionItem(painterResource(R.drawable.ic_electrical_services), stringResource(MR.strings.webrtc_ice_servers), showModal { RTCServersView(it) })
}
SectionBottomSpacer()
}
@@ -209,15 +210,15 @@ fun UseSocksProxySwitch(
) {
Icon(
painterResource(R.drawable.ic_settings_ethernet),
stringResource(R.string.network_socks_toggle_use_socks_proxy),
stringResource(MR.strings.network_socks_toggle_use_socks_proxy),
tint = MaterialTheme.colors.secondary
)
TextIconSpaced(false)
val text = buildAnnotatedString {
append(generalGetString(R.string.network_socks_toggle_use_socks_proxy) + " (")
append(generalGetString(MR.strings.network_socks_toggle_use_socks_proxy) + " (")
val style = SpanStyle(color = MaterialTheme.colors.primary)
withAnnotation(tag = "PORT", annotation = generalGetString(R.string.network_proxy_port).format(proxyPort.value)) {
withStyle(style) { append(generalGetString(R.string.network_proxy_port).format(proxyPort.value)) }
withAnnotation(tag = "PORT", annotation = generalGetString(MR.strings.network_proxy_port).format(proxyPort.value)) {
withStyle(style) { append(generalGetString(MR.strings.network_proxy_port).format(proxyPort.value)) }
}
append(")")
}
@@ -250,7 +251,7 @@ fun SockProxySettings(m: ChatModel) {
.verticalScroll(rememberScrollState())
) {
val defaultHostPort = remember { "localhost:9050" }
AppBarTitle(generalGetString(R.string.network_socks_proxy_settings))
AppBarTitle(generalGetString(MR.strings.network_socks_proxy_settings))
val hostPort by remember { m.controller.appPrefs.networkProxyHostPort.state }
val hostUnsaved = rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(hostPort?.split(":")?.firstOrNull() ?: "localhost"))
@@ -289,7 +290,7 @@ fun SockProxySettings(m: ChatModel) {
SectionItemView {
DefaultConfigurableTextField(
hostUnsaved,
stringResource(R.string.host_verb),
stringResource(MR.strings.host_verb),
modifier = Modifier,
isValid = ::validHost,
keyboardActions = KeyboardActions(onNext = { defaultKeyboardAction(ImeAction.Next) }),
@@ -299,7 +300,7 @@ fun SockProxySettings(m: ChatModel) {
SectionItemView {
DefaultConfigurableTextField(
portUnsaved,
stringResource(R.string.port_verb),
stringResource(MR.strings.port_verb),
modifier = Modifier,
isValid = ::validPort,
keyboardActions = KeyboardActions(onDone = { defaultKeyboardAction(ImeAction.Done); save() }),
@@ -336,9 +337,9 @@ private fun UseOnionHosts(
val values = remember {
OnionHosts.values().map {
when (it) {
OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(R.string.network_use_onion_hosts_no), generalGetString(R.string.network_use_onion_hosts_no_desc))
OnionHosts.PREFER -> ValueTitleDesc(OnionHosts.PREFER, generalGetString(R.string.network_use_onion_hosts_prefer), generalGetString(R.string.network_use_onion_hosts_prefer_desc))
OnionHosts.REQUIRED -> ValueTitleDesc(OnionHosts.REQUIRED, generalGetString(R.string.network_use_onion_hosts_required), generalGetString(R.string.network_use_onion_hosts_required_desc))
OnionHosts.NEVER -> ValueTitleDesc(OnionHosts.NEVER, generalGetString(MR.strings.network_use_onion_hosts_no), generalGetString(MR.strings.network_use_onion_hosts_no_desc))
OnionHosts.PREFER -> ValueTitleDesc(OnionHosts.PREFER, generalGetString(MR.strings.network_use_onion_hosts_prefer), generalGetString(MR.strings.network_use_onion_hosts_prefer_desc))
OnionHosts.REQUIRED -> ValueTitleDesc(OnionHosts.REQUIRED, generalGetString(MR.strings.network_use_onion_hosts_required), generalGetString(MR.strings.network_use_onion_hosts_required_desc))
}
}
}
@@ -346,13 +347,13 @@ private fun UseOnionHosts(
Column(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(R.string.network_use_onion_hosts))
AppBarTitle(stringResource(MR.strings.network_use_onion_hosts))
SectionViewSelectable(null, onionHosts, values, useOnion)
}
}
SectionItemWithValue(
generalGetString(R.string.network_use_onion_hosts),
generalGetString(MR.strings.network_use_onion_hosts),
onionHosts,
values,
icon = painterResource(R.drawable.ic_security),
@@ -370,14 +371,14 @@ private fun SessionModePicker(
val values = remember {
TransportSessionMode.values().map {
when (it) {
TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(R.string.network_session_mode_user), generalGetString(R.string.network_session_mode_user_description))
TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(R.string.network_session_mode_entity), generalGetString(R.string.network_session_mode_entity_description))
TransportSessionMode.User -> ValueTitleDesc(TransportSessionMode.User, generalGetString(MR.strings.network_session_mode_user), generalGetString(MR.strings.network_session_mode_user_description))
TransportSessionMode.Entity -> ValueTitleDesc(TransportSessionMode.Entity, generalGetString(MR.strings.network_session_mode_entity), generalGetString(MR.strings.network_session_mode_entity_description))
}
}
}
SectionItemWithValue(
generalGetString(R.string.network_session_mode_transport_isolation),
generalGetString(MR.strings.network_session_mode_transport_isolation),
sessionMode,
values,
icon = painterResource(R.drawable.ic_safety_divider),
@@ -385,7 +386,7 @@ private fun SessionModePicker(
Column(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(R.string.network_session_mode_transport_isolation))
AppBarTitle(stringResource(MR.strings.network_session_mode_transport_isolation))
SectionViewSelectable(null, sessionMode, values, updateSessionMode)
}
}
@@ -399,8 +400,8 @@ private fun NetworkSectionFooter(revert: () -> Unit, save: () -> Unit, revertDis
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
FooterButton(painterResource(R.drawable.ic_replay), stringResource(R.string.network_options_revert), revert, revertDisabled)
FooterButton(painterResource(R.drawable.ic_check), stringResource(R.string.network_options_save), save, saveDisabled)
FooterButton(painterResource(R.drawable.ic_replay), stringResource(MR.strings.network_options_revert), revert, revertDisabled)
FooterButton(painterResource(R.drawable.ic_check), stringResource(MR.strings.network_options_save), save, saveDisabled)
}
}
@@ -420,14 +421,14 @@ private fun validPort(s: String): Boolean {
private fun showUpdateNetworkSettingsDialog(
title: String,
startsWith: String = "",
message: String = generalGetString(R.string.updating_settings_will_reconnect_client_to_all_servers),
message: String = generalGetString(MR.strings.updating_settings_will_reconnect_client_to_all_servers),
onDismiss: () -> Unit,
onConfirm: () -> Unit
) {
AlertManager.shared.showAlertDialog(
title = title,
text = startsWith + "\n\n" + message,
confirmText = generalGetString(R.string.update_network_settings_confirmation),
confirmText = generalGetString(MR.strings.update_network_settings_confirmation),
onDismiss = onDismiss,
onConfirm = onConfirm,
onDismissRequest = onDismiss
@@ -11,7 +11,7 @@ import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.capitalize
import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.text.style.TextOverflow
@@ -20,6 +20,7 @@ import chat.simplex.app.R
import chat.simplex.app.model.ChatModel
import chat.simplex.app.ui.theme.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
import kotlinx.coroutines.*
import kotlin.collections.ArrayList
@@ -81,9 +82,9 @@ fun NotificationsSettingsLayout(
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.notifications))
AppBarTitle(stringResource(MR.strings.notifications))
SectionView(null) {
SettingsActionItemWithContent(null, stringResource(R.string.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) {
SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notifications_mode_title), { showPage(CurrentPage.NOTIFICATIONS_MODE) }) {
Text(
modes.first { it.value == notificationsMode.value }.title,
maxLines = 1,
@@ -91,7 +92,7 @@ fun NotificationsSettingsLayout(
color = MaterialTheme.colors.secondary
)
}
SettingsActionItemWithContent(null, stringResource(R.string.settings_notification_preview_mode_title), { showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) {
SettingsActionItemWithContent(null, stringResource(MR.strings.settings_notification_preview_mode_title), { showPage(CurrentPage.NOTIFICATION_PREVIEW_MODE) }) {
Text(
previewModes.first { it.value == notificationPreviewMode.value }.title,
maxLines = 1,
@@ -113,7 +114,7 @@ fun NotificationsModeView(
Column(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(R.string.settings_notifications_mode_title).lowercase().capitalize(Locale.current))
AppBarTitle(stringResource(MR.strings.settings_notifications_mode_title).lowercase().capitalize(Locale.current))
SectionViewSelectable(null, notificationsMode, modes, onNotificationsModeSelected)
}
}
@@ -127,7 +128,7 @@ fun NotificationPreviewView(
Column(
Modifier.fillMaxWidth(),
) {
AppBarTitle(stringResource(R.string.settings_notification_preview_title))
AppBarTitle(stringResource(MR.strings.settings_notification_preview_title))
SectionViewSelectable(null, notificationPreviewMode, previewModes, onNotificationPreviewModeSelected)
}
}
@@ -138,22 +139,22 @@ private fun notificationModes(): List<ValueTitleDesc<NotificationsMode>> {
res.add(
ValueTitleDesc(
NotificationsMode.OFF,
generalGetString(R.string.notifications_mode_off),
generalGetString(R.string.notifications_mode_off_desc),
generalGetString(MR.strings.notifications_mode_off),
generalGetString(MR.strings.notifications_mode_off_desc),
)
)
res.add(
ValueTitleDesc(
NotificationsMode.PERIODIC,
generalGetString(R.string.notifications_mode_periodic),
generalGetString(R.string.notifications_mode_periodic_desc),
generalGetString(MR.strings.notifications_mode_periodic),
generalGetString(MR.strings.notifications_mode_periodic_desc),
)
)
res.add(
ValueTitleDesc(
NotificationsMode.SERVICE,
generalGetString(R.string.notifications_mode_service),
generalGetString(R.string.notifications_mode_service_desc),
generalGetString(MR.strings.notifications_mode_service),
generalGetString(MR.strings.notifications_mode_service_desc),
)
)
return res
@@ -165,22 +166,22 @@ fun notificationPreviewModes(): List<ValueTitleDesc<NotificationPreviewMode>> {
res.add(
ValueTitleDesc(
NotificationPreviewMode.MESSAGE,
generalGetString(R.string.notification_preview_mode_message),
generalGetString(R.string.notification_preview_mode_message_desc),
generalGetString(MR.strings.notification_preview_mode_message),
generalGetString(MR.strings.notification_preview_mode_message_desc),
)
)
res.add(
ValueTitleDesc(
NotificationPreviewMode.CONTACT,
generalGetString(R.string.notification_preview_mode_contact),
generalGetString(R.string.notification_preview_mode_contact_desc),
generalGetString(MR.strings.notification_preview_mode_contact),
generalGetString(MR.strings.notification_preview_mode_contact_desc),
)
)
res.add(
ValueTitleDesc(
NotificationPreviewMode.HIDDEN,
generalGetString(R.string.notification_preview_mode_hidden),
generalGetString(R.string.notification_display_mode_hidden_desc),
generalGetString(MR.strings.notification_preview_mode_hidden),
generalGetString(MR.strings.notification_display_mode_hidden_desc),
)
)
return res
@@ -12,10 +12,11 @@ import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import dev.icerock.moko.resources.compose.stringResource
import chat.simplex.app.R
import chat.simplex.app.model.*
import chat.simplex.app.views.helpers.*
import chat.simplex.res.MR
@Composable
fun PreferencesView(m: ChatModel, user: User, close: () -> Unit,) {
@@ -60,7 +61,7 @@ private fun PreferencesLayout(
Column(
Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
) {
AppBarTitle(stringResource(R.string.your_preferences))
AppBarTitle(stringResource(MR.strings.your_preferences))
val timedMessages = remember(preferences) { mutableStateOf(preferences.timedMessages.allow) }
TimedMessagesFeatureSection(timedMessages) {
applyPrefs(preferences.copy(timedMessages = TimedMessagesPreference(allow = if (it) FeatureAllowed.YES else FeatureAllowed.NO)))
@@ -128,19 +129,19 @@ private fun TimedMessagesFeatureSection(allowFeature: State<FeatureAllowed>, onS
private fun ResetSaveButtons(reset: () -> Unit, save: () -> Unit, disabled: Boolean) {
SectionView {
SectionItemView(reset, disabled = disabled) {
Text(stringResource(R.string.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.reset_verb), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
SectionItemView(save, disabled = disabled) {
Text(stringResource(R.string.save_and_notify_contacts), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
Text(stringResource(MR.strings.save_and_notify_contacts), color = if (disabled) MaterialTheme.colors.secondary else MaterialTheme.colors.primary)
}
}
}
private fun showUnsavedChangesAlert(save: () -> Unit, revert: () -> Unit) {
AlertManager.shared.showAlertDialogStacked(
title = generalGetString(R.string.save_preferences_question),
confirmText = generalGetString(R.string.save_and_notify_contacts),
dismissText = generalGetString(R.string.exit_without_saving),
title = generalGetString(MR.strings.save_preferences_question),
confirmText = generalGetString(MR.strings.save_and_notify_contacts),
dismissText = generalGetString(MR.strings.exit_without_saving),
onConfirm = save,
onDismiss = revert,
)

Some files were not shown because too many files have changed in this diff Show More