Merge branch 'master' into master-ios

This commit is contained in:
Evgeny Poberezkin
2023-07-05 09:10:43 +01:00
174 changed files with 10486 additions and 3497 deletions
+4
View File
@@ -464,6 +464,10 @@ func setNetworkConfig(_ cfg: NetCfg) throws {
throw r
}
func reconnectAllServers() async throws {
try await sendCommandOkResp(.reconnectAllServers)
}
func apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings) async throws {
try await sendCommandOkResp(.apiSetChatSettings(type: type, id: id, chatSettings: chatSettings))
}
@@ -55,6 +55,22 @@ struct ChatListView: View {
.onChange(of: chatModel.appOpenUrl) { _ in connectViaUrl() }
.onAppear() { connectViaUrl() }
.onDisappear() { withAnimation { userPickerVisible = false } }
.refreshable {
AlertManager.shared.showAlert(Alert(
title: Text("Reconnect servers?"),
message: Text("Reconnect all connected servers to force message delivery. It uses additional traffic."),
primaryButton: .default(Text("Ok")) {
Task {
do {
try await reconnectAllServers()
} catch let error {
AlertManager.shared.showAlertMsg(title: "Error", message: "\(responseError(error))")
}
}
},
secondaryButton: .cancel()
))
}
.offset(x: -8)
.listStyle(.plain)
.navigationBarTitleDisplayMode(.inline)
@@ -53,6 +53,7 @@ struct AdvancedNetworkSettings: View {
timeoutSettingPicker("TCP connection timeout", selection: $netCfg.tcpConnectTimeout, values: [2_500000, 5_000000, 7_500000, 10_000000, 15_000000, 20_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout", selection: $netCfg.tcpTimeout, values: [1_500000, 3_000000, 5_000000, 7_000000, 10_000000, 15_000000], label: secondsLabel)
timeoutSettingPicker("Protocol timeout per KB", selection: $netCfg.tcpTimeoutPerKb, values: [5_000, 10_000, 20_000, 40_000], label: secondsLabel)
timeoutSettingPicker("PING interval", selection: $netCfg.smpPingInterval, values: [120_000000, 300_000000, 600_000000, 1200_000000, 2400_000000, 3600_000000], label: secondsLabel)
intSettingPicker("PING count", selection: $netCfg.smpPingCount, values: [1, 2, 3, 5, 8], label: "")
Toggle("Enable TCP keep-alive", isOn: $enableKeepAlive)
File diff suppressed because it is too large Load Diff
@@ -587,6 +587,10 @@
<target>Povolit nevratné smazání odeslaných zpráv.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Povolit odesílání hlasových zpráv.</target>
@@ -2089,6 +2093,18 @@
<target>Soubory a média</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Konečně je máme! 🚀</target>
@@ -2199,6 +2215,10 @@
<target>Členové skupiny mohou posílat mizící zprávy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Členové skupiny mohou posílat hlasové zprávy.</target>
@@ -2927,6 +2947,10 @@
<target>Žádný token zařízení!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Skupina nebyla nalezena!</target>
@@ -3016,6 +3040,10 @@
<target>Předvolby skupiny mohou měnit pouze vlastníci skupiny.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Pouze majitelé skupin mohou povolit zasílání hlasových zpráv.</target>
@@ -3336,6 +3364,10 @@
<target>Zakázat posílání mizících zpráv.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Zakázat odesílání hlasových zpráv.</target>
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>Abbrechen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>Wechsel der Adresse abbrechen</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>Wechsel der Adresse abbrechen?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>Unwiederbringliches löschen von gesendeten Nachrichten erlauben.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Das Senden von Sprachnachrichten erlauben.</target>
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>Fehler beim Abbrechen des Adresswechsels</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favorit</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>Dateien &amp; Medien</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Endlich haben wir sie! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>Gruppenmitglieder können verschwindende Nachrichten senden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Gruppenmitglieder können Sprachnachrichten versenden.</target>
@@ -2579,7 +2605,7 @@
</trans-unit>
<trans-unit id="KeyChain error" xml:space="preserve">
<source>KeyChain error</source>
<target>Keystore Fehler</target>
<target>KeyChain Fehler</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Keychain error" xml:space="preserve">
@@ -2927,6 +2953,10 @@
<target>Kein Geräte-Token!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Die Gruppe wurde nicht gefunden!</target>
@@ -3016,6 +3046,10 @@
<target>Gruppenpräferenzen können nur von Gruppen-Eigentümern geändert werden.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Sprachnachrichten können nur von Gruppen-Eigentümern aktiviert werden.</target>
@@ -3336,6 +3370,10 @@
<target>Das Senden von verschwindenden Nachrichten verbieten.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Das Senden von Sprachnachrichten nicht erlauben.</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4441,6 +4480,7 @@ Sie werden aufgefordert, die Authentifizierung abzuschließen, bevor diese Funkt
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>Unfav.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
@@ -591,6 +591,11 @@
<target>Allow to irreversibly delete sent messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<target>Allow to send files and media.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Allow to send voice messages.</target>
@@ -2095,6 +2100,21 @@
<target>Files &amp; media</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<target>Files and media</target>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<target>Files and media are prohibited in this group.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<target>Files and media prohibited!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Finally, we have them! 🚀</target>
@@ -2205,6 +2225,11 @@
<target>Group members can send disappearing messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<target>Group members can send files and media.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Group members can send voice messages.</target>
@@ -2933,6 +2958,11 @@
<target>No device token!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<target>No filtered chats</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Group not found!</target>
@@ -3022,6 +3052,11 @@
<target>Only group owners can change group preferences.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<target>Only group owners can enable files and media.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Only group owners can enable voice messages.</target>
@@ -3342,6 +3377,11 @@
<target>Prohibit sending disappearing messages.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<target>Prohibit sending files and media.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Prohibit sending voice messages.</target>
@@ -587,6 +587,10 @@
<target>Se permite la eliminación irreversible de mensajes.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Permites enviar mensajes de voz.</target>
@@ -2089,6 +2093,18 @@
<target>Archivos y multimedia</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>¡Por fin los tenemos! 🚀</target>
@@ -2199,6 +2215,10 @@
<target>Los miembros del grupo pueden enviar mensajes temporales.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Los miembros del grupo pueden enviar mensajes de voz.</target>
@@ -2927,6 +2947,10 @@
<target>¡Sin dispositivo token!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>¡Grupo no encontrado!</target>
@@ -3016,6 +3040,10 @@
<target>Sólo los propietarios pueden modificar las preferencias de grupo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Sólo los propietarios pueden activar los mensajes de voz.</target>
@@ -3336,6 +3364,10 @@
<target>No se permiten mensajes temporales.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>No se permiten mensajes de voz.</target>
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>Annuler</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>Annuler le changement d'adresse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>Abandonner le changement d'adresse ?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>Le changement d'adresse sera annulé. L'ancienne adresse de réception sera utilisée.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>Autoriser la suppression irréversible de messages envoyés.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Autoriser l'envoi de messages vocaux.</target>
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>Erreur lors de l'annulation du changement d'adresse</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favoris</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>Fichiers &amp; médias</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Enfin, les voilà ! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>Les membres du groupes peuvent envoyer des messages éphémères.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Les membres du groupe peuvent envoyer des messages vocaux.</target>
@@ -2927,6 +2953,10 @@
<target>Pas de token d'appareil!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Groupe introuvable !</target>
@@ -3016,6 +3046,10 @@
<target>Seuls les propriétaires du groupe peuvent modifier les préférences du groupe.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Seuls les propriétaires de groupes peuvent activer les messages vocaux.</target>
@@ -3336,6 +3370,10 @@
<target>Interdire lenvoi de messages éphémères.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Interdire l'envoi de messages vocaux.</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4441,6 +4480,7 @@ Vous serez invité à confirmer l'authentification avant que cette fonction ne s
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>Unfav.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
@@ -222,32 +222,38 @@ Available in v5.1</source>
<target state="translated">**הוסיפו איש קשר חדש**: ליצירת קוד QR או קישור חד־פעמיים עבור איש הקשר שלכם.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Create link / QR code** for your contact to use." xml:space="preserve">
<trans-unit id="**Create link / QR code** for your contact to use." xml:space="preserve" approved="no">
<source>**Create link / QR code** for your contact to use.</source>
<target state="translated">**צור קישור / קוד QR** לשימוש איש הקשר שלך.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have." xml:space="preserve">
<trans-unit id="**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have." xml:space="preserve" approved="no">
<source>**More private**: check new messages every 20 minutes. Device token is shared with SimpleX Chat server, but not how many contacts or messages you have.</source>
<target state="translated">**יותר פרטי**: בדוק הודעות חדשות כל 20 דקות. אסימון המכשיר משותף עם שרת SimpleX Chat, אך לא כמה אנשי קשר או הודעות יש לך.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve">
<trans-unit id="**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app)." xml:space="preserve" approved="no">
<source>**Most private**: do not use SimpleX Chat notifications server, check messages periodically in the background (depends on how often you use the app).</source>
<target state="translated">**הכי פרטי**: אל תשתמש בשרת ההתראות של SimpleX Chat, בדוק הודעות מעת לעת ברקע (תלוי בתדירות השימוש באפליקציה).</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Paste received link** or open it in the browser and tap **Open in mobile app**." xml:space="preserve">
<source>**Paste received link** or open it in the browser and tap **Open in mobile app**.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve">
<trans-unit id="**Please note**: you will NOT be able to recover or change passphrase if you lose it." xml:space="preserve" approved="no">
<source>**Please note**: you will NOT be able to recover or change passphrase if you lose it.</source>
<target state="translated">**שימו לב**: לא ניתן יהיה לשחזר או לשנות את הסיסמה אם תאבדו אותה.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve">
<trans-unit id="**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from." xml:space="preserve" approved="no">
<source>**Recommended**: device token and notifications are sent to SimpleX Chat notification server, but not the message content, size or who it is from.</source>
<target state="translated">**מומלץ**: אסימון מכשיר והתראות נשלחים לשרת ההתראות של SimpleX Chat, אך לא תוכן ההודעה, גודלה או ממי היא.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Scan QR code**: to connect to your contact in person or via video call." xml:space="preserve">
<trans-unit id="**Scan QR code**: to connect to your contact in person or via video call." xml:space="preserve" approved="no">
<source>**Scan QR code**: to connect to your contact in person or via video call.</source>
<target state="translated">**סרוק קוד QR**: כדי להתחבר לאיש הקשר שלך באופן אישי או באמצעות שיחת וידאו.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="**Warning**: Instant push notifications require passphrase saved in Keychain." xml:space="preserve">
@@ -262,44 +268,52 @@ Available in v5.1</source>
<source>**e2e encrypted** video call</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="*bold*" xml:space="preserve">
<trans-unit id="*bold*" xml:space="preserve" approved="no">
<source>\*bold*</source>
<target state="translated">\*מובלט*</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=", " xml:space="preserve">
<source>, </source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="." xml:space="preserve">
<trans-unit id="." xml:space="preserve" approved="no">
<source>.</source>
<target state="needs-translation">.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="1 day" xml:space="preserve">
<trans-unit id="1 day" xml:space="preserve" approved="no">
<source>1 day</source>
<target state="translated">יום 1</target>
<note>message ttl</note>
</trans-unit>
<trans-unit id="1 hour" xml:space="preserve">
<trans-unit id="1 hour" xml:space="preserve" approved="no">
<source>1 hour</source>
<target state="translated">שעה</target>
<note>message ttl</note>
</trans-unit>
<trans-unit id="1 month" xml:space="preserve">
<trans-unit id="1 month" xml:space="preserve" approved="no">
<source>1 month</source>
<target state="translated">חודש</target>
<note>message ttl</note>
</trans-unit>
<trans-unit id="1 week" xml:space="preserve">
<trans-unit id="1 week" xml:space="preserve" approved="no">
<source>1 week</source>
<target state="translated">שבוע</target>
<note>message ttl</note>
</trans-unit>
<trans-unit id="2 weeks" xml:space="preserve">
<source>2 weeks</source>
<note>message ttl</note>
</trans-unit>
<trans-unit id="6" xml:space="preserve">
<trans-unit id="6" xml:space="preserve" approved="no">
<source>6</source>
<target state="translated">6</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id=": " xml:space="preserve">
<trans-unit id=": " xml:space="preserve" approved="no">
<source>: </source>
<target state="translated">: </target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="A new contact" xml:space="preserve">
@@ -4225,6 +4239,26 @@ SimpleX servers cannot see your profile.</source>
<target state="translated">%d שבועות</target>
<note>time interval</note>
</trans-unit>
<trans-unit id="1 minute" xml:space="preserve" approved="no">
<source>1 minute</source>
<target state="translated">דקה</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="1-time link" xml:space="preserve" approved="no">
<source>1-time link</source>
<target state="translated">קישור חד־פעמי</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="5 minutes" xml:space="preserve" approved="no">
<source>5 minutes</source>
<target state="translated">5 דקות</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="30 seconds" xml:space="preserve" approved="no">
<source>30 seconds</source>
<target state="translated">30 שניות</target>
<note>No comment provided by engineer.</note>
</trans-unit>
</body>
</file>
<file original="en.lproj/SimpleX--iOS--InfoPlist.strings" source-language="en" target-language="he" datatype="plaintext">
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>Interrompi</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>Interrompi il cambio di indirizzo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>Interrompere il cambio di indirizzo?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>Permetti di eliminare irreversibilmente i messaggi inviati.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Permetti l'invio di messaggi vocali.</target>
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>Errore nell'interruzione del cambio di indirizzo</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Preferito</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>File e multimediali</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Finalmente le abbiamo! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>I membri del gruppo possono inviare messaggi a tempo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>I membri del gruppo possono inviare messaggi vocali.</target>
@@ -2927,6 +2953,10 @@
<target>Nessun token del dispositivo!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Gruppo non trovato!</target>
@@ -3016,6 +3046,10 @@
<target>Solo i proprietari del gruppo possono modificarne le preferenze.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Solo i proprietari del gruppo possono attivare i messaggi vocali.</target>
@@ -3336,6 +3370,10 @@
<target>Proibisci l'invio di messaggi a tempo.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Proibisci l'invio di messaggi vocali.</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4441,6 +4480,7 @@ Ti verrà chiesto di completare l'autenticazione prima di attivare questa funzio
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>Non pref.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
@@ -587,6 +587,10 @@
<target>送信済みメッセージの永久削除を許可する。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>音声メッセージの送信を許可する。</target>
@@ -2088,6 +2092,18 @@
<target>ファイルとメディア</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<note>No comment provided by engineer.</note>
@@ -2197,6 +2213,10 @@
<target>グループのメンバーが消えるメッセージを送信できます。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>グループのメンバーが音声メッセージを送信できます。</target>
@@ -2925,6 +2945,10 @@
<target>デバイストークンがありません!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>グループが見つかりません!</target>
@@ -3014,6 +3038,10 @@
<target>グループ設定を変えられるのはグループのオーナーだけです。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>音声メッセージを利用可能に設定できるのはグループのオーナーだけです。</target>
@@ -3334,6 +3362,10 @@
<target>消えるメッセージを使用禁止にする。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>音声メッセージを使用禁止にする。</target>
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>Afbreken</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>Annuleer het wijzigen van het adres</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>Adres wijziging afbreken?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>Adres wijziging wordt afgebroken. Het oude ontvangstadres wordt gebruikt.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>Sta toe om verzonden berichten onomkeerbaar te verwijderen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Sta toe om spraak berichten te verzenden.</target>
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>Fout bij het afbreken van adres wijziging</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Favoriet</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>Bestanden en media</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Eindelijk, we hebben ze! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>Groepsleden kunnen verdwijnende berichten sturen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Groepsleden kunnen spraak berichten verzenden.</target>
@@ -2927,6 +2953,10 @@
<target>Geen apparaattoken!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Groep niet gevonden!</target>
@@ -3016,6 +3046,10 @@
<target>Alleen groep eigenaren kunnen groep voorkeuren wijzigen.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Alleen groep eigenaren kunnen spraak berichten inschakelen.</target>
@@ -3336,6 +3370,10 @@
<target>Verbied het verzenden van verdwijnende berichten.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Verbieden het verzenden van spraak berichten.</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4441,6 +4480,7 @@ U wordt gevraagd de authenticatie te voltooien voordat deze functie wordt ingesc
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>Niet fav.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>Przerwij</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>Przerwij zmianę adresu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>Przerwać zmianę adresu?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>Zezwól na nieodwracalne usunięcie wysłanych wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Zezwól na wysyłanie wiadomości głosowych.</target>
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>Błąd przerwania zmiany adresu</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>Ulubione</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>Pliki i media</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>W końcu je mamy! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>Członkowie grupy mogą wysyłać znikające wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Członkowie grupy mogą wysyłać wiadomości głosowe.</target>
@@ -2927,6 +2953,10 @@
<target>Brak tokenu urządzenia!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Nie znaleziono grupy!</target>
@@ -3016,6 +3046,10 @@
<target>Tylko właściciele grup mogą zmieniać preferencje grupy.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Tylko właściciele grup mogą włączyć wiadomości głosowe.</target>
@@ -3336,6 +3370,10 @@
<target>Zabroń wysyłania znikających wiadomości.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Zabroń wysyłania wiadomości głosowych.</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4032,6 +4071,7 @@
</trans-unit>
<trans-unit id="Some non-fatal errors occurred during import - you may see Chat console for more details." xml:space="preserve">
<source>Some non-fatal errors occurred during import - you may see Chat console for more details.</source>
<target>Podczas importu wystąpiły niekrytyczne błędy - więcej szczegółów można znaleźć w konsoli czatu.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Somebody" xml:space="preserve">
@@ -4440,6 +4480,7 @@ Przed włączeniem tej funkcji zostanie wyświetlony monit uwierzytelniania.</ta
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>Nie ulub.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
@@ -587,6 +587,10 @@
<target>Разрешить необратимо удалять отправленные сообщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>Разрешить отправлять голосовые сообщения.</target>
@@ -2089,6 +2093,18 @@
<target>Файлы и медиа</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>Наконец-то, мы их добавили! 🚀</target>
@@ -2199,6 +2215,10 @@
<target>Члены группы могут посылать исчезающие сообщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>Члены группы могут отправлять голосовые сообщения.</target>
@@ -2927,6 +2947,10 @@
<target>Отсутствует токен устройства!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>Группа не найдена!</target>
@@ -3016,6 +3040,10 @@
<target>Только владельцы группы могут изменять предпочтения группы.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>Только владельцы группы могут разрешить голосовые сообщения.</target>
@@ -3336,6 +3364,10 @@
<target>Запретить посылать исчезающие сообщения.</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>Запретить отправлять голосовые сообщений.</target>
File diff suppressed because it is too large Load Diff
@@ -402,14 +402,17 @@
</trans-unit>
<trans-unit id="Abort" xml:space="preserve">
<source>Abort</source>
<target>中止</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address" xml:space="preserve">
<source>Abort changing address</source>
<target>中止地址更改</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Abort changing address?" xml:space="preserve">
<source>Abort changing address?</source>
<target>中止地址更改?</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="About SimpleX" xml:space="preserve">
@@ -495,6 +498,7 @@
</trans-unit>
<trans-unit id="Address change will be aborted. Old receiving address will be used." xml:space="preserve">
<source>Address change will be aborted. Old receiving address will be used.</source>
<target>将中止地址更改。将使用旧接收地址。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Admins can create the links to join groups." xml:space="preserve">
@@ -587,6 +591,10 @@
<target>允许不可撤回地删除已发送消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send files and media." xml:space="preserve">
<source>Allow to send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Allow to send voice messages." xml:space="preserve">
<source>Allow to send voice messages.</source>
<target>允许发送语音消息。</target>
@@ -694,7 +702,7 @@
</trans-unit>
<trans-unit id="Audio and video calls" xml:space="preserve">
<source>Audio and video calls</source>
<target>视频通话</target>
<target>语音和视频通话</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Audio/video calls" xml:space="preserve">
@@ -1798,6 +1806,7 @@
</trans-unit>
<trans-unit id="Error aborting address change" xml:space="preserve">
<source>Error aborting address change</source>
<target>中止地址更改错误</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Error accepting contact request" xml:space="preserve">
@@ -2062,6 +2071,7 @@
</trans-unit>
<trans-unit id="Favorite" xml:space="preserve">
<source>Favorite</source>
<target>最喜欢</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="File will be deleted from servers." xml:space="preserve">
@@ -2089,6 +2099,18 @@
<target>文件和媒体</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media" xml:space="preserve">
<source>Files and media</source>
<note>chat feature</note>
</trans-unit>
<trans-unit id="Files and media are prohibited in this group." xml:space="preserve">
<source>Files and media are prohibited in this group.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Files and media prohibited!" xml:space="preserve">
<source>Files and media prohibited!</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Finally, we have them! 🚀" xml:space="preserve">
<source>Finally, we have them! 🚀</source>
<target>终于我们有它们了! 🚀</target>
@@ -2199,6 +2221,10 @@
<target>群组成员可以发送限时消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send files and media." xml:space="preserve">
<source>Group members can send files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Group members can send voice messages." xml:space="preserve">
<source>Group members can send voice messages.</source>
<target>群组成员可以发送语音消息。</target>
@@ -2574,7 +2600,7 @@
</trans-unit>
<trans-unit id="Joining group" xml:space="preserve">
<source>Joining group</source>
<target>加入群组</target>
<target>加入群组</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="KeyChain error" xml:space="preserve">
@@ -2927,6 +2953,10 @@
<target>无设备令牌!</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No filtered chats" xml:space="preserve">
<source>No filtered chats</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="No group!" xml:space="preserve">
<source>Group not found!</source>
<target>未找到群组!</target>
@@ -3016,6 +3046,10 @@
<target>只有群主可以改变群组偏好设置。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable files and media." xml:space="preserve">
<source>Only group owners can enable files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Only group owners can enable voice messages." xml:space="preserve">
<source>Only group owners can enable voice messages.</source>
<target>只有群主可以启用语音信息。</target>
@@ -3336,6 +3370,10 @@
<target>禁止发送限时消息。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending files and media." xml:space="preserve">
<source>Prohibit sending files and media.</source>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Prohibit sending voice messages." xml:space="preserve">
<source>Prohibit sending voice messages.</source>
<target>禁止发送语音消息。</target>
@@ -3423,6 +3461,7 @@
</trans-unit>
<trans-unit id="Receiving address will be changed to a different server. Address change will complete after sender comes online." xml:space="preserve">
<source>Receiving address will be changed to a different server. Address change will complete after sender comes online.</source>
<target>接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Receiving file will be stopped." xml:space="preserve">
@@ -4441,6 +4480,7 @@ You will be prompted to complete authentication before this feature is enabled.<
</trans-unit>
<trans-unit id="Unfav." xml:space="preserve">
<source>Unfav.</source>
<target>取消最喜欢</target>
<note>No comment provided by engineer.</note>
</trans-unit>
<trans-unit id="Unhide" xml:space="preserve">
+20 -20
View File
@@ -115,6 +115,11 @@
5CC2C0FC2809BF11000C35E3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FA2809BF11000C35E3 /* Localizable.strings */; };
5CC2C0FF2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 5CC2C0FD2809BF11000C35E3 /* SimpleX--iOS--InfoPlist.strings */; };
5CC868F329EB540C0017BBFD /* CIRcvDecryptionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */; };
5CCAA6DF2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */; };
5CCAA6E02A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */; };
5CCAA6E12A53713A00BAF93B /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */; };
5CCAA6E22A53713A00BAF93B /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DD2A53713A00BAF93B /* libgmp.a */; };
5CCAA6E32A53713A00BAF93B /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5CCAA6DE2A53713A00BAF93B /* libffi.a */; };
5CCB939C297EFCB100399E78 /* NavStackCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCB939B297EFCB100399E78 /* NavStackCompat.swift */; };
5CCD403427A5F6DF00368C90 /* AddContactView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403327A5F6DF00368C90 /* AddContactView.swift */; };
5CCD403727A5F9A200368C90 /* ScanToConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */; };
@@ -165,11 +170,6 @@
648010AB281ADD15009009B9 /* CIFileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 648010AA281ADD15009009B9 /* CIFileView.swift */; };
649BCDA0280460FD00C3A862 /* ComposeImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCD9F280460FD00C3A862 /* ComposeImageView.swift */; };
649BCDA22805D6EF00C3A862 /* CIImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 649BCDA12805D6EF00C3A862 /* CIImageView.swift */; };
64A353102A4C84CE007CD71D /* libgmp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530B2A4C84CE007CD71D /* libgmp.a */; };
64A353112A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */; };
64A353122A4C84CE007CD71D /* libffi.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530D2A4C84CE007CD71D /* libffi.a */; };
64A353132A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */; };
64A353142A4C84CE007CD71D /* libgmpxx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 64A3530F2A4C84CE007CD71D /* libgmpxx.a */; };
64AA1C6927EE10C800AC7277 /* ContextItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6827EE10C800AC7277 /* ContextItemView.swift */; };
64AA1C6C27F3537400AC7277 /* DeletedItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */; };
64C06EB52A0A4A7C00792D4D /* ChatItemInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */; };
@@ -392,6 +392,11 @@
5CC2C0FB2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
5CC2C0FE2809BF11000C35E3 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = "ru.lproj/SimpleX--iOS--InfoPlist.strings"; sourceTree = "<group>"; };
5CC868F229EB540C0017BBFD /* CIRcvDecryptionError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIRcvDecryptionError.swift; sourceTree = "<group>"; };
5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a"; sourceTree = "<group>"; };
5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a"; sourceTree = "<group>"; };
5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
5CCAA6DD2A53713A00BAF93B /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
5CCAA6DE2A53713A00BAF93B /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
5CCB939B297EFCB100399E78 /* NavStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavStackCompat.swift; sourceTree = "<group>"; };
5CCD403327A5F6DF00368C90 /* AddContactView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactView.swift; sourceTree = "<group>"; };
5CCD403627A5F9A200368C90 /* ScanToConnectView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScanToConnectView.swift; sourceTree = "<group>"; };
@@ -441,11 +446,6 @@
6493D667280ED77F007A76FB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
649BCD9F280460FD00C3A862 /* ComposeImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeImageView.swift; sourceTree = "<group>"; };
649BCDA12805D6EF00C3A862 /* CIImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIImageView.swift; sourceTree = "<group>"; };
64A3530B2A4C84CE007CD71D /* libgmp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmp.a; sourceTree = "<group>"; };
64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a"; sourceTree = "<group>"; };
64A3530D2A4C84CE007CD71D /* libffi.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libffi.a; sourceTree = "<group>"; };
64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a"; sourceTree = "<group>"; };
64A3530F2A4C84CE007CD71D /* libgmpxx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libgmpxx.a; sourceTree = "<group>"; };
64AA1C6827EE10C800AC7277 /* ContextItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextItemView.swift; sourceTree = "<group>"; };
64AA1C6B27F3537400AC7277 /* DeletedItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeletedItemView.swift; sourceTree = "<group>"; };
64C06EB42A0A4A7C00792D4D /* ChatItemInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatItemInfoView.swift; sourceTree = "<group>"; };
@@ -498,12 +498,12 @@
buildActionMask = 2147483647;
files = (
5CE2BA93284534B000EC33A6 /* libiconv.tbd in Frameworks */,
64A353132A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a in Frameworks */,
64A353102A4C84CE007CD71D /* libgmp.a in Frameworks */,
64A353112A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a in Frameworks */,
64A353122A4C84CE007CD71D /* libffi.a in Frameworks */,
5CCAA6E12A53713A00BAF93B /* libgmpxx.a in Frameworks */,
5CCAA6DF2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a in Frameworks */,
5CCAA6E02A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a in Frameworks */,
5CCAA6E32A53713A00BAF93B /* libffi.a in Frameworks */,
5CCAA6E22A53713A00BAF93B /* libgmp.a in Frameworks */,
5CE2BA94284534BB00EC33A6 /* libz.tbd in Frameworks */,
64A353142A4C84CE007CD71D /* libgmpxx.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -564,11 +564,11 @@
5C764E5C279C70B7000C6508 /* Libraries */ = {
isa = PBXGroup;
children = (
64A3530D2A4C84CE007CD71D /* libffi.a */,
64A3530B2A4C84CE007CD71D /* libgmp.a */,
64A3530F2A4C84CE007CD71D /* libgmpxx.a */,
64A3530E2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm-ghc8.10.7.a */,
64A3530C2A4C84CE007CD71D /* libHSsimplex-chat-5.2.0.0-ESKsZ4YorLH7yFQuFvHeIm.a */,
5CCAA6DE2A53713A00BAF93B /* libffi.a */,
5CCAA6DD2A53713A00BAF93B /* libgmp.a */,
5CCAA6DC2A53713A00BAF93B /* libgmpxx.a */,
5CCAA6DA2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i-ghc8.10.7.a */,
5CCAA6DB2A53713A00BAF93B /* libHSsimplex-chat-5.2.0.0-H74s0RJkRXv7ArDExYHa6i.a */,
);
path = Libraries;
sourceTree = "<group>";
+6
View File
@@ -66,6 +66,7 @@ public enum ChatCommand {
case apiGetChatItemTTL(userId: Int64)
case apiSetNetworkConfig(networkConfig: NetCfg)
case apiGetNetworkConfig
case reconnectAllServers
case apiSetChatSettings(type: ChatType, id: Int64, chatSettings: ChatSettings)
case apiContactInfo(contactId: Int64)
case apiGroupMemberInfo(groupId: Int64, groupMemberId: Int64)
@@ -176,6 +177,7 @@ public enum ChatCommand {
case let .apiGetChatItemTTL(userId): return "/_ttl \(userId)"
case let .apiSetNetworkConfig(networkConfig): return "/_network \(encodeJSON(networkConfig))"
case .apiGetNetworkConfig: return "/network"
case .reconnectAllServers: return "/reconnect"
case let .apiSetChatSettings(type, id, chatSettings): return "/_settings \(ref(type, id)) \(encodeJSON(chatSettings))"
case let .apiContactInfo(contactId): return "/_info @\(contactId)"
case let .apiGroupMemberInfo(groupId, groupMemberId): return "/_info #\(groupId) \(groupMemberId)"
@@ -284,6 +286,7 @@ public enum ChatCommand {
case .apiGetChatItemTTL: return "apiGetChatItemTTL"
case .apiSetNetworkConfig: return "apiSetNetworkConfig"
case .apiGetNetworkConfig: return "apiGetNetworkConfig"
case .reconnectAllServers: return "reconnectAllServers"
case .apiSetChatSettings: return "apiSetChatSettings"
case .apiContactInfo: return "apiContactInfo"
case .apiGroupMemberInfo: return "apiGroupMemberInfo"
@@ -994,6 +997,7 @@ public struct NetCfg: Codable, Equatable {
public var sessionMode: TransportSessionMode
public var tcpConnectTimeout: Int // microseconds
public var tcpTimeout: Int // microseconds
public var tcpTimeoutPerKb: Int // microseconds
public var tcpKeepAlive: KeepAliveOpts?
public var smpPingInterval: Int // microseconds
public var smpPingCount: Int // times
@@ -1004,6 +1008,7 @@ public struct NetCfg: Codable, Equatable {
sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 10_000_000,
tcpTimeout: 7_000_000,
tcpTimeoutPerKb: 10_000,
tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000,
smpPingCount: 3,
@@ -1015,6 +1020,7 @@ public struct NetCfg: Codable, Equatable {
sessionMode: TransportSessionMode.user,
tcpConnectTimeout: 20_000_000,
tcpTimeout: 15_000_000,
tcpTimeoutPerKb: 20_000,
tcpKeepAlive: KeepAliveOpts.defaults,
smpPingInterval: 1200_000_000,
smpPingCount: 3,
+5
View File
@@ -20,6 +20,7 @@ let GROUP_DEFAULT_NETWORK_USE_ONION_HOSTS = "networkUseOnionHosts"
let GROUP_DEFAULT_NETWORK_SESSION_MODE = "networkSessionMode"
let GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT = "networkTCPConnectTimeout"
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT = "networkTCPTimeout"
let GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
let GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL = "networkSMPPingInterval"
let GROUP_DEFAULT_NETWORK_SMP_PING_COUNT = "networkSMPPingCount"
let GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE = "networkEnableKeepAlive"
@@ -42,6 +43,7 @@ public func registerGroupDefaults() {
GROUP_DEFAULT_NETWORK_SESSION_MODE: TransportSessionMode.user.rawValue,
GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT: NetCfg.defaults.tcpConnectTimeout,
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT: NetCfg.defaults.tcpTimeout,
GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB: NetCfg.defaults.tcpTimeoutPerKb,
GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL: NetCfg.defaults.smpPingInterval,
GROUP_DEFAULT_NETWORK_SMP_PING_COUNT: NetCfg.defaults.smpPingCount,
GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE: NetCfg.defaults.enableKeepAlive,
@@ -209,6 +211,7 @@ public func getNetCfg() -> NetCfg {
let sessionMode = networkSessionModeGroupDefault.get()
let tcpConnectTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
let tcpTimeout = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
let tcpTimeoutPerKb = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
let smpPingInterval = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
let smpPingCount = groupDefaults.integer(forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
let enableKeepAlive = groupDefaults.bool(forKey: GROUP_DEFAULT_NETWORK_ENABLE_KEEP_ALIVE)
@@ -227,6 +230,7 @@ public func getNetCfg() -> NetCfg {
sessionMode: sessionMode,
tcpConnectTimeout: tcpConnectTimeout,
tcpTimeout: tcpTimeout,
tcpTimeoutPerKb: tcpTimeoutPerKb,
tcpKeepAlive: tcpKeepAlive,
smpPingInterval: smpPingInterval,
smpPingCount: smpPingCount,
@@ -239,6 +243,7 @@ public func setNetCfg(_ cfg: NetCfg) {
networkSessionModeGroupDefault.set(cfg.sessionMode)
groupDefaults.set(cfg.tcpConnectTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_CONNECT_TIMEOUT)
groupDefaults.set(cfg.tcpTimeout, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT)
groupDefaults.set(cfg.tcpTimeoutPerKb, forKey: GROUP_DEFAULT_NETWORK_TCP_TIMEOUT_PER_KB)
groupDefaults.set(cfg.smpPingInterval, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_INTERVAL)
groupDefaults.set(cfg.smpPingCount, forKey: GROUP_DEFAULT_NETWORK_SMP_PING_COUNT)
if let tcpKeepAlive = cfg.tcpKeepAlive {
+25 -1
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "**Für jeden Kontakt und jedes Gruppenmitglied** wird eine separate TCP-Verbindung genutzt.\n**Bitte beachten Sie**: Wenn Sie viele Verbindungen haben, kann der Batterieverbrauch und die Datennutzung wesentlich höher sein und einige Verbindungen können scheitern.";
/* No comment provided by engineer. */
"Abort" = "Abbrechen";
/* No comment provided by engineer. */
"Abort changing address" = "Wechsel der Adresse abbrechen";
/* No comment provided by engineer. */
"Abort changing address?" = "Wechsel der Adresse abbrechen?";
/* No comment provided by engineer. */
"About SimpleX" = "Über SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "Adresse";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "Der Wechsel der Adresse wird abgebrochen. Die bisherige Adresse wird weiter verwendet.";
/* member role */
"admin" = "Admin";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "Fehler";
/* No comment provided by engineer. */
"Error aborting address change" = "Fehler beim Abbrechen des Adresswechsels";
/* No comment provided by engineer. */
"Error accepting contact request" = "Fehler beim Annehmen der Kontaktanfrage";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Schnell und ohne warten auf den Absender, bis er online ist!";
/* No comment provided by engineer. */
"Favorite" = "Favorit";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Die Datei wird von den Servern gelöscht.";
@@ -1738,7 +1756,7 @@
"Keychain error" = "Schlüsselbundfehler";
/* No comment provided by engineer. */
"KeyChain error" = "Keystore Fehler";
"KeyChain error" = "KeyChain Fehler";
/* No comment provided by engineer. */
"Large file!" = "Große Datei!";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "Empfangene Nachricht";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Die Empfängeradresse wird auf einen anderen Server geändert. Der Adresswechsel wird abgeschlossen, wenn der Absender wieder online ist.";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "Der Empfang der Datei wird beendet.";
@@ -2950,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "Unerwarteter Migrationsstatus";
/* No comment provided by engineer. */
"Unfav." = "Unfav.";
/* No comment provided by engineer. */
"Unhide" = "Verbergen aufheben";
+24
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Une connexion TCP distincte sera utilisée **pour chaque contact et membre de groupe**.\n**Veuillez noter** : si vous avez de nombreuses connexions, votre consommation de batterie et de réseau peut être nettement plus élevée et certaines liaisons peuvent échouer.";
/* No comment provided by engineer. */
"Abort" = "Annuler";
/* No comment provided by engineer. */
"Abort changing address" = "Annuler le changement d'adresse";
/* No comment provided by engineer. */
"Abort changing address?" = "Abandonner le changement d'adresse ?";
/* No comment provided by engineer. */
"About SimpleX" = "À propos de SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "Adresse";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "Le changement d'adresse sera annulé. L'ancienne adresse de réception sera utilisée.";
/* member role */
"admin" = "admin";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "Erreur";
/* No comment provided by engineer. */
"Error aborting address change" = "Erreur lors de l'annulation du changement d'adresse";
/* No comment provided by engineer. */
"Error accepting contact request" = "Erreur de validation de la demande de contact";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Rapide et ne nécessitant pas d'attendre que l'expéditeur soit en ligne !";
/* No comment provided by engineer. */
"Favorite" = "Favoris";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Le fichier sera supprimé des serveurs.";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "Message reçu";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "L'adresse de réception sera changée pour un autre serveur. Le changement d'adresse sera terminé lorsque l'expéditeur sera en ligne.";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "La réception du fichier sera interrompue.";
@@ -2950,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "État de la migration inattendu";
/* No comment provided by engineer. */
"Unfav." = "Unfav.";
/* No comment provided by engineer. */
"Unhide" = "Dévoiler";
+24
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Verrà usata una connessione TCP separata **per ogni contatto e membro del gruppo**.\n** Nota**: se hai molte connessioni, il consumo di batteria e traffico può essere notevolmente superiore e alcune connessioni potrebbero fallire.";
/* No comment provided by engineer. */
"Abort" = "Interrompi";
/* No comment provided by engineer. */
"Abort changing address" = "Interrompi il cambio di indirizzo";
/* No comment provided by engineer. */
"Abort changing address?" = "Interrompere il cambio di indirizzo?";
/* No comment provided by engineer. */
"About SimpleX" = "Riguardo SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "Indirizzo";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "Il cambio di indirizzo verrà interrotto. Verrà usato il vecchio indirizzo di ricezione.";
/* member role */
"admin" = "amministratore";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "Errore";
/* No comment provided by engineer. */
"Error aborting address change" = "Errore nell'interruzione del cambio di indirizzo";
/* No comment provided by engineer. */
"Error accepting contact request" = "Errore nell'accettazione della richiesta di contatto";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Veloce e senza aspettare che il mittente sia in linea!";
/* No comment provided by engineer. */
"Favorite" = "Preferito";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Il file verrà eliminato dai server.";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "Messaggio ricevuto";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "L'indirizzo di ricezione verrà cambiato in un server diverso. La modifica dell'indirizzo verrà completata dopo che il mittente sarà in linea.";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "La ricezione del file verrà interrotta.";
@@ -2950,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "Stato di migrazione imprevisto";
/* No comment provided by engineer. */
"Unfav." = "Non pref.";
/* No comment provided by engineer. */
"Unhide" = "Svela";
+24
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Er wordt een aparte TCP-verbinding gebruikt **voor elk contact en groepslid**.\n**Let op**: als u veel verbindingen heeft, kan uw batterij- en verkeersverbruik aanzienlijk hoger zijn en kunnen sommige verbindingen uitvallen.";
/* No comment provided by engineer. */
"Abort" = "Afbreken";
/* No comment provided by engineer. */
"Abort changing address" = "Annuleer het wijzigen van het adres";
/* No comment provided by engineer. */
"Abort changing address?" = "Adres wijziging afbreken?";
/* No comment provided by engineer. */
"About SimpleX" = "Over SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "Adres";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "Adres wijziging wordt afgebroken. Het oude ontvangstadres wordt gebruikt.";
/* member role */
"admin" = "Beheerder";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "Fout";
/* No comment provided by engineer. */
"Error aborting address change" = "Fout bij het afbreken van adres wijziging";
/* No comment provided by engineer. */
"Error accepting contact request" = "Fout bij het accepteren van een contactverzoek";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Snel en niet wachten tot de afzender online is!";
/* No comment provided by engineer. */
"Favorite" = "Favoriet";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Het bestand wordt van de servers verwijderd.";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "Ontvangen bericht";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Het ontvangstadres wordt gewijzigd naar een andere server. Adres wijziging wordt voltooid nadat de afzender online is.";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "Het ontvangen van het bestand wordt gestopt.";
@@ -2950,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "Onverwachte migratiestatus";
/* No comment provided by engineer. */
"Unfav." = "Niet fav.";
/* No comment provided by engineer. */
"Unhide" = "zichtbaar maken";
+27
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "Oddzielne połączenie TCP będzie używane **dla każdego kontaktu i członka grupy**.\n**Uwaga**: jeśli masz wiele połączeń, zużycie baterii i ruchu może być znacznie wyższe, a niektóre połączenia mogą się nie udać.";
/* No comment provided by engineer. */
"Abort" = "Przerwij";
/* No comment provided by engineer. */
"Abort changing address" = "Przerwij zmianę adresu";
/* No comment provided by engineer. */
"Abort changing address?" = "Przerwać zmianę adresu?";
/* No comment provided by engineer. */
"About SimpleX" = "O SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "Adres";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "Zmiana adresu zostanie przerwana. Użyty zostanie stary adres odbiorczy.";
/* member role */
"admin" = "administrator";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "Błąd";
/* No comment provided by engineer. */
"Error aborting address change" = "Błąd przerwania zmiany adresu";
/* No comment provided by engineer. */
"Error accepting contact request" = "Błąd przyjmowania prośby o kontakt";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "Szybko i bez czekania aż nadawca będzie online!";
/* No comment provided by engineer. */
"Favorite" = "Ulubione";
/* No comment provided by engineer. */
"File will be deleted from servers." = "Plik zostanie usunięty z serwerów.";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "Otrzymano wiadomość";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "Adres odbiorczy zostanie zmieniony na inny serwer. Zmiana adresu zostanie zakończona gdy nadawca będzie online.";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "Odbieranie pliku zostanie przerwane.";
@@ -2698,6 +2719,9 @@
/* No comment provided by engineer. */
"SMP servers" = "Serwery SMP";
/* No comment provided by engineer. */
"Some non-fatal errors occurred during import - you may see Chat console for more details." = "Podczas importu wystąpiły niekrytyczne błędy - więcej szczegółów można znaleźć w konsoli czatu.";
/* notification title */
"Somebody" = "Ktoś";
@@ -2947,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "Nieoczekiwany stan migracji";
/* No comment provided by engineer. */
"Unfav." = "Nie ulub.";
/* No comment provided by engineer. */
"Unhide" = "Odkryj";
+26 -2
View File
@@ -247,6 +247,15 @@
/* No comment provided by engineer. */
"A separate TCP connection will be used **for each contact and group member**.\n**Please note**: if you have many connections, your battery and traffic consumption can be substantially higher and some connections may fail." = "每个联系人和群成员将使用一个独立的 TCP 连接。\n请注意:如果您有许多连接,将会消耗更多的电量和流量,并且某些连接可能会失败。";
/* No comment provided by engineer. */
"Abort" = "中止";
/* No comment provided by engineer. */
"Abort changing address" = "中止地址更改";
/* No comment provided by engineer. */
"Abort changing address?" = "中止地址更改?";
/* No comment provided by engineer. */
"About SimpleX" = "关于SimpleX";
@@ -302,6 +311,9 @@
/* No comment provided by engineer. */
"Address" = "地址";
/* No comment provided by engineer. */
"Address change will be aborted. Old receiving address will be used." = "将中止地址更改。将使用旧接收地址。";
/* member role */
"admin" = "管理员";
@@ -426,7 +438,7 @@
"Audio & video calls" = "语音和视频通话";
/* No comment provided by engineer. */
"Audio and video calls" = "视频通话";
"Audio and video calls" = "语音和视频通话";
/* No comment provided by engineer. */
"audio call (not e2e encrypted)" = "语音通话(非端到端加密)";
@@ -1218,6 +1230,9 @@
/* No comment provided by engineer. */
"Error" = "错误";
/* No comment provided by engineer. */
"Error aborting address change" = "中止地址更改错误";
/* No comment provided by engineer. */
"Error accepting contact request" = "接受联系人请求错误";
@@ -1374,6 +1389,9 @@
/* No comment provided by engineer. */
"Fast and no wait until the sender is online!" = "快速且无需等待发件人在线!";
/* No comment provided by engineer. */
"Favorite" = "最喜欢";
/* No comment provided by engineer. */
"File will be deleted from servers." = "文件将从服务器中删除。";
@@ -1732,7 +1750,7 @@
"Join incognito" = "加入隐身聊天";
/* No comment provided by engineer. */
"Joining group" = "加入群组";
"Joining group" = "加入群组";
/* No comment provided by engineer. */
"Keychain error" = "钥匙串错误";
@@ -2314,6 +2332,9 @@
/* message info title */
"Received message" = "收到的信息";
/* No comment provided by engineer. */
"Receiving address will be changed to a different server. Address change will complete after sender comes online." = "接收地址将变更到不同的服务器。地址更改将在发件人上线后完成。";
/* No comment provided by engineer. */
"Receiving file will be stopped." = "即将停止接收文件。";
@@ -2950,6 +2971,9 @@
/* No comment provided by engineer. */
"Unexpected migration state" = "未预料的迁移状态";
/* No comment provided by engineer. */
"Unfav." = "取消最喜欢";
/* No comment provided by engineer. */
"Unhide" = "取消隐藏";
@@ -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
@@ -129,6 +131,7 @@ class AppPreferences {
val networkRequiredHostMode = mkBoolPreference(SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE, false)
val networkTCPConnectTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT, NetCfg.defaults.tcpConnectTimeout, NetCfg.proxyDefaults.tcpConnectTimeout)
val networkTCPTimeout = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT, NetCfg.defaults.tcpTimeout, NetCfg.proxyDefaults.tcpTimeout)
val networkTCPTimeoutPerKb = mkTimeoutPreference(SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB, NetCfg.defaults.tcpTimeoutPerKb, NetCfg.proxyDefaults.tcpTimeoutPerKb)
val networkSMPPingInterval = mkLongPreference(SHARED_PREFS_NETWORK_SMP_PING_INTERVAL, NetCfg.defaults.smpPingInterval)
val networkSMPPingCount = mkIntPreference(SHARED_PREFS_NETWORK_SMP_PING_COUNT, NetCfg.defaults.smpPingCount)
val networkEnableKeepAlive = mkBoolPreference(SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE, NetCfg.defaults.enableKeepAlive)
@@ -264,6 +267,7 @@ class AppPreferences {
private const val SHARED_PREFS_NETWORK_REQUIRED_HOST_MODE = "NetworkRequiredHostMode"
private const val SHARED_PREFS_NETWORK_TCP_CONNECT_TIMEOUT = "NetworkTCPConnectTimeout"
private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT = "NetworkTCPTimeout"
private const val SHARED_PREFS_NETWORK_TCP_TIMEOUT_PER_KB = "networkTCPTimeoutPerKb"
private const val SHARED_PREFS_NETWORK_SMP_PING_INTERVAL = "NetworkSMPPingInterval"
private const val SHARED_PREFS_NETWORK_SMP_PING_COUNT = "NetworkSMPPingCount"
private const val SHARED_PREFS_NETWORK_ENABLE_KEEP_ALIVE = "NetworkEnableKeepAlive"
@@ -355,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())
}
}
@@ -448,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
@@ -566,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()
}
@@ -574,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
}
@@ -585,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
}
@@ -596,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
}
}
@@ -637,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
@@ -652,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
}
@@ -700,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
@@ -736,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
}
@@ -799,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
}
@@ -816,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
}
@@ -833,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
}
@@ -855,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)
}
@@ -927,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
}
@@ -974,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
}
@@ -1054,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
}
@@ -1066,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
@@ -1108,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
}
@@ -1125,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)
}
}
@@ -1142,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
}
@@ -1153,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}")
}
@@ -1177,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
@@ -1196,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
}
@@ -1208,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
}
@@ -1220,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
}
@@ -1268,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
}
@@ -1277,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
}
@@ -1427,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) {
@@ -1705,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
)
}
@@ -1716,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)) }
}
)
}
@@ -1742,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
)
}
@@ -1753,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)) }
}
)
}
@@ -1773,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
)
}
@@ -1784,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)) }
}
)
}
@@ -1832,6 +1836,7 @@ object ChatController {
val sessionMode = appPrefs.networkSessionMode.get()
val tcpConnectTimeout = appPrefs.networkTCPConnectTimeout.get()
val tcpTimeout = appPrefs.networkTCPTimeout.get()
val tcpTimeoutPerKb = appPrefs.networkTCPTimeoutPerKb.get()
val smpPingInterval = appPrefs.networkSMPPingInterval.get()
val smpPingCount = appPrefs.networkSMPPingCount.get()
val enableKeepAlive = appPrefs.networkEnableKeepAlive.get()
@@ -1850,6 +1855,7 @@ object ChatController {
sessionMode = sessionMode,
tcpConnectTimeout = tcpConnectTimeout,
tcpTimeout = tcpTimeout,
tcpTimeoutPerKb = tcpTimeoutPerKb,
tcpKeepAlive = tcpKeepAlive,
smpPingInterval = smpPingInterval,
smpPingCount = smpPingCount
@@ -1866,6 +1872,7 @@ object ChatController {
appPrefs.networkSessionMode.set(cfg.sessionMode)
appPrefs.networkTCPConnectTimeout.set(cfg.tcpConnectTimeout)
appPrefs.networkTCPTimeout.set(cfg.tcpTimeout)
appPrefs.networkTCPTimeoutPerKb.set(cfg.tcpTimeoutPerKb)
appPrefs.networkSMPPingInterval.set(cfg.smpPingInterval)
appPrefs.networkSMPPingCount.set(cfg.smpPingCount)
if (cfg.tcpKeepAlive != null) {
@@ -2324,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)
}
}
@@ -2352,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
}
}
@@ -2419,6 +2426,7 @@ data class NetCfg(
val sessionMode: TransportSessionMode,
val tcpConnectTimeout: Long, // microseconds
val tcpTimeout: Long, // microseconds
val tcpTimeoutPerKb: Long, // microseconds
val tcpKeepAlive: KeepAliveOpts?,
val smpPingInterval: Long, // microseconds
val smpPingCount: Int,
@@ -2445,6 +2453,7 @@ data class NetCfg(
sessionMode = TransportSessionMode.User,
tcpConnectTimeout = 10_000_000,
tcpTimeout = 7_000_000,
tcpTimeoutPerKb = 10_000,
tcpKeepAlive = KeepAliveOpts.defaults,
smpPingInterval = 1200_000_000,
smpPingCount = 3
@@ -2458,6 +2467,7 @@ data class NetCfg(
sessionMode = TransportSessionMode.User,
tcpConnectTimeout = 20_000_000,
tcpTimeout = 15_000_000,
tcpTimeoutPerKb = 20_000,
tcpKeepAlive = KeepAliveOpts.defaults,
smpPingInterval = 1200_000_000,
smpPingCount = 3
@@ -2621,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 {
@@ -2649,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)
}
}
}
@@ -2674,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)
}
@@ -2760,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
@@ -2837,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
@@ -2865,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)
}
}
}
@@ -2942,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
@@ -2974,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)
}
}
}
@@ -3048,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)
}
}
@@ -3124,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)
}
}
@@ -3204,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
@@ -3648,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")
}
}

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