diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index eb2873e7ed57bab6887aec5b9785a87c916facee..ca65b3ec5c8debdf74ba65d4b1173a111821f247 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -26,5 +26,10 @@ <option name="name" value="Google" /> <option name="url" value="https://dl.google.com/dl/android/maven2/" /> </remote-repository> + <remote-repository> + <option name="id" value="maven2" /> + <option name="name" value="maven2" /> + <option name="url" value="https://github.com/vector-im/jitsi_libre_maven/raw/master/android-sdk-2.9.3" /> + </remote-repository> </component> </project> \ No newline at end of file diff --git a/CHANGES.md b/CHANGES.md index ff42b7d759b272723aeceba0babc10aca5a9fc81..125e9b3ac914145cddc73865193cf5e5559d7558 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ Please also refer to the Changelog of Element Android: https://github.com/vector-im/element-android/blob/master/CHANGES.md +Changes in Matrix-SDK 1.0.6 (2020-09-08) +=================================================== + +Imported from Element 1.0.6. + Changes in Matrix-SDK 1.0.5 (2020-08-21) =================================================== diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 29a8b67550418884d30dcee7d5c303f24afc54a5..e2ad3986e09e89dcd9715f47612682ef3886e210 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -26,7 +26,7 @@ android { minSdkVersion 21 targetSdkVersion 29 versionCode 1 - versionName "1.0.5" + versionName "1.0.6" // Multidex is useful for tests multiDexEnabled true testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -112,18 +112,18 @@ dependencies { def moshi_version = '1.8.0' def lifecycle_version = '2.2.0' def arch_version = '2.1.0' - def coroutines_version = "1.3.2" + def coroutines_version = "1.3.8" def markwon_version = '3.1.0' def daggerVersion = '2.25.4' - def work_version = '2.3.3' + def work_version = '2.4.0' def retrofit_version = '2.6.2' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "androidx.appcompat:appcompat:1.1.0" - implementation "androidx.core:core-ktx:1.3.0" + implementation "androidx.appcompat:appcompat:1.2.0" + implementation "androidx.core:core-ktx:1.3.1" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" @@ -131,8 +131,6 @@ dependencies { // Network implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" - implementation "com.squareup.retrofit2:converter-scalars:$retrofit_version" - implementation(platform("com.squareup.okhttp3:okhttp-bom:4.8.1")) implementation 'com.squareup.okhttp3:okhttp' @@ -146,7 +144,6 @@ dependencies { // Image implementation 'androidx.exifinterface:exifinterface:1.3.0-alpha01' - implementation 'id.zelory:compressor:3.0.0' // Database implementation 'com.github.Zhuinden:realm-monarchy:0.5.1' diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt index df359f2adc42af8c47250ad303e8b3b652b4c2b4..df26bb12273f973dc48dc6419e7fc9ce67021b97 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/api/Matrix.kt @@ -23,15 +23,12 @@ import androidx.work.WorkManager import com.zhuinden.monarchy.Monarchy import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.auth.AuthenticationService -import org.matrix.android.sdk.common.DaggerTestMatrixComponent import org.matrix.android.sdk.api.legacy.LegacySessionImporter +import org.matrix.android.sdk.common.DaggerTestMatrixComponent import org.matrix.android.sdk.internal.SessionManager -import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt -import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.olm.OlmManager -import java.io.InputStream import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @@ -96,9 +93,5 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo fun getSdkVersion(): String { return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")" } - - fun decryptStream(inputStream: InputStream?, elementToDecrypt: ElementToDecrypt): InputStream? { - return MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) - } } } diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt index 05dbc40e1e42b545c37f5d7608322d783dcbb44d..1e109f11ae053f573d7ec3f44e37454b5bd0af7e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/AttachmentEncryptionTest.kt @@ -19,17 +19,17 @@ package org.matrix.android.sdk.internal.crypto import android.os.MemoryFile import android.util.Base64 import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments -import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo -import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey import org.junit.Assert.assertEquals import org.junit.Assert.assertNotEquals -import org.junit.Assert.assertNotNull import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters -import java.io.ByteArrayInputStream +import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments +import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo +import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey +import org.matrix.android.sdk.internal.crypto.attachments.toElementToDecrypt +import java.io.ByteArrayOutputStream import java.io.InputStream /** @@ -41,29 +41,26 @@ import java.io.InputStream class AttachmentEncryptionTest { private fun checkDecryption(input: String, encryptedFileInfo: EncryptedFileInfo): String { - val `in` = Base64.decode(input, Base64.DEFAULT) + val inputAsByteArray = Base64.decode(input, Base64.DEFAULT) val inputStream: InputStream - inputStream = if (`in`.isEmpty()) { - ByteArrayInputStream(`in`) + inputStream = if (inputAsByteArray.isEmpty()) { + inputAsByteArray.inputStream() } else { - val memoryFile = MemoryFile("file" + System.currentTimeMillis(), `in`.size) - memoryFile.outputStream.write(`in`) + val memoryFile = MemoryFile("file" + System.currentTimeMillis(), inputAsByteArray.size) + memoryFile.outputStream.write(inputAsByteArray) memoryFile.inputStream } - val decryptedStream = MXEncryptedAttachments.decryptAttachment(inputStream, encryptedFileInfo) - - assertNotNull(decryptedStream) - - val buffer = ByteArray(100) + val decryptedStream = ByteArrayOutputStream() + val result = MXEncryptedAttachments.decryptAttachment(inputStream, encryptedFileInfo.toElementToDecrypt()!!, decryptedStream) - val len = decryptedStream!!.read(buffer) + assert(result) - decryptedStream.close() + val toByteArray = decryptedStream.toByteArray() - return Base64.encodeToString(buffer, 0, len, Base64.DEFAULT).replace("\n".toRegex(), "").replace("=".toRegex(), "") + return Base64.encodeToString(toByteArray, 0, toByteArray.size, Base64.DEFAULT).replace("\n".toRegex(), "").replace("=".toRegex(), "") } @Test @@ -74,7 +71,7 @@ class AttachmentEncryptionTest { key = EncryptedFileKey( alg = "A256CTR", k = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", - key_ops = listOf("encrypt", "decrypt"), + keyOps = listOf("encrypt", "decrypt"), kty = "oct", ext = true ), @@ -93,7 +90,7 @@ class AttachmentEncryptionTest { key = EncryptedFileKey( alg = "A256CTR", k = "__________________________________________8", - key_ops = listOf("encrypt", "decrypt"), + keyOps = listOf("encrypt", "decrypt"), kty = "oct", ext = true ), @@ -112,7 +109,7 @@ class AttachmentEncryptionTest { key = EncryptedFileKey( alg = "A256CTR", k = "__________________________________________8", - key_ops = listOf("encrypt", "decrypt"), + keyOps = listOf("encrypt", "decrypt"), kty = "oct", ext = true ), @@ -133,7 +130,7 @@ class AttachmentEncryptionTest { key = EncryptedFileKey( alg = "A256CTR", k = "__________________________________________8", - key_ops = listOf("encrypt", "decrypt"), + keyOps = listOf("encrypt", "decrypt"), kty = "oct", ext = true ), diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt index 9b85310d506513668706b58f4e9a1bad6d3e4f86..eebaa93415d8ec0529f4dfadc84feb93a8bb309b 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParserTest.kt @@ -17,23 +17,22 @@ package org.matrix.android.sdk.internal.session.room.send import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.matrix.android.sdk.InstrumentedTest import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer -import org.commonmark.renderer.text.TextContentRenderer import org.junit.Assert.assertEquals import org.junit.FixMethodOrder import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.MethodSorters +import org.matrix.android.sdk.InstrumentedTest /** * It will not be possible to test all combinations. For the moment I add a few tests, then, depending on the problem discovered in the wild, * we can add more tests to cover the edge cases. * Some tests are suffixed with `_not_passing`, maybe one day we will fix them... - * Riot-Web should be used as a reference for expected results, but not always. Especially Riot-Web add lots of `\n` in the - * formatted body, which is quite useless. - * Also Riot-Web does not provide plain text body when formatted text is provided. The body contains what the user has entered. + * Element Web should be used as a reference for expected results, but not always. + * Also Element Web does not provide plain text body when formatted text is provided. The body contains what the user has entered. We are doing + * the same to be able to edit messages (See #1939) * See https://matrix.org/docs/spec/client_server/latest#m-room-message-msgtypes */ @Suppress("SpellCheckingInspection") @@ -46,8 +45,7 @@ class MarkdownParserTest : InstrumentedTest { */ private val markdownParser = MarkdownParser( Parser.builder().build(), - HtmlRenderer.builder().build(), - TextContentRenderer.builder().build() + HtmlRenderer.builder().build() ) @Test @@ -83,6 +81,15 @@ class MarkdownParserTest : InstrumentedTest { ) } + @Test + fun parseBoldNewLines() { + testTypeNewLines( + name = "bold", + markdownPattern = "**", + htmlExpectedTag = "strong" + ) + } + @Test fun parseItalic() { testType( @@ -92,14 +99,23 @@ class MarkdownParserTest : InstrumentedTest { ) } + @Test + fun parseItalicNewLines() { + testTypeNewLines( + name = "italic", + markdownPattern = "*", + htmlExpectedTag = "em" + ) + } + @Test fun parseItalic2() { - // Riot-Web format - "_italic_".let { markdownParser.parse(it) }.expect("italic", "<em>italic</em>") + // Element Web format + "_italic_".let { markdownParser.parse(it).expect(it, "<em>italic</em>") } } /** - * Note: the test is not passing, it does not work on Riot-Web neither + * Note: the test is not passing, it does not work on Element Web neither */ @Test fun parseStrike_not_passing() { @@ -110,14 +126,30 @@ class MarkdownParserTest : InstrumentedTest { ) } + @Test + fun parseStrikeNewLines() { + testTypeNewLines( + name = "strike", + markdownPattern = "~~", + htmlExpectedTag = "del" + ) + } + @Test fun parseCode() { testType( name = "code", markdownPattern = "`", - htmlExpectedTag = "code", - plainTextPrefix = "\"", - plainTextSuffix = "\"" + htmlExpectedTag = "code" + ) + } + + @Test + fun parseCodeNewLines() { + testTypeNewLines( + name = "code", + markdownPattern = "`", + htmlExpectedTag = "code" ) } @@ -126,9 +158,16 @@ class MarkdownParserTest : InstrumentedTest { testType( name = "code", markdownPattern = "``", - htmlExpectedTag = "code", - plainTextPrefix = "\"", - plainTextSuffix = "\"" + htmlExpectedTag = "code" + ) + } + + @Test + fun parseCode2NewLines() { + testTypeNewLines( + name = "code", + markdownPattern = "``", + htmlExpectedTag = "code" ) } @@ -137,78 +176,85 @@ class MarkdownParserTest : InstrumentedTest { testType( name = "code", markdownPattern = "```", - htmlExpectedTag = "code", - plainTextPrefix = "\"", - plainTextSuffix = "\"" + htmlExpectedTag = "code" + ) + } + + @Test + fun parseCode3NewLines() { + testTypeNewLines( + name = "code", + markdownPattern = "```", + htmlExpectedTag = "code" ) } @Test fun parseUnorderedList() { - "- item1".let { markdownParser.parse(it).expect(it, "<ul><li>item1</li></ul>") } - "- item1\n- item2".let { markdownParser.parse(it).expect(it, "<ul><li>item1</li><li>item2</li></ul>") } + "- item1".let { markdownParser.parse(it).expect(it, "<ul>\n<li>item1</li>\n</ul>") } + "- item1\n- item2".let { markdownParser.parse(it).expect(it, "<ul>\n<li>item1</li>\n<li>item2</li>\n</ul>") } } @Test fun parseOrderedList() { - "1. item1".let { markdownParser.parse(it).expect(it, "<ol><li>item1</li></ol>") } - "1. item1\n2. item2".let { markdownParser.parse(it).expect(it, "<ol><li>item1</li><li>item2</li></ol>") } + "1. item1".let { markdownParser.parse(it).expect(it, "<ol>\n<li>item1</li>\n</ol>") } + "1. item1\n2. item2".let { markdownParser.parse(it).expect(it, "<ol>\n<li>item1</li>\n<li>item2</li>\n</ol>") } } @Test fun parseHorizontalLine() { - "---".let { markdownParser.parse(it) }.expect("***", "<hr />") + "---".let { markdownParser.parse(it).expect(it, "<hr />") } } @Test fun parseH2AndContent() { - "a\n---\nb".let { markdownParser.parse(it) }.expect("a\nb", "<h2>a</h2><p>b</p>") + "a\n---\nb".let { markdownParser.parse(it).expect(it, "<h2>a</h2>\n<p>b</p>") } } @Test fun parseQuote() { - "> quoted".let { markdownParser.parse(it) }.expect("«quoted»", "<blockquote><p>quoted</p></blockquote>") + "> quoted".let { markdownParser.parse(it).expect(it, "<blockquote>\n<p>quoted</p>\n</blockquote>") } } @Test fun parseQuote_not_passing() { - "> quoted\nline2".let { markdownParser.parse(it) }.expect("«quoted\nline2»", "<blockquote><p>quoted<br/>line2</p></blockquote>") + "> quoted\nline2".let { markdownParser.parse(it).expect(it, "<blockquote><p>quoted<br />line2</p></blockquote>") } } @Test fun parseBoldItalic() { - "*italic* **bold**".let { markdownParser.parse(it) }.expect("italic bold", "<em>italic</em> <strong>bold</strong>") - "**bold** *italic*".let { markdownParser.parse(it) }.expect("bold italic", "<strong>bold</strong> <em>italic</em>") + "*italic* **bold**".let { markdownParser.parse(it).expect(it, "<em>italic</em> <strong>bold</strong>") } + "**bold** *italic*".let { markdownParser.parse(it).expect(it, "<strong>bold</strong> <em>italic</em>") } } @Test fun parseHead() { - "# head1".let { markdownParser.parse(it) }.expect("head1", "<h1>head1</h1>") - "## head2".let { markdownParser.parse(it) }.expect("head2", "<h2>head2</h2>") - "### head3".let { markdownParser.parse(it) }.expect("head3", "<h3>head3</h3>") - "#### head4".let { markdownParser.parse(it) }.expect("head4", "<h4>head4</h4>") - "##### head5".let { markdownParser.parse(it) }.expect("head5", "<h5>head5</h5>") - "###### head6".let { markdownParser.parse(it) }.expect("head6", "<h6>head6</h6>") + "# head1".let { markdownParser.parse(it).expect(it, "<h1>head1</h1>") } + "## head2".let { markdownParser.parse(it).expect(it, "<h2>head2</h2>") } + "### head3".let { markdownParser.parse(it).expect(it, "<h3>head3</h3>") } + "#### head4".let { markdownParser.parse(it).expect(it, "<h4>head4</h4>") } + "##### head5".let { markdownParser.parse(it).expect(it, "<h5>head5</h5>") } + "###### head6".let { markdownParser.parse(it).expect(it, "<h6>head6</h6>") } } @Test fun parseHeads() { - "# head1\n# head2".let { markdownParser.parse(it) }.expect("head1\nhead2", "<h1>head1</h1><h1>head2</h1>") + "# head1\n# head2".let { markdownParser.parse(it).expect(it, "<h1>head1</h1>\n<h1>head2</h1>") } } @Test fun parseBoldNewLines_not_passing() { - "**bold**\nline2".let { markdownParser.parse(it) }.expect("bold\nline2", "<strong>bold</strong><br />line2") + "**bold**\nline2".let { markdownParser.parse(it).expect(it, "<strong>bold</strong><br />line2") } } @Test fun parseLinks() { - "[link](target)".let { markdownParser.parse(it) }.expect(""""link" (target)""", """<a href="target">link</a>""") + "[link](target)".let { markdownParser.parse(it).expect(it, """<a href="target">link</a>""") } } @Test fun parseParagraph() { - "# head\ncontent".let { markdownParser.parse(it) }.expect("head\ncontent", "<h1>head</h1><p>content</p>") + "# head\ncontent".let { markdownParser.parse(it).expect(it, "<h1>head</h1>\n<p>content</p>") } } private fun testIdentity(text: String) { @@ -217,59 +263,93 @@ class MarkdownParserTest : InstrumentedTest { private fun testType(name: String, markdownPattern: String, - htmlExpectedTag: String, - plainTextPrefix: String = "", - plainTextSuffix: String = "") { + htmlExpectedTag: String) { // Test simple case "$markdownPattern$name$markdownPattern" - .let { markdownParser.parse(it) } - .expect(expectedText = "$plainTextPrefix$name$plainTextSuffix", - expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>") + } // Test twice the same tag "$markdownPattern$name$markdownPattern and $markdownPattern$name bis$markdownPattern" - .let { markdownParser.parse(it) } - .expect(expectedText = "$plainTextPrefix$name$plainTextSuffix and $plainTextPrefix$name bis$plainTextSuffix", - expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> and <$htmlExpectedTag>$name bis</$htmlExpectedTag>") + } val textBefore = "a" val textAfter = "b" // With sticked text before "$textBefore$markdownPattern$name$markdownPattern" - .let { markdownParser.parse(it) } - .expect(expectedText = "$textBefore$plainTextPrefix$name$plainTextSuffix", - expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "$textBefore<$htmlExpectedTag>$name</$htmlExpectedTag>") + } // With text before and space "$textBefore $markdownPattern$name$markdownPattern" - .let { markdownParser.parse(it) } - .expect(expectedText = "$textBefore $plainTextPrefix$name$plainTextSuffix", - expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag>") + } // With sticked text after "$markdownPattern$name$markdownPattern$textAfter" - .let { markdownParser.parse(it) } - .expect(expectedText = "$plainTextPrefix$name$plainTextSuffix$textAfter", - expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter") + } // With space and text after "$markdownPattern$name$markdownPattern $textAfter" - .let { markdownParser.parse(it) } - .expect(expectedText = "$plainTextPrefix$name$plainTextSuffix $textAfter", - expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter") + } // With sticked text before and text after "$textBefore$markdownPattern$name$markdownPattern$textAfter" - .let { markdownParser.parse(it) } - .expect(expectedText = "$textBefore$plainTextPrefix$name$plainTextSuffix$textAfter", - expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "a<$htmlExpectedTag>$name</$htmlExpectedTag>$textAfter") + } // With text before and after, with spaces "$textBefore $markdownPattern$name$markdownPattern $textAfter" - .let { markdownParser.parse(it) } - .expect(expectedText = "$textBefore $plainTextPrefix$name$plainTextSuffix $textAfter", - expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter") + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "$textBefore <$htmlExpectedTag>$name</$htmlExpectedTag> $textAfter") + } + } + + private fun testTypeNewLines(name: String, + markdownPattern: String, + htmlExpectedTag: String) { + // With new line inside the block + "$markdownPattern$name\n$name$markdownPattern" + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name<br />$name</$htmlExpectedTag>") + } + + // With new line between two blocks + "$markdownPattern$name$markdownPattern\n$markdownPattern$name$markdownPattern" + .let { + markdownParser.parse(it) + .expect(expectedText = it, + expectedFormattedText = "<$htmlExpectedTag>$name</$htmlExpectedTag><$htmlExpectedTag>$name</$htmlExpectedTag>") + } } private fun TextContent.expect(expectedText: String, expectedFormattedText: String?) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt index 6cd003ddae4865952d50c8b7245e9f0d5d77b91e..aafefa204861176dbd2e27ac06a3751f3901bff2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/Matrix.kt @@ -26,13 +26,10 @@ import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.legacy.LegacySessionImporter import org.matrix.android.sdk.internal.SessionManager -import org.matrix.android.sdk.internal.crypto.attachments.ElementToDecrypt -import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments import org.matrix.android.sdk.internal.di.DaggerMatrixComponent import org.matrix.android.sdk.internal.network.UserAgentHolder import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.olm.OlmManager -import java.io.InputStream import java.util.concurrent.Executors import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject @@ -97,9 +94,5 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo fun getSdkVersion(): String { return BuildConfig.VERSION_NAME + " (" + BuildConfig.GIT_SDK_REVISION + ")" } - - fun decryptStream(inputStream: InputStream?, elementToDecrypt: ElementToDecrypt): InputStream? { - return MXEncryptedAttachments.decryptAttachment(inputStream, elementToDecrypt) - } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt index a736a4f1be8ffe5afc86417856f12c8e01d1adf8..ec2dfd214cd1894999fa629cabdc70d1dbf43324 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/wellknown/WellknownResult.kt @@ -45,7 +45,7 @@ sealed class WellknownResult { /** * Inform the user that auto-discovery failed due to invalid/empty data and PROMPT for the parameter. */ - object FailPrompt : WellknownResult() + data class FailPrompt(val homeServerUrl: String?, val wellKnown: WellKnown?) : WellknownResult() /** * Inform the user that auto-discovery did not return any usable URLs. Do not continue further with the current login process. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt index 7a21920e586bb7873ac1836173fc16d0dfda7f1b..ff586507814a219fccc7577754652918dccd4ca6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Action.kt @@ -24,20 +24,23 @@ sealed class Action { object DoNotNotify : Action() data class Sound(val sound: String = ACTION_OBJECT_VALUE_VALUE_DEFAULT) : Action() data class Highlight(val highlight: Boolean) : Action() -} -private const val ACTION_NOTIFY = "notify" -private const val ACTION_DONT_NOTIFY = "dont_notify" -private const val ACTION_COALESCE = "coalesce" + companion object { + const val ACTION_NOTIFY = "notify" + const val ACTION_DONT_NOTIFY = "dont_notify" + const val ACTION_COALESCE = "coalesce" -// Ref: https://matrix.org/docs/spec/client_server/latest#tweaks -private const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak" + // Ref: https://matrix.org/docs/spec/client_server/latest#tweaks + const val ACTION_OBJECT_SET_TWEAK_KEY = "set_tweak" -private const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound" -private const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight" + const val ACTION_OBJECT_SET_TWEAK_VALUE_SOUND = "sound" + const val ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT = "highlight" -private const val ACTION_OBJECT_VALUE_KEY = "value" -private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default" + const val ACTION_OBJECT_VALUE_KEY = "value" + const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default" + const val ACTION_OBJECT_VALUE_VALUE_RING = "ring" + } +} /** * Ref: https://matrix.org/docs/spec/client_server/latest#actions @@ -69,18 +72,18 @@ private const val ACTION_OBJECT_VALUE_VALUE_DEFAULT = "default" fun List<Action>.toJson(): List<Any> { return map { action -> when (action) { - is Action.Notify -> ACTION_NOTIFY - is Action.DoNotNotify -> ACTION_DONT_NOTIFY - is Action.Sound -> { + is Action.Notify -> Action.ACTION_NOTIFY + is Action.DoNotNotify -> Action.ACTION_DONT_NOTIFY + is Action.Sound -> { mapOf( - ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_SOUND, - ACTION_OBJECT_VALUE_KEY to action.sound + Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND, + Action.ACTION_OBJECT_VALUE_KEY to action.sound ) } - is Action.Highlight -> { + is Action.Highlight -> { mapOf( - ACTION_OBJECT_SET_TWEAK_KEY to ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT, - ACTION_OBJECT_VALUE_KEY to action.highlight + Action.ACTION_OBJECT_SET_TWEAK_KEY to Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT, + Action.ACTION_OBJECT_VALUE_KEY to action.highlight ) } } @@ -92,26 +95,26 @@ fun PushRule.getActions(): List<Action> { actions.forEach { actionStrOrObj -> when (actionStrOrObj) { - ACTION_NOTIFY -> Action.Notify - ACTION_DONT_NOTIFY -> Action.DoNotNotify - is Map<*, *> -> { - when (actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]) { - ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { - (actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue -> + Action.ACTION_NOTIFY -> Action.Notify + Action.ACTION_DONT_NOTIFY -> Action.DoNotNotify + is Map<*, *> -> { + when (actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]) { + Action.ACTION_OBJECT_SET_TWEAK_VALUE_SOUND -> { + (actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? String)?.let { stringValue -> Action.Sound(stringValue) } // When the value is not there, default sound (not specified by the spec) - ?: Action.Sound(ACTION_OBJECT_VALUE_VALUE_DEFAULT) + ?: Action.Sound(Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT) } - ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> { - (actionStrOrObj[ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue -> + Action.ACTION_OBJECT_SET_TWEAK_VALUE_HIGHLIGHT -> { + (actionStrOrObj[Action.ACTION_OBJECT_VALUE_KEY] as? Boolean)?.let { boolValue -> Action.Highlight(boolValue) } // When the value is not there, default is true, says the spec ?: Action.Highlight(true) } else -> { - Timber.w("Unsupported set_tweak value ${actionStrOrObj[ACTION_OBJECT_SET_TWEAK_KEY]}") + Timber.w("Unsupported set_tweak value ${actionStrOrObj[Action.ACTION_OBJECT_SET_TWEAK_KEY]}") null } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt index 50c2f8505bd3446262fe3e7cd96108397e1356b4..3b1082ea0abb8c89e882918526de72ca56983428 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Condition.kt @@ -18,32 +18,8 @@ package org.matrix.android.sdk.api.pushrules import org.matrix.android.sdk.api.session.events.model.Event -abstract class Condition(val kind: Kind) { +interface Condition { + fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean - enum class Kind(val value: String) { - EventMatch("event_match"), - ContainsDisplayName("contains_display_name"), - RoomMemberCount("room_member_count"), - SenderNotificationPermission("sender_notification_permission"), - Unrecognised(""); - - companion object { - - fun fromString(value: String): Kind { - return when (value) { - "event_match" -> EventMatch - "contains_display_name" -> ContainsDisplayName - "room_member_count" -> RoomMemberCount - "sender_notification_permission" -> SenderNotificationPermission - else -> Unrecognised - } - } - } - } - - abstract fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean - - open fun technicalDescription(): String { - return "Kind: $kind" - } + fun technicalDescription(): String } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt index a836c24c4eb761efac94e0664a25ae737fc476cd..72eda20679e4afe6334e49e0558b3c269499454b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/ContainsDisplayNameCondition.kt @@ -20,17 +20,15 @@ import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageContent -import timber.log.Timber +import org.matrix.android.sdk.internal.util.caseInsensitiveFind -class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) { +class ContainsDisplayNameCondition : Condition { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveContainsDisplayNameCondition(event, this) } - override fun technicalDescription(): String { - return "User is mentioned" - } + override fun technicalDescription() = "User is mentioned" fun isSatisfied(event: Event, displayName: String): Boolean { val message = when (event.type) { @@ -45,31 +43,6 @@ class ContainsDisplayNameCondition : Condition(Kind.ContainsDisplayName) { else -> null } ?: return false - return caseInsensitiveFind(displayName, message.body) - } - - companion object { - /** - * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. - * - * @param subString the string to search for - * @param longString the string to search in - * @return whether a match was found - */ - fun caseInsensitiveFind(subString: String, longString: String): Boolean { - // add sanity checks - if (subString.isEmpty() || longString.isEmpty()) { - return false - } - - try { - val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE) - return regex.containsMatchIn(longString) - } catch (e: Exception) { - Timber.e(e, "## caseInsensitiveFind() : failed") - } - - return false - } + return message.body.caseInsensitiveFind(displayName) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt index 5eed785899143b9a173a777a0e4d1a9a5d62224c..c9aa0d001a0330e25bfeb546d3c34d4d05c92b80 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/EventMatchCondition.kt @@ -18,6 +18,9 @@ package org.matrix.android.sdk.api.pushrules import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.util.caseInsensitiveFind +import org.matrix.android.sdk.internal.util.hasSpecialGlobChar +import org.matrix.android.sdk.internal.util.simpleGlobToRegExp import timber.log.Timber class EventMatchCondition( @@ -29,16 +32,18 @@ class EventMatchCondition( * The glob-style pattern to match against. Patterns with no special glob characters should * be treated as having asterisks prepended and appended when testing the condition. */ - val pattern: String -) : Condition(Kind.EventMatch) { + val pattern: String, + /** + * true to match only words. In this case pattern will not be considered as a glob + */ + val wordsOnly: Boolean +) : Condition { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveEventMatchCondition(event, this) } - override fun technicalDescription(): String { - return "'$key' Matches '$pattern'" - } + override fun technicalDescription() = "'$key' matches '$pattern', words only '$wordsOnly'" fun isSatisfied(event: Event): Boolean { // TODO encrypted events? @@ -48,14 +53,18 @@ class EventMatchCondition( // Patterns with no special glob characters should be treated as having asterisks prepended // and appended when testing the condition. - try { - val modPattern = if (hasSpecialGlobChar(pattern)) simpleGlobToRegExp(pattern) else simpleGlobToRegExp("*$pattern*") - val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL) - return regex.containsMatchIn(value) + return try { + if (wordsOnly) { + value.caseInsensitiveFind(pattern) + } else { + val modPattern = if (pattern.hasSpecialGlobChar()) pattern.simpleGlobToRegExp() else "*$pattern*".simpleGlobToRegExp() + val regex = Regex(modPattern, RegexOption.DOT_MATCHES_ALL) + regex.containsMatchIn(value) + } } catch (e: Throwable) { // e.g PatternSyntaxException Timber.e(e, "Failed to evaluate push condition") - return false + false } } @@ -78,27 +87,4 @@ class EventMatchCondition( } return null } - - companion object { - - private fun hasSpecialGlobChar(glob: String): Boolean { - return glob.contains("*") || glob.contains("?") - } - - // Very simple glob to regexp converter - private fun simpleGlobToRegExp(glob: String): String { - var out = "" // "^" - for (element in glob) { - when (element) { - '*' -> out += ".*" - '?' -> out += '.'.toString() - '.' -> out += "\\." - '\\' -> out += "\\\\" - else -> out += element - } - } - out += "" // '$'.toString() - return out - } - } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt new file mode 100644 index 0000000000000000000000000000000000000000..78f3a8a15656726ad85a02ef7d9a9f4241780cba --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/Kind.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.pushrules + +enum class Kind(val value: String) { + EventMatch("event_match"), + ContainsDisplayName("contains_display_name"), + RoomMemberCount("room_member_count"), + SenderNotificationPermission("sender_notification_permission"), + Unrecognised(""); + + companion object { + + fun fromString(value: String): Kind { + return when (value) { + "event_match" -> EventMatch + "contains_display_name" -> ContainsDisplayName + "room_member_count" -> RoomMemberCount + "sender_notification_permission" -> SenderNotificationPermission + else -> Unrecognised + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt index f97636a7bdc6a0b1eb8278ede13ee2ec3b8d5bbe..ba36c54fb4469ab5c9e16357e12c16a2103cafd5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RoomMemberCountCondition.kt @@ -29,15 +29,13 @@ class RoomMemberCountCondition( * If no prefix is present, this parameter defaults to ==. */ val iz: String -) : Condition(Kind.RoomMemberCount) { +) : Condition { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveRoomMemberCountCondition(event, this) } - override fun technicalDescription(): String { - return "Room member count is $iz" - } + override fun technicalDescription() = "Room member count is $iz" internal fun isSatisfied(event: Event, roomGetter: RoomGetter): Boolean { // sanity checks diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt index eeb2577d4c3395286455069eb0787c1477105381..2353d06252cc52f2f06295540804f580926debe6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/RuleIds.kt @@ -45,4 +45,6 @@ object RuleIds { // Not documented const val RULE_ID_FALLBACK = ".m.rule.fallback" + + const val RULE_ID_REACTION = ".m.rule.reaction" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt index a8d08e54586bfdf6c93f654427c1c35bdf8b24c8..aeb2f01c8087574cbe1dcfb1b5ebff1196e1b40e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/SenderNotificationPermissionCondition.kt @@ -28,15 +28,13 @@ class SenderNotificationPermissionCondition( * type from the notifications object in the power level event content. */ val key: String -) : Condition(Kind.SenderNotificationPermission) { +) : Condition { override fun isSatisfied(event: Event, conditionResolver: ConditionResolver): Boolean { return conditionResolver.resolveSenderNotificationPermissionCondition(event, this) } - override fun technicalDescription(): String { - return "User power level <$key>" - } + override fun technicalDescription() = "User power level <$key>" fun isSatisfied(event: Event, powerLevels: PowerLevelsContent): Boolean { val powerLevelsHelper = PowerLevelsHelper(powerLevels) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt index 9469da3ea5e99e4b681d461b904b0a80544c3002..29466ca33bf798fd1962e69dc788fb68154b10de 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushCondition.kt @@ -21,7 +21,9 @@ import com.squareup.moshi.JsonClass import org.matrix.android.sdk.api.pushrules.Condition import org.matrix.android.sdk.api.pushrules.ContainsDisplayNameCondition import org.matrix.android.sdk.api.pushrules.EventMatchCondition +import org.matrix.android.sdk.api.pushrules.Kind import org.matrix.android.sdk.api.pushrules.RoomMemberCountCondition +import org.matrix.android.sdk.api.pushrules.RuleIds import org.matrix.android.sdk.api.pushrules.SenderNotificationPermissionCondition import timber.log.Timber @@ -58,20 +60,20 @@ data class PushCondition( val iz: String? = null ) { - fun asExecutableCondition(): Condition? { - return when (Condition.Kind.fromString(kind)) { - Condition.Kind.EventMatch -> { + fun asExecutableCondition(rule: PushRule): Condition? { + return when (Kind.fromString(kind)) { + Kind.EventMatch -> { if (key != null && pattern != null) { - EventMatchCondition(key, pattern) + EventMatchCondition(key, pattern, rule.ruleId == RuleIds.RULE_ID_CONTAIN_USER_NAME) } else { Timber.e("Malformed Event match condition") null } } - Condition.Kind.ContainsDisplayName -> { + Kind.ContainsDisplayName -> { ContainsDisplayNameCondition() } - Condition.Kind.RoomMemberCount -> { + Kind.RoomMemberCount -> { if (iz.isNullOrEmpty()) { Timber.e("Malformed ROOM_MEMBER_COUNT condition") null @@ -79,7 +81,7 @@ data class PushCondition( RoomMemberCountCondition(iz) } } - Condition.Kind.SenderNotificationPermission -> { + Kind.SenderNotificationPermission -> { if (key == null) { Timber.e("Malformed Sender Notification Permission condition") null @@ -87,7 +89,7 @@ data class PushCondition( SenderNotificationPermissionCondition(key) } } - Condition.Kind.Unrecognised -> { + Kind.Unrecognised -> { Timber.e("Unknown kind $kind") null } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt index 46d73a8aa28fa8208ebb6505daad9eb1566a014e..bdb4f2cf29fb303ae4ec0d4bf0358d8d7f556330 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/PushRule.kt @@ -63,7 +63,7 @@ data class PushRule( * Add the default notification sound. */ fun setNotificationSound(): PushRule { - return setNotificationSound(ACTION_VALUE_DEFAULT) + return setNotificationSound(Action.ACTION_OBJECT_VALUE_VALUE_DEFAULT) } fun getNotificationSound(): String? { @@ -109,13 +109,13 @@ data class PushRule( fun setNotify(notify: Boolean): PushRule { val mutableActions = actions.toMutableList() - mutableActions.remove(ACTION_DONT_NOTIFY) - mutableActions.remove(ACTION_NOTIFY) + mutableActions.remove(Action.ACTION_DONT_NOTIFY) + mutableActions.remove(Action.ACTION_NOTIFY) if (notify) { - mutableActions.add(ACTION_NOTIFY) + mutableActions.add(Action.ACTION_NOTIFY) } else { - mutableActions.add(ACTION_DONT_NOTIFY) + mutableActions.add(Action.ACTION_DONT_NOTIFY) } return copy(actions = mutableActions) @@ -126,51 +126,12 @@ data class PushRule( * * @return true if the rule should play sound */ - fun shouldNotify() = actions.contains(ACTION_NOTIFY) + fun shouldNotify() = actions.contains(Action.ACTION_NOTIFY) /** * Return true if the rule should not highlight the event. * * @return true if the rule should not play sound */ - fun shouldNotNotify() = actions.contains(ACTION_DONT_NOTIFY) - - companion object { - /* ========================================================================================== - * Rule id - * ========================================================================================== */ - - const val RULE_ID_DISABLE_ALL = ".m.rule.master" - const val RULE_ID_CONTAIN_USER_NAME = ".m.rule.contains_user_name" - const val RULE_ID_CONTAIN_DISPLAY_NAME = ".m.rule.contains_display_name" - const val RULE_ID_ONE_TO_ONE_ROOM = ".m.rule.room_one_to_one" - const val RULE_ID_INVITE_ME = ".m.rule.invite_for_me" - const val RULE_ID_PEOPLE_JOIN_LEAVE = ".m.rule.member_event" - const val RULE_ID_CALL = ".m.rule.call" - const val RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS = ".m.rule.suppress_notices" - const val RULE_ID_ALL_OTHER_MESSAGES_ROOMS = ".m.rule.message" - const val RULE_ID_AT_ROOMS = ".m.rule.roomnotif" - const val RULE_ID_TOMBSTONE = ".m.rule.tombstone" - const val RULE_ID_E2E_ONE_TO_ONE_ROOM = ".m.rule.encrypted_room_one_to_one" - const val RULE_ID_E2E_GROUP = ".m.rule.encrypted" - const val RULE_ID_REACTION = ".m.rule.reaction" - const val RULE_ID_FALLBACK = ".m.rule.fallback" - - /* ========================================================================================== - * Actions - * ========================================================================================== */ - - const val ACTION_NOTIFY = "notify" - const val ACTION_DONT_NOTIFY = "dont_notify" - const val ACTION_COALESCE = "coalesce" - - const val ACTION_SET_TWEAK_SOUND_VALUE = "sound" - const val ACTION_SET_TWEAK_HIGHLIGHT_VALUE = "highlight" - - const val ACTION_PARAMETER_SET_TWEAK = "set_tweak" - const val ACTION_PARAMETER_VALUE = "value" - - const val ACTION_VALUE_DEFAULT = "default" - const val ACTION_VALUE_RING = "ring" - } + fun shouldNotNotify() = actions.contains(Action.ACTION_DONT_NOTIFY) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt index eb813dba45f59c6c8447b12228111ed822b18c07..a8708819f57596af7ba92ae6e168c69443716fc3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/pushrules/rest/RuleSet.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.pushrules.rest import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.pushrules.RuleIds import org.matrix.android.sdk.api.pushrules.RuleSetKey /** @@ -51,7 +52,7 @@ data class RuleSet( var result: PushRuleAndKind? = null // sanity check if (null != ruleId) { - if (PushRule.RULE_ID_CONTAIN_USER_NAME == ruleId) { + if (RuleIds.RULE_ID_CONTAIN_USER_NAME == ruleId) { result = findRule(content, ruleId)?.let { PushRuleAndKind(it, RuleSetKey.CONTENT) } } else { // assume that the ruleId is unique. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt index 2962f9fac346a762342913fb125e3500f1cb8968..382ab54248b1e57a24af6566d35c4a65197ffd63 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallSignalingService.kt @@ -34,4 +34,6 @@ interface CallSignalingService { fun removeCallListener(listener: CallsListener) fun getCallWithId(callId: String) : MxCall? + + fun isThereAnyActiveCall(): Boolean } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt index a29e7110e2dae8413e7d43266aebdd93554d901f..a21677093903f7c6e7e50cfcd169d6b0980b12ef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/content/ContentUploadStateTracker.kt @@ -33,7 +33,7 @@ interface ContentUploadStateTracker { object Idle : State() object EncryptingThumbnail : State() data class UploadingThumbnail(val current: Long, val total: Long) : State() - object Encrypting : State() + data class Encrypting(val current: Long, val total: Long) : State() data class Uploading(val current: Long, val total: Long) : State() object Success : State() data class Failure(val throwable: Throwable) : State() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt index fdd3e667036959be57b5d6a7a59fa0bbb63b766d..1068b920191895cf1def7a5f0a187dc291bfa472 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt @@ -239,6 +239,14 @@ fun Event.isVideoMessage(): Boolean { } } +fun Event.isAudioMessage(): Boolean { + return getClearType() == EventType.MESSAGE + && when (getClearContent()?.toModel<MessageContent>()?.msgType) { + MessageType.MSGTYPE_AUDIO -> true + else -> false + } +} + fun Event.isFileMessage(): Boolean { return getClearType() == EventType.MESSAGE && when (getClearContent()?.toModel<MessageContent>()?.msgType) { @@ -246,6 +254,16 @@ fun Event.isFileMessage(): Boolean { else -> false } } +fun Event.isAttachmentMessage(): Boolean { + return getClearType() == EventType.MESSAGE + && when (getClearContent()?.toModel<MessageContent>()?.msgType) { + MessageType.MSGTYPE_IMAGE, + MessageType.MSGTYPE_AUDIO, + MessageType.MSGTYPE_VIDEO, + MessageType.MSGTYPE_FILE -> true + else -> false + } +} fun Event.getRelationContent(): RelationDefaultContent? { return if (isEncrypted()) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt index 85632d6e83d39d3cd25eb026ceb71f9364467410..1da65b3002ab418623fa79797bd51545b24f1853 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkData.kt @@ -25,7 +25,12 @@ import android.net.Uri */ sealed class PermalinkData { - data class RoomLink(val roomIdOrAlias: String, val isRoomAlias: Boolean, val eventId: String?) : PermalinkData() + data class RoomLink( + val roomIdOrAlias: String, + val isRoomAlias: Boolean, + val eventId: String?, + val viaParameters: List<String> + ) : PermalinkData() data class UserLink(val userId: String) : PermalinkData() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt index dd6847f1e368d04f33cae94068957fd04646f4bb..59e289ffd70d06010132f3f87d554fba871d5e92 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/permalinks/PermalinkParser.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.api.session.permalinks import android.net.Uri +import android.net.UrlQuerySanitizer import org.matrix.android.sdk.api.MatrixPatterns /** @@ -40,14 +41,13 @@ object PermalinkParser { if (!uri.toString().startsWith(PermalinkService.MATRIX_TO_URL_BASE)) { return PermalinkData.FallbackLink(uri) } - val fragment = uri.fragment if (fragment.isNullOrEmpty()) { return PermalinkData.FallbackLink(uri) } - val indexOfQuery = fragment.indexOf("?") val safeFragment = if (indexOfQuery != -1) fragment.substring(0, indexOfQuery) else fragment + val viaQueryParameters = fragment.getViaParameters() // we are limiting to 2 params val params = safeFragment @@ -65,17 +65,29 @@ object PermalinkParser { PermalinkData.RoomLink( roomIdOrAlias = identifier, isRoomAlias = false, - eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) } + eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, + viaParameters = viaQueryParameters ) } MatrixPatterns.isRoomAlias(identifier) -> { PermalinkData.RoomLink( roomIdOrAlias = identifier, isRoomAlias = true, - eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) } + eventId = extraParameter.takeIf { !it.isNullOrEmpty() && MatrixPatterns.isEventId(it) }, + viaParameters = viaQueryParameters ) } else -> PermalinkData.FallbackLink(uri) } } + + private fun String.getViaParameters(): List<String> { + return UrlQuerySanitizer(this) + .parameterList + .filter { + it.mParameter == "via" + }.map { + it.mValue + } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt index 449c670983f7206ceda91ccd7f8cf3964214bee8..15066cc4a658ebb6add28531c523c09c80d148b5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/profile/ProfileService.kt @@ -83,4 +83,43 @@ interface ProfileService { * @param refreshData set to true to fetch data from the homeserver */ fun getThreePidsLive(refreshData: Boolean): LiveData<List<ThreePid>> + + /** + * Get the pending 3Pids, i.e. ThreePids that have requested a token, but not yet validated by the user. + */ + fun getPendingThreePids(): List<ThreePid> + + /** + * Get the pending 3Pids Live + */ + fun getPendingThreePidsLive(): LiveData<List<ThreePid>> + + /** + * Add a 3Pids. This is the first step to add a ThreePid to an account. Then the threePid will be added to the pending threePid list. + */ + fun addThreePid(threePid: ThreePid, matrixCallback: MatrixCallback<Unit>): Cancelable + + /** + * Validate a code received by text message + */ + fun submitSmsCode(threePid: ThreePid.Msisdn, code: String, matrixCallback: MatrixCallback<Unit>): Cancelable + + /** + * Finalize adding a 3Pids. Call this method once the user has validated that he owns the ThreePid + */ + fun finalizeAddingThreePid(threePid: ThreePid, + uiaSession: String?, + accountPassword: String?, + matrixCallback: MatrixCallback<Unit>): Cancelable + + /** + * Cancel adding a threepid. It will remove locally stored data about this ThreePid + */ + fun cancelAddingThreePid(threePid: ThreePid, + matrixCallback: MatrixCallback<Unit>): Cancelable + + /** + * Remove a 3Pid from the Matrix account. + */ + fun deleteThreePid(threePid: ThreePid, matrixCallback: MatrixCallback<Unit>): Cancelable } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt index e84b75d0af8e4d8429eb58bf35814a42a01dcff6..b8e536cb33e8ac29e426d662512c57e4c75a7443 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt @@ -110,13 +110,13 @@ interface SendService { * Schedule this message to be resent * @param localEcho the unsent local echo */ - fun resendTextMessage(localEcho: TimelineEvent): Cancelable? + fun resendTextMessage(localEcho: TimelineEvent): Cancelable /** * Schedule this message to be resent * @param localEcho the unsent local echo */ - fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? + fun resendMediaMessage(localEcho: TimelineEvent): Cancelable /** * Remove this failed message from the timeline @@ -124,8 +124,16 @@ interface SendService { */ fun deleteFailedEcho(localEcho: TimelineEvent) + /** + * Delete all the events in one of the sending states + */ fun clearSendingQueue() + /** + * Cancel sending a specific event. It has to be in one of the sending states + */ + fun cancelSend(eventId: String) + /** * Resend all failed messages one by one (and keep order) */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt index f0dd2f3025c876996c511305c8f092dd1b95c2ff..be8849b20e67dffe24682664095c78d3bde1044e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendState.kt @@ -37,7 +37,8 @@ enum class SendState { internal companion object { val HAS_FAILED_STATES = listOf(UNDELIVERED, FAILED_UNKNOWN_DEVICES) val IS_SENT_STATES = listOf(SENT, SYNCED) - val IS_SENDING_STATES = listOf(UNSENT, ENCRYPTING, SENDING) + val IS_PROGRESSING_STATES = listOf(ENCRYPTING, SENDING) + val IS_SENDING_STATES = IS_PROGRESSING_STATES + UNSENT val PENDING_STATES = IS_SENDING_STATES + HAS_FAILED_STATES } @@ -45,5 +46,7 @@ enum class SendState { fun hasFailed() = HAS_FAILED_STATES.contains(this) + fun isInProgress() = IS_PROGRESSING_STATES.contains(this) + fun isSending() = IS_SENDING_STATES.contains(this) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt index 7fbdaacb81f55de699466e6d1a9ea879c482c4ff..3e6e3054b538571e309cc49bd62f7f16b247561a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/AddThreePidRegistrationParams.kt @@ -54,7 +54,7 @@ internal data class AddThreePidRegistrationParams( * This parameter is ignored when the homeserver handles 3PID verification. */ @Json(name = "id_server") - val id_server: String? = null, + val idServer: String? = null, /* ========================================================================================== * For emails diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt index 79b71b208e6aa685e5a4abc93743e3e93a01e614..676f40a918cffbb855973274684d5ec78a991fef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/DefaultRegistrationWizard.kt @@ -17,6 +17,9 @@ package org.matrix.android.sdk.internal.auth.registration +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.delay +import okhttp3.OkHttpClient import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.auth.registration.RegisterThreePid @@ -33,9 +36,6 @@ import org.matrix.android.sdk.internal.auth.db.PendingSessionData import org.matrix.android.sdk.internal.network.RetrofitFactory import org.matrix.android.sdk.internal.task.launchToCallback import org.matrix.android.sdk.internal.util.MatrixCoroutineDispatchers -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.delay -import okhttp3.OkHttpClient /** * This class execute the registration request and is responsible to keep the session of interactive authentication @@ -193,7 +193,7 @@ internal class DefaultRegistrationWizard( val registrationParams = pendingSessionData.currentThreePidData?.registrationParams ?: throw IllegalStateException("developer error, no pending three pid") val safeCurrentData = pendingSessionData.currentThreePidData ?: throw IllegalStateException("developer error, call createAccount() method first") - val url = safeCurrentData.addThreePidRegistrationResponse.submitUrl ?: throw IllegalStateException("Missing url the send the code") + val url = safeCurrentData.addThreePidRegistrationResponse.submitUrl ?: throw IllegalStateException("Missing url to send the code") val validationBody = ValidationCodeBody( clientSecret = pendingSessionData.clientSecret, sid = safeCurrentData.addThreePidRegistrationResponse.sid, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationParams.kt index 4089e280d749aecfddc3bb8c11865dfb4bbdb18d..ca475566f17a8c39e31afe0bdb08b4f088c584a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/registration/RegistrationParams.kt @@ -44,5 +44,6 @@ internal data class RegistrationParams( // Temporary flag to notify the server that we support msisdn flow. Used to prevent old app // versions to end up in fallback because the HS returns the msisdn flow which they don't support - val x_show_msisdn: Boolean? = null + @Json(name = "x_show_msisdn") + val xShowMsisdn: Boolean? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt index 4526ba8a51d0dd3bbe10f75289d55dcc841b54c2..85ecc540cd5b2f0814eb38b68c806c9fcbde06a7 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/MXMegolmExportEncryption.kt @@ -145,7 +145,7 @@ object MXMegolmExportEncryption { */ @Throws(Exception::class) @JvmOverloads - fun encryptMegolmKeyFile(data: String, password: String, kdf_rounds: Int = DEFAULT_ITERATION_COUNT): ByteArray { + fun encryptMegolmKeyFile(data: String, password: String, kdfRounds: Int = DEFAULT_ITERATION_COUNT): ByteArray { if (password.isEmpty()) { throw Exception("Empty password is not supported") } @@ -163,7 +163,7 @@ object MXMegolmExportEncryption { // of a single bit of salt is a price we have to pay. iv[9] = iv[9] and 0x7f - val deriveKey = deriveKeys(salt, kdf_rounds, password) + val deriveKey = deriveKeys(salt, kdfRounds, password) val decryptCipher = Cipher.getInstance("AES/CTR/NoPadding") @@ -188,10 +188,10 @@ object MXMegolmExportEncryption { System.arraycopy(iv, 0, resultBuffer, idx, iv.size) idx += iv.size - resultBuffer[idx++] = (kdf_rounds shr 24 and 0xff).toByte() - resultBuffer[idx++] = (kdf_rounds shr 16 and 0xff).toByte() - resultBuffer[idx++] = (kdf_rounds shr 8 and 0xff).toByte() - resultBuffer[idx++] = (kdf_rounds and 0xff).toByte() + resultBuffer[idx++] = (kdfRounds shr 24 and 0xff).toByte() + resultBuffer[idx++] = (kdfRounds shr 16 and 0xff).toByte() + resultBuffer[idx++] = (kdfRounds shr 8 and 0xff).toByte() + resultBuffer[idx++] = (kdfRounds and 0xff).toByte() System.arraycopy(cipherArray, 0, resultBuffer, idx, cipherArray.size) idx += cipherArray.size @@ -320,26 +320,26 @@ object MXMegolmExportEncryption { // 512 bits key length val key = ByteArray(64) - val Uc = ByteArray(64) + val uc = ByteArray(64) // U1 = PRF(Password, Salt || INT_32_BE(i)) prf.update(salt) val int32BE = ByteArray(4) { 0.toByte() } int32BE[3] = 1.toByte() prf.update(int32BE) - prf.doFinal(Uc, 0) + prf.doFinal(uc, 0) // copy to the key - System.arraycopy(Uc, 0, key, 0, Uc.size) + System.arraycopy(uc, 0, key, 0, uc.size) for (index in 2..iterations) { // Uc = PRF(Password, Uc-1) - prf.update(Uc) - prf.doFinal(Uc, 0) + prf.update(uc) + prf.doFinal(uc, 0) // F(Password, Salt, c, i) = U1 ^ U2 ^ ... ^ Uc - for (byteIndex in Uc.indices) { - key[byteIndex] = key[byteIndex] xor Uc[byteIndex] + for (byteIndex in uc.indices) { + key[byteIndex] = key[byteIndex] xor uc[byteIndex] } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt index d4295e2cec04640ab3b3138692dbe080bfda8cb7..a4e3ee950d24788ecf5acb89657380a154e2738b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/algorithms/olm/MXOlmDecryption.kt @@ -102,7 +102,7 @@ internal class MXOlmDecryption( String.format(MXCryptoError.BAD_RECIPIENT_REASON, olmPayloadContent.recipient)) } - val recipientKeys = olmPayloadContent.recipient_keys ?: run { + val recipientKeys = olmPayloadContent.recipientKeys ?: run { Timber.e("## decryptEvent() : Olm event (id=${event.eventId}) contains no 'recipient_keys'" + " property; cannot prevent unknown-key attack") throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_PROPERTY, @@ -129,10 +129,10 @@ internal class MXOlmDecryption( String.format(MXCryptoError.FORWARDED_MESSAGE_REASON, olmPayloadContent.sender)) } - if (olmPayloadContent.room_id != event.roomId) { - Timber.e("## decryptEvent() : Event ${event.eventId}: original room ${olmPayloadContent.room_id} does not match reported room ${event.roomId}") + if (olmPayloadContent.roomId != event.roomId) { + Timber.e("## decryptEvent() : Event ${event.eventId}: original room ${olmPayloadContent.roomId} does not match reported room ${event.roomId}") throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_ROOM, - String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.room_id)) + String.format(MXCryptoError.BAD_ROOM_REASON, olmPayloadContent.roomId)) } val keys = olmPayloadContent.keys ?: run { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt index cec1480d7b8a270c6c5d416cf1e967ca95cc685a..11d5b4796a894d8bbab6841dadf4d480cabdd11d 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MXEncryptedAttachments.kt @@ -20,10 +20,14 @@ package org.matrix.android.sdk.internal.crypto.attachments import android.util.Base64 import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileKey +import org.matrix.android.sdk.internal.util.base64ToBase64Url +import org.matrix.android.sdk.internal.util.base64ToUnpaddedBase64 +import org.matrix.android.sdk.internal.util.base64UrlToBase64 import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream +import java.io.File import java.io.InputStream +import java.io.OutputStream import java.security.MessageDigest import java.security.SecureRandom import javax.crypto.Cipher @@ -36,8 +40,121 @@ internal object MXEncryptedAttachments { private const val SECRET_KEY_SPEC_ALGORITHM = "AES" private const val MESSAGE_DIGEST_ALGORITHM = "SHA-256" + fun encrypt(clearStream: InputStream, mimetype: String?, outputFile: File, progress: ((current: Int, total: Int) -> Unit)): EncryptedFileInfo { + val t0 = System.currentTimeMillis() + val secureRandom = SecureRandom() + val initVectorBytes = ByteArray(16) { 0.toByte() } + + val ivRandomPart = ByteArray(8) + secureRandom.nextBytes(ivRandomPart) + + System.arraycopy(ivRandomPart, 0, initVectorBytes, 0, ivRandomPart.size) + + val key = ByteArray(32) + secureRandom.nextBytes(key) + + val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) + + outputFile.outputStream().use { outputStream -> + val encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) + val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) + val ivParameterSpec = IvParameterSpec(initVectorBytes) + encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) + + val data = ByteArray(CRYPTO_BUFFER_SIZE) + var read: Int + var encodedBytes: ByteArray + clearStream.use { inputStream -> + val estimatedSize = inputStream.available() + progress.invoke(0, estimatedSize) + read = inputStream.read(data) + var totalRead = read + while (read != -1) { + progress.invoke(totalRead, estimatedSize) + encodedBytes = encryptCipher.update(data, 0, read) + messageDigest.update(encodedBytes, 0, encodedBytes.size) + outputStream.write(encodedBytes) + read = inputStream.read(data) + totalRead += read + } + } + + // encrypt the latest chunk + encodedBytes = encryptCipher.doFinal() + messageDigest.update(encodedBytes, 0, encodedBytes.size) + outputStream.write(encodedBytes) + } + + return EncryptedFileInfo( + url = null, + mimetype = mimetype, + key = EncryptedFileKey( + alg = "A256CTR", + ext = true, + keyOps = listOf("encrypt", "decrypt"), + kty = "oct", + k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)) + ), + iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""), + hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))), + v = "v2" + ) + .also { Timber.v("Encrypt in ${System.currentTimeMillis() - t0}ms") } + } + +// fun cipherInputStream(attachmentStream: InputStream, mimetype: String?): Pair<DigestInputStream, EncryptedFileInfo> { +// val secureRandom = SecureRandom() +// +// // generate a random iv key +// // Half of the IV is random, the lower order bits are zeroed +// // such that the counter never wraps. +// // See https://github.com/matrix-org/matrix-ios-kit/blob/3dc0d8e46b4deb6669ed44f72ad79be56471354c/MatrixKit/Models/Room/MXEncryptedAttachments.m#L75 +// val initVectorBytes = ByteArray(16) { 0.toByte() } +// +// val ivRandomPart = ByteArray(8) +// secureRandom.nextBytes(ivRandomPart) +// +// System.arraycopy(ivRandomPart, 0, initVectorBytes, 0, ivRandomPart.size) +// +// val key = ByteArray(32) +// secureRandom.nextBytes(key) +// +// val encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) +// val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) +// val ivParameterSpec = IvParameterSpec(initVectorBytes) +// encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) +// +// val cipherInputStream = CipherInputStream(attachmentStream, encryptCipher) +// +// // Could it be possible to get the digest on the fly instead of +// val info = EncryptedFileInfo( +// url = null, +// mimetype = mimetype, +// key = EncryptedFileKey( +// alg = "A256CTR", +// ext = true, +// key_ops = listOf("encrypt", "decrypt"), +// kty = "oct", +// k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)) +// ), +// iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""), +// //hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))), +// v = "v2" +// ) +// +// val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) +// return DigestInputStream(cipherInputStream, messageDigest) to info +// } +// +// fun updateInfoWithDigest(digestInputStream: DigestInputStream, info: EncryptedFileInfo): EncryptedFileInfo { +// return info.copy( +// hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(digestInputStream.messageDigest.digest(), Base64.DEFAULT))) +// ) +// } + /*** * Encrypt an attachment stream. + * DO NOT USE for big files, it will load all in memory * @param attachmentStream the attachment stream. Will be closed after this method call. * @param mimetype the mime type * @return the encryption file info @@ -60,14 +177,14 @@ internal object MXEncryptedAttachments { val key = ByteArray(32) secureRandom.nextBytes(key) - ByteArrayOutputStream().use { outputStream -> + val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) + val byteArrayOutputStream = ByteArrayOutputStream() + byteArrayOutputStream.use { outputStream -> val encryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) val ivParameterSpec = IvParameterSpec(initVectorBytes) encryptCipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec) - val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) - val data = ByteArray(CRYPTO_BUFFER_SIZE) var read: Int var encodedBytes: ByteArray @@ -86,44 +203,26 @@ internal object MXEncryptedAttachments { encodedBytes = encryptCipher.doFinal() messageDigest.update(encodedBytes, 0, encodedBytes.size) outputStream.write(encodedBytes) - - return EncryptionResult( - encryptedFileInfo = EncryptedFileInfo( - url = null, - mimetype = mimetype, - key = EncryptedFileKey( - alg = "A256CTR", - ext = true, - key_ops = listOf("encrypt", "decrypt"), - kty = "oct", - k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)) - ), - iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""), - hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))), - v = "v2" - ), - encryptedByteArray = outputStream.toByteArray() - ) - .also { Timber.v("Encrypt in ${System.currentTimeMillis() - t0}ms") } - } - } - - /** - * Decrypt an attachment - * - * @param attachmentStream the attachment stream. Will be closed after this method call. - * @param encryptedFileInfo the encryption file info - * @return the decrypted attachment stream - */ - fun decryptAttachment(attachmentStream: InputStream?, encryptedFileInfo: EncryptedFileInfo?): InputStream? { - if (encryptedFileInfo?.isValid() != true) { - Timber.e("## decryptAttachment() : some fields are not defined, or invalid key fields") - return null } - val elementToDecrypt = encryptedFileInfo.toElementToDecrypt() - - return decryptAttachment(attachmentStream, elementToDecrypt) + return EncryptionResult( + encryptedFileInfo = EncryptedFileInfo( + url = null, + mimetype = mimetype, + key = EncryptedFileKey( + alg = "A256CTR", + ext = true, + keyOps = listOf("encrypt", "decrypt"), + kty = "oct", + k = base64ToBase64Url(Base64.encodeToString(key, Base64.DEFAULT)) + ), + iv = Base64.encodeToString(initVectorBytes, Base64.DEFAULT).replace("\n", "").replace("=", ""), + hashes = mapOf("sha256" to base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT))), + v = "v2" + ), + encryptedByteArray = byteArrayOutputStream.toByteArray() + ) + .also { Timber.v("Encrypt in ${System.currentTimeMillis() - t0}ms") } } /** @@ -131,84 +230,61 @@ internal object MXEncryptedAttachments { * * @param attachmentStream the attachment stream. Will be closed after this method call. * @param elementToDecrypt the elementToDecrypt info - * @return the decrypted attachment stream + * @param outputStream the outputStream where the decrypted attachment will be write. + * @return true in case of success, false in case of error */ - fun decryptAttachment(attachmentStream: InputStream?, elementToDecrypt: ElementToDecrypt?): InputStream? { + fun decryptAttachment(attachmentStream: InputStream?, elementToDecrypt: ElementToDecrypt?, outputStream: OutputStream): Boolean { // sanity checks if (null == attachmentStream || elementToDecrypt == null) { Timber.e("## decryptAttachment() : null stream") - return null + return false } val t0 = System.currentTimeMillis() - ByteArrayOutputStream().use { outputStream -> - try { - val key = Base64.decode(base64UrlToBase64(elementToDecrypt.k), Base64.DEFAULT) - val initVectorBytes = Base64.decode(elementToDecrypt.iv, Base64.DEFAULT) + try { + val key = Base64.decode(base64UrlToBase64(elementToDecrypt.k), Base64.DEFAULT) + val initVectorBytes = Base64.decode(elementToDecrypt.iv, Base64.DEFAULT) - val decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) - val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) - val ivParameterSpec = IvParameterSpec(initVectorBytes) - decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) + val decryptCipher = Cipher.getInstance(CIPHER_ALGORITHM) + val secretKeySpec = SecretKeySpec(key, SECRET_KEY_SPEC_ALGORITHM) + val ivParameterSpec = IvParameterSpec(initVectorBytes) + decryptCipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec) - val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) + val messageDigest = MessageDigest.getInstance(MESSAGE_DIGEST_ALGORITHM) - var read: Int - val data = ByteArray(CRYPTO_BUFFER_SIZE) - var decodedBytes: ByteArray + var read: Int + val data = ByteArray(CRYPTO_BUFFER_SIZE) + var decodedBytes: ByteArray - attachmentStream.use { inputStream -> + attachmentStream.use { inputStream -> + read = inputStream.read(data) + while (read != -1) { + messageDigest.update(data, 0, read) + decodedBytes = decryptCipher.update(data, 0, read) + outputStream.write(decodedBytes) read = inputStream.read(data) - while (read != -1) { - messageDigest.update(data, 0, read) - decodedBytes = decryptCipher.update(data, 0, read) - outputStream.write(decodedBytes) - read = inputStream.read(data) - } } - - // decrypt the last chunk - decodedBytes = decryptCipher.doFinal() - outputStream.write(decodedBytes) - - val currentDigestValue = base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT)) - - if (elementToDecrypt.sha256 != currentDigestValue) { - Timber.e("## decryptAttachment() : Digest value mismatch") - return null - } - - return ByteArrayInputStream(outputStream.toByteArray()) - .also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") } - } catch (oom: OutOfMemoryError) { - Timber.e(oom, "## decryptAttachment() failed: OOM") - } catch (e: Exception) { - Timber.e(e, "## decryptAttachment() failed") } - } - return null - } + // decrypt the last chunk + decodedBytes = decryptCipher.doFinal() + outputStream.write(decodedBytes) - /** - * Base64 URL conversion methods - */ + val currentDigestValue = base64ToUnpaddedBase64(Base64.encodeToString(messageDigest.digest(), Base64.DEFAULT)) - private fun base64UrlToBase64(base64Url: String): String { - return base64Url.replace('-', '+') - .replace('_', '/') - } + if (elementToDecrypt.sha256 != currentDigestValue) { + Timber.e("## decryptAttachment() : Digest value mismatch") + return false + } - internal fun base64ToBase64Url(base64: String): String { - return base64.replace("\n".toRegex(), "") - .replace("\\+".toRegex(), "-") - .replace('/', '_') - .replace("=", "") - } + return true.also { Timber.v("Decrypt in ${System.currentTimeMillis() - t0}ms") } + } catch (oom: OutOfMemoryError) { + Timber.e(oom, "## decryptAttachment() failed: OOM") + } catch (e: Exception) { + Timber.e(e, "## decryptAttachment() failed") + } - private fun base64ToUnpaddedBase64(base64: String): String { - return base64.replace("\n".toRegex(), "") - .replace("=", "") + return false } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MatrixDigestCheckInputStream.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MatrixDigestCheckInputStream.kt new file mode 100644 index 0000000000000000000000000000000000000000..7ca5158f64bde065a055cd99de61ecd410e82aab --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/attachments/MatrixDigestCheckInputStream.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.attachments + +import android.util.Base64 +import org.matrix.android.sdk.internal.util.base64ToUnpaddedBase64 +import java.io.FilterInputStream +import java.io.IOException +import java.io.InputStream +import java.security.MessageDigest + +class MatrixDigestCheckInputStream( + inputStream: InputStream?, + private val expectedDigest: String +) : FilterInputStream(inputStream) { + + private val digest = MessageDigest.getInstance("SHA-256") + + @Throws(IOException::class) + override fun read(): Int { + val b = `in`.read() + if (b >= 0) { + digest.update(b.toByte()) + } + + if (b == -1) { + ensureDigest() + } + return b + } + + @Throws(IOException::class) + override fun read( + b: ByteArray, + off: Int, + len: Int): Int { + val n = `in`.read(b, off, len) + if (n > 0) { + digest.update(b, off, n) + } + + if (n == -1) { + ensureDigest() + } + return n + } + + @Throws(IOException::class) + private fun ensureDigest() { + val currentDigestValue = base64ToUnpaddedBase64(Base64.encodeToString(digest.digest(), Base64.DEFAULT)) + if (currentDigestValue != expectedDigest) { + throw IOException("Bad digest") + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/event/OlmPayloadContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/event/OlmPayloadContent.kt index a3a9ee2e5161255c544b88265b156f6c1cd5ad6c..bf18cad0f49f23aa0a056630606646b86de94531 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/event/OlmPayloadContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/event/OlmPayloadContent.kt @@ -16,6 +16,7 @@ */ package org.matrix.android.sdk.internal.crypto.model.event +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import org.matrix.android.sdk.internal.di.MoshiProvider @@ -27,27 +28,32 @@ data class OlmPayloadContent( /** * The room id */ - var room_id: String? = null, + @Json(name = "room_id") + val roomId: String? = null, /** * The sender */ - var sender: String? = null, + @Json(name = "sender") + val sender: String? = null, /** * The recipient */ - var recipient: String? = null, + @Json(name = "recipient") + val recipient: String? = null, /** * the recipient keys */ - var recipient_keys: Map<String, String>? = null, + @Json(name = "recipient_keys") + val recipientKeys: Map<String, String>? = null, /** * The keys */ - var keys: Map<String, String>? = null + @Json(name = "keys") + val keys: Map<String, String>? = null ) { fun toJsonString(): String { return MoshiProvider.providesMoshi().adapter(OlmPayloadContent::class.java).toJson(this) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeviceInfo.kt index 97c7c59b503ccf1ade3df88789192ef88acb7aea..0c6d03613a53ee6bcea1d86d4648ed69023dcbad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeviceInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/DeviceInfo.kt @@ -31,7 +31,7 @@ data class DeviceInfo( * The owner user id (not documented and useless but the homeserver sent it. You should not need it) */ @Json(name = "user_id") - val user_id: String? = null, + val userId: String? = null, /** * The device id diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileKey.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileKey.kt index f0a680cfd3b1a05f347301a5690ad480a34487b4..077fd4451ff70463be41bff19a21ff305561ca05 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileKey.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/model/rest/EncryptedFileKey.kt @@ -37,7 +37,7 @@ data class EncryptedFileKey( * Required. Key operations. Must at least contain "encrypt" and "decrypt". */ @Json(name = "key_ops") - val key_ops: List<String>? = null, + val keyOps: List<String>? = null, /** * Required. Key type. Must be "oct". @@ -63,7 +63,7 @@ data class EncryptedFileKey( return false } - if (key_ops?.contains("encrypt") != true || !key_ops.contains("decrypt")) { + if (keyOps?.contains("encrypt") != true || !keyOps.contains("decrypt")) { return false } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt index 978c82303ecc8623f7c708669874a7a0e149bd7a..67e06b545548c9d1c183ad6d84b0278b653ba0c8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/Helper.kt @@ -21,7 +21,6 @@ import android.util.Base64 import io.realm.Realm import io.realm.RealmConfiguration import io.realm.RealmObject -import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.ObjectOutputStream import java.util.zip.GZIPInputStream @@ -96,7 +95,7 @@ fun <T> deserializeFromRealm(string: String?): T? { } val decodedB64 = Base64.decode(string.toByteArray(), Base64.DEFAULT) - val bais = ByteArrayInputStream(decodedB64) + val bais = decodedB64.inputStream() val gzis = GZIPInputStream(bais) val ois = SafeObjectInputStream(gzis) return ois.use { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt index 17538c7cbe44b7211b7295dd4dd69834e6c0cc69..3f811ed7d2459a809087c331ea29440a94f129dc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/SafeObjectInputStream.kt @@ -28,7 +28,7 @@ import java.io.ObjectStreamClass * * Ref: https://stackoverflow.com/questions/3884492/how-can-i-change-package-for-a-bunch-of-java-serializable-classes */ -internal class SafeObjectInputStream(`in`: InputStream) : ObjectInputStream(`in`) { +internal class SafeObjectInputStream(inputStream: InputStream) : ObjectInputStream(inputStream) { init { enableResolveObject(true) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt index 7ebd3b51b0af40d12aabf0fc1d44347c8ea13dd0..17eb33c886df7ddc7a183732f0a6b2bea40fe1f4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/SASDefaultVerificationTransaction.kt @@ -175,8 +175,8 @@ internal abstract class SASDefaultVerificationTransaction( ?.unpaddedBase64PublicKey ?.let { masterPublicKey -> val crossSigningKeyId = "ed25519:$masterPublicKey" - macUsingAgreedMethod(masterPublicKey, baseInfo + crossSigningKeyId)?.let { MSKMacString -> - keyMap[crossSigningKeyId] = MSKMacString + macUsingAgreedMethod(masterPublicKey, baseInfo + crossSigningKeyId)?.let { mskMacString -> + keyMap[crossSigningKeyId] = mskMacString } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt index 5a55ec2a9c7214d908125cdecf8efba81038ae45..ae5852452a8c27a988e1d793ed8e94b45c0cd08c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationEmoji.kt @@ -55,14 +55,14 @@ internal fun getEmojiForCode(code: Int): EmojiRepresentation { 31 -> EmojiRepresentation("🤖", R.string.verification_emoji_robot, R.drawable.ic_verification_robot) 32 -> EmojiRepresentation("🎩", R.string.verification_emoji_hat, R.drawable.ic_verification_hat) 33 -> EmojiRepresentation("👓", R.string.verification_emoji_glasses, R.drawable.ic_verification_glasses) - 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_wrench, R.drawable.ic_verification_wrench) + 34 -> EmojiRepresentation("🔧", R.string.verification_emoji_spanner, R.drawable.ic_verification_spanner) 35 -> EmojiRepresentation("🎅", R.string.verification_emoji_santa, R.drawable.ic_verification_santa) - 36 -> EmojiRepresentation("ðŸ‘", R.string.verification_emoji_thumbsup, R.drawable.ic_verification_thumbs_up) + 36 -> EmojiRepresentation("ðŸ‘", R.string.verification_emoji_thumbs_up, R.drawable.ic_verification_thumbs_up) 37 -> EmojiRepresentation("☂ï¸", R.string.verification_emoji_umbrella, R.drawable.ic_verification_umbrella) 38 -> EmojiRepresentation("⌛", R.string.verification_emoji_hourglass, R.drawable.ic_verification_hourglass) 39 -> EmojiRepresentation("â°", R.string.verification_emoji_clock, R.drawable.ic_verification_clock) 40 -> EmojiRepresentation("ðŸŽ", R.string.verification_emoji_gift, R.drawable.ic_verification_gift) - 41 -> EmojiRepresentation("💡", R.string.verification_emoji_lightbulb, R.drawable.ic_verification_light_bulb) + 41 -> EmojiRepresentation("💡", R.string.verification_emoji_light_bulb, R.drawable.ic_verification_light_bulb) 42 -> EmojiRepresentation("📕", R.string.verification_emoji_book, R.drawable.ic_verification_book) 43 -> EmojiRepresentation("âœï¸", R.string.verification_emoji_pencil, R.drawable.ic_verification_pencil) 44 -> EmojiRepresentation("📎", R.string.verification_emoji_paperclip, R.drawable.ic_verification_paperclip) @@ -74,7 +74,7 @@ internal fun getEmojiForCode(code: Int): EmojiRepresentation { 50 -> EmojiRepresentation("ðŸ", R.string.verification_emoji_flag, R.drawable.ic_verification_flag) 51 -> EmojiRepresentation("🚂", R.string.verification_emoji_train, R.drawable.ic_verification_train) 52 -> EmojiRepresentation("🚲", R.string.verification_emoji_bicycle, R.drawable.ic_verification_bicycle) - 53 -> EmojiRepresentation("✈ï¸", R.string.verification_emoji_airplane, R.drawable.ic_verification_airplane) + 53 -> EmojiRepresentation("✈ï¸", R.string.verification_emoji_aeroplane, R.drawable.ic_verification_aeroplane) 54 -> EmojiRepresentation("🚀", R.string.verification_emoji_rocket, R.drawable.ic_verification_rocket) 55 -> EmojiRepresentation("ðŸ†", R.string.verification_emoji_trophy, R.drawable.ic_verification_trophy) 56 -> EmojiRepresentation("âš½", R.string.verification_emoji_ball, R.drawable.ic_verification_ball) @@ -82,7 +82,7 @@ internal fun getEmojiForCode(code: Int): EmojiRepresentation { 58 -> EmojiRepresentation("🎺", R.string.verification_emoji_trumpet, R.drawable.ic_verification_trumpet) 59 -> EmojiRepresentation("🔔", R.string.verification_emoji_bell, R.drawable.ic_verification_bell) 60 -> EmojiRepresentation("âš“", R.string.verification_emoji_anchor, R.drawable.ic_verification_anchor) - 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphone, R.drawable.ic_verification_headphone) + 61 -> EmojiRepresentation("🎧", R.string.verification_emoji_headphones, R.drawable.ic_verification_headphones) 62 -> EmojiRepresentation("ðŸ“", R.string.verification_emoji_folder, R.drawable.ic_verification_folder) /* 63 */ else -> EmojiRepresentation("📌", R.string.verification_emoji_pin, R.drawable.ic_verification_pin) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 7d2a4ea581cf928e653825b2f8198bdd491919fc..ad05406aa0bd9dfa03cbab06e405128206dd12bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -20,18 +20,24 @@ package org.matrix.android.sdk.internal.database import io.realm.DynamicRealm import io.realm.RealmMigration import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields import timber.log.Timber import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { + companion object { + const val SESSION_STORE_SCHEMA_VERSION = 4L + } + override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { Timber.v("Migrating Realm Session from $oldVersion to $newVersion") if (oldVersion <= 0) migrateTo1(realm) if (oldVersion <= 1) migrateTo2(realm) if (oldVersion <= 2) migrateTo3(realm) + if (oldVersion <= 3) migrateTo4(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -63,4 +69,17 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0) } } + + private fun migrateTo4(realm: DynamicRealm) { + Timber.d("Step 3 -> 4") + realm.schema.create("PendingThreePidEntity") + .addField(PendingThreePidEntityFields.CLIENT_SECRET, String::class.java) + .setRequired(PendingThreePidEntityFields.CLIENT_SECRET, true) + .addField(PendingThreePidEntityFields.EMAIL, String::class.java) + .addField(PendingThreePidEntityFields.MSISDN, String::class.java) + .addField(PendingThreePidEntityFields.SEND_ATTEMPT, Int::class.java) + .addField(PendingThreePidEntityFields.SID, String::class.java) + .setRequired(PendingThreePidEntityFields.SID, true) + .addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt index 456eecc54a9c7c27fd33fc32bc42cff6f1b4046d..d5c259050f00e0fa0c99f103ecd38d6efedb79e1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/SessionRealmConfigurationFactory.kt @@ -19,13 +19,14 @@ package org.matrix.android.sdk.internal.database import android.content.Context import androidx.core.content.edit +import io.realm.Realm +import io.realm.RealmConfiguration +import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.internal.database.model.SessionRealmModule import org.matrix.android.sdk.internal.di.SessionFilesDirectory import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.UserMd5 import org.matrix.android.sdk.internal.session.SessionModule -import io.realm.Realm -import io.realm.RealmConfiguration import timber.log.Timber import java.io.File import javax.inject.Inject @@ -46,20 +47,16 @@ internal class SessionRealmConfigurationFactory @Inject constructor( val migration: RealmSessionStoreMigration, context: Context) { - companion object { - const val SESSION_STORE_SCHEMA_VERSION = 3L - } - // Keep legacy preferences name for compatibility reason private val sharedPreferences = context.getSharedPreferences("im.vector.matrix.android.realm", Context.MODE_PRIVATE) fun create(): RealmConfiguration { val shouldClearRealm = sharedPreferences.getBoolean("$REALM_SHOULD_CLEAR_FLAG_$sessionId", false) if (shouldClearRealm) { - Timber.v("************************************************************") - Timber.v("The realm file session was corrupted and couldn't be loaded.") - Timber.v("The file has been deleted to recover.") - Timber.v("************************************************************") + Timber.e("************************************************************") + Timber.e("The realm file session was corrupted and couldn't be loaded.") + Timber.e("The file has been deleted to recover.") + Timber.e("************************************************************") deleteRealmFiles() } sharedPreferences.edit { @@ -74,7 +71,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor( realmKeysUtils.configureEncryption(this, SessionModule.getKeyAlias(userMd5)) } .modules(SessionRealmModule()) - .schemaVersion(SESSION_STORE_SCHEMA_VERSION) + .schemaVersion(RealmSessionStoreMigration.SESSION_STORE_SCHEMA_VERSION) .migration(migration) .build() @@ -90,6 +87,11 @@ internal class SessionRealmConfigurationFactory @Inject constructor( // Delete all the realm files of the session private fun deleteRealmFiles() { + if (BuildConfig.DEBUG) { + Timber.e("No op because it is a debug build") + return + } + listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file -> try { File(directory, file).deleteRecursively() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt index 90fc62f8f37f659d87397e9c8adc8f3394c32cc5..3bcc3d2ea71ae6cefca141fe3890c475923a8784 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/PushRulesMapper.kt @@ -17,12 +17,12 @@ package org.matrix.android.sdk.internal.database.mapper import com.squareup.moshi.Types -import org.matrix.android.sdk.api.pushrules.Condition +import io.realm.RealmList +import org.matrix.android.sdk.api.pushrules.Kind import org.matrix.android.sdk.api.pushrules.rest.PushCondition import org.matrix.android.sdk.api.pushrules.rest.PushRule import org.matrix.android.sdk.internal.database.model.PushRuleEntity import org.matrix.android.sdk.internal.di.MoshiProvider -import io.realm.RealmList import timber.log.Timber internal object PushRulesMapper { @@ -39,7 +39,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.value, "content.body", pushrule.pattern) + PushCondition(Kind.EventMatch.value, "content.body", pushrule.pattern) ) ) } @@ -60,7 +60,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.value, "room_id", pushrule.ruleId) + PushCondition(Kind.EventMatch.value, "room_id", pushrule.ruleId) ) ) } @@ -72,7 +72,7 @@ internal object PushRulesMapper { enabled = pushrule.enabled, ruleId = pushrule.ruleId, conditions = listOf( - PushCondition(Condition.Kind.EventMatch.value, "user_id", pushrule.ruleId) + PushCondition(Kind.EventMatch.value, "user_id", pushrule.ruleId) ) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt new file mode 100644 index 0000000000000000000000000000000000000000..2f5643d7bc265d625a3dd65e892a6172ed2175ba --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/PendingThreePidEntity.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.database.model + +import io.realm.RealmObject + +/** + * This class is used to store pending threePid data, when user wants to add a threePid to his account + */ +internal open class PendingThreePidEntity( + var email: String? = null, + var msisdn: String? = null, + var clientSecret: String = "", + var sendAttempt: Int = 0, + var sid: String = "", + var submitUrl: String? = null +) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt index ea466db3529af62d47db507fc8e323a02f358110..2c45cfcdbf809843e488b3df0b2550267f0bd882 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt @@ -36,6 +36,7 @@ import io.realm.annotations.RealmModule RoomSummaryEntity::class, RoomTagEntity::class, SyncEntity::class, + PendingThreePidEntity::class, UserEntity::class, IgnoredUserEntity::class, BreadcrumbsEntity::class, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt index 7ce260e54e9b07e2fef05e3026c586aece1bbe5e..98dec301ee36e4715e942ed0cf1fb34655e3d11f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ProgressRequestBody.kt @@ -24,6 +24,7 @@ import okio.BufferedSink import okio.ForwardingSink import okio.Sink import okio.buffer +import org.matrix.android.sdk.api.extensions.tryThis import java.io.IOException internal class ProgressRequestBody(private val delegate: RequestBody, @@ -35,15 +36,13 @@ internal class ProgressRequestBody(private val delegate: RequestBody, return delegate.contentType() } - override fun contentLength(): Long { - try { - return delegate.contentLength() - } catch (e: IOException) { - e.printStackTrace() - } + override fun isOneShot() = delegate.isOneShot() - return -1 - } + override fun isDuplex() = delegate.isDuplex() + + val length = tryThis { delegate.contentLength() } ?: -1 + + override fun contentLength() = length @Throws(IOException::class) override fun writeTo(sink: BufferedSink) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt index 368611dd7d09d36d673fda7e9f96020735ffaab0..89a0ce597a20c81b49fb60c4bad6c139cf06f079 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/RetrofitFactory.kt @@ -19,13 +19,12 @@ package org.matrix.android.sdk.internal.network import com.squareup.moshi.Moshi import dagger.Lazy -import org.matrix.android.sdk.internal.util.ensureTrailingSlash import okhttp3.Call import okhttp3.OkHttpClient import okhttp3.Request +import org.matrix.android.sdk.internal.util.ensureTrailingSlash import retrofit2.Retrofit import retrofit2.converter.moshi.MoshiConverterFactory -import retrofit2.converter.scalars.ScalarsConverterFactory import javax.inject.Inject internal class RetrofitFactory @Inject constructor(private val moshi: Moshi) { @@ -50,7 +49,6 @@ internal class RetrofitFactory @Inject constructor(private val moshi: Moshi) { return okHttpClient.get().newCall(request) } }) - .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(UnitConverterFactory) .addConverterFactory(MoshiConverterFactory.create(moshi)) .build() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt new file mode 100644 index 0000000000000000000000000000000000000000..d4ceca200638d9baac9d8f2da826aeb5b0317d97 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/parsing/CheckNumberType.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.network.parsing + +import androidx.annotation.Nullable +import com.squareup.moshi.JsonAdapter +import com.squareup.moshi.JsonReader +import com.squareup.moshi.JsonWriter + +import com.squareup.moshi.Moshi +import java.io.IOException +import java.lang.reflect.Type +import java.math.BigDecimal + +/** + * This is used to check if NUMBER in json is integer or double, so we can preserve typing when serializing/deserializing in a row. + */ +interface CheckNumberType { + + companion object { + val JSON_ADAPTER_FACTORY = object : JsonAdapter.Factory { + @Nullable + override fun create(type: Type, annotations: Set<Annotation?>?, moshi: Moshi): JsonAdapter<*>? { + if (type !== Any::class.java) { + return null + } + val delegate: JsonAdapter<Any> = moshi.nextAdapter(this, Any::class.java, emptySet()) + return object : JsonAdapter<Any?>() { + @Nullable + @Throws(IOException::class) + override fun fromJson(reader: JsonReader): Any? { + return if (reader.peek() !== JsonReader.Token.NUMBER) { + delegate.fromJson(reader) + } else { + val numberAsString = reader.nextString() + val decimal = BigDecimal(numberAsString) + if (decimal.scale() <= 0) { + decimal.intValueExact() + } else { + decimal.toDouble() + } + } + } + + override fun toJson(writer: JsonWriter, value: Any?) { + delegate.toJson(writer, value) + } + } + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt index 97ebe943ec46a273111d3effe916b797a53708c1..aa4114c8c2899221d81a71d374892249481a6cf6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/DefaultFileService.kt @@ -143,20 +143,22 @@ internal class DefaultFileService @Inject constructor( Timber.v("Response size ${response.body?.contentLength()} - Stream available: ${!source.exhausted()}") if (elementToDecrypt != null) { - Timber.v("## decrypt file") - val decryptedStream = MXEncryptedAttachments.decryptAttachment(source.inputStream(), elementToDecrypt) + Timber.v("## FileService: decrypt file") + val decryptSuccess = MXEncryptedAttachments.decryptAttachment( + source.inputStream(), + elementToDecrypt, + destFile.outputStream().buffered() + ) response.close() - if (decryptedStream == null) { + if (!decryptSuccess) { return@flatMap Try.Failure(IllegalStateException("Decryption error")) - } else { - decryptedStream.use { - writeToFile(decryptedStream, destFile) - } } } else { writeToFile(source.inputStream(), destFile) response.close() } + } else { + Timber.v("## FileService: cache hit for $url") } Try.just(copyFile(destFile, downloadMode)) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/ActiveCallHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/ActiveCallHandler.kt new file mode 100644 index 0000000000000000000000000000000000000000..40f5a56c33c2a0d5fee4d54224e9b05cfc2de125 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/ActiveCallHandler.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.call + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import org.matrix.android.sdk.api.session.call.MxCall +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject + +@SessionScope +internal class ActiveCallHandler @Inject constructor() { + + private val activeCallListLiveData: MutableLiveData<MutableList<MxCall>> by lazy { + MutableLiveData<MutableList<MxCall>>(mutableListOf()) + } + + fun addCall(call: MxCall) { + activeCallListLiveData.postValue(activeCallListLiveData.value?.apply { add(call) }) + } + + fun removeCall(callId: String) { + activeCallListLiveData.postValue(activeCallListLiveData.value?.apply { removeAll { it.callId == callId } }) + } + + fun getCallWithId(callId: String): MxCall? { + return activeCallListLiveData.value?.find { it.callId == callId } + } + + fun getActiveCallsLiveData(): LiveData<MutableList<MxCall>> = activeCallListLiveData +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt index 6a17f0e92565134ca67de52d55b6b173357aa637..d9bc66eddfc59ef661c1be8e19392fdeab6dc317 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.call +import android.os.SystemClock import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.session.call.CallSignalingService @@ -48,6 +49,7 @@ import javax.inject.Inject internal class DefaultCallSignalingService @Inject constructor( @UserId private val userId: String, + private val activeCallHandler: ActiveCallHandler, private val localEchoEventFactory: LocalEchoEventFactory, private val roomEventSender: RoomEventSender, private val taskExecutor: TaskExecutor, @@ -56,13 +58,11 @@ internal class DefaultCallSignalingService @Inject constructor( private val callListeners = mutableSetOf<CallsListener>() - private val activeCalls = mutableListOf<MxCall>() - private val cachedTurnServerResponse = object { - + // Keep one minute safe to avoid considering the data is valid and then actually it is not when effectively using it. private val MIN_TTL = 60 - private val now = { System.currentTimeMillis() / 1000 } + private val now = { SystemClock.elapsedRealtime() / 1000 } private var expiresAt: Long = 0 @@ -96,7 +96,7 @@ internal class DefaultCallSignalingService @Inject constructor( } override fun createOutgoingCall(roomId: String, otherUserId: String, isVideoCall: Boolean): MxCall { - return MxCallImpl( + val call = MxCallImpl( callId = UUID.randomUUID().toString(), isOutgoing = true, roomId = roomId, @@ -105,8 +105,9 @@ internal class DefaultCallSignalingService @Inject constructor( isVideoCall = isVideoCall, localEchoEventFactory = localEchoEventFactory, roomEventSender = roomEventSender - ).also { - activeCalls.add(it) + ) + activeCallHandler.addCall(call).also { + return call } } @@ -119,8 +120,12 @@ internal class DefaultCallSignalingService @Inject constructor( } override fun getCallWithId(callId: String): MxCall? { - Timber.v("## VOIP getCallWithId $callId all calls ${activeCalls.map { it.callId }}") - return activeCalls.find { it.callId == callId } + Timber.v("## VOIP getCallWithId $callId all calls ${activeCallHandler.getActiveCallsLiveData().value?.map { it.callId }}") + return activeCallHandler.getCallWithId(callId) + } + + override fun isThereAnyActiveCall(): Boolean { + return activeCallHandler.getActiveCallsLiveData().value?.isNotEmpty() == true } internal fun onCallEvent(event: Event) { @@ -151,6 +156,7 @@ internal class DefaultCallSignalingService @Inject constructor( // Always ignore local echos of invite return } + event.getClearContent().toModel<CallInviteContent>()?.let { content -> val incomingCall = MxCallImpl( callId = content.callId ?: return@let, @@ -162,7 +168,7 @@ internal class DefaultCallSignalingService @Inject constructor( localEchoEventFactory = localEchoEventFactory, roomEventSender = roomEventSender ) - activeCalls.add(incomingCall) + activeCallHandler.addCall(incomingCall) onCallInvite(incomingCall, content) } } @@ -184,8 +190,8 @@ internal class DefaultCallSignalingService @Inject constructor( return } + activeCallHandler.removeCall(content.callId) onCallHangup(content) - activeCalls.removeAll { it.callId == content.callId } } } EventType.CALL_CANDIDATES -> { @@ -194,7 +200,7 @@ internal class DefaultCallSignalingService @Inject constructor( return } event.getClearContent().toModel<CallCandidatesContent>()?.let { content -> - activeCalls.firstOrNull { it.callId == content.callId }?.let { + activeCallHandler.getCallWithId(content.callId)?.let { onCallIceCandidate(it, content) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt index aa8b98ae62d533df266ed77f543d4129e69998f3..951c24ccb70732ea5104fd8e3219edfa3c638446 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/DefaultContentUploadStateTracker.kt @@ -74,8 +74,8 @@ internal class DefaultContentUploadStateTracker @Inject constructor() : ContentU updateState(key, progressData) } - internal fun setEncrypting(key: String) { - val progressData = ContentUploadStateTracker.State.Encrypting + internal fun setEncrypting(key: String, current: Long, total: Long) { + val progressData = ContentUploadStateTracker.State.Encrypting(current, total) updateState(key, progressData) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt index 5e5380fce1360e67ea52ec901efc28afe1df9cba..4ddf394b00f016e5d855f81e8873e450db6a8dbb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/FileUploader.kt @@ -23,13 +23,16 @@ import com.squareup.moshi.Moshi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody -import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody +import okio.BufferedSink +import okio.source import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.internal.di.Authenticated import org.matrix.android.sdk.internal.network.ProgressRequestBody @@ -38,6 +41,7 @@ import org.matrix.android.sdk.internal.network.toFailure import java.io.File import java.io.FileNotFoundException import java.io.IOException +import java.util.UUID import javax.inject.Inject internal class FileUploader @Inject constructor(@Authenticated @@ -54,7 +58,21 @@ internal class FileUploader @Inject constructor(@Authenticated filename: String?, mimeType: String?, progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { - val uploadBody = file.asRequestBody(mimeType?.toMediaTypeOrNull()) + val uploadBody = object : RequestBody() { + override fun contentLength() = file.length() + + // Disable okhttp auto resend for 'large files' + override fun isOneShot() = contentLength() == 0L || contentLength() >= 1_000_000 + + override fun contentType(): MediaType? { + return mimeType?.toMediaTypeOrNull() + } + + override fun writeTo(sink: BufferedSink) { + file.source().use { sink.writeAll(it) } + } + } + return upload(uploadBody, filename, progressListener) } @@ -70,14 +88,18 @@ internal class FileUploader @Inject constructor(@Authenticated filename: String?, mimeType: String?, progressListener: ProgressRequestBody.Listener? = null): ContentUploadResponse { - return withContext(Dispatchers.IO) { - val inputStream = context.contentResolver.openInputStream(uri) ?: throw FileNotFoundException() - - inputStream.use { - uploadByteArray(it.readBytes(), filename, mimeType, progressListener) - } + val inputStream = withContext(Dispatchers.IO) { + context.contentResolver.openInputStream(uri) + } ?: throw FileNotFoundException() + val workingFile = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir) + workingFile.outputStream().use { + inputStream.copyTo(it) + } + return uploadFile(workingFile, filename, mimeType, progressListener).also { + tryThis { workingFile.delete() } } } + private suspend fun upload(uploadBody: RequestBody, filename: String?, progressListener: ProgressRequestBody.Listener?): ContentUploadResponse { val urlBuilder = uploadUrl.toHttpUrlOrNull()?.newBuilder() ?: throw RuntimeException() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt new file mode 100644 index 0000000000000000000000000000000000000000..a125c0aea4801d8136fcac45c68304415b6f5a7f --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ImageCompressor.kt @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.content + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Matrix +import androidx.exifinterface.media.ExifInterface +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import timber.log.Timber +import java.io.File +import java.util.UUID +import javax.inject.Inject + +internal class ImageCompressor @Inject constructor() { + suspend fun compress( + context: Context, + imageFile: File, + desiredWidth: Int, + desiredHeight: Int, + desiredQuality: Int = 80): File { + return withContext(Dispatchers.IO) { + val compressedBitmap = BitmapFactory.Options().run { + inJustDecodeBounds = true + decodeBitmap(imageFile, this) + inSampleSize = calculateInSampleSize(outWidth, outHeight, desiredWidth, desiredHeight) + inJustDecodeBounds = false + decodeBitmap(imageFile, this)?.let { + rotateBitmap(imageFile, it) + } + } ?: return@withContext imageFile + + val destinationFile = createDestinationFile(context) + + runCatching { + destinationFile.outputStream().use { + compressedBitmap.compress(Bitmap.CompressFormat.JPEG, desiredQuality, it) + } + } + + return@withContext destinationFile + } + } + + private fun rotateBitmap(file: File, bitmap: Bitmap): Bitmap { + file.inputStream().use { inputStream -> + try { + ExifInterface(inputStream).let { exifInfo -> + val orientation = exifInfo.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL) + val matrix = Matrix() + when (orientation) { + ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270f) + ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180f) + ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90f) + ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> matrix.preScale(-1f, 1f) + ExifInterface.ORIENTATION_FLIP_VERTICAL -> matrix.preScale(1f, -1f) + ExifInterface.ORIENTATION_TRANSPOSE -> { + matrix.preRotate(-90f) + matrix.preScale(-1f, 1f) + } + ExifInterface.ORIENTATION_TRANSVERSE -> { + matrix.preRotate(90f) + matrix.preScale(-1f, 1f) + } + else -> return bitmap + } + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true) + } + } catch (e: Exception) { + Timber.e(e, "Cannot read orientation") + } + } + return bitmap + } + + // https://developer.android.com/topic/performance/graphics/load-bitmap + private fun calculateInSampleSize(width: Int, height: Int, desiredWidth: Int, desiredHeight: Int): Int { + var inSampleSize = 1 + + if (width > desiredWidth || height > desiredHeight) { + val halfHeight: Int = height / 2 + val halfWidth: Int = width / 2 + + // Calculate the largest inSampleSize value that is a power of 2 and keeps both + // height and width larger than the requested height and width. + while (halfHeight / inSampleSize >= desiredHeight && halfWidth / inSampleSize >= desiredWidth) { + inSampleSize *= 2 + } + } + + return inSampleSize + } + + private fun decodeBitmap(file: File, options: BitmapFactory.Options = BitmapFactory.Options()): Bitmap? { + return try { + file.inputStream().use { inputStream -> + BitmapFactory.decodeStream(inputStream, null, options) + } + } catch (e: Exception) { + Timber.e(e, "Cannot decode Bitmap") + null + } + } + + private fun createDestinationFile(context: Context): File { + return File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 6d354cdcbeeb002104a9c4d67d23ba6a591bba72..6e70906d13cc03876be8d318fee29ab59733f705 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -22,8 +22,7 @@ import android.graphics.BitmapFactory import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass -import id.zelory.compressor.Compressor -import id.zelory.compressor.constraint.default +import org.matrix.android.sdk.api.extensions.tryThis import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toContent @@ -37,15 +36,13 @@ import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments import org.matrix.android.sdk.internal.crypto.model.rest.EncryptedFileInfo import org.matrix.android.sdk.internal.network.ProgressRequestBody import org.matrix.android.sdk.internal.session.DefaultFileService +import org.matrix.android.sdk.internal.session.room.send.CancelSendTracker import org.matrix.android.sdk.internal.session.room.send.MultipleEventSendingDispatcherWorker import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.getSessionComponent import timber.log.Timber -import java.io.ByteArrayInputStream import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream import java.util.UUID import javax.inject.Inject @@ -74,6 +71,8 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter @Inject lateinit var fileUploader: FileUploader @Inject lateinit var contentUploadStateTracker: DefaultContentUploadStateTracker @Inject lateinit var fileService: DefaultFileService + @Inject lateinit var cancelSendTracker: CancelSendTracker + @Inject lateinit var imageCompressor: ImageCompressor override suspend fun doWork(): Result { val params = WorkerParamsFactory.fromData<Params>(inputData) @@ -101,9 +100,15 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success() sessionComponent.inject(this) - val attachment = params.attachment + val allCancelled = params.events.all { cancelSendTracker.isCancelRequestedFor(it.eventId, it.roomId) } + if (allCancelled) { + // there is no point in uploading the image! + return Result.success(inputData) + .also { Timber.e("## Send: Work cancelled by user") } + } - var newImageAttributes: NewImageAttributes? = null + val attachment = params.attachment + val filesToDelete = mutableListOf<File>() try { val inputStream = context.contentResolver.openInputStream(attachment.queryUri) @@ -115,124 +120,100 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) ) - inputStream.use { - var uploadedThumbnailUrl: String? = null - var uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? = null + // always use a temporary file, it guaranties that we could report progress on upload and simplifies the flows + val workingFile = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir) + .also { filesToDelete.add(it) } + workingFile.outputStream().use { outputStream -> + inputStream.use { inputStream -> + inputStream.copyTo(outputStream) + } + } - ThumbnailExtractor.extractThumbnail(context, params.attachment)?.let { thumbnailData -> - val thumbnailProgressListener = object : ProgressRequestBody.Listener { - override fun onProgress(current: Long, total: Long) { - notifyTracker(params) { contentUploadStateTracker.setProgressThumbnail(it, current, total) } - } - } + val uploadThumbnailResult = dealWithThumbnail(params) - try { - val contentUploadResponse = if (params.isEncrypted) { - Timber.v("Encrypt thumbnail") - notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) } - val encryptionResult = MXEncryptedAttachments.encryptAttachment(ByteArrayInputStream(thumbnailData.bytes), thumbnailData.mimeType) - uploadedThumbnailEncryptedFileInfo = encryptionResult.encryptedFileInfo - fileUploader.uploadByteArray(encryptionResult.encryptedByteArray, - "thumb_${attachment.name}", - "application/octet-stream", - thumbnailProgressListener) + val progressListener = object : ProgressRequestBody.Listener { + override fun onProgress(current: Long, total: Long) { + notifyTracker(params) { + if (isStopped) { + contentUploadStateTracker.setFailure(it, Throwable("Cancelled")) } else { - fileUploader.uploadByteArray(thumbnailData.bytes, - "thumb_${attachment.name}", - thumbnailData.mimeType, - thumbnailProgressListener) + contentUploadStateTracker.setProgress(it, current, total) } - - uploadedThumbnailUrl = contentUploadResponse.contentUri - } catch (t: Throwable) { - Timber.e(t, "Thumbnail update failed") } } + } - val progressListener = object : ProgressRequestBody.Listener { - override fun onProgress(current: Long, total: Long) { - notifyTracker(params) { - if (isStopped) { - contentUploadStateTracker.setFailure(it, Throwable("Cancelled")) - } else { - contentUploadStateTracker.setProgress(it, current, total) + var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null + + return try { + val fileToUpload: File + var newImageAttributes: NewImageAttributes? = null + + if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) { + fileToUpload = imageCompressor.compress(context, workingFile, MAX_IMAGE_SIZE, MAX_IMAGE_SIZE) + .also { compressedFile -> + // Get new Bitmap size + compressedFile.inputStream().use { + val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } + val bitmap = BitmapFactory.decodeStream(it, null, options) + val fileSize = bitmap?.byteCount ?: 0 + newImageAttributes = NewImageAttributes( + options.outWidth, + options.outHeight, + fileSize + ) + } } - } - } + .also { filesToDelete.add(it) } + } else { + fileToUpload = workingFile } - var uploadedFileEncryptedFileInfo: EncryptedFileInfo? = null - - return try { - // Compressor library works with File instead of Uri for now. Since Scoped Storage doesn't allow us to access files directly, we should - // copy it to a cache folder by using InputStream and OutputStream. - // https://github.com/zetbaitsu/Compressor/pull/150 - // As soon as the above PR is merged, we can use attachment.queryUri instead of creating a cacheFile. - var cacheFile = File.createTempFile(attachment.name ?: UUID.randomUUID().toString(), ".jpg", context.cacheDir) - cacheFile.parentFile?.mkdirs() - if (cacheFile.exists()) { - cacheFile.delete() - } - cacheFile.createNewFile() - cacheFile.deleteOnExit() - - val outputStream = FileOutputStream(cacheFile) - outputStream.use { - inputStream.copyTo(outputStream) - } + val contentUploadResponse = if (params.isEncrypted) { + Timber.v("## FileService: Encrypt file") - if (attachment.type == ContentAttachmentData.Type.IMAGE && params.compressBeforeSending) { - cacheFile = Compressor.compress(context, cacheFile) { - default( - width = MAX_IMAGE_SIZE, - height = MAX_IMAGE_SIZE - ) - }.also { compressedFile -> - val options = BitmapFactory.Options().apply { inJustDecodeBounds = true } - BitmapFactory.decodeFile(compressedFile.absolutePath, options) - val fileSize = compressedFile.length().toInt() - newImageAttributes = NewImageAttributes( - options.outWidth, - options.outHeight, - fileSize - ) - } - } + val tmpEncrypted = File.createTempFile(UUID.randomUUID().toString(), null, context.cacheDir) + .also { filesToDelete.add(it) } - val contentUploadResponse = if (params.isEncrypted) { - Timber.v("Encrypt file") - notifyTracker(params) { contentUploadStateTracker.setEncrypting(it) } + uploadedFileEncryptedFileInfo = + MXEncryptedAttachments.encrypt(fileToUpload.inputStream(), attachment.getSafeMimeType(), tmpEncrypted) { read, total -> + notifyTracker(params) { + contentUploadStateTracker.setEncrypting(it, read.toLong(), total.toLong()) + } + } - val encryptionResult = MXEncryptedAttachments.encryptAttachment(FileInputStream(cacheFile), attachment.getSafeMimeType()) - uploadedFileEncryptedFileInfo = encryptionResult.encryptedFileInfo + Timber.v("## FileService: Uploading file") - fileUploader - .uploadByteArray(encryptionResult.encryptedByteArray, attachment.name, "application/octet-stream", progressListener) - } else { - fileUploader - .uploadFile(cacheFile, attachment.name, attachment.getSafeMimeType(), progressListener) - } + fileUploader + .uploadFile(tmpEncrypted, attachment.name, "application/octet-stream", progressListener) + } else { + Timber.v("## FileService: Clear file") + fileUploader + .uploadFile(fileToUpload, attachment.name, attachment.getSafeMimeType(), progressListener) + } - // If it's a file update the file service so that it does not redownload? - if (params.attachment.type == ContentAttachmentData.Type.FILE) { - context.contentResolver.openInputStream(attachment.queryUri)?.let { - fileService.storeDataFor(contentUploadResponse.contentUri, params.attachment.getSafeMimeType(), it) - } + Timber.v("## FileService: Update cache storage for ${contentUploadResponse.contentUri}") + try { + context.contentResolver.openInputStream(attachment.queryUri)?.let { + fileService.storeDataFor(contentUploadResponse.contentUri, params.attachment.getSafeMimeType(), it) } - - handleSuccess(params, - contentUploadResponse.contentUri, - uploadedFileEncryptedFileInfo, - uploadedThumbnailUrl, - uploadedThumbnailEncryptedFileInfo, - newImageAttributes) - } catch (t: Throwable) { - Timber.e(t) - handleFailure(params, t) + Timber.v("## FileService: cache storage updated") + } catch (failure: Throwable) { + Timber.e(failure, "## FileService: Failed to update file cache") } + + handleSuccess(params, + contentUploadResponse.contentUri, + uploadedFileEncryptedFileInfo, + uploadThumbnailResult?.uploadedThumbnailUrl, + uploadThumbnailResult?.uploadedThumbnailEncryptedFileInfo, + newImageAttributes) + } catch (t: Throwable) { + Timber.e(t, "## FileService: ERROR ${t.localizedMessage}") + handleFailure(params, t) } } catch (e: Exception) { - Timber.e(e) + Timber.e(e, "## FileService: ERROR") notifyTracker(params) { contentUploadStateTracker.setFailure(it, e) } return Result.success( WorkerParamsFactory.toData( @@ -241,9 +222,61 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter ) ) ) + } finally { + // Delete all temporary files + filesToDelete.forEach { + tryThis { it.delete() } + } } } + private data class UploadThumbnailResult( + val uploadedThumbnailUrl: String, + val uploadedThumbnailEncryptedFileInfo: EncryptedFileInfo? + ) + + /** + * If appropriate, it will create and upload a thumbnail + */ + private suspend fun dealWithThumbnail(params: Params): UploadThumbnailResult? { + return ThumbnailExtractor.extractThumbnail(context, params.attachment) + ?.let { thumbnailData -> + val thumbnailProgressListener = object : ProgressRequestBody.Listener { + override fun onProgress(current: Long, total: Long) { + notifyTracker(params) { contentUploadStateTracker.setProgressThumbnail(it, current, total) } + } + } + + try { + if (params.isEncrypted) { + Timber.v("Encrypt thumbnail") + notifyTracker(params) { contentUploadStateTracker.setEncryptingThumbnail(it) } + val encryptionResult = MXEncryptedAttachments.encryptAttachment(thumbnailData.bytes.inputStream(), thumbnailData.mimeType) + val contentUploadResponse = fileUploader.uploadByteArray(encryptionResult.encryptedByteArray, + "thumb_${params.attachment.name}", + "application/octet-stream", + thumbnailProgressListener) + UploadThumbnailResult( + contentUploadResponse.contentUri, + encryptionResult.encryptedFileInfo + ) + } else { + val contentUploadResponse = fileUploader.uploadByteArray(thumbnailData.bytes, + "thumb_${params.attachment.name}", + thumbnailData.mimeType, + thumbnailProgressListener) + UploadThumbnailResult( + contentUploadResponse.contentUri, + null + ) + } + } catch (t: Throwable) { + Timber.e(t, "Thumbnail upload failed") + null + } + } + } + private fun handleFailure(params: Params, failure: Throwable): Result { notifyTracker(params) { contentUploadStateTracker.setFailure(it, failure) } @@ -262,7 +295,6 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter thumbnailUrl: String?, thumbnailEncryptedFileInfo: EncryptedFileInfo?, newImageAttributes: NewImageAttributes?): Result { - Timber.v("handleSuccess $attachmentUrl, work is stopped $isStopped") notifyTracker(params) { contentUploadStateTracker.setSuccess(it) } val updatedEvents = params.events @@ -271,7 +303,9 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter } val sendParams = MultipleEventSendingDispatcherWorker.Params(params.sessionId, updatedEvents, params.isEncrypted) - return Result.success(WorkerParamsFactory.toData(sendParams)) + return Result.success(WorkerParamsFactory.toData(sendParams)).also { + Timber.v("## handleSuccess $attachmentUrl, work is stopped $isStopped") + } } private fun updateEvent(event: Event, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/DefaultContentDownloadStateTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/DefaultContentDownloadStateTracker.kt index 295a829b0874bc2e03279d03496f8b068090646c..c4ba95af84ec5e193725a244526a013f01fb31c2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/DefaultContentDownloadStateTracker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/download/DefaultContentDownloadStateTracker.kt @@ -61,19 +61,23 @@ internal class DefaultContentDownloadStateTracker @Inject constructor() : Progre // private fun URL.toKey() = toString() override fun update(url: String, bytesRead: Long, contentLength: Long, done: Boolean) { - Timber.v("## DL Progress url:$url read:$bytesRead total:$contentLength done:$done") - if (done) { - updateState(url, ContentDownloadStateTracker.State.Success) - } else { - updateState(url, ContentDownloadStateTracker.State.Downloading(bytesRead, contentLength, contentLength == -1L)) + mainHandler.post { + Timber.v("## DL Progress url:$url read:$bytesRead total:$contentLength done:$done") + if (done) { + updateState(url, ContentDownloadStateTracker.State.Success) + } else { + updateState(url, ContentDownloadStateTracker.State.Downloading(bytesRead, contentLength, contentLength == -1L)) + } } } override fun error(url: String, errorCode: Int) { - Timber.v("## DL Progress Error code:$errorCode") - updateState(url, ContentDownloadStateTracker.State.Failure(errorCode)) - listeners[url]?.forEach { - tryThis { it.onDownloadStateUpdate(ContentDownloadStateTracker.State.Failure(errorCode)) } + mainHandler.post { + Timber.v("## DL Progress Error code:$errorCode") + updateState(url, ContentDownloadStateTracker.State.Failure(errorCode)) + listeners[url]?.forEach { + tryThis { it.onDownloadStateUpdate(ContentDownloadStateTracker.State.Failure(errorCode)) } + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt index ac33c2666f7abbaf53a5908b1baa62b4c78dc393..45d7d48a188f13a5035d241cca45473867c8c88f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/identity/IdentityBulkLookupTask.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.api.session.identity.FoundThreePid import org.matrix.android.sdk.api.session.identity.IdentityServiceError import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium -import org.matrix.android.sdk.internal.crypto.attachments.MXEncryptedAttachments.base64ToBase64Url import org.matrix.android.sdk.internal.crypto.tools.withOlmUtility import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.network.executeRequest @@ -32,6 +31,7 @@ import org.matrix.android.sdk.internal.session.identity.model.IdentityHashDetail import org.matrix.android.sdk.internal.session.identity.model.IdentityLookUpParams import org.matrix.android.sdk.internal.session.identity.model.IdentityLookUpResponse import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.base64ToBase64Url import java.util.Locale import javax.inject.Inject diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt index 49a92acc5416c4dad7229b43c6ed25f75b4543d4..a0667cc4a361dc51ed36eb83d4af93926869e0c0 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/notification/ProcessEventForPushTask.kt @@ -100,7 +100,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor( return rules.firstOrNull { rule -> // All conditions must hold true for an event in order to apply the action for the event. rule.enabled && rule.conditions?.all { - it.asExecutableCondition()?.isSatisfied(event, conditionResolver) ?: false + it.asExecutableCondition(rule)?.isSatisfied(event, conditionResolver) ?: false } ?: false } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailBody.kt new file mode 100644 index 0000000000000000000000000000000000000000..ff81ad6a5c7d1834fd5b83d07b2feebb99844236 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailBody.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class AddEmailBody( + /** + * Required. A unique string generated by the client, and used to identify the validation attempt. + * It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed + * 255 characters and it must not be empty. + */ + @Json(name = "client_secret") + val clientSecret: String, + + /** + * Required. The email address to validate. + */ + @Json(name = "email") + val email: String, + + /** + * Required. The server will only send an email if the send_attempt is a number greater than the most + * recent one which it has seen, scoped to that email + client_secret pair. This is to avoid repeatedly + * sending the same email in the case of request retries between the POSTing user and the identity server. + * The client should increment this value if they desire a new email (e.g. a reminder) to be sent. + * If they do not, the server should respond with success but not resend the email. + */ + @Json(name = "send_attempt") + val sendAttempt: Int +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..8654d7c5baf9cbffaad6d17470420c7d64bf668c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddEmailResponse.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class AddEmailResponse( + /** + * Required. The session ID. Session IDs are opaque strings that must consist entirely + * of the characters [0-9a-zA-Z.=_-]. Their length must not exceed 255 characters and they must not be empty. + */ + @Json(name = "sid") + val sid: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnBody.kt new file mode 100644 index 0000000000000000000000000000000000000000..64c53f6729d0b59b65365d3c40d29b3ef2350463 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnBody.kt @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class AddMsisdnBody( + /** + * Required. A unique string generated by the client, and used to identify the validation attempt. + * It must be a string consisting of the characters [0-9a-zA-Z.=_-]. Its length must not exceed + * 255 characters and it must not be empty. + */ + @Json(name = "client_secret") + val clientSecret: String, + + /** + * Required. The two-letter uppercase ISO-3166-1 alpha-2 country code that the number in + * phone_number should be parsed as if it were dialled from. + */ + @Json(name = "country") + val country: String, + + /** + * Required. The phone number to validate. + */ + @Json(name = "phone_number") + val phoneNumber: String, + + /** + * Required. The server will only send an SMS if the send_attempt is a number greater than the most + * recent one which it has seen, scoped to that country + phone_number + client_secret triple. This + * is to avoid repeatedly sending the same SMS in the case of request retries between the POSTing user + * and the identity server. The client should increment this value if they desire a new SMS (e.g. a + * reminder) to be sent. + */ + @Json(name = "send_attempt") + val sendAttempt: Int +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..b4c137b3a153a03a7aa228e88daa676f030a12f2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddMsisdnResponse.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class AddMsisdnResponse( + /** + * Required. The session ID. Session IDs are opaque strings that must consist entirely of the characters [0-9a-zA-Z.=_-]. + * Their length must not exceed 255 characters and they must not be empty. + */ + @Json(name = "sid") + val sid: String, + + /** + * An optional field containing a URL where the client must submit the validation token to, with identical parameters to the Identity + * Service API's POST /validate/email/submitToken endpoint (without the requirement for an access token). + * The homeserver must send this token to the user (if applicable), who should then be prompted to provide it to the client. + * + * If this field is not present, the client can assume that verification will happen without the client's involvement provided + * the homeserver advertises this specification version in the /versions response (ie: r0.5.0). + */ + @Json(name = "submit_url") + val submitUrl: String? = null, + + /* ========================================================================================== + * It seems that the homeserver is sending more data, we may need it + * ========================================================================================== */ + + @Json(name = "msisdn") + val msisdn: String? = null, + + @Json(name = "intl_fmt") + val formattedMsisdn: String? = null, + + @Json(name = "success") + val success: Boolean? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..c844c8ca6f54fda0f1a338cd4bfcd6660573a7c1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/AddThreePidTask.kt @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import com.google.i18n.phonenumbers.PhoneNumberUtil +import com.zhuinden.monarchy.Monarchy +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.awaitTransaction +import java.util.UUID +import javax.inject.Inject + +internal abstract class AddThreePidTask : Task<AddThreePidTask.Params, Unit> { + data class Params( + val threePid: ThreePid + ) +} + +internal class DefaultAddThreePidTask @Inject constructor( + private val profileAPI: ProfileAPI, + @SessionDatabase private val monarchy: Monarchy, + private val pendingThreePidMapper: PendingThreePidMapper, + private val eventBus: EventBus) : AddThreePidTask() { + + override suspend fun execute(params: Params) { + when (params.threePid) { + is ThreePid.Email -> addEmail(params.threePid) + is ThreePid.Msisdn -> addMsisdn(params.threePid) + } + } + + private suspend fun addEmail(threePid: ThreePid.Email) { + val clientSecret = UUID.randomUUID().toString() + val sendAttempt = 1 + + val result = executeRequest<AddEmailResponse>(eventBus) { + val body = AddEmailBody( + clientSecret = clientSecret, + email = threePid.email, + sendAttempt = sendAttempt + ) + apiCall = profileAPI.addEmail(body) + } + + // Store as a pending three pid + monarchy.awaitTransaction { realm -> + PendingThreePid( + threePid = threePid, + clientSecret = clientSecret, + sendAttempt = sendAttempt, + sid = result.sid, + submitUrl = null + ) + .let { pendingThreePidMapper.map(it) } + .let { realm.copyToRealm(it) } + } + } + + private suspend fun addMsisdn(threePid: ThreePid.Msisdn) { + val clientSecret = UUID.randomUUID().toString() + val sendAttempt = 1 + + // Get country code and national number from the phone number + val phoneNumber = threePid.msisdn + val phoneNumberUtil = PhoneNumberUtil.getInstance() + val parsedNumber = phoneNumberUtil.parse(phoneNumber, null) + val countryCode = parsedNumber.countryCode + val country = phoneNumberUtil.getRegionCodeForCountryCode(countryCode) + + val result = executeRequest<AddMsisdnResponse>(eventBus) { + val body = AddMsisdnBody( + clientSecret = clientSecret, + country = country, + phoneNumber = parsedNumber.nationalNumber.toString(), + sendAttempt = sendAttempt + ) + apiCall = profileAPI.addMsisdn(body) + } + + // Store as a pending three pid + monarchy.awaitTransaction { realm -> + PendingThreePid( + threePid = threePid, + clientSecret = clientSecret, + sendAttempt = sendAttempt, + sid = result.sid, + submitUrl = result.submitUrl + ) + .let { pendingThreePidMapper.map(it) } + .let { realm.copyToRealm(it) } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt index 633b0479948699af48760f535c12b20e284e1504..97212a8687ac42b20304629c0284acd21c888b86 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DefaultProfileService.kt @@ -28,6 +28,7 @@ import org.matrix.android.sdk.api.session.profile.ProfileService import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity import org.matrix.android.sdk.internal.database.model.UserThreePidEntity import org.matrix.android.sdk.internal.di.SessionDatabase import org.matrix.android.sdk.internal.session.content.FileUploader @@ -44,6 +45,11 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto private val getProfileInfoTask: GetProfileInfoTask, private val setDisplayNameTask: SetDisplayNameTask, private val setAvatarUrlTask: SetAvatarUrlTask, + private val addThreePidTask: AddThreePidTask, + private val validateSmsCodeTask: ValidateSmsCodeTask, + private val finalizeAddingThreePidTask: FinalizeAddingThreePidTask, + private val deleteThreePidTask: DeleteThreePidTask, + private val pendingThreePidMapper: PendingThreePidMapper, private val fileUploader: FileUploader) : ProfileService { override fun getDisplayName(userId: String, matrixCallback: MatrixCallback<Optional<String>>): Cancelable { @@ -116,9 +122,7 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto override fun getThreePidsLive(refreshData: Boolean): LiveData<List<ThreePid>> { if (refreshData) { // Force a refresh of the values - refreshUserThreePidsTask - .configureWith() - .executeBy(taskExecutor) + refreshThreePids() } return monarchy.findAllMappedWithChanges( @@ -126,6 +130,95 @@ internal class DefaultProfileService @Inject constructor(private val taskExecuto { it.asDomain() } ) } + + private fun refreshThreePids() { + refreshUserThreePidsTask + .configureWith() + .executeBy(taskExecutor) + } + + override fun getPendingThreePids(): List<ThreePid> { + return monarchy.fetchAllMappedSync( + { it.where<PendingThreePidEntity>() }, + { pendingThreePidMapper.map(it).threePid } + ) + } + + override fun getPendingThreePidsLive(): LiveData<List<ThreePid>> { + return monarchy.findAllMappedWithChanges( + { it.where<PendingThreePidEntity>() }, + { pendingThreePidMapper.map(it).threePid } + ) + } + + override fun addThreePid(threePid: ThreePid, matrixCallback: MatrixCallback<Unit>): Cancelable { + return addThreePidTask + .configureWith(AddThreePidTask.Params(threePid)) { + callback = matrixCallback + } + .executeBy(taskExecutor) + } + + override fun submitSmsCode(threePid: ThreePid.Msisdn, code: String, matrixCallback: MatrixCallback<Unit>): Cancelable { + return validateSmsCodeTask + .configureWith(ValidateSmsCodeTask.Params(threePid, code)) { + callback = matrixCallback + } + .executeBy(taskExecutor) + } + + override fun finalizeAddingThreePid(threePid: ThreePid, + uiaSession: String?, + accountPassword: String?, + matrixCallback: MatrixCallback<Unit>): Cancelable { + return finalizeAddingThreePidTask + .configureWith(FinalizeAddingThreePidTask.Params( + threePid = threePid, + session = uiaSession, + accountPassword = accountPassword, + userWantsToCancel = false + )) { + callback = alsoRefresh(matrixCallback) + } + .executeBy(taskExecutor) + } + + override fun cancelAddingThreePid(threePid: ThreePid, matrixCallback: MatrixCallback<Unit>): Cancelable { + return finalizeAddingThreePidTask + .configureWith(FinalizeAddingThreePidTask.Params( + threePid = threePid, + session = null, + accountPassword = null, + userWantsToCancel = true + )) { + callback = alsoRefresh(matrixCallback) + } + .executeBy(taskExecutor) + } + + /** + * Wrap the callback to fetch 3Pids from the server in case of success + */ + private fun alsoRefresh(callback: MatrixCallback<Unit>): MatrixCallback<Unit> { + return object : MatrixCallback<Unit> { + override fun onFailure(failure: Throwable) { + callback.onFailure(failure) + } + + override fun onSuccess(data: Unit) { + refreshThreePids() + callback.onSuccess(data) + } + } + } + + override fun deleteThreePid(threePid: ThreePid, matrixCallback: MatrixCallback<Unit>): Cancelable { + return deleteThreePidTask + .configureWith(DeleteThreePidTask.Params(threePid)) { + callback = alsoRefresh(matrixCallback) + } + .executeBy(taskExecutor) + } } private fun UserThreePidEntity.asDomain(): ThreePid { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidBody.kt new file mode 100644 index 0000000000000000000000000000000000000000..e7d4568f8bf48884c5a93d3a3c2a79a792c30c96 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidBody.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class DeleteThreePidBody( + /** + * Required. The medium of the third party identifier being removed. One of: ["email", "msisdn"] + */ + @Json(name = "medium") val medium: String, + /** + * Required. The third party address being removed. + */ + @Json(name = "address") val address: String +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidResponse.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidResponse.kt new file mode 100644 index 0000000000000000000000000000000000000000..3817277a9d0426903a0e52b11e87d42973150dd9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidResponse.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = true) +internal data class DeleteThreePidResponse( + /** + * Required. An indicator as to whether or not the homeserver was able to unbind the 3PID from + * the identity server. success indicates that the identity server has unbound the identifier + * whereas no-support indicates that the identity server refuses to support the request or the + * homeserver was not able to determine an identity server to unbind from. One of: ["no-support", "success"] + */ + @Json(name = "id_server_unbind_result") + val idServerUnbindResult: String? = null +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..69ff7d82da2c89d2f605b215ec392f57f1168264 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/DeleteThreePidTask.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.api.session.identity.toMedium +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal abstract class DeleteThreePidTask : Task<DeleteThreePidTask.Params, Unit> { + data class Params( + val threePid: ThreePid + ) +} + +internal class DefaultDeleteThreePidTask @Inject constructor( + private val profileAPI: ProfileAPI, + private val eventBus: EventBus) : DeleteThreePidTask() { + + override suspend fun execute(params: Params) { + executeRequest<DeleteThreePidResponse>(eventBus) { + val body = DeleteThreePidBody( + medium = params.threePid.toMedium(), + address = params.threePid.value + ) + apiCall = profileAPI.deleteThreePid(body) + } + + // We do not really care about the result for the moment + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt new file mode 100644 index 0000000000000000000000000000000000000000..73e9b39cea20b87413a95b9b43f32b924cdcf35c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddThreePidBody.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.matrix.android.sdk.internal.session.profile + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth + +@JsonClass(generateAdapter = true) +internal data class FinalizeAddThreePidBody( + /** + * Required. The client secret used in the session with the homeserver. + */ + @Json(name = "client_secret") + val clientSecret: String, + + /** + * Required. The session identifier given by the homeserver. + */ + @Json(name = "sid") + val sid: String, + + /** + * Additional authentication information for the user-interactive authentication API. + */ + @Json(name = "auth") + val auth: UserPasswordAuth? +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..3886b926ba36513c153fca96773bccd485ddef29 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/FinalizeAddingThreePidTask.kt @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import com.zhuinden.monarchy.Monarchy +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.internal.crypto.model.rest.UserPasswordAuth +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import org.matrix.android.sdk.internal.util.awaitTransaction +import javax.inject.Inject + +internal abstract class FinalizeAddingThreePidTask : Task<FinalizeAddingThreePidTask.Params, Unit> { + data class Params( + val threePid: ThreePid, + val session: String?, + val accountPassword: String?, + val userWantsToCancel: Boolean + ) +} + +internal class DefaultFinalizeAddingThreePidTask @Inject constructor( + private val profileAPI: ProfileAPI, + @SessionDatabase private val monarchy: Monarchy, + private val pendingThreePidMapper: PendingThreePidMapper, + @UserId private val userId: String, + private val eventBus: EventBus) : FinalizeAddingThreePidTask() { + + override suspend fun execute(params: Params) { + if (params.userWantsToCancel.not()) { + // Get the required pending data + val pendingThreePids = monarchy.fetchAllMappedSync( + { it.where(PendingThreePidEntity::class.java) }, + { pendingThreePidMapper.map(it) } + ) + .firstOrNull { it.threePid == params.threePid } + ?: throw IllegalArgumentException("unknown threepid") + + try { + executeRequest<Unit>(eventBus) { + val body = FinalizeAddThreePidBody( + clientSecret = pendingThreePids.clientSecret, + sid = pendingThreePids.sid, + auth = if (params.session != null && params.accountPassword != null) { + UserPasswordAuth( + session = params.session, + user = userId, + password = params.accountPassword + ) + } else null + ) + apiCall = profileAPI.finalizeAddThreePid(body) + } + } catch (throwable: Throwable) { + throw throwable.toRegistrationFlowResponse() + ?.let { Failure.RegistrationFlowError(it) } + ?: throwable + } + } + + cleanupDatabase(params) + } + + private suspend fun cleanupDatabase(params: Params) { + // Delete the pending three pid + monarchy.awaitTransaction { realm -> + realm.where(PendingThreePidEntity::class.java) + .equalTo(PendingThreePidEntityFields.EMAIL, params.threePid.value) + .or() + .equalTo(PendingThreePidEntityFields.MSISDN, params.threePid.value) + .findAll() + .deleteAllFromRealm() + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePid.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePid.kt new file mode 100644 index 0000000000000000000000000000000000000000..af7e217d479420a0cdba65684f1386f588b43bb4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePid.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import org.matrix.android.sdk.api.session.identity.ThreePid + +internal data class PendingThreePid( + val threePid: ThreePid, + val clientSecret: String, + val sendAttempt: Int, + // For Msisdn and Email + val sid: String, + // For Msisdn only + val submitUrl: String? +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePidMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePidMapper.kt new file mode 100644 index 0000000000000000000000000000000000000000..b1877027ed60e9561c58bd2137c8d191f0dcfe89 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/PendingThreePidMapper.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity +import javax.inject.Inject + +internal class PendingThreePidMapper @Inject constructor() { + + fun map(entity: PendingThreePidEntity): PendingThreePid { + return PendingThreePid( + threePid = entity.email?.let { ThreePid.Email(it) } + ?: entity.msisdn?.let { ThreePid.Msisdn(it) } + ?: error("Invalid data"), + clientSecret = entity.clientSecret, + sendAttempt = entity.sendAttempt, + sid = entity.sid, + submitUrl = entity.submitUrl + ) + } + + fun map(domain: PendingThreePid): PendingThreePidEntity { + return PendingThreePidEntity( + email = domain.threePid.takeIf { it is ThreePid.Email }?.value, + msisdn = domain.threePid.takeIf { it is ThreePid.Msisdn }?.value, + clientSecret = domain.clientSecret, + sendAttempt = domain.sendAttempt, + sid = domain.sid, + submitUrl = domain.submitUrl + ) + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt index 31e1f09bbd79939646e93c9718ea7c74a05f932c..4e2f518c5ae350cc7c44dd87920de069af6aac8b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileAPI.kt @@ -19,6 +19,8 @@ package org.matrix.android.sdk.internal.session.profile import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.internal.auth.registration.SuccessResult +import org.matrix.android.sdk.internal.auth.registration.ValidationCodeBody import org.matrix.android.sdk.internal.network.NetworkConstants import retrofit2.Call import retrofit2.http.Body @@ -26,9 +28,9 @@ import retrofit2.http.GET import retrofit2.http.POST import retrofit2.http.PUT import retrofit2.http.Path +import retrofit2.http.Url internal interface ProfileAPI { - /** * Get the combined profile information for this user. * This API may be used to fetch the user's own profile information or other users; either locally or on remote homeservers. @@ -71,4 +73,35 @@ internal interface ProfileAPI { */ @POST(NetworkConstants.URI_API_PREFIX_PATH_UNSTABLE + "account/3pid/unbind") fun unbindThreePid(@Body body: UnbindThreePidBody): Call<UnbindThreePidResponse> + + /** + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-email-requesttoken + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid/email/requestToken") + fun addEmail(@Body body: AddEmailBody): Call<AddEmailResponse> + + /** + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-msisdn-requesttoken + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid/msisdn/requestToken") + fun addMsisdn(@Body body: AddMsisdnBody): Call<AddMsisdnResponse> + + /** + * Validate Msisdn code (same model than for Identity server API) + */ + @POST + fun validateMsisdn(@Url url: String, + @Body params: ValidationCodeBody): Call<SuccessResult> + + /** + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-add + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid/add") + fun finalizeAddThreePid(@Body body: FinalizeAddThreePidBody): Call<Unit> + + /** + * Ref: https://matrix.org/docs/spec/client_server/r0.6.1#post-matrix-client-r0-account-3pid-delete + */ + @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "account/3pid/delete") + fun deleteThreePid(@Body body: DeleteThreePidBody): Call<DeleteThreePidResponse> } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileModule.kt index 57a86d03e08fcc50378219be686c0400143e6867..ae7ae7a6f3286838750ec939e58895d8fba837d1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ProfileModule.kt @@ -58,4 +58,16 @@ internal abstract class ProfileModule { @Binds abstract fun bindSetAvatarUrlTask(task: DefaultSetAvatarUrlTask): SetAvatarUrlTask + + @Binds + abstract fun bindAddThreePidTask(task: DefaultAddThreePidTask): AddThreePidTask + + @Binds + abstract fun bindValidateSmsCodeTask(task: DefaultValidateSmsCodeTask): ValidateSmsCodeTask + + @Binds + abstract fun bindFinalizeAddingThreePidTask(task: DefaultFinalizeAddingThreePidTask): FinalizeAddingThreePidTask + + @Binds + abstract fun bindDeleteThreePidTask(task: DefaultDeleteThreePidTask): DeleteThreePidTask } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt new file mode 100644 index 0000000000000000000000000000000000000000..b11955b96af6e611d34a4aa9cf2e102bc913f830 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/profile/ValidateSmsCodeTask.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2019 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.profile + +import com.zhuinden.monarchy.Monarchy +import org.greenrobot.eventbus.EventBus +import org.matrix.android.sdk.api.failure.Failure +import org.matrix.android.sdk.api.session.identity.ThreePid +import org.matrix.android.sdk.internal.auth.registration.SuccessResult +import org.matrix.android.sdk.internal.auth.registration.ValidationCodeBody +import org.matrix.android.sdk.internal.database.model.PendingThreePidEntity +import org.matrix.android.sdk.internal.di.SessionDatabase +import org.matrix.android.sdk.internal.network.executeRequest +import org.matrix.android.sdk.internal.task.Task +import javax.inject.Inject + +internal interface ValidateSmsCodeTask : Task<ValidateSmsCodeTask.Params, Unit> { + data class Params( + val threePid: ThreePid.Msisdn, + val code: String + ) +} + +internal class DefaultValidateSmsCodeTask @Inject constructor( + private val profileAPI: ProfileAPI, + @SessionDatabase + private val monarchy: Monarchy, + private val pendingThreePidMapper: PendingThreePidMapper, + private val eventBus: EventBus +) : ValidateSmsCodeTask { + + override suspend fun execute(params: ValidateSmsCodeTask.Params) { + // Search the pending ThreePid + val pendingThreePids = monarchy.fetchAllMappedSync( + { it.where(PendingThreePidEntity::class.java) }, + { pendingThreePidMapper.map(it) } + ) + .firstOrNull { it.threePid == params.threePid } + ?: throw IllegalArgumentException("unknown threepid") + + val url = pendingThreePids.submitUrl ?: throw IllegalArgumentException("invalid threepid") + val body = ValidationCodeBody( + clientSecret = pendingThreePids.clientSecret, + sid = pendingThreePids.sid, + code = params.code + ) + val result = executeRequest<SuccessResult>(eventBus) { + apiCall = profileAPI.validateMsisdn(url, body) + } + + if (!result.isSuccess()) { + throw Failure.SuccessError + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 4893947fc334cfc70a2219c1859ee701ecf85881..4a196193ba0abc92348e54fbf4bc47dc60afb084 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -347,7 +347,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr if (userId == senderId) { sumModel.myVote = optionIndex } - Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$relatedEventId ") + Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$targetEventId ") } else { Timber.v("## POLL Ignoring vote (older than known one) eventId:$eventId ") } @@ -356,7 +356,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr if (userId == senderId) { sumModel.myVote = optionIndex } - Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$relatedEventId ") + Timber.v("## POLL adding vote $optionIndex for user $senderId in poll :$targetEventId ") } sumModel.votes = votes if (isLocalEcho) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt index 25dcc69fa8d1873ad61782e07e45edb0fc71190c..35c20cf5cba63da8420d36f676da55082fac6d5e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomAPI.kt @@ -130,21 +130,6 @@ internal interface RoomAPI { @Body content: Content? ): Call<SendResponse> - /** - * Send an event to a room. - * - * @param txId the transaction Id - * @param roomId the room id - * @param eventType the event type - * @param content the event content as string - */ - @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send/{eventType}/{txId}") - fun send(@Path("txId") txId: String, - @Path("roomId") roomId: String, - @Path("eventType") eventType: String, - @Body content: String? - ): Call<SendResponse> - /** * Get the context surrounding an event. * @@ -235,9 +220,9 @@ internal interface RoomAPI { */ @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/send_relation/{parent_id}/{relation_type}/{event_type}") fun sendRelation(@Path("roomId") roomId: String, - @Path("parentId") parent_id: String, + @Path("parent_id") parentId: String, @Path("relation_type") relationType: String, - @Path("eventType") eventType: String, + @Path("event_type") eventType: String, @Body content: Content? ): Call<SendResponse> @@ -311,16 +296,16 @@ internal interface RoomAPI { * This cannot be undone. * Users may redact their own events, and any user with a power level greater than or equal to the redact power level of the room may redact events there. * - * @param txId the transaction Id - * @param roomId the room id - * @param eventId the event to delete + * @param txId the transaction Id + * @param roomId the room id + * @param eventId the event to delete * @param reason json containing reason key {"reason": "Indecent material"} */ @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/redact/{eventId}/{txnId}") fun redactEvent( @Path("txnId") txId: String, @Path("roomId") roomId: String, - @Path("eventId") parent_id: String, + @Path("eventId") eventId: String, @Body reason: Map<String, String> ): Call<SendResponse> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt index 7f21ee84f67bc534a34f67eeea99a2327a20d56f..700507735bfd7f281dd635a29c5dc538fabc386e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/RoomModule.kt @@ -20,6 +20,8 @@ package org.matrix.android.sdk.internal.session.room import dagger.Binds import dagger.Module import dagger.Provides +import org.commonmark.parser.Parser +import org.commonmark.renderer.html.HtmlRenderer import org.matrix.android.sdk.api.session.file.FileService import org.matrix.android.sdk.api.session.room.RoomDirectoryService import org.matrix.android.sdk.api.session.room.RoomService @@ -75,9 +77,6 @@ import org.matrix.android.sdk.internal.session.room.typing.DefaultSendTypingTask import org.matrix.android.sdk.internal.session.room.typing.SendTypingTask import org.matrix.android.sdk.internal.session.room.uploads.DefaultGetUploadsTask import org.matrix.android.sdk.internal.session.room.uploads.GetUploadsTask -import org.commonmark.parser.Parser -import org.commonmark.renderer.html.HtmlRenderer -import org.commonmark.renderer.text.TextContentRenderer import retrofit2.Retrofit @Module @@ -105,14 +104,6 @@ internal abstract class RoomModule { .builder() .build() } - - @Provides - @JvmStatic - fun providesTextContentRenderer(): TextContentRenderer { - return TextContentRenderer - .builder() - .build() - } } @Binds diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index 6e450e5428d8452afba899729a3d9a8773ed027c..0a814a4c93b63dc3fc9a87ef9c9439b7d59a9ef4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -57,8 +57,8 @@ internal class CreateRoomBodyBuilder @Inject constructor( invites.map { ThreePidInviteBody( - id_server = identityServerUrlWithoutProtocol, - id_access_token = identityServerAccessToken, + idServer = identityServerUrlWithoutProtocol, + idAccessToken = identityServerAccessToken, medium = it.toMedium(), address = it.value ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt index d11226bdb16d249846f195e97fc68acfdd3b3610..942da9995e7cbde8305b11075f0d9dc403067f9a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.internal.session.room.membership -import android.content.Context +import io.realm.Realm import org.matrix.android.sdk.R import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toModel @@ -34,14 +34,15 @@ import org.matrix.android.sdk.internal.database.model.RoomSummaryEntity import org.matrix.android.sdk.internal.database.query.getOrNull import org.matrix.android.sdk.internal.database.query.where import org.matrix.android.sdk.internal.di.UserId -import io.realm.Realm +import org.matrix.android.sdk.internal.util.StringProvider import javax.inject.Inject /** * This class computes room display name */ -internal class RoomDisplayNameResolver @Inject constructor(private val context: Context, - @UserId private val userId: String +internal class RoomDisplayNameResolver @Inject constructor( + private val stringProvider: StringProvider, + @UserId private val userId: String ) { /** @@ -89,7 +90,7 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: .findFirst() ?.displayName } else { - context.getString(R.string.room_displayname_room_invite) + stringProvider.getString(R.string.room_displayname_room_invite) } } else if (roomEntity?.membership == Membership.JOIN) { val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() @@ -108,13 +109,13 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: } val otherMembersCount = otherMembersSubset.count() name = when (otherMembersCount) { - 0 -> context.getString(R.string.room_displayname_empty_room) - 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) - 2 -> context.getString(R.string.room_displayname_two_members, + 0 -> stringProvider.getString(R.string.room_displayname_empty_room) + 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) + 2 -> stringProvider.getString(R.string.room_displayname_two_members, resolveRoomMemberName(otherMembersSubset[0], roomMembers), resolveRoomMemberName(otherMembersSubset[1], roomMembers) ) - else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, + else -> stringProvider.getQuantityString(R.plurals.room_displayname_three_and_more_members, roomMembers.getNumberOfJoinedMembers() - 1, resolveRoomMemberName(otherMembersSubset[0], roomMembers), roomMembers.getNumberOfJoinedMembers() - 1) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt index b18e44360dda98fb8c69990abd3be504b92d97a9..88809fec13a6f9b26dafd7747773d7fe39db9049 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/InviteThreePidTask.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.room.membership.threepid +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.session.identity.IdentityServiceError import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.identity.toMedium @@ -28,7 +29,6 @@ import org.matrix.android.sdk.internal.session.identity.data.IdentityStore import org.matrix.android.sdk.internal.session.identity.data.getIdentityServerUrlWithoutProtocol import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.task.Task -import org.greenrobot.eventbus.EventBus import javax.inject.Inject internal interface InviteThreePidTask : Task<InviteThreePidTask.Params, Unit> { @@ -55,8 +55,8 @@ internal class DefaultInviteThreePidTask @Inject constructor( return executeRequest(eventBus) { val body = ThreePidInviteBody( - id_server = identityServerUrlWithoutProtocol, - id_access_token = identityServerAccessToken, + idServer = identityServerUrlWithoutProtocol, + idAccessToken = identityServerAccessToken, medium = params.threePid.toMedium(), address = params.threePid.value ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt index 93b5c577fcc5706f2fc075a4fa32f6aa5b90ab51..5b0098dc9be94371fd2df8095d53543ec2473b6c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/threepid/ThreePidInviteBody.kt @@ -25,18 +25,22 @@ internal data class ThreePidInviteBody( /** * Required. The hostname+port of the identity server which should be used for third party identifier lookups. */ - @Json(name = "id_server") val id_server: String, + @Json(name = "id_server") + val idServer: String, /** * Required. An access token previously registered with the identity server. Servers can treat this as optional * to distinguish between r0.5-compatible clients and this specification version. */ - @Json(name = "id_access_token") val id_access_token: String, + @Json(name = "id_access_token") + val idAccessToken: String, /** * Required. The kind of address being passed in the address field, for example email. */ - @Json(name = "medium") val medium: String, + @Json(name = "medium") + val medium: String, /** * Required. The invitee's third party identifier. */ - @Json(name = "address") val address: String + @Json(name = "address") + val address: String ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt index 1a19a40602e6f8ee8c2aca25cf01d6fd190e7780..86a95003395cb18348e96ec259aad8f3cd549067 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/notification/RoomPushRuleMapper.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.session.room.notification import org.matrix.android.sdk.api.pushrules.Action -import org.matrix.android.sdk.api.pushrules.Condition +import org.matrix.android.sdk.api.pushrules.Kind import org.matrix.android.sdk.api.pushrules.RuleSetKey import org.matrix.android.sdk.api.pushrules.getActions import org.matrix.android.sdk.api.pushrules.rest.PushCondition @@ -59,7 +59,7 @@ internal fun RoomNotificationState.toRoomPushRule(roomId: String): RoomPushRule? } else -> { val condition = PushCondition( - kind = Condition.Kind.EventMatch.value, + kind = Kind.EventMatch.value, key = "room_id", pattern = roomId ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index 2199193de0ac1f7ce28882c1256680791793f07a..111551d66df5aa06156eb3a52b8b1052edd36035 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -208,7 +208,7 @@ internal class DefaultRelationService @AssistedInject constructor( } private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest { - val sendContentWorkerParams = SendEventWorker.Params(sessionId, event) + val sendContentWorkerParams = SendEventWorker.Params(sessionId = sessionId, event = event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return timeLineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt index dc72c3b96bcd5a37cf7da1c47fc908be5598d3d6..fc7f7126297275bd35ad7bfb9aa3a51b6c037cb7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/SendRelationWorker.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel @@ -31,7 +32,6 @@ import org.matrix.android.sdk.internal.session.room.send.SendResponse import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.getSessionComponent -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject @@ -92,7 +92,7 @@ internal class SendRelationWorker(context: Context, params: WorkerParameters) : executeRequest<SendResponse>(eventBus) { apiCall = roomAPI.sendRelation( roomId = roomId, - parent_id = relatedEventId, + parentId = relatedEventId, relationType = relationType, eventType = localEvent.type, content = localEvent.content diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/CancelSendTracker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/CancelSendTracker.kt new file mode 100644 index 0000000000000000000000000000000000000000..0b79b93cf6a7d36f3fc637b7d658d8eb3e7c187b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/CancelSendTracker.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.session.room.send + +import org.matrix.android.sdk.internal.session.SessionScope +import javax.inject.Inject + +/** + * We cannot use work manager cancellation mechanism because cancelling a work will just ignore + * any follow up send that was already queued. + * We use this class to track cancel requests, the workers will look for this to check for cancellation request + * and just ignore the work request and continue by returning success. + * + * Known limitation, for now requests are not persisted + */ +@SessionScope +internal class CancelSendTracker @Inject constructor() { + + data class Request( + val localId: String, + val roomId: String + ) + + private val cancellingRequests = ArrayList<Request>() + + fun markLocalEchoForCancel(eventId: String, roomId: String) { + synchronized(cancellingRequests) { + cancellingRequests.add(Request(eventId, roomId)) + } + } + + fun isCancelRequestedFor(eventId: String?, roomId: String?): Boolean { + val index = synchronized(cancellingRequests) { + cancellingRequests.indexOfFirst { it.localId == eventId && it.roomId == roomId } + } + return index != -1 + } + + fun markCancelled(eventId: String, roomId: String) { + synchronized(cancellingRequests) { + val index = cancellingRequests.indexOfFirst { it.localId == eventId && it.roomId == roomId } + if (index != -1) { + cancellingRequests.removeAt(index) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index d6fa6775ee1a6100b09cdead5f70fa67514cdcb0..95cd1c699cc4b5706b80b516fb7d9b532f960f76 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -17,24 +17,35 @@ package org.matrix.android.sdk.internal.session.room.send +import android.net.Uri import androidx.work.BackoffPolicy import androidx.work.ExistingWorkPolicy import androidx.work.OneTimeWorkRequest import androidx.work.Operation import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.events.model.isImageMessage +import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage +import org.matrix.android.sdk.api.session.events.model.toModel +import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent +import org.matrix.android.sdk.api.session.room.model.message.MessageContent +import org.matrix.android.sdk.api.session.room.model.message.MessageFileContent +import org.matrix.android.sdk.api.session.room.model.message.MessageImageContent +import org.matrix.android.sdk.api.session.room.model.message.MessageVideoContent +import org.matrix.android.sdk.api.session.room.model.message.MessageWithAttachmentContent import org.matrix.android.sdk.api.session.room.model.message.OptionItem +import org.matrix.android.sdk.api.session.room.model.message.getFileUrl import org.matrix.android.sdk.api.session.room.send.SendService import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.util.Cancelable import org.matrix.android.sdk.api.util.CancelableBag import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.api.util.NoOpCancellable import org.matrix.android.sdk.internal.di.SessionId import org.matrix.android.sdk.internal.di.WorkManagerProvider import org.matrix.android.sdk.internal.session.content.UploadContentWorker @@ -44,7 +55,6 @@ import org.matrix.android.sdk.internal.util.CancelableWork import org.matrix.android.sdk.internal.worker.AlwaysSuccessfulWorker import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.startChain -import kotlinx.coroutines.launch import timber.log.Timber import java.util.concurrent.Executors import java.util.concurrent.TimeUnit @@ -60,7 +70,8 @@ internal class DefaultSendService @AssistedInject constructor( private val cryptoService: CryptoService, private val taskExecutor: TaskExecutor, private val localEchoRepository: LocalEchoRepository, - private val roomEventSender: RoomEventSender + private val roomEventSender: RoomEventSender, + private val cancelSendTracker: CancelSendTracker ) : SendService { @AssistedInject.Factory @@ -127,48 +138,83 @@ internal class DefaultSendService @AssistedInject constructor( .let { timelineSendEventWorkCommon.postWork(roomId, it) } } - override fun resendTextMessage(localEcho: TimelineEvent): Cancelable? { + override fun resendTextMessage(localEcho: TimelineEvent): Cancelable { if (localEcho.root.isTextMessage() && localEcho.root.sendState.hasFailed()) { localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) return sendEvent(localEcho.root) } - return null + return NoOpCancellable } - override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable? { - if (localEcho.root.isImageMessage() && localEcho.root.sendState.hasFailed()) { - // TODO this need a refactoring of attachement sending -// val clearContent = localEcho.root.getClearContent() -// val messageContent = clearContent?.toModel<MessageContent>() ?: return null -// when (messageContent.type) { -// MessageType.MSGTYPE_IMAGE -> { -// val imageContent = clearContent.toModel<MessageImageContent>() ?: return null -// val url = imageContent.url ?: return null -// if (url.startsWith("mxc://")) { -// //TODO -// } else { -// //The image has not yet been sent -// val attachmentData = ContentAttachmentData( -// size = imageContent.info!!.size.toLong(), -// mimeType = imageContent.info.mimeType!!, -// width = imageContent.info.width.toLong(), -// height = imageContent.info.height.toLong(), -// name = imageContent.body, -// path = imageContent.url, -// type = ContentAttachmentData.Type.IMAGE -// ) -// monarchy.runTransactionSync { -// EventEntity.where(it,eventId = localEcho.root.eventId ?: "").findFirst()?.let { -// it.sendState = SendState.UNSENT -// } -// } -// return internalSendMedia(localEcho.root,attachmentData) -// } -// } -// } - return null + override fun resendMediaMessage(localEcho: TimelineEvent): Cancelable { + if (localEcho.root.sendState.hasFailed()) { + val clearContent = localEcho.root.getClearContent() + val messageContent = clearContent?.toModel<MessageContent>() as? MessageWithAttachmentContent ?: return NoOpCancellable + + val url = messageContent.getFileUrl() ?: return NoOpCancellable + if (url.startsWith("mxc://")) { + // We need to resend only the message as the attachment is ok + localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) + return sendEvent(localEcho.root) + } + + // we need to resend the media + return when (messageContent) { + is MessageImageContent -> { + // The image has not yet been sent + val attachmentData = ContentAttachmentData( + size = messageContent.info!!.size.toLong(), + mimeType = messageContent.info.mimeType!!, + width = messageContent.info.width.toLong(), + height = messageContent.info.height.toLong(), + name = messageContent.body, + queryUri = Uri.parse(messageContent.url), + type = ContentAttachmentData.Type.IMAGE + ) + localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) + internalSendMedia(listOf(localEcho.root), attachmentData, true) + } + is MessageVideoContent -> { + val attachmentData = ContentAttachmentData( + size = messageContent.videoInfo?.size ?: 0L, + mimeType = messageContent.mimeType, + width = messageContent.videoInfo?.width?.toLong(), + height = messageContent.videoInfo?.height?.toLong(), + duration = messageContent.videoInfo?.duration?.toLong(), + name = messageContent.body, + queryUri = Uri.parse(messageContent.url), + type = ContentAttachmentData.Type.VIDEO + ) + localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) + internalSendMedia(listOf(localEcho.root), attachmentData, true) + } + is MessageFileContent -> { + val attachmentData = ContentAttachmentData( + size = messageContent.info!!.size, + mimeType = messageContent.info.mimeType!!, + name = messageContent.body, + queryUri = Uri.parse(messageContent.url), + type = ContentAttachmentData.Type.FILE + ) + localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) + internalSendMedia(listOf(localEcho.root), attachmentData, true) + } + is MessageAudioContent -> { + val attachmentData = ContentAttachmentData( + size = messageContent.audioInfo?.size ?: 0, + duration = messageContent.audioInfo?.duration?.toLong() ?: 0L, + mimeType = messageContent.audioInfo?.mimeType, + name = messageContent.body, + queryUri = Uri.parse(messageContent.url), + type = ContentAttachmentData.Type.AUDIO + ) + localEchoRepository.updateSendState(localEcho.eventId, SendState.UNSENT) + internalSendMedia(listOf(localEcho.root), attachmentData, true) + } + else -> NoOpCancellable + } } - return null + return NoOpCancellable } override fun deleteFailedEcho(localEcho: TimelineEvent) { @@ -196,16 +242,34 @@ internal class DefaultSendService @AssistedInject constructor( } } + override fun cancelSend(eventId: String) { + cancelSendTracker.markLocalEchoForCancel(eventId, roomId) + taskExecutor.executorScope.launch { + localEchoRepository.deleteFailedEcho(roomId, eventId) + } + } + override fun resendAllFailedMessages() { taskExecutor.executorScope.launch { val eventsToResend = localEchoRepository.getAllFailedEventsToResend(roomId) eventsToResend.forEach { - sendEvent(it) + if (it.root.isTextMessage()) { + resendTextMessage(it) + } else if (it.root.isAttachmentMessage()) { + resendMediaMessage(it) + } } - localEchoRepository.updateSendState(roomId, eventsToResend.mapNotNull { it.eventId }, SendState.UNSENT) + localEchoRepository.updateSendState(roomId, eventsToResend.map { it.eventId }, SendState.UNSENT) } } +// override fun failAllPendingMessages() { +// taskExecutor.executorScope.launch { +// val eventsToResend = localEchoRepository.getAllEventsWithStates(roomId, SendState.PENDING_STATES) +// localEchoRepository.updateSendState(roomId, eventsToResend.map { it.eventId }, SendState.UNDELIVERED) +// } +// } + override fun sendMedia(attachment: ContentAttachmentData, compressBeforeSending: Boolean, roomIds: Set<String>): Cancelable { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/EncryptEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/EncryptEventWorker.kt index d23835e83883b93ecd8c3bc00393ba93d266c42e..6b2a2ab1156501bb3e83c951182a7f46c826e7a7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/EncryptEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/EncryptEventWorker.kt @@ -54,6 +54,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) @Inject lateinit var crypto: CryptoService @Inject lateinit var localEchoRepository: LocalEchoRepository + @Inject lateinit var cancelSendTracker: CancelSendTracker override suspend fun doWork(): Result { Timber.v("Start Encrypt work") @@ -61,7 +62,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) ?: return Result.success() .also { Timber.e("Unable to parse work parameters") } - Timber.v("Start Encrypt work for event ${params.event.eventId}") + Timber.v("## SendEvent: Start Encrypt work for event ${params.event.eventId}") if (params.lastFailureMessage != null) { // Transmit the error return Result.success(inputData) @@ -75,6 +76,12 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) if (localEvent.eventId == null) { return Result.success() } + + if (cancelSendTracker.isCancelRequestedFor(localEvent.eventId, localEvent.roomId)) { + return Result.success() + .also { Timber.e("## SendEvent: Event sending has been cancelled ${localEvent.eventId}") } + } + localEchoRepository.updateSendState(localEvent.eventId, SendState.ENCRYPTING) val localMutableContent = localEvent.content?.toMutableMap() ?: mutableMapOf() @@ -120,7 +127,7 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) localEchoRepository.updateEncryptedEcho(localEvent.eventId, safeResult.eventContent, decryptionLocalEcho) } - val nextWorkerParams = SendEventWorker.Params(params.sessionId, encryptedEvent) + val nextWorkerParams = SendEventWorker.Params(sessionId = params.sessionId, event = encryptedEvent) return Result.success(WorkerParamsFactory.toData(nextWorkerParams)) } else { val sendState = when (error) { @@ -129,8 +136,11 @@ internal class EncryptEventWorker(context: Context, params: WorkerParameters) } localEchoRepository.updateSendState(localEvent.eventId, sendState) // always return success, or the chain will be stuck for ever! - val nextWorkerParams = SendEventWorker.Params(params.sessionId, localEvent, error?.localizedMessage - ?: "Error") + val nextWorkerParams = SendEventWorker.Params( + sessionId = params.sessionId, + event = localEvent, + lastFailureMessage = error?.localizedMessage ?: "Error" + ) return Result.success(WorkerParamsFactory.toData(nextWorkerParams)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt index a9859136ad96e38757f8a7df1b802d200f18f3d7..b3188883c052385ef6f250a30bf44657a91c0ca4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoRepository.kt @@ -30,7 +30,6 @@ import org.matrix.android.sdk.internal.crypto.MXEventDecryptionResult import org.matrix.android.sdk.internal.database.helper.nextId import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.TimelineEventMapper -import org.matrix.android.sdk.internal.database.mapper.asDomain import org.matrix.android.sdk.internal.database.mapper.toEntity import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventInsertEntity @@ -88,7 +87,7 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } fun updateSendState(eventId: String, sendState: SendState) { - Timber.v("Update local state of $eventId to ${sendState.name}") + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Update local state of $eventId to ${sendState.name}") monarchy.writeAsync { realm -> val sendingEventEntity = EventEntity.where(realm, eventId).findFirst() if (sendingEventEntity != null) { @@ -114,9 +113,13 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } suspend fun deleteFailedEcho(roomId: String, localEcho: TimelineEvent) { + deleteFailedEcho(roomId, localEcho.eventId) + } + + suspend fun deleteFailedEcho(roomId: String, eventId: String?) { monarchy.awaitTransaction { realm -> - TimelineEventEntity.where(realm, roomId = roomId, eventId = localEcho.root.eventId ?: "").findFirst()?.deleteFromRealm() - EventEntity.where(realm, eventId = localEcho.root.eventId ?: "").findFirst()?.deleteFromRealm() + TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId ?: "").findFirst()?.deleteFromRealm() + EventEntity.where(realm, eventId = eventId ?: "").findFirst()?.deleteFromRealm() roomSummaryUpdater.updateSendingInformation(realm, roomId) } } @@ -142,45 +145,47 @@ internal class LocalEchoRepository @Inject constructor(@SessionDatabase private } } - fun getAllFailedEventsToResend(roomId: String): List<Event> { + fun getAllFailedEventsToResend(roomId: String): List<TimelineEvent> { + return getAllEventsWithStates(roomId, SendState.HAS_FAILED_STATES) + } + + fun getAllEventsWithStates(roomId: String, states : List<SendState>): List<TimelineEvent> { return Realm.getInstance(monarchy.realmConfiguration).use { realm -> TimelineEventEntity - .findAllInRoomWithSendStates(realm, roomId, SendState.HAS_FAILED_STATES) + .findAllInRoomWithSendStates(realm, roomId, states) .sortedByDescending { it.displayIndex } - .mapNotNull { it.root?.asDomain() } + .mapNotNull { it?.let { timelineEventMapper.map(it) } } .filter { event -> - when (event.getClearType()) { + when (event.root.getClearType()) { EventType.MESSAGE, EventType.REDACTION, EventType.REACTION -> { - val content = event.getClearContent().toModel<MessageContent>() + val content = event.root.getClearContent().toModel<MessageContent>() if (content != null) { when (content.msgType) { MessageType.MSGTYPE_EMOTE, MessageType.MSGTYPE_NOTICE, MessageType.MSGTYPE_LOCATION, - MessageType.MSGTYPE_TEXT -> { - true - } + MessageType.MSGTYPE_TEXT, MessageType.MSGTYPE_FILE, MessageType.MSGTYPE_VIDEO, MessageType.MSGTYPE_IMAGE, MessageType.MSGTYPE_AUDIO -> { // need to resend the attachment - false + true } else -> { - Timber.e("Cannot resend message ${event.type} / ${content.msgType}") + Timber.e("Cannot resend message ${event.root.getClearType()} / ${content.msgType}") false } } } else { - Timber.e("Unsupported message to resend ${event.type}") + Timber.e("Unsupported message to resend ${event.root.getClearType()}") false } } else -> { - Timber.e("Unsupported message to resend ${event.type}") + Timber.e("Unsupported message to resend ${event.root.getClearType()}") false } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt index 3390d9dc79ecd1e978ebe6aa46c4e3019392be47..f80285574e6fb9ead16b13635ddf6237e66ba423 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MarkdownParser.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.session.room.send import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer -import org.commonmark.renderer.text.TextContentRenderer import javax.inject.Inject /** @@ -29,11 +28,10 @@ import javax.inject.Inject */ internal class MarkdownParser @Inject constructor( private val parser: Parser, - private val htmlRenderer: HtmlRenderer, - private val textContentRenderer: TextContentRenderer + private val htmlRenderer: HtmlRenderer ) { - private val mdSpecialChars = "[`_\\-\\*>\\.\\[\\]#~]".toRegex() + private val mdSpecialChars = "[`_\\-*>.\\[\\]#~]".toRegex() fun parse(text: String): TextContent { // If no special char are detected, just return plain text @@ -54,8 +52,8 @@ internal class MarkdownParser @Inject constructor( return if (isFormattedTextPertinent(text, cleanHtmlText)) { // According to https://matrix.org/docs/spec/client_server/latest#m-room-message-msgtypes: // The plain text version of the HTML should be provided in the body. - val plainText = textContentRenderer.render(document) - TextContent(plainText, cleanHtmlText.postTreatment()) + // But it caused too many problems so it has been removed in #2002 + TextContent(text, cleanHtmlText.postTreatment()) } else { TextContent(text) } @@ -72,6 +70,7 @@ internal class MarkdownParser @Inject constructor( // Remove extra space before and after the content .trim() // There is no need to include new line in an html-like source - .replace("\n", "") + // But new line can be in embedded code block, so do not remove them + // .replace("\n", "") } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt index 73791e84127f4fc68297ec2b4489e9ad7d0dec2c..8e8d24c227b8c63e5c03e82e996f78dae5f2f61c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/MultipleEventSendingDispatcherWorker.kt @@ -58,7 +58,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo @Inject lateinit var localEchoRepository: LocalEchoRepository override suspend fun doWork(): Result { - Timber.v("Start dispatch sending multiple event work") + Timber.v("## SendEvent: Start dispatch sending multiple event work") val params = WorkerParamsFactory.fromData<Params>(inputData) ?: return Result.success() .also { Timber.e("Unable to parse work parameters") } @@ -72,18 +72,21 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo } // Transmit the error if needed? return Result.success(inputData) - .also { Timber.e("Work cancelled due to input error from parent") } + .also { Timber.e("## SendEvent: Work cancelled due to input error from parent ${params.lastFailureMessage}") } } // Create a work for every event params.events.forEach { event -> if (params.isEncrypted) { - Timber.v("Send event in encrypted room") + localEchoRepository.updateSendState(event.eventId ?: "", SendState.ENCRYPTING) + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Schedule encrypt and send event ${event.eventId}") val encryptWork = createEncryptEventWork(params.sessionId, event, true) // Note that event will be replaced by the result of the previous work val sendWork = createSendEventWork(params.sessionId, event, false) timelineSendEventWorkCommon.postSequentialWorks(event.roomId!!, encryptWork, sendWork) } else { + localEchoRepository.updateSendState(event.eventId ?: "", SendState.SENDING) + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Schedule send event ${event.eventId}") val sendWork = createSendEventWork(params.sessionId, event, true) timelineSendEventWorkCommon.postWork(event.roomId!!, sendWork) } @@ -105,7 +108,7 @@ internal class MultipleEventSendingDispatcherWorker(context: Context, params: Wo } private fun createSendEventWork(sessionId: String, event: Event, startChain: Boolean): OneTimeWorkRequest { - val sendContentWorkerParams = SendEventWorker.Params(sessionId, event) + val sendContentWorkerParams = SendEventWorker.Params(sessionId = sessionId, event = event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return timelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RoomEventSender.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RoomEventSender.kt index 65c692f42e199cdc2c15a3a099a68393a5b67f73..6085459a08010c6cf34794899010febc64b2e3c3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RoomEventSender.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/RoomEventSender.kt @@ -39,13 +39,16 @@ internal class RoomEventSender @Inject constructor( ) { fun sendEvent(event: Event): Cancelable { // Encrypted room handling - return if (cryptoService.isRoomEncrypted(event.roomId ?: "")) { - Timber.v("Send event in encrypted room") + return if (cryptoService.isRoomEncrypted(event.roomId ?: "") + && !event.isEncrypted() // In case of resend where it's already encrypted so skip to send + ) { + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Schedule encrypt and send event ${event.eventId}") val encryptWork = createEncryptEventWork(event, true) // Note that event will be replaced by the result of the previous work val sendWork = createSendEventWork(event, false) timelineSendEventWorkCommon.postSequentialWorks(event.roomId ?: "", encryptWork, sendWork) } else { + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Schedule send event ${event.eventId}") val sendWork = createSendEventWork(event, true) timelineSendEventWorkCommon.postWork(event.roomId ?: "", sendWork) } @@ -65,7 +68,7 @@ internal class RoomEventSender @Inject constructor( } private fun createSendEventWork(event: Event, startChain: Boolean): OneTimeWorkRequest { - val sendContentWorkerParams = SendEventWorker.Params(sessionId, event) + val sendContentWorkerParams = SendEventWorker.Params(sessionId = sessionId, event = event) val sendWorkData = WorkerParamsFactory.toData(sendContentWorkerParams) return timelineSendEventWorkCommon.createWork<SendEventWorker>(sendWorkData, startChain) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt index 2868ce29c1f86a1496667476a56686847fa9458f..16acde7d163a1ffa66d730e82fa56c8d7a2dd3f2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/SendEventWorker.kt @@ -21,20 +21,20 @@ import android.content.Context import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.squareup.moshi.JsonClass +import org.greenrobot.eventbus.EventBus import org.matrix.android.sdk.api.failure.shouldBeRetried +import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.send.SendState -import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.network.executeRequest import org.matrix.android.sdk.internal.session.room.RoomAPI import org.matrix.android.sdk.internal.worker.SessionWorkerParams import org.matrix.android.sdk.internal.worker.WorkerParamsFactory import org.matrix.android.sdk.internal.worker.getSessionComponent -import org.greenrobot.eventbus.EventBus import timber.log.Timber import javax.inject.Inject -private const val MAX_NUMBER_OF_RETRY_BEFORE_FAILING = 3 +// private const val MAX_NUMBER_OF_RETRY_BEFORE_FAILING = 3 /** * Possible previous worker: [EncryptEventWorker] or first worker @@ -47,68 +47,69 @@ internal class SendEventWorker(context: Context, @JsonClass(generateAdapter = true) internal data class Params( override val sessionId: String, - // TODO remove after some time, it's used for compat + override val lastFailureMessage: String? = null, val event: Event? = null, - val eventId: String? = null, - val roomId: String? = null, - val type: String? = null, - val contentStr: String? = null, - override val lastFailureMessage: String? = null - ) : SessionWorkerParams { - - constructor(sessionId: String, event: Event, lastFailureMessage: String? = null) : this( - sessionId = sessionId, - eventId = event.eventId, - roomId = event.roomId, - type = event.type, - contentStr = ContentMapper.map(event.content), - lastFailureMessage = lastFailureMessage - ) - } + // Keep for compat at the moment, will be removed later + val eventId: String? = null + ) : SessionWorkerParams @Inject lateinit var localEchoRepository: LocalEchoRepository @Inject lateinit var roomAPI: RoomAPI @Inject lateinit var eventBus: EventBus + @Inject lateinit var cancelSendTracker: CancelSendTracker override suspend fun doWork(): Result { val params = WorkerParamsFactory.fromData<Params>(inputData) ?: return Result.success() - .also { Timber.e("Unable to parse work parameters") } - + .also { Timber.e("## SendEvent: Unable to parse work parameters") } val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success() sessionComponent.inject(this) - if (params.eventId == null || params.roomId == null || params.type == null) { - // compat with old params, make it fail if any - if (params.event?.eventId != null) { - localEchoRepository.updateSendState(params.event.eventId, SendState.UNDELIVERED) + + val event = params.event + if (event?.eventId == null || event.roomId == null) { + // Old way of sending + if (params.eventId != null) { + localEchoRepository.updateSendState(params.eventId, SendState.UNDELIVERED) } return Result.success() + .also { Timber.e("Work cancelled due to bad input data") } } + + if (cancelSendTracker.isCancelRequestedFor(params.eventId, event.roomId)) { + return Result.success() + .also { + cancelSendTracker.markCancelled(event.eventId, event.roomId) + Timber.e("## SendEvent: Event sending has been cancelled ${params.eventId}") + } + } + if (params.lastFailureMessage != null) { - localEchoRepository.updateSendState(params.eventId, SendState.UNDELIVERED) + localEchoRepository.updateSendState(event.eventId, SendState.UNDELIVERED) // Transmit the error return Result.success(inputData) .also { Timber.e("Work cancelled due to input error from parent") } } + + Timber.v("## SendEvent: [${System.currentTimeMillis()}] Send event ${params.eventId}") return try { - sendEvent(params.eventId, params.roomId, params.type, params.contentStr) + sendEvent(event.eventId, event.roomId, event.type, event.content) Result.success() } catch (exception: Throwable) { - // It does start from 0, we want it to stop if it fails the third time - val currentAttemptCount = runAttemptCount + 1 - if (currentAttemptCount >= MAX_NUMBER_OF_RETRY_BEFORE_FAILING || !exception.shouldBeRetried()) { - localEchoRepository.updateSendState(params.eventId, SendState.UNDELIVERED) + if (/*currentAttemptCount >= MAX_NUMBER_OF_RETRY_BEFORE_FAILING ||**/ !exception.shouldBeRetried()) { + Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed cannot retry ${params.eventId} > ${exception.localizedMessage}") + localEchoRepository.updateSendState(event.eventId, SendState.UNDELIVERED) return Result.success() } else { + Timber.e("## SendEvent: [${System.currentTimeMillis()}] Send event Failed schedule retry ${params.eventId} > ${exception.localizedMessage}") Result.retry() } } } - private suspend fun sendEvent(eventId: String, roomId: String, type: String, contentStr: String?) { + private suspend fun sendEvent(eventId: String, roomId: String, type: String, content: Content?) { localEchoRepository.updateSendState(eventId, SendState.SENDING) executeRequest<SendResponse>(eventBus) { - apiCall = roomAPI.send(eventId, roomId, type, contentStr) + apiCall = roomAPI.send(eventId, roomId, type, content) } localEchoRepository.updateSendState(eventId, SendState.SENT) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index b4c32c045e0174ebdc63b6e127ff6e4863245804..421cd1b0631924dca08fa8741e89a5f55e9828cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -17,6 +17,16 @@ package org.matrix.android.sdk.internal.session.room.timeline +import io.realm.OrderedCollectionChangeSet +import io.realm.OrderedRealmCollectionChangeListener +import io.realm.Realm +import io.realm.RealmConfiguration +import io.realm.RealmQuery +import io.realm.RealmResults +import io.realm.Sort +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe +import org.greenrobot.eventbus.ThreadMode import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.events.model.EventType @@ -44,16 +54,6 @@ import org.matrix.android.sdk.internal.task.configureWith import org.matrix.android.sdk.internal.util.Debouncer import org.matrix.android.sdk.internal.util.createBackgroundHandler import org.matrix.android.sdk.internal.util.createUIHandler -import io.realm.OrderedCollectionChangeSet -import io.realm.OrderedRealmCollectionChangeListener -import io.realm.Realm -import io.realm.RealmConfiguration -import io.realm.RealmQuery -import io.realm.RealmResults -import io.realm.Sort -import org.greenrobot.eventbus.EventBus -import org.greenrobot.eventbus.Subscribe -import org.greenrobot.eventbus.ThreadMode import timber.log.Timber import java.util.Collections import java.util.UUID @@ -115,6 +115,7 @@ internal class DefaultTimeline( if (!results.isLoaded || !results.isValid) { return@OrderedRealmCollectionChangeListener } + Timber.v("## SendEvent: [${System.currentTimeMillis()}] DB update for room $roomId") handleUpdates(results, changeSet) } @@ -316,12 +317,15 @@ internal class DefaultTimeline( @Subscribe(threadMode = ThreadMode.MAIN) fun onLocalEchoCreated(onLocalEchoCreated: OnLocalEchoCreated) { if (isLive && onLocalEchoCreated.roomId == roomId) { - listeners.forEach { - it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId)) + // do not add events that would have been filtered + if (listOf(onLocalEchoCreated.timelineEvent).filterEventsWithSettings().isNotEmpty()) { + listeners.forEach { + it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId)) + } + Timber.v("On local echo created: ${onLocalEchoCreated.timelineEvent.eventId}") + inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent) + postSnapshot() } - Timber.v("On local echo created: $onLocalEchoCreated") - inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent) - postSnapshot() } } @@ -777,7 +781,7 @@ internal class DefaultTimeline( val filterEdits = if (settings.filterEdits && it.root.type == EventType.MESSAGE) { val messageContent = it.root.content.toModel<MessageContent>() - messageContent?.relatesTo?.type != RelationType.REPLACE + messageContent?.relatesTo?.type != RelationType.REPLACE && messageContent?.relatesTo?.type != RelationType.RESPONSE } else { true } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineSendEventWorkCommon.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineSendEventWorkCommon.kt index d3124b68ca8a1303d69e4cdb63d343170949427a..3bc6a85cfbc9e07f74f99d5683357cfc9de376d6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineSendEventWorkCommon.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/TimelineSendEventWorkCommon.kt @@ -57,7 +57,7 @@ internal class TimelineSendEventWorkCommon @Inject constructor( } } - fun postWork(roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND): Cancelable { + fun postWork(roomId: String, workRequest: OneTimeWorkRequest, policy: ExistingWorkPolicy = ExistingWorkPolicy.APPEND_OR_REPLACE): Cancelable { workManagerProvider.workManager .beginUniqueWork(buildWorkName(roomId), policy, workRequest) .enqueue() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt index 2ae115f325f4d0f9aa39df11e460c82283bf4760..8eab44366c68b2f7ba02760c3222d7d05aaf836c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/securestorage/SecretStoringUtils.kt @@ -219,7 +219,7 @@ internal class SecretStoringUtils @Inject constructor(private val context: Conte @RequiresApi(Build.VERSION_CODES.M) private fun decryptStringM(encryptedChunk: ByteArray, keyAlias: String): String { - val (iv, encryptedText) = formatMExtract(ByteArrayInputStream(encryptedChunk)) + val (iv, encryptedText) = formatMExtract(encryptedChunk.inputStream()) val secretKey = getOrGenerateSymmetricKeyForAliasM(keyAlias) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt index 1a2d6b1fd32f3ad337a4557551789a7f579ac5bb..9fd9c313dbe8ab29f84c177a288e86339b408fb3 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt @@ -19,6 +19,7 @@ package org.matrix.android.sdk.internal.session.sync.job import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer import com.squareup.moshi.JsonEncodingException import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isTokenError @@ -30,11 +31,14 @@ import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.Debouncer import org.matrix.android.sdk.internal.util.createUIHandler import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.matrix.android.sdk.api.session.call.MxCall +import org.matrix.android.sdk.internal.session.call.ActiveCallHandler import timber.log.Timber import java.net.SocketTimeoutException import java.util.Timer @@ -48,8 +52,9 @@ private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L internal class SyncThread @Inject constructor(private val syncTask: SyncTask, private val typingUsersTracker: DefaultTypingUsersTracker, private val networkConnectivityChecker: NetworkConnectivityChecker, - private val backgroundDetectionObserver: BackgroundDetectionObserver) - : Thread(), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { + private val backgroundDetectionObserver: BackgroundDetectionObserver, + private val activeCallHandler: ActiveCallHandler +) : Thread(), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { private var state: SyncState = SyncState.Idle private var liveState = MutableLiveData<SyncState>(state) @@ -62,6 +67,12 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, private var isTokenValid = true private var retryNoNetworkTask: TimerTask? = null + private val activeCallListObserver = Observer<MutableList<MxCall>> { activeCalls -> + if (activeCalls.isEmpty() && backgroundDetectionObserver.isInBackground) { + pause() + } + } + init { updateStateTo(SyncState.Idle) } @@ -115,9 +126,11 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, override fun run() { Timber.v("Start syncing...") + isStarted = true networkConnectivityChecker.register(this) backgroundDetectionObserver.register(this) + registerActiveCallsObserver() while (state != SyncState.Killing) { Timber.v("Entering loop, state: $state") if (!isStarted) { @@ -163,6 +176,19 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, updateStateTo(SyncState.Killed) backgroundDetectionObserver.unregister(this) networkConnectivityChecker.unregister(this) + unregisterActiveCallsObserver() + } + + private fun registerActiveCallsObserver() { + syncScope.launch(Dispatchers.Main) { + activeCallHandler.getActiveCallsLiveData().observeForever(activeCallListObserver) + } + } + + private fun unregisterActiveCallsObserver() { + syncScope.launch(Dispatchers.Main) { + activeCallHandler.getActiveCallsLiveData().removeObserver(activeCallListObserver) + } } private suspend fun doSync(params: SyncTask.Params) { @@ -215,6 +241,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, } override fun onMoveToBackground() { - pause() + if (activeCallHandler.getActiveCallsLiveData().value.isNullOrEmpty()) { + pause() + } } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt index 226486596ed620f6ae86ac590e18abc35eb95123..0e7fbf492f4b3f9d0724cbd0d3aed9e0db9a5aef 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/model/DeviceInfo.kt @@ -16,6 +16,7 @@ */ package org.matrix.android.sdk.internal.session.sync.model +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass /** @@ -26,26 +27,30 @@ internal data class DeviceInfo( /** * The owner user id */ - val user_id: String? = null, + @Json(name = "user_id") + val userId: String? = null, /** * The device id */ - val device_id: String? = null, + @Json(name = "device_id") + val deviceId: String? = null, /** * The device display name */ - val display_name: String? = null, + @Json(name = "display_name") + val displayName: String? = null, /** * The last time this device has been seen. */ - val last_seen_ts: Long = 0, + @Json(name = "last_seen_ts") + val lastSeenTs: Long = 0, /** * The last ip address */ - val last_seen_ip: String? = null - + @Json(name = "last_seen_ip") + val lastSeenIp: String? = null ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt new file mode 100644 index 0000000000000000000000000000000000000000..76e24c4e31274bf39e43987972c2539cbd3b1c9b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Base64.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.util + +/** + * Base64 URL conversion methods + */ + +internal fun base64UrlToBase64(base64Url: String): String { + return base64Url.replace('-', '+') + .replace('_', '/') +} + +internal fun base64ToBase64Url(base64: String): String { + return base64.replace("\n".toRegex(), "") + .replace("\\+".toRegex(), "-") + .replace('/', '_') + .replace("=", "") +} + +internal fun base64ToUnpaddedBase64(base64: String): String { + return base64.replace("\n".toRegex(), "") + .replace("=", "") +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CompatUtil.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CompatUtil.kt index 6583dc89ea88b4169bbb75f8c98e52eacf9b309a..6a5cfec0950dba39be02c5f5d8bfcf943283633c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CompatUtil.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/CompatUtil.kt @@ -257,12 +257,11 @@ object CompatUtil { /** * Create a CipherInputStream instance. - * Before Kitkat, this method will return `in` because local storage encryption is not implemented for devices before KitKat. - * Warning, if `in` is not an encrypted stream, it's up to the caller to close and reopen `in`, because the stream has been read. + * Warning, if inputStream is not an encrypted stream, it's up to the caller to close and reopen inputStream, because the stream has been read. * - * @param in the input stream - * @param context the context holding the application shared preferences - * @return in, or the created InputStream, or null if the InputStream `in` does not contain encrypted data + * @param inputStream the input stream + * @param context the context holding the application shared preferences + * @return inputStream, or the created InputStream, or null if the InputStream inputStream does not contain encrypted data */ @Throws(NoSuchPaddingException::class, NoSuchAlgorithmException::class, @@ -274,15 +273,15 @@ object CompatUtil { NoSuchProviderException::class, InvalidAlgorithmParameterException::class, IOException::class) - fun createCipherInputStream(`in`: InputStream, context: Context): InputStream? { - val iv_len = `in`.read() - if (iv_len != AES_GCM_IV_LENGTH) { - Timber.e(TAG, "Invalid IV length $iv_len") + fun createCipherInputStream(inputStream: InputStream, context: Context): InputStream? { + val ivLen = inputStream.read() + if (ivLen != AES_GCM_IV_LENGTH) { + Timber.e(TAG, "Invalid IV length $ivLen") return null } val iv = ByteArray(AES_GCM_IV_LENGTH) - `in`.read(iv) + inputStream.read(iv) val cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE) @@ -296,6 +295,6 @@ object CompatUtil { cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.secretKey, spec) - return CipherInputStream(`in`, cipher) + return CipherInputStream(inputStream, cipher) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt index 27625d90bc990d5de2d1afd184e063790653ba56..da524cc1b236982c9813adb1e064e46e8b387c25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/FileSaver.kt @@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.util import androidx.annotation.WorkerThread import java.io.File -import java.io.FileOutputStream import java.io.InputStream /** @@ -27,7 +26,7 @@ import java.io.InputStream */ @WorkerThread fun writeToFile(inputStream: InputStream, outputFile: File) { - FileOutputStream(outputFile).use { + outputFile.outputStream().use { inputStream.copyTo(it) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt new file mode 100644 index 0000000000000000000000000000000000000000..129bf0dec4191720372a12a42865e23bd8f34e31 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/Glob.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * Copyright 2020 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.util + +internal fun String.hasSpecialGlobChar(): Boolean { + return contains("*") || contains("?") +} + +// Very simple glob to regexp converter +internal fun String.simpleGlobToRegExp(): String { + val string = this + return buildString { + // append("^") + string.forEach { char -> + when (char) { + '*' -> append(".*") + '?' -> append(".") + '.' -> append("\\.") + '\\' -> append("\\\\") + else -> append(char) + } + } + // append("$") + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt index 902d7d33161ac9ae99dfeb7a7adda61fb449c172..9233b2b80747802c3851e4d75388f69df8d5547b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringProvider.kt @@ -18,8 +18,8 @@ package org.matrix.android.sdk.internal.util import android.content.res.Resources -import androidx.annotation.ArrayRes import androidx.annotation.NonNull +import androidx.annotation.PluralsRes import androidx.annotation.StringRes import dagger.Reusable import javax.inject.Inject @@ -56,8 +56,8 @@ internal class StringProvider @Inject constructor(private val resources: Resourc return resources.getString(resId, *formatArgs) } - @Throws(Resources.NotFoundException::class) - fun getStringArray(@ArrayRes id: Int): Array<String> { - return resources.getStringArray(id) + @NonNull + fun getQuantityString(@PluralsRes resId: Int, quantity: Int, vararg formatArgs: Any?): String { + return resources.getQuantityString(resId, quantity, *formatArgs) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt index a236771cd65ec7a07ae13b023088611ecb1132d2..681e7e5feda0a339484a4f6af3d834c1a5f8a404 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/util/StringUtils.kt @@ -52,3 +52,25 @@ fun convertFromUTF8(s: String): String { } fun String.withoutPrefix(prefix: String) = if (startsWith(prefix)) substringAfter(prefix) else this + +/** + * Returns whether a string contains an occurrence of another, as a standalone word, regardless of case. + * + * @param subString the string to search for + * @return whether a match was found + */ +fun String.caseInsensitiveFind(subString: String): Boolean { + // add sanity checks + if (subString.isEmpty() || isEmpty()) { + return false + } + + try { + val regex = Regex("(\\W|^)" + Regex.escape(subString) + "(\\W|$)", RegexOption.IGNORE_CASE) + return regex.containsMatchIn(this) + } catch (e: Exception) { + Timber.e(e, "## caseInsensitiveFind() : failed") + } + + return false +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt index e20fe9a30453c24647187c75f00d57ab57729d22..80ede5e884e52294c119d9301f5b8e8223f2fe0e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/wellknown/GetWellknownTask.kt @@ -97,7 +97,7 @@ internal class DefaultGetWellknownTask @Inject constructor( // Success val homeServerBaseUrl = wellKnown.homeServer?.baseURL if (homeServerBaseUrl.isNullOrBlank()) { - WellknownResult.FailPrompt + WellknownResult.FailPrompt(null, null) } else { if (homeServerBaseUrl.isValidUrl()) { // Check that HS is a real one @@ -120,11 +120,11 @@ internal class DefaultGetWellknownTask @Inject constructor( is Failure.OtherServerError -> { when (throwable.httpCode) { HttpsURLConnection.HTTP_NOT_FOUND -> WellknownResult.Ignore - else -> WellknownResult.FailPrompt + else -> WellknownResult.FailPrompt(null, null) } } is MalformedJsonException, is EOFException -> { - WellknownResult.FailPrompt + WellknownResult.FailPrompt(null, null) } else -> { throw throwable @@ -162,7 +162,7 @@ internal class DefaultGetWellknownTask @Inject constructor( // All is ok WellknownResult.Prompt(homeServerBaseUrl, identityServerBaseUrl, wellKnown) } else { - WellknownResult.FailError + WellknownResult.FailPrompt(homeServerBaseUrl, wellKnown) } } else { WellknownResult.FailError diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/WorkerParamsFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/WorkerParamsFactory.kt index 2b7cba0b0cadbe7f99487063da5d0b6d65a5eb38..b162566403aa59c68afdc7a4490e39cdc434e3b2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/WorkerParamsFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/worker/WorkerParamsFactory.kt @@ -19,13 +19,23 @@ package org.matrix.android.sdk.internal.worker import androidx.work.Data import org.matrix.android.sdk.internal.di.MoshiProvider +import org.matrix.android.sdk.internal.network.parsing.CheckNumberType -object WorkerParamsFactory { +internal object WorkerParamsFactory { + + val moshi by lazy { + // We are adding the CheckNumberType as we are serializing/deserializing multiple time in a row + // and we lost typing information doing so. + // We don't want this check to be done on all adapters, so we just add it here. + MoshiProvider.providesMoshi() + .newBuilder() + .add(CheckNumberType.JSON_ADAPTER_FACTORY) + .build() + } const val KEY = "WORKER_PARAMS_JSON" inline fun <reified T> toData(params: T): Data { - val moshi = MoshiProvider.providesMoshi() val adapter = moshi.adapter(T::class.java) val json = adapter.toJson(params) return Data.Builder().putString(KEY, json).build() @@ -36,7 +46,6 @@ object WorkerParamsFactory { return if (json == null) { null } else { - val moshi = MoshiProvider.providesMoshi() val adapter = moshi.adapter(T::class.java) adapter.fromJson(json) } diff --git a/matrix-sdk-android/src/main/res/drawable/ic_verification_airplane.xml b/matrix-sdk-android/src/main/res/drawable/ic_verification_aeroplane.xml similarity index 100% rename from matrix-sdk-android/src/main/res/drawable/ic_verification_airplane.xml rename to matrix-sdk-android/src/main/res/drawable/ic_verification_aeroplane.xml diff --git a/matrix-sdk-android/src/main/res/drawable/ic_verification_headphone.xml b/matrix-sdk-android/src/main/res/drawable/ic_verification_headphones.xml similarity index 100% rename from matrix-sdk-android/src/main/res/drawable/ic_verification_headphone.xml rename to matrix-sdk-android/src/main/res/drawable/ic_verification_headphones.xml diff --git a/matrix-sdk-android/src/main/res/drawable/ic_verification_wrench.xml b/matrix-sdk-android/src/main/res/drawable/ic_verification_spanner.xml similarity index 100% rename from matrix-sdk-android/src/main/res/drawable/ic_verification_wrench.xml rename to matrix-sdk-android/src/main/res/drawable/ic_verification_spanner.xml diff --git a/matrix-sdk-android/src/main/res/values-az/strings.xml b/matrix-sdk-android/src/main/res/values-az/strings.xml index 9c60dfafa7ccc71510a652bd7cf8e82cf35690a8..1f366c647f1632b8d9e8ae9d41abcd648f549a3a 100644 --- a/matrix-sdk-android/src/main/res/values-az/strings.xml +++ b/matrix-sdk-android/src/main/res/values-az/strings.xml @@ -79,72 +79,6 @@ <string name="room_displayname_empty_room">BoÅŸ otaq</string> - - <string name="verification_emoji_dog">It</string> - <string name="verification_emoji_cat">PiÅŸik</string> - <string name="verification_emoji_lion">Aslan</string> - <string name="verification_emoji_horse">At</string> - <string name="verification_emoji_unicorn">KÉ™rgÉ™dan</string> - <string name="verification_emoji_pig">Donuz</string> - <string name="verification_emoji_elephant">Fil</string> - <string name="verification_emoji_rabbit">DovÅŸan</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Xoruz</string> - <string name="verification_emoji_penguin">Pinqvin</string> - <string name="verification_emoji_turtle">TısbaÄŸa</string> - <string name="verification_emoji_fish">Balıq</string> - <string name="verification_emoji_octopus">Ahtapot</string> - <string name="verification_emoji_butterfly">KÉ™pÉ™nÉ™k</string> - <string name="verification_emoji_flower">Çiçək</string> - <string name="verification_emoji_tree">AÄŸac</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">GöbÉ™lÉ™k</string> - <string name="verification_emoji_globe">Qlobus</string> - <string name="verification_emoji_moon">Ay</string> - <string name="verification_emoji_cloud">Bulud</string> - <string name="verification_emoji_fire">Atəş</string> - <string name="verification_emoji_banana">Banan</string> - <string name="verification_emoji_apple">Alma</string> - <string name="verification_emoji_strawberry">ÇiyÉ™lÉ™k</string> - <string name="verification_emoji_corn">Qarğıdalı</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Tort</string> - <string name="verification_emoji_heart">ÃœrÉ™k</string> - <string name="verification_emoji_smiley">TÉ™bÉ™ssüm</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Papaq</string> - <string name="verification_emoji_glasses">EynÉ™klÉ™r</string> - <string name="verification_emoji_wrench">Açar</string> - <string name="verification_emoji_santa">Santa</string> - <string name="verification_emoji_thumbsup">BaÅŸ barmaqlar yuxarı</string> - <string name="verification_emoji_umbrella">Çətir</string> - <string name="verification_emoji_hourglass">Qum saatı</string> - <string name="verification_emoji_clock">Saat</string> - <string name="verification_emoji_gift">HÉ™diyyÉ™</string> - <string name="verification_emoji_lightbulb">Lampa</string> - <string name="verification_emoji_book">Kitab</string> - <string name="verification_emoji_pencil">QÉ™lÉ™m</string> - <string name="verification_emoji_paperclip">Kağız sancağı</string> - <string name="verification_emoji_scissors">Qayçı</string> - <string name="verification_emoji_lock">Qıfıl</string> - <string name="verification_emoji_key">Açar</string> - <string name="verification_emoji_hammer">Çəkic</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Bayraq</string> - <string name="verification_emoji_train">Qatar</string> - <string name="verification_emoji_bicycle">Velosiped</string> - <string name="verification_emoji_airplane">TÉ™yyarÉ™</string> - <string name="verification_emoji_rocket">Raket</string> - <string name="verification_emoji_trophy">Kubok</string> - <string name="verification_emoji_ball">Top</string> - <string name="verification_emoji_guitar">Gitara</string> - <string name="verification_emoji_trumpet">Saz</string> - <string name="verification_emoji_bell">ZÉ™ng</string> - <string name="verification_emoji_anchor">Anker</string> - <string name="verification_emoji_headphone">Qulaqlıqlar</string> - <string name="verification_emoji_folder">Qovluq</string> - <string name="verification_emoji_pin">Sancaq</string> - <string name="initial_sync_start_importing_account">Ä°lkin sinxronizasiya: \nHesab idxal olunur…</string> <string name="initial_sync_start_importing_account_crypto">Ä°lkin sinxronizasiya: diff --git a/matrix-sdk-android/src/main/res/values-bg/strings.xml b/matrix-sdk-android/src/main/res/values-bg/strings.xml index 07d59852f34054e3893d02e2a610816614e3ee64..9654fd00b5a3ad1ab2cb5d3cf0d7a28ce56aab01 100644 --- a/matrix-sdk-android/src/main/res/values-bg/strings.xml +++ b/matrix-sdk-android/src/main/res/values-bg/strings.xml @@ -78,70 +78,6 @@ <string name="notice_event_redacted_by">Съобщение премахнато от %1$s</string> <string name="notice_event_redacted_with_reason">Премахнато Ñъобщение [причина: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Съобщение премахнато от %1$s [причина: %2$s]</string> - <string name="verification_emoji_dog">Куче</string> - <string name="verification_emoji_cat">Котка</string> - <string name="verification_emoji_lion">Лъв</string> - <string name="verification_emoji_horse">Кон</string> - <string name="verification_emoji_unicorn">Еднорог</string> - <string name="verification_emoji_pig">ПраÑе</string> - <string name="verification_emoji_elephant">Слон</string> - <string name="verification_emoji_rabbit">Заек</string> - <string name="verification_emoji_panda">Панда</string> - <string name="verification_emoji_rooster">Петел</string> - <string name="verification_emoji_penguin">Пингвин</string> - <string name="verification_emoji_turtle">КоÑтенурка</string> - <string name="verification_emoji_fish">Риба</string> - <string name="verification_emoji_octopus">Октопод</string> - <string name="verification_emoji_butterfly">Пеперуда</string> - <string name="verification_emoji_flower">Цвете</string> - <string name="verification_emoji_tree">Дърво</string> - <string name="verification_emoji_cactus">КактуÑ</string> - <string name="verification_emoji_mushroom">Гъба</string> - <string name="verification_emoji_globe">ГлобуÑ</string> - <string name="verification_emoji_moon">Луна</string> - <string name="verification_emoji_cloud">Облак</string> - <string name="verification_emoji_fire">Огън</string> - <string name="verification_emoji_banana">Банан</string> - <string name="verification_emoji_apple">Ябълка</string> - <string name="verification_emoji_strawberry">Ягода</string> - <string name="verification_emoji_corn">Царевица</string> - <string name="verification_emoji_pizza">Пица</string> - <string name="verification_emoji_cake">Торта</string> - <string name="verification_emoji_heart">Сърце</string> - <string name="verification_emoji_smiley">УÑмивка</string> - <string name="verification_emoji_robot">Робот</string> - <string name="verification_emoji_hat">Шапка</string> - <string name="verification_emoji_glasses">Очила</string> - <string name="verification_emoji_wrench">Гаечен ключ</string> - <string name="verification_emoji_santa">ДÑдо Коледа</string> - <string name="verification_emoji_thumbsup">Палец нагоре</string> - <string name="verification_emoji_umbrella">Чадър</string> - <string name="verification_emoji_hourglass">ПÑÑъчен чаÑовник</string> - <string name="verification_emoji_clock">ЧаÑовник</string> - <string name="verification_emoji_gift">Подарък</string> - <string name="verification_emoji_lightbulb">Лампа</string> - <string name="verification_emoji_book">Книга</string> - <string name="verification_emoji_pencil">Молив</string> - <string name="verification_emoji_paperclip">Кламер</string> - <string name="verification_emoji_scissors">Ðожици</string> - <string name="verification_emoji_lock">Катинар</string> - <string name="verification_emoji_key">Ключ</string> - <string name="verification_emoji_hammer">Чук</string> - <string name="verification_emoji_telephone">Телефон</string> - <string name="verification_emoji_flag">Знаме</string> - <string name="verification_emoji_train">Влак</string> - <string name="verification_emoji_bicycle">Колело</string> - <string name="verification_emoji_airplane">Самолет</string> - <string name="verification_emoji_rocket">Ракета</string> - <string name="verification_emoji_trophy">Трофей</string> - <string name="verification_emoji_ball">Топка</string> - <string name="verification_emoji_guitar">Китара</string> - <string name="verification_emoji_trumpet">Тромпет</string> - <string name="verification_emoji_bell">Звънец</string> - <string name="verification_emoji_anchor">Котва</string> - <string name="verification_emoji_headphone">Слушалки</string> - <string name="verification_emoji_folder">Папка</string> - <string name="verification_emoji_pin">Карфица</string> <string name="initial_sync_start_importing_account">Ðачална ÑинхронизациÑ: \nИмпортиране на профил…</string> @@ -204,4 +140,16 @@ <string name="key_verification_request_fallback_message">%s изпрати запитване за потвърждение на ключа ви, но клиентът ви не поддържа верифициране поÑредÑтвом чат. Ще Ñ‚Ñ€Ñбва да използвате ÑÑ‚Ð°Ñ€Ð¸Ñ Ð¼ÐµÑ‚Ð¾Ð´ за верифициране на ключове.</string> <string name="notice_room_created">%1$s Ñъздаде ÑтаÑта</string> + <string name="summary_you_sent_image">Изпратихте Ñнимка.</string> + <string name="summary_you_sent_sticker">Изпратихте Ñтикер.</string> + + <string name="notice_room_invite_no_invitee_by_you">Ваша покана</string> + <string name="notice_room_created_by_you">Създадохте ÑтаÑта</string> + <string name="notice_room_invite_by_you">Поканихте %1$s</string> + <string name="notice_room_join_by_you">ПриÑъединихте Ñе в ÑтаÑта</string> + <string name="notice_room_leave_by_you">ÐапуÑнахте ÑтаÑта</string> + <string name="notice_room_reject_by_you">Отхвърлихте поканата</string> + <string name="notice_room_kick_by_you">Изгонихте %1$s</string> + <string name="notice_room_unban_by_you">Отблокирахте %1$s</string> + <string name="notice_room_ban_by_you">Блокирахте %1$s</string> </resources> diff --git a/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml b/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml index c8e70a9b2048830f431b7445aef9d8077bff22b9..5d38f0b3eeb8959f504beb2ee77d0decf8934015 100644 --- a/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml +++ b/matrix-sdk-android/src/main/res/values-bn-rIN/strings.xml @@ -136,72 +136,6 @@ <string name="room_displayname_empty_room">খালি ককà§à¦·</string> - - <string name="verification_emoji_dog">কà§à¦•à§à¦°</string> - <string name="verification_emoji_cat">বেড়াল</string> - <string name="verification_emoji_lion">সিংহ</string> - <string name="verification_emoji_horse">ঘোড়া</string> - <string name="verification_emoji_unicorn">ইউনিকরà§à¦¨</string> - <string name="verification_emoji_pig">শূকর</string> - <string name="verification_emoji_elephant">হাতি</string> - <string name="verification_emoji_rabbit">খরগোশ</string> - <string name="verification_emoji_panda">পানà§à¦¡à¦¾</string> - <string name="verification_emoji_rooster">গৃহপালিত মোরগ</string> - <string name="verification_emoji_penguin">পেংগà§à¦‡à¦¨</string> - <string name="verification_emoji_turtle">কচà§à¦›à¦ª</string> - <string name="verification_emoji_fish">মাছ</string> - <string name="verification_emoji_octopus">অকà§à¦Ÿà§‹à¦ªà¦¾à¦¸</string> - <string name="verification_emoji_butterfly">পà§à¦°à¦œà¦¾à¦ªà¦¤à¦¿</string> - <string name="verification_emoji_flower">ফà§à¦²</string> - <string name="verification_emoji_tree">গাছ</string> - <string name="verification_emoji_cactus">ফণীমনসা</string> - <string name="verification_emoji_mushroom">মাশরà§à¦®</string> - <string name="verification_emoji_globe">পৃথিবী</string> - <string name="verification_emoji_moon">চনà§à¦¦à§à¦°</string> - <string name="verification_emoji_cloud">মেঘ</string> - <string name="verification_emoji_fire">আগà§à¦¨</string> - <string name="verification_emoji_banana">কলা</string> - <string name="verification_emoji_apple">আপেল</string> - <string name="verification_emoji_strawberry">সà§à¦Ÿà§à¦°à¦¬à§‡à¦°à¦¿</string> - <string name="verification_emoji_corn">à¦à§‚টà§à¦Ÿà¦¾</string> - <string name="verification_emoji_pizza">পিজা</string> - <string name="verification_emoji_cake">কেক</string> - <string name="verification_emoji_heart">হৃদয়</string> - <string name="verification_emoji_smiley">সà§à¦®à¦¾à¦‡à¦²à¦¿</string> - <string name="verification_emoji_robot">রোবট</string> - <string name="verification_emoji_hat">টà§à¦ªà¦¿</string> - <string name="verification_emoji_glasses">চশমা</string> - <string name="verification_emoji_wrench">রেঞà§à¦š</string> - <string name="verification_emoji_santa">সানà§à¦¤à¦¾</string> - <string name="verification_emoji_thumbsup">থামà§à¦¬à¦¸ আপ</string> - <string name="verification_emoji_umbrella">ছাতা</string> - <string name="verification_emoji_hourglass">বালিঘড়ি</string> - <string name="verification_emoji_clock">ঘড়ি</string> - <string name="verification_emoji_gift">উপহার</string> - <string name="verification_emoji_lightbulb">আলো বালব</string> - <string name="verification_emoji_book">বই</string> - <string name="verification_emoji_pencil">পেনà§à¦¸à¦¿à¦²</string> - <string name="verification_emoji_paperclip">পেপার কà§à¦²à¦¿à¦ª</string> - <string name="verification_emoji_scissors">কাà¦à¦šà¦¿</string> - <string name="verification_emoji_lock">লক</string> - <string name="verification_emoji_key">চাবি</string> - <string name="verification_emoji_hammer">হাতà§à¦¡à¦¼à¦¿</string> - <string name="verification_emoji_telephone">টেলিফোন</string> - <string name="verification_emoji_flag">পতাকা</string> - <string name="verification_emoji_train">রেলগাড়ি</string> - <string name="verification_emoji_bicycle">সাইকেল</string> - <string name="verification_emoji_airplane">বিমান</string> - <string name="verification_emoji_rocket">রকেট</string> - <string name="verification_emoji_trophy">টà§à¦°à¦«à¦¿</string> - <string name="verification_emoji_ball">বল</string> - <string name="verification_emoji_guitar">গিটার</string> - <string name="verification_emoji_trumpet">টà§à¦°à¦¾à¦®à§à¦ªà§‡à¦Ÿ</string> - <string name="verification_emoji_bell">ঘণà§à¦Ÿà¦¾</string> - <string name="verification_emoji_anchor">নোঙà§à¦—র</string> - <string name="verification_emoji_headphone">হেডফোন</string> - <string name="verification_emoji_folder">ফোলà§à¦¡à¦¾à¦°</string> - <string name="verification_emoji_pin">পিন</string> - <string name="initial_sync_start_importing_account">পà§à¦°à¦¾à¦¥à¦®à¦¿à¦• সিঙà§à¦•: \nঅà§à¦¯à¦¾à¦•à¦¾à¦‰à¦¨à§à¦Ÿ আমদানি করা হচà§à¦›à§‡â€¦</string> <string name="initial_sync_start_importing_account_crypto">পà§à¦°à¦¾à¦¥à¦®à¦¿à¦• সিঙà§à¦•: @@ -288,8 +222,4 @@ <string name="key_verification_request_fallback_message">%s আপনার কীটি যাচাই করার জনà§à¦¯ অনà§à¦°à§‹à¦§ করছে, তবে আপনার কà§à¦²à¦¾à¦¯à¦¼à§‡à¦¨à§à¦Ÿ ইন-চà§à¦¯à¦¾à¦Ÿ কী যাচাইকরণ সমরà§à¦¥à¦¨ করে না। কীগà§à¦²à¦¿ যাচাই করতে আপনাকে লিগà§à¦¯à¦¾à¦¸à¦¿ কী যাচাইকরণ বà§à¦¯à¦¬à¦¹à¦¾à¦° করতে হবে।</string> - <string name="call_notification_answer">গà§à¦°à¦¹à¦£</string> - <string name="call_notification_reject">পতন</string> - <string name="call_notification_hangup">বনà§à¦§ করà§à¦¨</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-cs/strings.xml b/matrix-sdk-android/src/main/res/values-cs/strings.xml index 44908c38f7c8b998ca70c1201a2037a6edbce471..9e208f812a796e4376ec1a810b26b0c4564c201a 100644 --- a/matrix-sdk-android/src/main/res/values-cs/strings.xml +++ b/matrix-sdk-android/src/main/res/values-cs/strings.xml @@ -79,68 +79,7 @@ <string name="notice_event_redacted_with_reason">Zpráva byla smazána [důvod: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Zpráva smazána uživatelem %1$s [důvod: %2$s]</string> <string name="notice_room_third_party_revoked_invite">Uživatel %1$s obnovil pozvánku do mÃstnosti pro uživatele %2$s</string> - <string name="verification_emoji_cat">KoÄka</string> - <string name="verification_emoji_lion">Lev</string> - <string name="verification_emoji_horse">Kůň</string> - <string name="verification_emoji_unicorn">Jednorožec</string> - <string name="verification_emoji_pig">Prase</string> - <string name="verification_emoji_elephant">Slon</string> - <string name="verification_emoji_rabbit">KrálÃk</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Kohout</string> - <string name="verification_emoji_penguin">TuÄňák</string> - <string name="verification_emoji_turtle">Želva</string> - <string name="verification_emoji_fish">Ryba</string> - <string name="verification_emoji_octopus">Chobotnice</string> - <string name="verification_emoji_butterfly">Motýl</string> - <string name="verification_emoji_flower">KvÄ›tina</string> - <string name="verification_emoji_tree">Strom</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Houba</string> - <string name="verification_emoji_globe">ZemÄ›koule</string> - <string name="verification_emoji_moon">MÄ›sÃc</string> - <string name="verification_emoji_cloud">Mrak</string> - <string name="verification_emoji_fire">Oheň</string> - <string name="verification_emoji_banana">Banán</string> - <string name="verification_emoji_apple">Jablko</string> - <string name="verification_emoji_strawberry">Jahoda</string> - <string name="verification_emoji_corn">KukuÅ™ice</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Dort</string> - <string name="verification_emoji_heart">Srdce</string> - <string name="verification_emoji_smiley">SmajlÃk</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Klobouk</string> - <string name="verification_emoji_glasses">Brýle</string> - <string name="verification_emoji_santa">Santa Klaus</string> - <string name="verification_emoji_thumbsup">Zvednutý palec</string> - <string name="verification_emoji_umbrella">DeÅ¡tnÃk</string> - <string name="verification_emoji_hourglass">PÅ™esÃpacà hodiny</string> - <string name="verification_emoji_clock">Hodiny</string> - <string name="verification_emoji_gift">Dárek</string> - <string name="verification_emoji_lightbulb">Žárovka</string> - <string name="verification_emoji_book">Kniha</string> - <string name="verification_emoji_pencil">Tužka</string> - <string name="verification_emoji_paperclip">Sponka</string> - <string name="verification_emoji_scissors">Nůžky</string> - <string name="verification_emoji_lock">Zámek</string> - <string name="verification_emoji_key">KlÃÄ</string> - <string name="verification_emoji_hammer">Kladivo</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Vlajka</string> - <string name="verification_emoji_train">Vlak</string> - <string name="verification_emoji_bicycle">JÃzdnà kolo</string> - <string name="verification_emoji_airplane">Letadlo</string> - <string name="verification_emoji_rocket">Raketa</string> - <string name="verification_emoji_trophy">Trofej</string> - <string name="verification_emoji_ball">MÃÄ</string> - <string name="verification_emoji_guitar">Kytara</string> - <string name="verification_emoji_trumpet">Trumpeta</string> - <string name="verification_emoji_bell">Zvon</string> - <string name="verification_emoji_anchor">Kotva</string> - <string name="verification_emoji_headphone">Sluchátka</string> - <string name="verification_emoji_folder">Desky</string> - <string name="initial_sync_start_importing_account">Úvodnà synchronizace: + <string name="initial_sync_start_importing_account">Úvodnà synchronizace: \nImport úÄtu…</string> <string name="initial_sync_start_importing_account_crypto">Úvodnà synchronizace: \nImport klÃÄů</string> @@ -156,8 +95,6 @@ \nImport dat úÄtu</string> <string name="event_status_sending_message">OdesÃlánà zprávy…</string> - <string name="verification_emoji_wrench">Maticový klÃÄ</string> - <string name="verification_emoji_pin">PÅ™ipÃnáÄek</string> <string name="initial_sync_start_importing_account_invited_rooms">Úvodnà synchronizace: \nImport pozvánek</string> diff --git a/matrix-sdk-android/src/main/res/values-de/strings.xml b/matrix-sdk-android/src/main/res/values-de/strings.xml index 0c857e78ee25fb96ab3387dab040c3f6dad577e9..ae80edb47fd2fee07b0433425c02f87d72ff2d77 100644 --- a/matrix-sdk-android/src/main/res/values-de/strings.xml +++ b/matrix-sdk-android/src/main/res/values-de/strings.xml @@ -89,73 +89,8 @@ <string name="notice_event_redacted_by">Nachricht entfernt von %1$s</string> <string name="notice_event_redacted_with_reason">Nachricht entfernt [Grund: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Nachricht entfernt von %1$s [Grund: %2$s]</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_dog">Hund</string> - <string name="verification_emoji_cat">Katze</string> - <string name="verification_emoji_lion">Löwe</string> - <string name="verification_emoji_horse">Pferd</string> - <string name="verification_emoji_unicorn">Einhorn</string> - <string name="verification_emoji_pig">Schwein</string> - <string name="verification_emoji_elephant">Elefant</string> - <string name="verification_emoji_rabbit">Kaninchen</string> <string name="notice_room_update">%s hat diesen Raum aufgewertet.</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Hahn</string> - <string name="verification_emoji_penguin">Pinguin</string> - <string name="verification_emoji_turtle">Schildkröte</string> - <string name="verification_emoji_fish">Fisch</string> - <string name="verification_emoji_octopus">Oktopus</string> - <string name="verification_emoji_butterfly">Schmetterling</string> - <string name="verification_emoji_flower">Blume</string> - <string name="verification_emoji_tree">Baum</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Pilz</string> - <string name="verification_emoji_globe">Globus</string> - <string name="verification_emoji_moon">Mond</string> - <string name="verification_emoji_cloud">Wolke</string> - <string name="verification_emoji_fire">Feuer</string> - <string name="verification_emoji_banana">Banane</string> - <string name="verification_emoji_apple">Apfel</string> - <string name="verification_emoji_strawberry">Erdbeere</string> - <string name="verification_emoji_corn">Mais</string> - <string name="verification_emoji_cake">Kuchen</string> - <string name="verification_emoji_heart">Herz</string> - <string name="verification_emoji_smiley">Smiley</string> - <string name="verification_emoji_robot">Roboter</string> - <string name="verification_emoji_hat">Hut</string> - <string name="verification_emoji_glasses">Brille</string> - <string name="verification_emoji_wrench">Schraubenschlüssel</string> - <string name="verification_emoji_santa">Weihnachtsmann</string> - <string name="verification_emoji_thumbsup">Daumen hoch</string> - <string name="verification_emoji_umbrella">Regenschirm</string> - <string name="verification_emoji_hourglass">Sanduhr</string> - <string name="verification_emoji_clock">Uhr</string> - <string name="verification_emoji_gift">Geschenk</string> - <string name="verification_emoji_lightbulb">Glühbirne</string> - <string name="verification_emoji_book">Buch</string> - <string name="verification_emoji_pencil">Bleistift</string> - <string name="verification_emoji_paperclip">Büroklammer</string> - <string name="verification_emoji_scissors">Schere</string> - <string name="verification_emoji_lock">Schloss</string> - <string name="verification_emoji_key">Schlüssel</string> - <string name="verification_emoji_hammer">Hammer</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Flagge</string> - <string name="verification_emoji_train">Zug</string> - <string name="verification_emoji_bicycle">Fahrrad</string> - <string name="verification_emoji_airplane">Flugzeug</string> - <string name="verification_emoji_rocket">Rakete</string> - <string name="verification_emoji_trophy">Pokal</string> - <string name="verification_emoji_ball">Ball</string> - <string name="verification_emoji_guitar">Gitarre</string> - <string name="verification_emoji_trumpet">Trompete</string> - <string name="verification_emoji_bell">Glocke</string> - <string name="verification_emoji_anchor">Anker</string> - <string name="verification_emoji_headphone">Kopfhörer</string> - <string name="verification_emoji_folder">Ordner</string> - <string name="verification_emoji_pin">Stecknadel</string> - <string name="event_status_sending_message">Sende eine Nachricht…</string> <string name="clear_timeline_send_queue">Sendewarteschlange leeren</string> @@ -297,10 +232,6 @@ <string name="notice_end_to_end_ok_by_you">Du hast Ende-zu-Ende-Verschlüsselung aktiviert.</string> <string name="notice_end_to_end_unknown_algorithm_by_you">Du hast Ende-zu-Ende-Verschlüsselung aktiviert (unbekannter Algorithmus %1$s).</string> - <string name="call_notification_answer">Akzeptiere</string> - <string name="call_notification_reject">Ablehnen</string> - <string name="call_notification_hangup">Anruf beenden</string> - <string name="notice_call_candidates">%s hat Daten gesendet, um einen Anruf zu starten.</string> <string name="notice_call_candidates_by_you">Du hast Daten geschickt, um eine Anruf zu starten.</string> </resources> diff --git a/matrix-sdk-android/src/main/res/values-de/strings_sas.xml b/matrix-sdk-android/src/main/res/values-de/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..108dedd1a593dfc37cbdd61c0c1e36443544773a --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-de/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hund</string> + <string name="verification_emoji_cat">Katze</string> + <string name="verification_emoji_lion">Löwe</string> + <string name="verification_emoji_horse">Pferd</string> + <string name="verification_emoji_unicorn">Einhorn</string> + <string name="verification_emoji_pig">Schwein</string> + <string name="verification_emoji_elephant">Elefant</string> + <string name="verification_emoji_rabbit">Hase</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Hahn</string> + <string name="verification_emoji_penguin">Pinguin</string> + <string name="verification_emoji_turtle">Schildkröte</string> + <string name="verification_emoji_fish">Fisch</string> + <string name="verification_emoji_octopus">Oktopus</string> + <string name="verification_emoji_butterfly">Schmetterling</string> + <string name="verification_emoji_flower">Blume</string> + <string name="verification_emoji_tree">Baum</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Pilz</string> + <string name="verification_emoji_globe">Globus</string> + <string name="verification_emoji_moon">Mond</string> + <string name="verification_emoji_cloud">Wolke</string> + <string name="verification_emoji_fire">Feuer</string> + <string name="verification_emoji_banana">Banane</string> + <string name="verification_emoji_apple">Apfel</string> + <string name="verification_emoji_strawberry">Erdbeere</string> + <string name="verification_emoji_corn">Korn</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Kuchen</string> + <string name="verification_emoji_heart">Herz</string> + <string name="verification_emoji_smiley">Smiley</string> + <string name="verification_emoji_robot">Roboter</string> + <string name="verification_emoji_hat">Hut</string> + <string name="verification_emoji_glasses">Brille</string> + <string name="verification_emoji_spanner">Schraubenschlüssel</string> + <string name="verification_emoji_santa">Nikolaus</string> + <string name="verification_emoji_thumbs_up">Daumen Hoch</string> + <string name="verification_emoji_umbrella">Regenschirm</string> + <string name="verification_emoji_hourglass">Sanduhr</string> + <string name="verification_emoji_clock">Wecker</string> + <string name="verification_emoji_gift">Geschenk</string> + <string name="verification_emoji_light_bulb">Glühbirne</string> + <string name="verification_emoji_book">Buch</string> + <string name="verification_emoji_pencil">Bleistift</string> + <string name="verification_emoji_paperclip">Büroklammer</string> + <string name="verification_emoji_scissors">Schere</string> + <string name="verification_emoji_lock">Schloss</string> + <string name="verification_emoji_key">Schlüssel</string> + <string name="verification_emoji_hammer">Hammer</string> + <string name="verification_emoji_telephone">Telefon</string> + <string name="verification_emoji_flag">Flagge</string> + <string name="verification_emoji_train">Zug</string> + <string name="verification_emoji_bicycle">Fahrrad</string> + <string name="verification_emoji_aeroplane">Flugzeug</string> + <string name="verification_emoji_rocket">Rakete</string> + <string name="verification_emoji_trophy">Trophäe</string> + <string name="verification_emoji_ball">Ball</string> + <string name="verification_emoji_guitar">Gitarre</string> + <string name="verification_emoji_trumpet">Trompete</string> + <string name="verification_emoji_bell">Glocke</string> + <string name="verification_emoji_anchor">Anker</string> + <string name="verification_emoji_headphones">Kopfhörer</string> + <string name="verification_emoji_folder">Ordner</string> + <string name="verification_emoji_pin">Stecknadel</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml b/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml deleted file mode 100644 index f457e30ed0236eb131814eb4bdb927b282cf9e49..0000000000000000000000000000000000000000 --- a/matrix-sdk-android/src/main/res/values-en-rGB/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version='1.0' encoding='UTF-8'?> -<resources> - <string name="verification_emoji_wrench">Spanner</string> - <string name="verification_emoji_airplane">Aeroplane</string> -</resources> diff --git a/matrix-sdk-android/src/main/res/values-eo/strings.xml b/matrix-sdk-android/src/main/res/values-eo/strings.xml index 4a1e2c4c658d15b5f99d31d2f82cb887e432310f..69b009ca7e3956e69decd6930773cab1d118c184 100644 --- a/matrix-sdk-android/src/main/res/values-eo/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eo/strings.xml @@ -72,72 +72,6 @@ <string name="room_displayname_empty_room">Malplena ĉambro</string> - - <string name="verification_emoji_dog">Hundo</string> - <string name="verification_emoji_cat">Kato</string> - <string name="verification_emoji_lion">Leono</string> - <string name="verification_emoji_horse">Ĉevalo</string> - <string name="verification_emoji_unicorn">Unukorno</string> - <string name="verification_emoji_pig">Porko</string> - <string name="verification_emoji_elephant">Elefanto</string> - <string name="verification_emoji_rabbit">Kuniklo</string> - <string name="verification_emoji_panda">Pando</string> - <string name="verification_emoji_rooster">Koko</string> - <string name="verification_emoji_penguin">Pingveno</string> - <string name="verification_emoji_turtle">Testudo</string> - <string name="verification_emoji_fish">FiÅo</string> - <string name="verification_emoji_octopus">Polpo</string> - <string name="verification_emoji_butterfly">Papilio</string> - <string name="verification_emoji_flower">Floro</string> - <string name="verification_emoji_tree">Arbo</string> - <string name="verification_emoji_cactus">Kakto</string> - <string name="verification_emoji_mushroom">Fungo</string> - <string name="verification_emoji_globe">Globo</string> - <string name="verification_emoji_moon">Luno</string> - <string name="verification_emoji_cloud">Nubo</string> - <string name="verification_emoji_fire">Fajro</string> - <string name="verification_emoji_banana">Banano</string> - <string name="verification_emoji_apple">Pomo</string> - <string name="verification_emoji_strawberry">Frago</string> - <string name="verification_emoji_corn">Maizo</string> - <string name="verification_emoji_pizza">Pico</string> - <string name="verification_emoji_cake">Kuko</string> - <string name="verification_emoji_heart">Koro</string> - <string name="verification_emoji_smiley">Mieneto</string> - <string name="verification_emoji_robot">Roboto</string> - <string name="verification_emoji_hat">Ĉapelo</string> - <string name="verification_emoji_glasses">Okulvitroj</string> - <string name="verification_emoji_wrench">Boltilo</string> - <string name="verification_emoji_santa">Kristnaska viro</string> - <string name="verification_emoji_thumbsup">Dikfingro supren</string> - <string name="verification_emoji_umbrella">Ombrelo</string> - <string name="verification_emoji_hourglass">SablohorloÄo</string> - <string name="verification_emoji_clock">HorloÄo</string> - <string name="verification_emoji_gift">Donaco</string> - <string name="verification_emoji_lightbulb">Lampo</string> - <string name="verification_emoji_book">Libro</string> - <string name="verification_emoji_pencil">Grifelo</string> - <string name="verification_emoji_paperclip">Paperkuntenilo</string> - <string name="verification_emoji_scissors">Tondilo</string> - <string name="verification_emoji_lock">Seruro</string> - <string name="verification_emoji_key">Åœlosilo</string> - <string name="verification_emoji_hammer">Martelo</string> - <string name="verification_emoji_telephone">Telefono</string> - <string name="verification_emoji_flag">Flago</string> - <string name="verification_emoji_train">Vagonaro</string> - <string name="verification_emoji_bicycle">Biciklo</string> - <string name="verification_emoji_airplane">Aviadilo</string> - <string name="verification_emoji_rocket">Raketo</string> - <string name="verification_emoji_trophy">Trofeo</string> - <string name="verification_emoji_ball">Pilko</string> - <string name="verification_emoji_guitar">Gitaro</string> - <string name="verification_emoji_trumpet">Trumpeto</string> - <string name="verification_emoji_bell">Sonorilo</string> - <string name="verification_emoji_anchor">Ankro</string> - <string name="verification_emoji_headphone">KapaÅdilo</string> - <string name="verification_emoji_folder">Dosierujo</string> - <string name="verification_emoji_pin">Pinglo</string> - <string name="initial_sync_start_importing_account">Komenca spegulado: \nEnportante konton…</string> <string name="initial_sync_start_importing_account_crypto">Komenca spegulado: diff --git a/matrix-sdk-android/src/main/res/values-eo/strings_sas.xml b/matrix-sdk-android/src/main/res/values-eo/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..16f762e362c9959743edd925ee5e82e6b5804d18 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-eo/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hundo</string> + <string name="verification_emoji_cat">Kato</string> + <string name="verification_emoji_lion">Leono</string> + <string name="verification_emoji_horse">Ĉevalo</string> + <string name="verification_emoji_unicorn">Unukorno</string> + <string name="verification_emoji_pig">Porko</string> + <string name="verification_emoji_elephant">Elefanto</string> + <string name="verification_emoji_rabbit">Kuniklo</string> + <string name="verification_emoji_panda">Pando</string> + <string name="verification_emoji_rooster">Virkoko</string> + <string name="verification_emoji_penguin">Pingveno</string> + <string name="verification_emoji_turtle">Testudo</string> + <string name="verification_emoji_fish">FiÅo</string> + <string name="verification_emoji_octopus">Polpo</string> + <string name="verification_emoji_butterfly">Papilio</string> + <string name="verification_emoji_flower">Floro</string> + <string name="verification_emoji_tree">Arbo</string> + <string name="verification_emoji_cactus">Kakto</string> + <string name="verification_emoji_mushroom">Fungo</string> + <string name="verification_emoji_globe">Globo</string> + <string name="verification_emoji_moon">Luno</string> + <string name="verification_emoji_cloud">Nubo</string> + <string name="verification_emoji_fire">Fajro</string> + <string name="verification_emoji_banana">Banano</string> + <string name="verification_emoji_apple">Pomo</string> + <string name="verification_emoji_strawberry">Frago</string> + <string name="verification_emoji_corn">Maizo</string> + <string name="verification_emoji_pizza">Pico</string> + <string name="verification_emoji_cake">Torto</string> + <string name="verification_emoji_heart">Koro</string> + <string name="verification_emoji_smiley">Rideto</string> + <string name="verification_emoji_robot">Roboto</string> + <string name="verification_emoji_hat">Ĉapelo</string> + <string name="verification_emoji_glasses">Okulvitroj</string> + <string name="verification_emoji_spanner">ÅœraÅbÅlosilo</string> + <string name="verification_emoji_santa">Kristnaska viro</string> + <string name="verification_emoji_thumbs_up">Dikfingro supren</string> + <string name="verification_emoji_umbrella">Ombrelo</string> + <string name="verification_emoji_hourglass">SablohorloÄo</string> + <string name="verification_emoji_clock">HorloÄo</string> + <string name="verification_emoji_gift">Donaco</string> + <string name="verification_emoji_light_bulb">Lampo</string> + <string name="verification_emoji_book">Libro</string> + <string name="verification_emoji_pencil">Krajono</string> + <string name="verification_emoji_paperclip">Paperkuntenilo</string> + <string name="verification_emoji_scissors">Tondilo</string> + <string name="verification_emoji_lock">Seruro</string> + <string name="verification_emoji_key">Åœlosilo</string> + <string name="verification_emoji_hammer">Martelo</string> + <string name="verification_emoji_telephone">Telefono</string> + <string name="verification_emoji_flag">Flago</string> + <string name="verification_emoji_train">Vagonaro</string> + <string name="verification_emoji_bicycle">Biciklo</string> + <string name="verification_emoji_aeroplane">Aviadilo</string> + <string name="verification_emoji_rocket">Raketo</string> + <string name="verification_emoji_trophy">Trofeo</string> + <string name="verification_emoji_ball">Pilko</string> + <string name="verification_emoji_guitar">Gitaro</string> + <string name="verification_emoji_trumpet">Trumpeto</string> + <string name="verification_emoji_bell">Sonorilo</string> + <string name="verification_emoji_anchor">Ankro</string> + <string name="verification_emoji_headphones">KapaÅdilo</string> + <string name="verification_emoji_folder">Dosierujo</string> + <string name="verification_emoji_pin">Pinglo</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml index 35b7bfc829d3caead13723506787fd3eae80e970..a8e8477005195e49021d3217de53866d1a54d8c4 100644 --- a/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es-rMX/strings.xml @@ -89,8 +89,4 @@ <string name="notice_event_redacted_by">Mensaje eliminado por %1$s</string> <string name="notice_event_redacted_with_reason">Mensaje eliminado [motivo: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Mensaje eliminado por %1$s [motivo: %2$s]</string> - <string name="verification_emoji_dog">Perro</string> - <string name="verification_emoji_cat">Gato</string> - <string name="verification_emoji_lion">León</string> - <string name="verification_emoji_horse">Caballo</string> </resources> diff --git a/matrix-sdk-android/src/main/res/values-es/strings.xml b/matrix-sdk-android/src/main/res/values-es/strings.xml index 3c019b3b80935e7953bda2202e554a6ae52be429..ae1f5633bf1e16b56dfbcdcc26288aaa5a86ba2a 100644 --- a/matrix-sdk-android/src/main/res/values-es/strings.xml +++ b/matrix-sdk-android/src/main/res/values-es/strings.xml @@ -90,65 +90,6 @@ <string name="notice_event_redacted_with_reason">Mensaje eliminado [motivo: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Mensaje eliminado por %1$s [motivo: %2$s]</string> <string name="notice_room_third_party_revoked_invite">%1$s ha revocado la invitación a unirse a la sala para %2$s</string> - <string name="verification_emoji_dog">Perro</string> - <string name="verification_emoji_cat">Gato</string> - <string name="verification_emoji_lion">León</string> - <string name="verification_emoji_horse">Caballo</string> - <string name="verification_emoji_unicorn">Unicornio</string> - <string name="verification_emoji_pig">Cerdo</string> - <string name="verification_emoji_elephant">Elefante</string> - <string name="verification_emoji_rabbit">Conejo</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Gallo</string> - <string name="verification_emoji_penguin">Pingüino</string> - <string name="verification_emoji_turtle">Tortuga</string> - <string name="verification_emoji_fish">Pez</string> - <string name="verification_emoji_octopus">Pulpo</string> - <string name="verification_emoji_butterfly">Mariposa</string> - <string name="verification_emoji_flower">Flor</string> - <string name="verification_emoji_tree">Ãrbol</string> - <string name="verification_emoji_cactus">Cactus</string> - <string name="verification_emoji_mushroom">Seta</string> - <string name="verification_emoji_moon">Luna</string> - <string name="verification_emoji_cloud">Nube</string> - <string name="verification_emoji_fire">Fuego</string> - <string name="verification_emoji_banana">Plátano</string> - <string name="verification_emoji_apple">Manzana</string> - <string name="verification_emoji_strawberry">Fresa</string> - <string name="verification_emoji_corn">MaÃz</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Pastel</string> - <string name="verification_emoji_heart">Corazón</string> - <string name="verification_emoji_hat">Sombrero</string> - <string name="verification_emoji_glasses">Gafas</string> - <string name="verification_emoji_wrench">Llave inglesa</string> - <string name="verification_emoji_thumbsup">Pulgares arriba</string> - <string name="verification_emoji_umbrella">Paraguas</string> - <string name="verification_emoji_hourglass">Reloj de arena</string> - <string name="verification_emoji_clock">Reloj</string> - <string name="verification_emoji_gift">Regalo</string> - <string name="verification_emoji_lightbulb">Bombilla</string> - <string name="verification_emoji_book">Libro</string> - <string name="verification_emoji_pencil">Lápiz</string> - <string name="verification_emoji_paperclip">Clip</string> - <string name="verification_emoji_scissors">Tijeras</string> - <string name="verification_emoji_lock">Candado</string> - <string name="verification_emoji_key">Llave</string> - <string name="verification_emoji_hammer">Martillo</string> - <string name="verification_emoji_telephone">Teléfono</string> - <string name="verification_emoji_flag">Bandera</string> - <string name="verification_emoji_train">Tren</string> - <string name="verification_emoji_bicycle">Bicicleta</string> - <string name="verification_emoji_airplane">Avión</string> - <string name="verification_emoji_rocket">Cohete</string> - <string name="verification_emoji_trophy">Trofeo</string> - <string name="verification_emoji_ball">Pelota</string> - <string name="verification_emoji_guitar">Guitarra</string> - <string name="verification_emoji_trumpet">Trompeta</string> - <string name="verification_emoji_bell">Campana</string> - <string name="verification_emoji_anchor">Ancla</string> - <string name="verification_emoji_headphone">Auriculares</string> - <string name="verification_emoji_folder">Carpeta</string> <string name="initial_sync_start_importing_account">Sincronización Inicial \nImportando cuenta…</string> <string name="initial_sync_start_importing_account_rooms">Sincronización Inicial: @@ -173,12 +114,6 @@ <string name="notice_room_update">%s ha actualizado la sala.</string> - <string name="verification_emoji_globe">Globo Terráqueo</string> - <string name="verification_emoji_smiley">Cara sonriente</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_santa">Papá Noel</string> - <string name="verification_emoji_pin">Pin</string> - <string name="initial_sync_start_importing_account_crypto">Sincronización Inicial: \nImportando criptografÃa</string> <string name="initial_sync_start_importing_account_joined_rooms">Sincronización Inicial: diff --git a/matrix-sdk-android/src/main/res/values-es/strings_sas.xml b/matrix-sdk-android/src/main/res/values-es/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..fd396c1778a787d1808e7ee99ca7870a0da03196 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-es/strings_sas.xml @@ -0,0 +1,53 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Perro</string> + <string name="verification_emoji_cat">Gato</string> + <string name="verification_emoji_lion">León</string> + <string name="verification_emoji_horse">Caballo</string> + <string name="verification_emoji_unicorn">Unicornio</string> + <string name="verification_emoji_pig">Cerdo</string> + <string name="verification_emoji_elephant">Elefante</string> + <string name="verification_emoji_rabbit">Conejo</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Gallo</string> + <string name="verification_emoji_penguin">Pingüino</string> + <string name="verification_emoji_turtle">Tortuga</string> + <string name="verification_emoji_fish">Pez</string> + <string name="verification_emoji_octopus">Pulpo</string> + <string name="verification_emoji_butterfly">Mariposa</string> + <string name="verification_emoji_flower">Flor</string> + <string name="verification_emoji_tree">Ãrbol</string> + <string name="verification_emoji_cactus">Cactus</string> + <string name="verification_emoji_mushroom">Seta</string> + <string name="verification_emoji_globe">Globo</string> + <string name="verification_emoji_moon">Luna</string> + <string name="verification_emoji_cloud">Nube</string> + <string name="verification_emoji_fire">Fuego</string> + <string name="verification_emoji_banana">Plátano</string> + <string name="verification_emoji_apple">Manzana</string> + <string name="verification_emoji_strawberry">Fresa</string> + <string name="verification_emoji_corn">MaÃz</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Tarta</string> + <string name="verification_emoji_heart">Corazón</string> + <string name="verification_emoji_smiley">Emoticono</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Sombrero</string> + <string name="verification_emoji_glasses">Gafas</string> + <string name="verification_emoji_spanner">Llave inglesa</string> + <string name="verification_emoji_clock">Reloj</string> + <string name="verification_emoji_gift">Regalo</string> + <string name="verification_emoji_book">Libro</string> + <string name="verification_emoji_pencil">Lápiz</string> + <string name="verification_emoji_key">Llave</string> + <string name="verification_emoji_hammer">Martillo</string> + <string name="verification_emoji_telephone">Telefono</string> + <string name="verification_emoji_train">Tren</string> + <string name="verification_emoji_bicycle">Bicicleta</string> + <string name="verification_emoji_ball">Bola</string> + <string name="verification_emoji_guitar">Guitarra</string> + <string name="verification_emoji_trumpet">Trompeta</string> + <string name="verification_emoji_bell">Campana</string> + <string name="verification_emoji_pin">Alfiler</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-et/strings.xml b/matrix-sdk-android/src/main/res/values-et/strings.xml index b7cd202063cdf0839ac21fead9012aa3cd4c0120..2fbe2634646aa911e99bbc537ca190ccc40fd0ae 100644 --- a/matrix-sdk-android/src/main/res/values-et/strings.xml +++ b/matrix-sdk-android/src/main/res/values-et/strings.xml @@ -77,72 +77,6 @@ <string name="room_displayname_empty_room">Tühi jututuba</string> - - <string name="verification_emoji_dog">Koer</string> - <string name="verification_emoji_cat">Kass</string> - <string name="verification_emoji_lion">Lõvi</string> - <string name="verification_emoji_horse">Hobune</string> - <string name="verification_emoji_unicorn">Ãœkssarvik</string> - <string name="verification_emoji_pig">Siga</string> - <string name="verification_emoji_elephant">Elevant</string> - <string name="verification_emoji_rabbit">Jänes</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Kukk</string> - <string name="verification_emoji_penguin">Pingviin</string> - <string name="verification_emoji_turtle">Kilpkonn</string> - <string name="verification_emoji_fish">Kala</string> - <string name="verification_emoji_octopus">Kaheksajalg</string> - <string name="verification_emoji_butterfly">Liblikas</string> - <string name="verification_emoji_flower">Lill</string> - <string name="verification_emoji_tree">Puu</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Seen</string> - <string name="verification_emoji_globe">Maakera</string> - <string name="verification_emoji_moon">Kuu</string> - <string name="verification_emoji_cloud">Pilv</string> - <string name="verification_emoji_fire">Tuli</string> - <string name="verification_emoji_banana">Banaan</string> - <string name="verification_emoji_apple">Õun</string> - <string name="verification_emoji_strawberry">Maasikas</string> - <string name="verification_emoji_corn">Mais</string> - <string name="verification_emoji_pizza">Pitsa</string> - <string name="verification_emoji_cake">Kook</string> - <string name="verification_emoji_heart">Süda</string> - <string name="verification_emoji_smiley">Smaili</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Kübar</string> - <string name="verification_emoji_glasses">Prillid</string> - <string name="verification_emoji_wrench">Mutrivõti</string> - <string name="verification_emoji_santa">Jõuluvana</string> - <string name="verification_emoji_thumbsup">Pöidlad püsti</string> - <string name="verification_emoji_umbrella">Vihmavari</string> - <string name="verification_emoji_hourglass">Liivakell</string> - <string name="verification_emoji_clock">Kell</string> - <string name="verification_emoji_gift">Kingitus</string> - <string name="verification_emoji_lightbulb">Lambipirn</string> - <string name="verification_emoji_book">Raamat</string> - <string name="verification_emoji_pencil">Pliiats</string> - <string name="verification_emoji_paperclip">Kirjaklamber</string> - <string name="verification_emoji_scissors">Käärid</string> - <string name="verification_emoji_lock">Lukk</string> - <string name="verification_emoji_key">Võti</string> - <string name="verification_emoji_hammer">Haamer</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Lipp</string> - <string name="verification_emoji_train">Rong</string> - <string name="verification_emoji_bicycle">Jalgratas</string> - <string name="verification_emoji_airplane">Lennuk</string> - <string name="verification_emoji_rocket">Rakett</string> - <string name="verification_emoji_trophy">Auhind</string> - <string name="verification_emoji_ball">Pall</string> - <string name="verification_emoji_guitar">Kitarr</string> - <string name="verification_emoji_trumpet">Trompet</string> - <string name="verification_emoji_bell">Kelluke</string> - <string name="verification_emoji_anchor">Ankur</string> - <string name="verification_emoji_headphone">Kõrvaklapid</string> - <string name="verification_emoji_folder">Kaust</string> - <string name="verification_emoji_pin">Nööpnõel</string> - <string name="initial_sync_start_importing_account">Alglaadimine: \nImpordin kontot…</string> <string name="initial_sync_start_importing_account_crypto">Alglaadimine: @@ -295,8 +229,4 @@ <string name="notice_end_to_end_ok_by_you">Sa lülitasid sisse läbiva krüptimise.</string> <string name="notice_end_to_end_unknown_algorithm_by_you">Sa lülitasid sisse läbiva krüptimise (kasutusel on tundmatu algoritm %1$s).</string> - <string name="call_notification_answer">Võta vastu</string> - <string name="call_notification_reject">Keeldu</string> - <string name="call_notification_hangup">Lõpeta kõne</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-et/strings_sas.xml b/matrix-sdk-android/src/main/res/values-et/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..60df725eaa80e3e5c3ec1bd08bbc7d1f9171e74a --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-et/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Koer</string> + <string name="verification_emoji_cat">Kass</string> + <string name="verification_emoji_lion">Lõvi</string> + <string name="verification_emoji_horse">Hobune</string> + <string name="verification_emoji_unicorn">Ãœkssarvik</string> + <string name="verification_emoji_pig">Siga</string> + <string name="verification_emoji_elephant">Elevant</string> + <string name="verification_emoji_rabbit">Jänes</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Kukk</string> + <string name="verification_emoji_penguin">Pingviin</string> + <string name="verification_emoji_turtle">Kilpkonn</string> + <string name="verification_emoji_fish">Kala</string> + <string name="verification_emoji_octopus">Kaheksajalg</string> + <string name="verification_emoji_butterfly">Liblikas</string> + <string name="verification_emoji_flower">Lill</string> + <string name="verification_emoji_tree">Puu</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Seen</string> + <string name="verification_emoji_globe">Maakera</string> + <string name="verification_emoji_moon">Kuu</string> + <string name="verification_emoji_cloud">Pilv</string> + <string name="verification_emoji_fire">Tuli</string> + <string name="verification_emoji_banana">Banaan</string> + <string name="verification_emoji_apple">Õun</string> + <string name="verification_emoji_strawberry">Maasikas</string> + <string name="verification_emoji_corn">Mais</string> + <string name="verification_emoji_pizza">Pitsa</string> + <string name="verification_emoji_cake">Kook</string> + <string name="verification_emoji_heart">Süda</string> + <string name="verification_emoji_smiley">Smaili</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Kübar</string> + <string name="verification_emoji_glasses">Prillid</string> + <string name="verification_emoji_spanner">Mutrivõti</string> + <string name="verification_emoji_santa">Jõuluvana</string> + <string name="verification_emoji_thumbs_up">Pöidlad püsti</string> + <string name="verification_emoji_umbrella">Vihmavari</string> + <string name="verification_emoji_hourglass">Liivakell</string> + <string name="verification_emoji_clock">Kell</string> + <string name="verification_emoji_gift">Kingitus</string> + <string name="verification_emoji_light_bulb">Lambipirn</string> + <string name="verification_emoji_book">Raamat</string> + <string name="verification_emoji_pencil">Pliiats</string> + <string name="verification_emoji_paperclip">Kirjaklamber</string> + <string name="verification_emoji_scissors">Käärid</string> + <string name="verification_emoji_lock">Lukk</string> + <string name="verification_emoji_key">Võti</string> + <string name="verification_emoji_hammer">Haamer</string> + <string name="verification_emoji_telephone">Telefon</string> + <string name="verification_emoji_flag">Lipp</string> + <string name="verification_emoji_train">Rong</string> + <string name="verification_emoji_bicycle">Jalgratas</string> + <string name="verification_emoji_aeroplane">Lennuk</string> + <string name="verification_emoji_rocket">Rakett</string> + <string name="verification_emoji_trophy">Auhind</string> + <string name="verification_emoji_ball">Pall</string> + <string name="verification_emoji_guitar">Kitarr</string> + <string name="verification_emoji_trumpet">Trompet</string> + <string name="verification_emoji_bell">Kelluke</string> + <string name="verification_emoji_anchor">Ankur</string> + <string name="verification_emoji_headphones">Kõrvaklapid</string> + <string name="verification_emoji_folder">Kaust</string> + <string name="verification_emoji_pin">Nööpnõel</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-eu/strings.xml b/matrix-sdk-android/src/main/res/values-eu/strings.xml index 1a5c81fe5e08818b96f2b7e73a9692c153b5cb9f..bc61035c245c02e6fa65a6d1dae15941f56a63eb 100644 --- a/matrix-sdk-android/src/main/res/values-eu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-eu/strings.xml @@ -78,70 +78,6 @@ <string name="notice_event_redacted_by">%1$s erabiltzaileak mezua kendu du</string> <string name="notice_event_redacted_with_reason">Mezua kendu da [arrazoia: %1$s]</string> <string name="notice_event_redacted_by_with_reason">%1$s erabiltzaileak mezua kendu du [arrazoia: %2$s]</string> - <string name="verification_emoji_dog">Txakurra</string> - <string name="verification_emoji_cat">Katua</string> - <string name="verification_emoji_lion">Lehoia</string> - <string name="verification_emoji_horse">Zaldia</string> - <string name="verification_emoji_unicorn">Unikornioa</string> - <string name="verification_emoji_pig">Zerria</string> - <string name="verification_emoji_elephant">Elefantea</string> - <string name="verification_emoji_rabbit">Untxia</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Oilarra</string> - <string name="verification_emoji_penguin">Pinguinoa</string> - <string name="verification_emoji_turtle">Dortoka</string> - <string name="verification_emoji_fish">Arraina</string> - <string name="verification_emoji_octopus">Olagarroa</string> - <string name="verification_emoji_butterfly">Tximeleta</string> - <string name="verification_emoji_flower">Lorea</string> - <string name="verification_emoji_tree">Zuhaitza</string> - <string name="verification_emoji_cactus">Kaktusa</string> - <string name="verification_emoji_mushroom">Perretxikoa</string> - <string name="verification_emoji_globe">Lurra</string> - <string name="verification_emoji_moon">Ilargia</string> - <string name="verification_emoji_cloud">Hodeia</string> - <string name="verification_emoji_fire">Sua</string> - <string name="verification_emoji_banana">Banana</string> - <string name="verification_emoji_apple">Sagarra</string> - <string name="verification_emoji_strawberry">Marrubia</string> - <string name="verification_emoji_corn">Artoa</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Pastela</string> - <string name="verification_emoji_heart">Bihotza</string> - <string name="verification_emoji_smiley">Irrifartxoa</string> - <string name="verification_emoji_robot">Robota</string> - <string name="verification_emoji_hat">Txanoa</string> - <string name="verification_emoji_glasses">Betaurrekoak</string> - <string name="verification_emoji_wrench">Giltza</string> - <string name="verification_emoji_santa">Santa</string> - <string name="verification_emoji_thumbsup">Ederto</string> - <string name="verification_emoji_umbrella">Aterkia</string> - <string name="verification_emoji_hourglass">Harea-erlojua</string> - <string name="verification_emoji_clock">Erlojua</string> - <string name="verification_emoji_gift">Oparia</string> - <string name="verification_emoji_lightbulb">Bonbilla</string> - <string name="verification_emoji_book">Liburua</string> - <string name="verification_emoji_pencil">Arkatza</string> - <string name="verification_emoji_paperclip">Klipa</string> - <string name="verification_emoji_scissors">Artaziak</string> - <string name="verification_emoji_lock">Giltzarrapoa</string> - <string name="verification_emoji_key">Giltza</string> - <string name="verification_emoji_hammer">Mailua</string> - <string name="verification_emoji_telephone">Telefonoa</string> - <string name="verification_emoji_flag">Bandera</string> - <string name="verification_emoji_train">Trena</string> - <string name="verification_emoji_bicycle">Bizikleta</string> - <string name="verification_emoji_airplane">Hegazkina</string> - <string name="verification_emoji_rocket">Kohetea</string> - <string name="verification_emoji_trophy">Saria</string> - <string name="verification_emoji_ball">Baloia</string> - <string name="verification_emoji_guitar">Gitarra</string> - <string name="verification_emoji_trumpet">Tronpeta</string> - <string name="verification_emoji_bell">Kanpaia</string> - <string name="verification_emoji_anchor">Aingura</string> - <string name="verification_emoji_headphone">Aurikularrak</string> - <string name="verification_emoji_folder">Karpeta</string> - <string name="verification_emoji_pin">Txintxeta</string> <string name="initial_sync_start_importing_account">Hasierako sinkronizazioa: \nKontua inportatzen…</string> diff --git a/matrix-sdk-android/src/main/res/values-fa/strings.xml b/matrix-sdk-android/src/main/res/values-fa/strings.xml index 18d8578e5426add31c03a90cf4b4b4177bc8c744..b88a98459d771e9cea462a14aa0878253e417166 100644 --- a/matrix-sdk-android/src/main/res/values-fa/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fa/strings.xml @@ -77,72 +77,6 @@ <string name="room_displayname_empty_room">اتاق خالی</string> - - <string name="verification_emoji_dog">سگ</string> - <string name="verification_emoji_cat">گربه</string> - <string name="verification_emoji_lion">شیر</string> - <string name="verification_emoji_horse">اسب</string> - <string name="verification_emoji_unicorn">تک‌شاخ</string> - <string name="verification_emoji_pig">خوک</string> - <string name="verification_emoji_elephant">Ùیل</string> - <string name="verification_emoji_rabbit">خرگوش</string> - <string name="verification_emoji_panda">پاندا</string> - <string name="verification_emoji_rooster">خروس</string> - <string name="verification_emoji_penguin">پنگوئن</string> - <string name="verification_emoji_turtle">لاک‌پشت</string> - <string name="verification_emoji_fish">ماهی</string> - <string name="verification_emoji_octopus">هشت‌پا</string> - <string name="verification_emoji_butterfly">پروانه</string> - <string name="verification_emoji_flower">Ú¯Ù„</string> - <string name="verification_emoji_tree">درخت</string> - <string name="verification_emoji_cactus">کاکتوس</string> - <string name="verification_emoji_mushroom">قارچ</string> - <string name="verification_emoji_globe">جهان</string> - <string name="verification_emoji_moon">ماه</string> - <string name="verification_emoji_cloud">ابر</string> - <string name="verification_emoji_fire">آتش</string> - <string name="verification_emoji_banana">موز</string> - <string name="verification_emoji_apple">سیب</string> - <string name="verification_emoji_strawberry">توت‌Ùرنگی</string> - <string name="verification_emoji_corn">بلال</string> - <string name="verification_emoji_pizza">پیتزا</string> - <string name="verification_emoji_cake">کیک</string> - <string name="verification_emoji_heart">قلب</string> - <string name="verification_emoji_smiley">لبخند</string> - <string name="verification_emoji_robot">آدم‌آهنی</string> - <string name="verification_emoji_hat">کلاه</string> - <string name="verification_emoji_glasses">عینک</string> - <string name="verification_emoji_wrench">آچار</string> - <string name="verification_emoji_santa">بابانوئل</string> - <string name="verification_emoji_thumbsup">شست</string> - <string name="verification_emoji_umbrella">چتر</string> - <string name="verification_emoji_hourglass">ساعت شنی</string> - <string name="verification_emoji_clock">ساعت</string> - <string name="verification_emoji_gift">هدیه</string> - <string name="verification_emoji_lightbulb">لامپ</string> - <string name="verification_emoji_book">کتاب</string> - <string name="verification_emoji_pencil">مداد</string> - <string name="verification_emoji_paperclip">گیره کاغذ</string> - <string name="verification_emoji_scissors">قیچی</string> - <string name="verification_emoji_lock">Ù‚ÙÙ„</string> - <string name="verification_emoji_key">کلید</string> - <string name="verification_emoji_hammer">چکّش</string> - <string name="verification_emoji_telephone">تلÙÙ†</string> - <string name="verification_emoji_flag">پرچم</string> - <string name="verification_emoji_train">قطار</string> - <string name="verification_emoji_bicycle">دوچرخه</string> - <string name="verification_emoji_airplane">هواپیما</string> - <string name="verification_emoji_rocket">موشک</string> - <string name="verification_emoji_trophy">جام</string> - <string name="verification_emoji_ball">توپ</string> - <string name="verification_emoji_guitar">گیتار</string> - <string name="verification_emoji_trumpet">ترومپت</string> - <string name="verification_emoji_bell">زنگ</string> - <string name="verification_emoji_anchor">لنگر</string> - <string name="verification_emoji_headphone">هدÙون</string> - <string name="verification_emoji_folder">پوشه</string> - <string name="verification_emoji_pin">پونز</string> - <string name="initial_sync_start_importing_account">همگام‌سازی نخستین: \nدر Øال درون‌ریزی Øساب…</string> <string name="initial_sync_start_importing_account_crypto">همگام‌سازی نخستین: diff --git a/matrix-sdk-android/src/main/res/values-fi/strings.xml b/matrix-sdk-android/src/main/res/values-fi/strings.xml index 078769942c584916e10bd21d0488e6c92289aa16..fccd22d3b63a928435e3fd3fcaf033327889bf6e 100644 --- a/matrix-sdk-android/src/main/res/values-fi/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fi/strings.xml @@ -79,70 +79,6 @@ <string name="notice_event_redacted_by">%1$s poisti viestin</string> <string name="notice_event_redacted_with_reason">Viesti poistettu [syy: %1$s]</string> <string name="notice_event_redacted_by_with_reason">%1$s poisti viestin [syy: %2$s]</string> - <string name="verification_emoji_dog">Koira</string> - <string name="verification_emoji_cat">Kissa</string> - <string name="verification_emoji_lion">Leijona</string> - <string name="verification_emoji_horse">Hevonen</string> - <string name="verification_emoji_unicorn">Yksisarvinen</string> - <string name="verification_emoji_pig">Sika</string> - <string name="verification_emoji_elephant">Norsu</string> - <string name="verification_emoji_rabbit">Kani</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Kukko</string> - <string name="verification_emoji_penguin">Pingviini</string> - <string name="verification_emoji_turtle">Kilpikonna</string> - <string name="verification_emoji_fish">Kala</string> - <string name="verification_emoji_octopus">Tursas</string> - <string name="verification_emoji_butterfly">Perhonen</string> - <string name="verification_emoji_flower">Kukka</string> - <string name="verification_emoji_tree">Puu</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Sieni</string> - <string name="verification_emoji_globe">Maapallo</string> - <string name="verification_emoji_moon">Kuu</string> - <string name="verification_emoji_cloud">Pilvi</string> - <string name="verification_emoji_fire">Tuli</string> - <string name="verification_emoji_banana">Banaani</string> - <string name="verification_emoji_apple">Omena</string> - <string name="verification_emoji_strawberry">Mansikka</string> - <string name="verification_emoji_corn">Maissi</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Kakku</string> - <string name="verification_emoji_heart">Sydän</string> - <string name="verification_emoji_smiley">Hymiö</string> - <string name="verification_emoji_robot">Robotti</string> - <string name="verification_emoji_hat">Hattu</string> - <string name="verification_emoji_glasses">Silmälasit</string> - <string name="verification_emoji_wrench">Jakoavain</string> - <string name="verification_emoji_santa">Joulupukki</string> - <string name="verification_emoji_thumbsup">Peukut ylös</string> - <string name="verification_emoji_umbrella">Sateenvarjo</string> - <string name="verification_emoji_hourglass">Tiimalasi</string> - <string name="verification_emoji_clock">Kello</string> - <string name="verification_emoji_gift">Lahja</string> - <string name="verification_emoji_lightbulb">Hehkulamppu</string> - <string name="verification_emoji_book">Kirja</string> - <string name="verification_emoji_pencil">Lyijykynä</string> - <string name="verification_emoji_paperclip">Klemmari</string> - <string name="verification_emoji_scissors">Sakset</string> - <string name="verification_emoji_lock">Lukko</string> - <string name="verification_emoji_key">Avain</string> - <string name="verification_emoji_hammer">Vasara</string> - <string name="verification_emoji_telephone">Puhelin</string> - <string name="verification_emoji_flag">Lippu</string> - <string name="verification_emoji_train">Juna</string> - <string name="verification_emoji_bicycle">Polkupyörä</string> - <string name="verification_emoji_airplane">Lentokone</string> - <string name="verification_emoji_rocket">Raketti</string> - <string name="verification_emoji_trophy">Palkinto</string> - <string name="verification_emoji_ball">Pallo</string> - <string name="verification_emoji_guitar">Kitara</string> - <string name="verification_emoji_trumpet">Trumpetti</string> - <string name="verification_emoji_bell">Soittokello</string> - <string name="verification_emoji_anchor">Ankkuri</string> - <string name="verification_emoji_headphone">Kuulokkeet</string> - <string name="verification_emoji_folder">Kansio</string> - <string name="verification_emoji_pin">Nuppineula</string> <string name="initial_sync_start_importing_account">Alkusynkronointi: \nTuodaan tiliä…</string> diff --git a/matrix-sdk-android/src/main/res/values-fi/strings_sas.xml b/matrix-sdk-android/src/main/res/values-fi/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..b690fee4ed4fe74d7f208927a370bc2dccc8bfe9 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-fi/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Koira</string> + <string name="verification_emoji_cat">Kissa</string> + <string name="verification_emoji_lion">Leijona</string> + <string name="verification_emoji_horse">Hevonen</string> + <string name="verification_emoji_unicorn">Yksisarvinen</string> + <string name="verification_emoji_pig">Sika</string> + <string name="verification_emoji_elephant">Norsu</string> + <string name="verification_emoji_rabbit">Kani</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Kukko</string> + <string name="verification_emoji_penguin">Pingviini</string> + <string name="verification_emoji_turtle">Kilpikonna</string> + <string name="verification_emoji_fish">Kala</string> + <string name="verification_emoji_octopus">Tursas</string> + <string name="verification_emoji_butterfly">Perhonen</string> + <string name="verification_emoji_flower">Kukka</string> + <string name="verification_emoji_tree">Puu</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Sieni</string> + <string name="verification_emoji_globe">Maapallo</string> + <string name="verification_emoji_moon">Kuu</string> + <string name="verification_emoji_cloud">Pilvi</string> + <string name="verification_emoji_fire">Tuli</string> + <string name="verification_emoji_banana">Banaani</string> + <string name="verification_emoji_apple">Omena</string> + <string name="verification_emoji_strawberry">Mansikka</string> + <string name="verification_emoji_corn">Maissi</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Kakku</string> + <string name="verification_emoji_heart">Sydän</string> + <string name="verification_emoji_smiley">Hymynaama</string> + <string name="verification_emoji_robot">Robotti</string> + <string name="verification_emoji_hat">Hattu</string> + <string name="verification_emoji_glasses">Silmälasit</string> + <string name="verification_emoji_spanner">Mutteriavain</string> + <string name="verification_emoji_santa">Joulupukki</string> + <string name="verification_emoji_thumbs_up">Peukalo ylös</string> + <string name="verification_emoji_umbrella">Sateenvarjo</string> + <string name="verification_emoji_hourglass">Tiimalasi</string> + <string name="verification_emoji_clock">Pöytäkello</string> + <string name="verification_emoji_gift">Lahja</string> + <string name="verification_emoji_light_bulb">Hehkulamppu</string> + <string name="verification_emoji_book">Kirja</string> + <string name="verification_emoji_pencil">Lyijykynä</string> + <string name="verification_emoji_paperclip">Paperiliitin</string> + <string name="verification_emoji_scissors">Sakset</string> + <string name="verification_emoji_lock">Lukko</string> + <string name="verification_emoji_key">Avain</string> + <string name="verification_emoji_hammer">Vasara</string> + <string name="verification_emoji_telephone">Puhelin</string> + <string name="verification_emoji_flag">Lippu</string> + <string name="verification_emoji_train">Juna</string> + <string name="verification_emoji_bicycle">Polkupyörä</string> + <string name="verification_emoji_aeroplane">Lentokone</string> + <string name="verification_emoji_rocket">Raketti</string> + <string name="verification_emoji_trophy">Palkinto</string> + <string name="verification_emoji_ball">Pallo</string> + <string name="verification_emoji_guitar">Kitara</string> + <string name="verification_emoji_trumpet">Trumpetti</string> + <string name="verification_emoji_bell">Soittokello</string> + <string name="verification_emoji_anchor">Ankkuri</string> + <string name="verification_emoji_headphones">Kuulokkeet</string> + <string name="verification_emoji_folder">Kansio</string> + <string name="verification_emoji_pin">Nuppineula</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-fr/strings.xml b/matrix-sdk-android/src/main/res/values-fr/strings.xml index aad3bd1afb6aee9285227eb4ff49acd6dfc8fcb4..71b956a7e7ac9230613b7a76b5a8565efce1e568 100644 --- a/matrix-sdk-android/src/main/res/values-fr/strings.xml +++ b/matrix-sdk-android/src/main/res/values-fr/strings.xml @@ -78,70 +78,6 @@ <string name="notice_event_redacted_by">Message supprimé par %1$s</string> <string name="notice_event_redacted_with_reason">Message supprimé [motif : %1$s]</string> <string name="notice_event_redacted_by_with_reason">Message supprimé par %1$s [motif : %2$s]</string> - <string name="verification_emoji_dog">Chien</string> - <string name="verification_emoji_cat">Chat</string> - <string name="verification_emoji_lion">Lion</string> - <string name="verification_emoji_horse">Cheval</string> - <string name="verification_emoji_unicorn">Licorne</string> - <string name="verification_emoji_pig">Cochon</string> - <string name="verification_emoji_elephant">Éléphant</string> - <string name="verification_emoji_rabbit">Lapin</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Coq</string> - <string name="verification_emoji_penguin">Manchot</string> - <string name="verification_emoji_turtle">Tortue</string> - <string name="verification_emoji_fish">Poisson</string> - <string name="verification_emoji_octopus">Pieuvre</string> - <string name="verification_emoji_butterfly">Papillon</string> - <string name="verification_emoji_flower">Fleur</string> - <string name="verification_emoji_tree">Arbre</string> - <string name="verification_emoji_cactus">Cactus</string> - <string name="verification_emoji_mushroom">Champignon</string> - <string name="verification_emoji_globe">Terre</string> - <string name="verification_emoji_moon">Lune</string> - <string name="verification_emoji_cloud">Nuage</string> - <string name="verification_emoji_fire">Feu</string> - <string name="verification_emoji_banana">Banane</string> - <string name="verification_emoji_apple">Pomme</string> - <string name="verification_emoji_strawberry">Fraise</string> - <string name="verification_emoji_corn">Maïs</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Gâteau</string> - <string name="verification_emoji_heart">CÅ“ur</string> - <string name="verification_emoji_smiley">Smiley</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Chapeau</string> - <string name="verification_emoji_glasses">Lunettes</string> - <string name="verification_emoji_wrench">Clé plate</string> - <string name="verification_emoji_santa">Père Noël</string> - <string name="verification_emoji_thumbsup">Pouce levé</string> - <string name="verification_emoji_umbrella">Parapluie</string> - <string name="verification_emoji_hourglass">Sablier</string> - <string name="verification_emoji_clock">Horloge</string> - <string name="verification_emoji_gift">Cadeau</string> - <string name="verification_emoji_lightbulb">Ampoule</string> - <string name="verification_emoji_book">Livre</string> - <string name="verification_emoji_pencil">Crayon</string> - <string name="verification_emoji_paperclip">Trombone</string> - <string name="verification_emoji_scissors">Ciseaux</string> - <string name="verification_emoji_lock">Cadenas</string> - <string name="verification_emoji_key">Clé</string> - <string name="verification_emoji_hammer">Marteau</string> - <string name="verification_emoji_telephone">Téléphone</string> - <string name="verification_emoji_flag">Drapeau</string> - <string name="verification_emoji_train">Train</string> - <string name="verification_emoji_bicycle">Vélo</string> - <string name="verification_emoji_airplane">Avion</string> - <string name="verification_emoji_rocket">Fusée</string> - <string name="verification_emoji_trophy">Trophée</string> - <string name="verification_emoji_ball">Balle</string> - <string name="verification_emoji_guitar">Guitare</string> - <string name="verification_emoji_trumpet">Trompette</string> - <string name="verification_emoji_bell">Cloche</string> - <string name="verification_emoji_anchor">Ancre</string> - <string name="verification_emoji_headphone">Écouteurs</string> - <string name="verification_emoji_folder">Dossier</string> - <string name="verification_emoji_pin">Épingle</string> <string name="initial_sync_start_importing_account">Synchronisation initiale : \nImportation du compte…</string> diff --git a/matrix-sdk-android/src/main/res/values-fr/strings_sas.xml b/matrix-sdk-android/src/main/res/values-fr/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..af9d797542edaf6ad53ee88a923c036f7bb1a35b --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-fr/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Chien</string> + <string name="verification_emoji_cat">Chat</string> + <string name="verification_emoji_lion">Lion</string> + <string name="verification_emoji_horse">Cheval</string> + <string name="verification_emoji_unicorn">Licorne</string> + <string name="verification_emoji_pig">Cochon</string> + <string name="verification_emoji_elephant">Éléphant</string> + <string name="verification_emoji_rabbit">Lapin</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Coq</string> + <string name="verification_emoji_penguin">Manchot</string> + <string name="verification_emoji_turtle">Tortue</string> + <string name="verification_emoji_fish">Poisson</string> + <string name="verification_emoji_octopus">Poulpe</string> + <string name="verification_emoji_butterfly">Papillon</string> + <string name="verification_emoji_flower">Fleur</string> + <string name="verification_emoji_tree">Arbre</string> + <string name="verification_emoji_cactus">Cactus</string> + <string name="verification_emoji_mushroom">Champignon</string> + <string name="verification_emoji_globe">Globe</string> + <string name="verification_emoji_moon">Lune</string> + <string name="verification_emoji_cloud">Nuage</string> + <string name="verification_emoji_fire">Feu</string> + <string name="verification_emoji_banana">Banane</string> + <string name="verification_emoji_apple">Pomme</string> + <string name="verification_emoji_strawberry">Fraise</string> + <string name="verification_emoji_corn">Maïs</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Gâteau</string> + <string name="verification_emoji_heart">CÅ“ur</string> + <string name="verification_emoji_smiley">Sourire</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Châpeau</string> + <string name="verification_emoji_glasses">Lunettes</string> + <string name="verification_emoji_spanner">Clé à molette</string> + <string name="verification_emoji_santa">Père Noël</string> + <string name="verification_emoji_thumbs_up">Pouce en l\'air</string> + <string name="verification_emoji_umbrella">Parapluie</string> + <string name="verification_emoji_hourglass">Sablier</string> + <string name="verification_emoji_clock">Réveil</string> + <string name="verification_emoji_gift">Cadeau</string> + <string name="verification_emoji_light_bulb">Ampoule</string> + <string name="verification_emoji_book">Livre</string> + <string name="verification_emoji_pencil">Crayon</string> + <string name="verification_emoji_paperclip">Trombone</string> + <string name="verification_emoji_scissors">Ciseaux</string> + <string name="verification_emoji_lock">Cadenas</string> + <string name="verification_emoji_key">Clé</string> + <string name="verification_emoji_hammer">Marteau</string> + <string name="verification_emoji_telephone">Téléphone</string> + <string name="verification_emoji_flag">Drapeau</string> + <string name="verification_emoji_train">Train</string> + <string name="verification_emoji_bicycle">Vélo</string> + <string name="verification_emoji_aeroplane">Avion</string> + <string name="verification_emoji_rocket">Fusée</string> + <string name="verification_emoji_trophy">Trophée</string> + <string name="verification_emoji_ball">Ballon</string> + <string name="verification_emoji_guitar">Guitare</string> + <string name="verification_emoji_trumpet">Trompette</string> + <string name="verification_emoji_bell">Cloche</string> + <string name="verification_emoji_anchor">Ancre</string> + <string name="verification_emoji_headphones">Casque audio</string> + <string name="verification_emoji_folder">Dossier</string> + <string name="verification_emoji_pin">Punaise</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-hu/strings.xml b/matrix-sdk-android/src/main/res/values-hu/strings.xml index 35f35eaecd14490e053a40959a189df8221addab..896a97b0234eec2e2e3bac55ba4a7ec868567ceb 100644 --- a/matrix-sdk-android/src/main/res/values-hu/strings.xml +++ b/matrix-sdk-android/src/main/res/values-hu/strings.xml @@ -77,70 +77,6 @@ <string name="notice_event_redacted_by">Ãœzenetet eltávolÃtotta: %1$s</string> <string name="notice_event_redacted_with_reason">Ãœzenet eltávolÃtva [ok: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Ãœzenetet eltávolÃtotta: %1$s [ok: %2$s]</string> - <string name="verification_emoji_dog">Kutya</string> - <string name="verification_emoji_cat">Macska</string> - <string name="verification_emoji_lion">Oroszlán</string> - <string name="verification_emoji_horse">Ló</string> - <string name="verification_emoji_unicorn">Egyszarvú</string> - <string name="verification_emoji_pig">Malac</string> - <string name="verification_emoji_elephant">Elefánt</string> - <string name="verification_emoji_rabbit">Nyúl</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Kakas</string> - <string name="verification_emoji_penguin">Pingvin</string> - <string name="verification_emoji_turtle">TeknÅ‘s</string> - <string name="verification_emoji_fish">Hal</string> - <string name="verification_emoji_octopus">Polip</string> - <string name="verification_emoji_butterfly">Pillangó</string> - <string name="verification_emoji_flower">Virág</string> - <string name="verification_emoji_tree">Fa</string> - <string name="verification_emoji_cactus">Kaktusz</string> - <string name="verification_emoji_mushroom">Gomba</string> - <string name="verification_emoji_globe">Föld</string> - <string name="verification_emoji_moon">Hold</string> - <string name="verification_emoji_cloud">FelhÅ‘</string> - <string name="verification_emoji_fire">Tűz</string> - <string name="verification_emoji_banana">Banán</string> - <string name="verification_emoji_apple">Alma</string> - <string name="verification_emoji_strawberry">Eper</string> - <string name="verification_emoji_corn">Kukorica</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Süti</string> - <string name="verification_emoji_heart">SzÃv</string> - <string name="verification_emoji_smiley">Smiley</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Kalap</string> - <string name="verification_emoji_glasses">Szemüveg</string> - <string name="verification_emoji_wrench">Csavarkulcs</string> - <string name="verification_emoji_santa">Télapó</string> - <string name="verification_emoji_thumbsup">Hüvelykujj fel</string> - <string name="verification_emoji_umbrella">EsernyÅ‘</string> - <string name="verification_emoji_hourglass">Homokóra</string> - <string name="verification_emoji_clock">Óra</string> - <string name="verification_emoji_gift">Ajándék</string> - <string name="verification_emoji_lightbulb">ÉgÅ‘</string> - <string name="verification_emoji_book">Könyv</string> - <string name="verification_emoji_pencil">Ceruza</string> - <string name="verification_emoji_paperclip">Gémkapocs</string> - <string name="verification_emoji_scissors">Olló</string> - <string name="verification_emoji_lock">Zár</string> - <string name="verification_emoji_key">Kulcs</string> - <string name="verification_emoji_hammer">Kalapács</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Zászló</string> - <string name="verification_emoji_train">Vonat</string> - <string name="verification_emoji_bicycle">Kerékpár</string> - <string name="verification_emoji_airplane">RepülÅ‘</string> - <string name="verification_emoji_rocket">Rakéta</string> - <string name="verification_emoji_trophy">Trófea</string> - <string name="verification_emoji_ball">Labda</string> - <string name="verification_emoji_guitar">Gitár</string> - <string name="verification_emoji_trumpet">Trombita</string> - <string name="verification_emoji_bell">Harang</string> - <string name="verification_emoji_anchor">Vasmacska</string> - <string name="verification_emoji_headphone">Fejhallgató</string> - <string name="verification_emoji_folder">Mappa</string> - <string name="verification_emoji_pin">Tű</string> <string name="initial_sync_start_importing_account">Induló szinkronizáció: \nFiók betöltése…</string> diff --git a/matrix-sdk-android/src/main/res/values-it/strings.xml b/matrix-sdk-android/src/main/res/values-it/strings.xml index 2b2a097f1323717ae3df0793ea652482b2fdb812..cf081752a248070f3c3a9889370e89f6690cedad 100644 --- a/matrix-sdk-android/src/main/res/values-it/strings.xml +++ b/matrix-sdk-android/src/main/res/values-it/strings.xml @@ -78,70 +78,6 @@ <string name="notice_event_redacted_by">Messaggio rimosso da %1$s</string> <string name="notice_event_redacted_with_reason">Messaggio rimosso [motivo: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Messaggio rimosso da %1$s [motivo: %2$s]</string> - <string name="verification_emoji_dog">Cane</string> - <string name="verification_emoji_cat">Gatto</string> - <string name="verification_emoji_lion">Leone</string> - <string name="verification_emoji_horse">Cavallo</string> - <string name="verification_emoji_unicorn">Unicorno</string> - <string name="verification_emoji_pig">Maiale</string> - <string name="verification_emoji_elephant">Elefante</string> - <string name="verification_emoji_rabbit">Coniglio</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Gallo</string> - <string name="verification_emoji_penguin">Pinguino</string> - <string name="verification_emoji_turtle">Tartaruga</string> - <string name="verification_emoji_fish">Pesce</string> - <string name="verification_emoji_octopus">Piovra</string> - <string name="verification_emoji_butterfly">Farfalla</string> - <string name="verification_emoji_flower">Fiore</string> - <string name="verification_emoji_tree">Albero</string> - <string name="verification_emoji_cactus">Cactus</string> - <string name="verification_emoji_mushroom">Fungo</string> - <string name="verification_emoji_globe">Globo</string> - <string name="verification_emoji_moon">Luna</string> - <string name="verification_emoji_cloud">Nuvola</string> - <string name="verification_emoji_fire">Fuoco</string> - <string name="verification_emoji_banana">Banana</string> - <string name="verification_emoji_apple">Mela</string> - <string name="verification_emoji_strawberry">Fragola</string> - <string name="verification_emoji_corn">Mais</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Torta</string> - <string name="verification_emoji_heart">Cuore</string> - <string name="verification_emoji_smiley">Sorriso</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Cappello</string> - <string name="verification_emoji_glasses">Occhiali</string> - <string name="verification_emoji_wrench">Chiave inglese</string> - <string name="verification_emoji_santa">Babbo Natale</string> - <string name="verification_emoji_thumbsup">Pollice in su</string> - <string name="verification_emoji_umbrella">Ombrello</string> - <string name="verification_emoji_hourglass">Clessidra</string> - <string name="verification_emoji_clock">Orologio</string> - <string name="verification_emoji_gift">Regalo</string> - <string name="verification_emoji_lightbulb">Lampadina</string> - <string name="verification_emoji_book">Libro</string> - <string name="verification_emoji_pencil">Matita</string> - <string name="verification_emoji_paperclip">Graffetta</string> - <string name="verification_emoji_scissors">Forbici</string> - <string name="verification_emoji_lock">Lucchetto</string> - <string name="verification_emoji_key">Chiave</string> - <string name="verification_emoji_hammer">Martello</string> - <string name="verification_emoji_telephone">Telefono</string> - <string name="verification_emoji_flag">Bandiera</string> - <string name="verification_emoji_train">Treno</string> - <string name="verification_emoji_bicycle">Bicicletta</string> - <string name="verification_emoji_airplane">Aeroplano</string> - <string name="verification_emoji_rocket">Razzo</string> - <string name="verification_emoji_trophy">Trofeo</string> - <string name="verification_emoji_ball">Palla</string> - <string name="verification_emoji_guitar">Chitarra</string> - <string name="verification_emoji_trumpet">Tromba</string> - <string name="verification_emoji_bell">Campana</string> - <string name="verification_emoji_anchor">Ancora</string> - <string name="verification_emoji_headphone">Cuffie</string> - <string name="verification_emoji_folder">Cartella</string> - <string name="verification_emoji_pin">Spillo</string> <string name="initial_sync_start_importing_account">Sync iniziale: \nImportazione account…</string> @@ -296,8 +232,4 @@ <string name="notice_end_to_end_ok_by_you">Hai attivato la crittografia end-to-end.</string> <string name="notice_end_to_end_unknown_algorithm_by_you">Hai attivato la crittografia end-to-end (algoritmo %1$s sconosciuto).</string> - <string name="call_notification_answer">Accetta</string> - <string name="call_notification_reject">Rifiuta</string> - <string name="call_notification_hangup">Riaggancia</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-ja/strings_sas.xml b/matrix-sdk-android/src/main/res/values-ja/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..618302eb4f9f20c61e078bbcb8fa1d87c0a87ac6 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-ja/strings_sas.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">犬</string> + <string name="verification_emoji_cat">猫</string> + <string name="verification_emoji_horse">馬</string> + <string name="verification_emoji_octopus">ãŸã“</string> + <string name="verification_emoji_flower">花</string> + <string name="verification_emoji_tree">木</string> + <string name="verification_emoji_mushroom">ãã®ã“</string> + <string name="verification_emoji_moon">月</string> + <string name="verification_emoji_apple">リンゴ</string> + <string name="verification_emoji_cake">ケーã‚</string> + <string name="verification_emoji_robot">ãƒãƒœã¨</string> + <string name="verification_emoji_glasses">ã‚ãŒã</string> + <string name="verification_emoji_book">本</string> + <string name="verification_emoji_telephone">電話機</string> + <string name="verification_emoji_train">電車</string> + <string name="verification_emoji_bicycle">自転車</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-kab/strings.xml b/matrix-sdk-android/src/main/res/values-kab/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..0d1cad6550d215cbb10a28aee32fa24d541945c4 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-kab/strings.xml @@ -0,0 +1,225 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="summary_message">%1$s: %2$s</string> + <string name="summary_user_sent_image">%1$s t.yuzen tugna.</string> + <string name="summary_you_sent_image">TuzneḠtugna.</string> + <string name="notice_room_invite_no_invitee">Tinubga n %s</string> + <string name="notice_room_invite_no_invitee_by_you">Tinubga-k•m</string> + <string name="notice_room_created">%1$s yesnulfa-d taxxamt</string> + <string name="notice_room_created_by_you">Tesnulfaá¸-d taxxamt-a</string> + <string name="notice_room_invite">%1$s inced-d %2$s</string> + <string name="notice_room_invite_by_you">Tnecdeá¸-d %1$s</string> + <string name="notice_room_invite_you">%1$s inced-ik-id</string> + <string name="notice_room_join">%1$s yedda É£er texxamt</string> + <string name="notice_room_join_by_you">TeddiḠɣer texxamt</string> + <string name="notice_room_leave">%1$s yeǧǧa taxxamt</string> + <string name="notice_room_leave_by_you">TeǧǧiḠtaxxamt</string> + <string name="notice_room_reject">%1$s yugi/tugi tinubga</string> + <string name="notice_room_reject_by_you">TufiḠtinubga</string> + <string name="notice_room_kick">%1$s yessufeÉ£ %2$s</string> + <string name="notice_room_kick_by_you">TessufÉ£eḠ%1$s</string> + <string name="notice_avatar_url_changed_by_you">TbeddleḠavatar-inek·inem</string> + <string name="power_level_admin">Anedbal</string> + <string name="power_level_moderator">AseÉ£yad</string> + <string name="power_level_default">Amezwer</string> + <string name="power_level_custom_no_value">Sagen</string> + + <string name="notice_power_level_diff">%1$s seg %2$s É£er %3$s</string> + + <string name="message_failed_to_upload">Tegguma ad d-tali tugna</string> + + <string name="medium_email">Tansa n yimayl</string> + + <string name="summary_user_sent_sticker">%1$s azen astiker.</string> + <string name="summary_you_sent_sticker">TuzneḠamená¹aá¸.</string> + + <string name="notice_room_unban">%1$s yekkes agdal i %2$s</string> + <string name="notice_room_unban_by_you">TekkseḠagdal i %1$s</string> + <string name="notice_room_ban">%1$s igdel %2$s</string> + <string name="notice_room_ban_by_you">TgedleḠ%1$s</string> + <string name="notice_room_withdraw">%1$s issefsex tinubga n %2$s</string> + <string name="notice_room_withdraw_by_you">TesfesxeḠtinubga n %1$s</string> + <string name="notice_avatar_url_changed">%1$s ibeddel avatar-is</string> + <string name="notice_display_name_set">%1$s isbadu isem-is i d-ittuseknen É£er %2$s</string> + <string name="notice_display_name_set_by_you">TesbaduḠisem-ik•im i d-ittuseknen É£er %1$s</string> + <string name="notice_display_name_changed_from">%1$s ibeddel isem-is i d-ittuseknen seg %2$s É£er %3$s</string> + <string name="notice_display_name_changed_from_by_you">TbeddleḠisem-ik•im i d-ittuseknen seg %1$s É£er %2$s</string> + <string name="notice_display_name_removed">%1$s yekkes isem-is i d-ittuseknen (yella %2$s)</string> + <string name="notice_display_name_removed_by_you">TekkseḠisem-ik·im yettwaskanen (d %1$s)</string> + <string name="notice_room_topic_changed">%1$S isnifel asentel s: %2$S</string> + <string name="notice_room_topic_changed_by_you">TesnifleḠasentel s: %2$S</string> + <string name="notice_room_avatar_changed">%1$s ibeddel avaá¹ar n texxamt</string> + <string name="notice_room_avatar_changed_by_you">TbeddleḠavaá¹ar n texxamt</string> + <string name="notice_room_name_changed">%1$s ibeddel isem n texxamt s: %2$s</string> + <string name="notice_room_name_changed_by_you">TbeddleḠisem n texxamt s: %2$s</string> + <string name="notice_placed_video_call">%s isÉ›edda siwel s tvidyut.</string> + <string name="notice_placed_video_call_by_you">TesÉ›eddaḠsiwel s tvidyut.</string> + <string name="notice_placed_voice_call">%s isÉ›edda asiwel s taÉ£ect.</string> + <string name="notice_placed_voice_call_by_you">TesÉ›eddaḠsiwel s taÉ£ect.</string> + <string name="notice_call_candidates">%s yuzen isefka i usbadu n usiwel.</string> + <string name="notice_call_candidates_by_you">TuzneḠisefka i usbadu n usiwel.</string> + <string name="notice_answered_call">%s yerra É£ef usiwel.</string> + <string name="notice_answered_call_by_you">TerriḠɣef usiwel.</string> + <string name="notice_ended_call">%s iḥbes asiwel.</string> + <string name="notice_ended_call_by_you">TḥebseḠasiwel.</string> + <string name="notice_room_visibility_invited">meṛṛa iÉ›eggalen n texxamt, segmi ara d-ttwanecden.</string> + <string name="notice_room_visibility_joined">meṛṛa iÉ›eggalen n texamt, segmi ara d-rnun.</string> + <string name="notice_room_visibility_shared">meṛṛa iÉ›eggalen n texxamt.</string> + <string name="notice_room_visibility_world_readable">yal yiwen.</string> + <string name="notice_room_visibility_unknown">arussin (%s).</string> + <string name="notice_end_to_end">%1$s isermed awgelhen seg yixef É£er yixef (%2$s)</string> + <string name="notice_end_to_end_by_you">TesremdeḠawgelhen seg yixef É£er yixef (%2$s)</string> + <string name="notice_room_update">%s ileqqem taxxamt-a.</string> + <string name="notice_room_update_by_you">TleqqmeḠtaxxamt-a.</string> + + <string name="notice_requested_voip_conference">%1$s isuter-d asarag VoIP</string> + <string name="notice_requested_voip_conference_by_you">Tsutreá¸-d asarag VoIP</string> + <string name="notice_voip_started">Asarag VoIP yebda</string> + <string name="notice_voip_finished">Asarag VoIP yekfa</string> + + <string name="notice_avatar_changed_too">(avatar daÉ£en ibeddel)</string> + <string name="notice_room_name_removed">%1$s yekkes isem n texxamt</string> + <string name="notice_room_name_removed_by_you">TekkseḠisem n texxamt</string> + <string name="notice_room_topic_removed">%1$s yekkes asentel n texxamt</string> + <string name="notice_room_topic_removed_by_you">TekkseḠasentel n texxamt</string> + <string name="notice_room_avatar_removed">%1$s yekkes avatar n texxamt</string> + <string name="notice_room_avatar_removed_by_you">TekkseḠavatar n texxamt</string> + <string name="notice_event_redacted">Izen ittwakkes</string> + <string name="notice_event_redacted_by">Izen ittwakkes sÉ£ur %1$s</string> + <string name="notice_event_redacted_with_reason">Izen ittwakkes [tamentilt: %1$s]</string> + <string name="notice_event_redacted_by_with_reason">Izen ittwakkes sÉ£ur %1$s [tamentilt: %2$s]</string> + <string name="notice_profile_change_redacted">%1$s ileqqem amaÉ£nu-ines %2$s</string> + <string name="notice_profile_change_redacted_by_you">TleqqmeḠamaÉ£nu-inek•inem %1$s</string> + <string name="notice_room_third_party_invite">%1$s yuzen tinubga i %2$s akken ad yeddu É£er texxamt</string> + <string name="notice_room_third_party_invite_by_you">TuzneḠtinubga i %1$s akken ad yeddu É£er texxamt</string> + <string name="notice_room_third_party_registered_invite">%1$s iqbel tinubga i %2$s</string> + <string name="notice_room_third_party_registered_invite_by_you">TqebleḠtinubga i %1$s</string> + + <string name="notice_widget_added">%1$s yerna awiǧit %2$s</string> + <string name="notice_widget_added_by_you">TerniḠawiǧit %1$s</string> + <string name="notice_widget_removed">%1$s yekkes awiǧit %2$s</string> + <string name="notice_widget_removed_by_you">TekkseḠawiǧit %1$s</string> + <string name="notice_widget_modified">%1$s ibeddel awiǧit %2$s</string> + <string name="notice_widget_modified_by_you">TbeddleḠawiǧit %1$s</string> + + <string name="power_level_custom">Sagen (%1$)</string> + <string name="notice_power_level_changed_by_you">TbeddleḠaswir n tezmert n %1$s.</string> + <string name="notice_power_level_changed">%1$s ibeddel aswir n tezmert n %2$s.</string> + <string name="notice_crypto_unable_to_decrypt">** Awgelhen d awezÉ£i: %s **</string> + <string name="notice_crypto_error_unkwown_inbound_session_id">Ibenk n umazan ur aÉ£-d-yuzin ara tisura i yizen-a.</string> + + <string name="unable_to_send_message">Tuzna n yizen d tawezÉ£it</string> + + <string name="network_error">Tuccá¸a deg uẓeá¹á¹a</string> + <string name="matrix_error">Tuccá¸a deg Matrix</string> + + <string name="notice_made_future_room_visibility">%1$s iga amazray n texxamyt i d-iteddun yettban i %2$s</string> + <string name="notice_made_future_room_visibility_by_you">TgiḠamazray n texxamyt i d-iteddun yettban i %1$s</string> + <string name="notice_room_third_party_revoked_invite">%1$s issefsax tinubga i %2$s i wakken ad d-yekcem É£er texxamt</string> + <string name="notice_room_third_party_revoked_invite_by_you">TesfesxeḠtinubga i %1$s i wakken ad d-yernu É£er texxamt</string> + <string name="room_error_join_failed_empty_room">D awezÉ£i tura ad nales ad nuÉ£al É£er texxamt tilemt.</string> + + <string name="encrypted_message">Izen yettwawgelhen</string> + + <string name="medium_phone_number">Uá¹á¹un n tiliÉ£ri</string> + + <string name="room_displayname_invite_from">Tinubga sÉ£ur %s</string> + <string name="room_displayname_room_invite">Tinubga É£er texxamt</string> + + <string name="room_displayname_two_members">%1$s d %2$s</string> + + <plurals name="room_displayname_three_and_more_members"> + <item quantity="one">%1$s d 1 wayeá¸</item> + <item quantity="other">%1$s d %2$d wiyaá¸</item> + </plurals> + + <string name="notice_end_to_end_unknown_algorithm_by_you">TremdeḠawgelhen seg yixef É£er yixef (alguritm %1$s ur yettwassen ara).</string> + + <string name="key_verification_request_fallback_message">%s isuter-d ad isenqed tasarut-ik·im, maca amsaÉ£-ik·im ur issefrak ara asenqed n tsura deg yidiwenniyen. Ilaq-ak·am useqdec asenqed iqdim n tsura i usenqed n tsura.</string> + + <string name="room_displayname_empty_room">Taxxamt tilemt</string> + + <string name="initial_sync_start_importing_account">Amtawi n tazwara: +\nAktar n umiá¸an…</string> + <string name="initial_sync_start_importing_account_crypto">Amtawi n tazwara: +\nAktar n uwgelhen</string> + <string name="initial_sync_start_importing_account_rooms">Amtawi n tazwara: +\nAktar n texxamin</string> + <string name="initial_sync_start_importing_account_joined_rooms">Amtawi n tazwara: +\nAktar n texxamin iÉ£er terniá¸</string> + <string name="initial_sync_start_importing_account_invited_rooms">Amtawi n tazwara: +\nAktar n texxamin iÉ£er tettwanecdeá¸</string> + <string name="initial_sync_start_importing_account_left_rooms">Amtawi n tazwara: +\nAktar n texxamin i teǧǧiá¸</string> + <string name="initial_sync_start_importing_account_groups">Amtawi n tazwara: +\nAktar n tmezdagnutin</string> + <string name="initial_sync_start_importing_account_data">Amtawi n tazwara: +\nAktar n yisefka n umiá¸an</string> + + <string name="event_status_sending_message">Tuzzna n yizen…</string> + <string name="notice_room_invite_no_invitee_with_reason">Tinubga n %1$s. Tamentilt: %2$s</string> + <string name="notice_room_invite_no_invitee_with_reason_by_you">Tinubga-k•m. Tamentilt: %1$s</string> + <string name="notice_room_invite_with_reason">%1$s inced %2$s. Tamentilt: %3$s</string> + <string name="notice_room_invite_with_reason_by_you">TnecdeḠ%1$s. Tamentilt: %2$s</string> + <string name="notice_room_invite_you_with_reason">%1$s inced-ik•ikem. Tamentilt: %2$s</string> + <string name="notice_room_join_with_reason">%1$s yedda É£er texxamt. Tamentilt: %2$s</string> + <string name="notice_room_join_with_reason_by_you">TeddiḠɣer texxamt. Tamentilt: %1$s</string> + <string name="notice_room_leave_with_reason">%1$s yeǧǧa taxxamt. Tamentilt: %2$s</string> + <string name="notice_room_leave_with_reason_by_you">TeǧǧiḠtaxxamt. Tamentilt: %1$s</string> + <string name="notice_room_reject_with_reason">%1$s yugi tinubga. Tamentilt: %2$s</string> + <string name="notice_room_reject_with_reason_by_you">TugiḠtinubga. Tamentilt: %1$s</string> + <string name="notice_room_kick_with_reason">%1$s yessufeÉ£ %2$s. Tamentilt: %3$s</string> + <string name="notice_room_kick_with_reason_by_you">TessufÉ£eḠ%1$s. Tamentilt: %2$s</string> + <string name="notice_room_unban_with_reason">%1$s yekkes agdal i %2$s. Tamentilt: %3$s</string> + <string name="notice_room_unban_with_reason_by_you">TekkseḠagdal i %1$s. Tamentilt: %2$s</string> + <string name="notice_room_ban_with_reason">%1$s igdel %2$s. Tamentilt: %3$s</string> + <string name="notice_room_ban_with_reason_by_you">TgedleḠ%1$s. Tamentilt: %2$s</string> + <string name="notice_room_third_party_invite_with_reason">%1$s yuzen tinubga i %2$s akken ad yeddu É£er texxamt. Tamentilt: %3$s</string> + <string name="notice_room_third_party_invite_with_reason_by_you">TuzneḠtinubga i %1$s iwakken ad yeddu É£er texxamt. Tamentilt: %2$s</string> + <string name="notice_room_third_party_registered_invite_with_reason">%1$s iqbel tinubga i %2$s. Tamentilt: %3$s</string> + <string name="notice_room_third_party_registered_invite_with_reason_by_you">TqebleḠtinubga i %1$s. Tamentilt: %2$s</string> + <string name="notice_room_withdraw_with_reason">%1$s issefsex tinubga n %2$s. Tamentilt: %3$s</string> + <string name="notice_room_withdraw_with_reason_by_you">TesfesxeḠtinubga n %1$s. Tamentilt: %2$s</string> + + <plurals name="notice_room_aliases_added"> + <item quantity="one">%1$s yerna %2$s d tansa i texxamt-a.</item> + <item quantity="other">%1$s yerna %2$s d tansiwin i texxamt-a.</item> + </plurals> + + <plurals name="notice_room_aliases_added_by_you"> + <item quantity="one">TerniḠ%1$s d tansa i texxamt-a.</item> + <item quantity="other">TerniḠ%1$s d tansiwin i texxamt-a.</item> + </plurals> + + <plurals name="notice_room_aliases_removed"> + <item quantity="one">%1$s yekkes %2$s am tansa i texxamt-a.</item> + <item quantity="other">%1$s yekkes %3$s am tansiwin i texxamt-a.</item> + </plurals> + + <plurals name="notice_room_aliases_removed_by_you"> + <item quantity="one">TekkseḠ%1$s am tansa i texxamt-a.</item> + <item quantity="other">TekkseḠ%2$s am tansiwin i texxamt-a.</item> + </plurals> + + <string name="notice_room_aliases_added_and_removed">%1$s yerna %2$s terniḠtekkseḠ%3s am tansiwin i texxamt-a.</string> + <string name="notice_room_aliases_added_and_removed_by_you">TerniḠ%1$s terniḠtekkseḠ%2$s am tansiwin i texxamt-a.</string> + + <string name="notice_room_canonical_alias_set">%1$s isbadu %2$s am tansa tagejdant i texxamt-a.</string> + <string name="notice_room_canonical_alias_set_by_you">TesbaduḠ%1$s am tansa tagejdant i texxamt-a.</string> + <string name="notice_room_canonical_alias_unset">%1$s yekkes tansa tagejdant i texxamt-a.</string> + <string name="notice_room_canonical_alias_unset_by_you">TekkseḠtansa tagejdant i texxamt-a.</string> + + <string name="notice_room_guest_access_can_join">%1$s isireg inebgawen ad ddun É£er texxamt.</string> + <string name="notice_room_guest_access_can_join_by_you">TsirgeḠinebgawen ad ddun É£er texxamt.</string> + <string name="notice_room_guest_access_forbidden">%1$s issewḥel inebgawen iwakken ur tteddun ara É£er texxamt.</string> + <string name="notice_room_guest_access_forbidden_by_you">TesweḥleḠinebgawen iwakken ur tteddun ara É£er texxamt.</string> + + <string name="notice_end_to_end_ok">%1$s yermed awgelhen seg yixef É£er yixef.</string> + <string name="notice_end_to_end_ok_by_you">TremdeḠawgelhen seg yixef É£er yixef.</string> + <string name="notice_end_to_end_unknown_algorithm">%1$s yermed awgelhen seg yixef É£er yixef (alguritm %2$s ur yettwassen ara).</string> + <string name="clear_timeline_send_queue">SfeḠtabdart n uraǧu n tuzzna</string> + + <string name="notice_room_third_party_revoked_invite_with_reason">%1$s issefsex tinubga n %2$s i tmerniwt É£er texxamt. Tamentilt: %2$s</string> + <string name="notice_room_third_party_revoked_invite_with_reason_by_you">TesfesxeḠtinubga n %1$s i tmerna É£er texxamt. Tamentilt: %2$s</string> + <string name="could_not_redact">Yegguma ad yaru</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-ko/strings.xml b/matrix-sdk-android/src/main/res/values-ko/strings.xml index 88c5e7d618eaf9a1ce85b6433983f7c7fe65df1f..eee67628ebeb16deea3a02e4f8a8da576a83d100 100644 --- a/matrix-sdk-android/src/main/res/values-ko/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ko/strings.xml @@ -2,7 +2,6 @@ <resources> <string name="summary_message">%1$s: %2$s</string> <string name="notice_room_invite_no_invitee">%së‹˜ì˜ ì´ˆëŒ€</string> - <string name="verification_emoji_headphone">헤드í°</string> <string name="summary_user_sent_image">%1$së‹˜ì´ ì‚¬ì§„ì„ ë³´ëƒˆìŠµë‹ˆë‹¤.</string> <string name="summary_user_sent_sticker">%1$së‹˜ì´ ìŠ¤í‹°ì»¤ë¥¼ 보냈습니다.</string> @@ -78,71 +77,6 @@ <string name="room_displayname_empty_room">빈 ë°©</string> - - <string name="verification_emoji_dog">ê°œ</string> - <string name="verification_emoji_cat">ê³ ì–‘ì´</string> - <string name="verification_emoji_lion">사ìž</string> - <string name="verification_emoji_horse">ë§</string> - <string name="verification_emoji_unicorn">ìœ ë‹ˆì½˜</string> - <string name="verification_emoji_pig">ë¼ì§€</string> - <string name="verification_emoji_elephant">ì½”ë¼ë¦¬</string> - <string name="verification_emoji_rabbit">í† ë¼</string> - <string name="verification_emoji_panda">íŒë‹¤</string> - <string name="verification_emoji_rooster">수탉</string> - <string name="verification_emoji_penguin">íŽê·„</string> - <string name="verification_emoji_turtle">ê±°ë¶</string> - <string name="verification_emoji_fish">ë¬¼ê³ ê¸°</string> - <string name="verification_emoji_octopus">문어</string> - <string name="verification_emoji_butterfly">나비</string> - <string name="verification_emoji_flower">꽃</string> - <string name="verification_emoji_tree">나무</string> - <string name="verification_emoji_cactus">ì„ ì¸ìž¥</string> - <string name="verification_emoji_mushroom">버섯</string> - <string name="verification_emoji_globe">지구본</string> - <string name="verification_emoji_moon">달</string> - <string name="verification_emoji_cloud">구름</string> - <string name="verification_emoji_fire">불</string> - <string name="verification_emoji_banana">바나나</string> - <string name="verification_emoji_apple">사과</string> - <string name="verification_emoji_strawberry">딸기</string> - <string name="verification_emoji_corn">옥수수</string> - <string name="verification_emoji_pizza">피ìž</string> - <string name="verification_emoji_cake">ì¼€ì´í¬</string> - <string name="verification_emoji_heart">하트</string> - <string name="verification_emoji_smiley">웃ìŒ</string> - <string name="verification_emoji_robot">로봇</string> - <string name="verification_emoji_hat">모ìž</string> - <string name="verification_emoji_glasses">안경</string> - <string name="verification_emoji_wrench">스패너</string> - <string name="verification_emoji_santa">산타í´ë¡œìŠ¤</string> - <string name="verification_emoji_thumbsup">좋아요</string> - <string name="verification_emoji_umbrella">ìš°ì‚°</string> - <string name="verification_emoji_hourglass">모래시계</string> - <string name="verification_emoji_clock">시계</string> - <string name="verification_emoji_gift">ì„ ë¬¼</string> - <string name="verification_emoji_lightbulb">ì „êµ¬</string> - <string name="verification_emoji_book">ì±…</string> - <string name="verification_emoji_pencil">ì—°í•„</string> - <string name="verification_emoji_paperclip">í´ë¦½</string> - <string name="verification_emoji_scissors">가위</string> - <string name="verification_emoji_lock">ìžë¬¼ì‡ </string> - <string name="verification_emoji_key">ì—´ì‡ </string> - <string name="verification_emoji_hammer">ë§ì¹˜</string> - <string name="verification_emoji_telephone">ì „í™”ê¸°</string> - <string name="verification_emoji_flag">깃발</string> - <string name="verification_emoji_train">기차</string> - <string name="verification_emoji_bicycle">ìžì „ê±°</string> - <string name="verification_emoji_airplane">비행기</string> - <string name="verification_emoji_rocket">로켓</string> - <string name="verification_emoji_trophy">트로피</string> - <string name="verification_emoji_ball">ê³µ</string> - <string name="verification_emoji_guitar">기타</string> - <string name="verification_emoji_trumpet">트럼펫</string> - <string name="verification_emoji_bell">종</string> - <string name="verification_emoji_anchor">ë‹»</string> - <string name="verification_emoji_folder">í´ë”</string> - <string name="verification_emoji_pin">í•€</string> - <string name="initial_sync_start_importing_account">초기 ë™ê¸°í™”: \nê³„ì • ê°€ì ¸ì˜¤ëŠ” 중…</string> <string name="initial_sync_start_importing_account_crypto">초기 ë™ê¸°í™”: diff --git a/matrix-sdk-android/src/main/res/values-nb-rNO/strings_sas.xml b/matrix-sdk-android/src/main/res/values-nb-rNO/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..c348b5bfbbcfddb3ec64467b350b047fd7c1c8c7 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-nb-rNO/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hund</string> + <string name="verification_emoji_cat">Katt</string> + <string name="verification_emoji_lion">Løve</string> + <string name="verification_emoji_horse">Hest</string> + <string name="verification_emoji_unicorn">Enhjørning</string> + <string name="verification_emoji_pig">Gris</string> + <string name="verification_emoji_elephant">Elefant</string> + <string name="verification_emoji_rabbit">Kanin</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Hane</string> + <string name="verification_emoji_penguin">Pingvin</string> + <string name="verification_emoji_turtle">Skilpadde</string> + <string name="verification_emoji_fish">Fisk</string> + <string name="verification_emoji_octopus">Blekksprut</string> + <string name="verification_emoji_butterfly">Sommerfugl</string> + <string name="verification_emoji_flower">Blomst</string> + <string name="verification_emoji_tree">Tre</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Sopp</string> + <string name="verification_emoji_globe">Globus</string> + <string name="verification_emoji_moon">MÃ¥ne</string> + <string name="verification_emoji_cloud">Sky</string> + <string name="verification_emoji_fire">Flamme</string> + <string name="verification_emoji_banana">Banan</string> + <string name="verification_emoji_apple">Eple</string> + <string name="verification_emoji_strawberry">Jordbær</string> + <string name="verification_emoji_corn">Mais</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Kake</string> + <string name="verification_emoji_heart">Hjerte</string> + <string name="verification_emoji_smiley">Smilefjes</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Hatt</string> + <string name="verification_emoji_glasses">Briller</string> + <string name="verification_emoji_spanner">Fastnøkkel</string> + <string name="verification_emoji_santa">Julenisse</string> + <string name="verification_emoji_thumbs_up">Tommel Opp</string> + <string name="verification_emoji_umbrella">Paraply</string> + <string name="verification_emoji_hourglass">Timeglass</string> + <string name="verification_emoji_clock">Klokke</string> + <string name="verification_emoji_gift">Gave</string> + <string name="verification_emoji_light_bulb">Lyspære</string> + <string name="verification_emoji_book">Bok</string> + <string name="verification_emoji_pencil">Blyant</string> + <string name="verification_emoji_paperclip">BInders</string> + <string name="verification_emoji_scissors">Saks</string> + <string name="verification_emoji_lock">LÃ¥s</string> + <string name="verification_emoji_key">Nøkkel</string> + <string name="verification_emoji_hammer">Hammer</string> + <string name="verification_emoji_telephone">Telefon</string> + <string name="verification_emoji_flag">Flagg</string> + <string name="verification_emoji_train">Tog</string> + <string name="verification_emoji_bicycle">Sykkel</string> + <string name="verification_emoji_aeroplane">Fly</string> + <string name="verification_emoji_rocket">Rakett</string> + <string name="verification_emoji_trophy">Pokal</string> + <string name="verification_emoji_ball">Ball</string> + <string name="verification_emoji_guitar">Gitar</string> + <string name="verification_emoji_trumpet">Trompet</string> + <string name="verification_emoji_bell">Bjelle</string> + <string name="verification_emoji_anchor">Anker</string> + <string name="verification_emoji_headphones">Hodetelefoner</string> + <string name="verification_emoji_folder">Mappe</string> + <string name="verification_emoji_pin">Tegnestift</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-nl/strings.xml b/matrix-sdk-android/src/main/res/values-nl/strings.xml index 22eb61f109c8958bb8ab1554e2d3ac638f276bb4..1b05052ba6c24ab2eb9abe2ef7adf3aa04913b9a 100644 --- a/matrix-sdk-android/src/main/res/values-nl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nl/strings.xml @@ -87,70 +87,6 @@ <string name="notice_event_redacted_by">Bericht verwijderd door %1$s</string> <string name="notice_event_redacted_with_reason">Bericht verwijderd [reden: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Bericht verwijderd door %1$s [reden: %2$s]</string> - <string name="verification_emoji_dog">Hond</string> - <string name="verification_emoji_cat">Kat</string> - <string name="verification_emoji_lion">Leeuw</string> - <string name="verification_emoji_horse">Paard</string> - <string name="verification_emoji_unicorn">Eenhoorn</string> - <string name="verification_emoji_pig">Varken</string> - <string name="verification_emoji_elephant">Olifant</string> - <string name="verification_emoji_rabbit">Konijn</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Haan</string> - <string name="verification_emoji_penguin">Pinguïn</string> - <string name="verification_emoji_turtle">Schildpad</string> - <string name="verification_emoji_fish">Vis</string> - <string name="verification_emoji_octopus">Octopus</string> - <string name="verification_emoji_butterfly">Vlinder</string> - <string name="verification_emoji_flower">Bloem</string> - <string name="verification_emoji_tree">Boom</string> - <string name="verification_emoji_cactus">Cactus</string> - <string name="verification_emoji_mushroom">Paddenstoel</string> - <string name="verification_emoji_globe">Aardbol</string> - <string name="verification_emoji_moon">Maan</string> - <string name="verification_emoji_cloud">Wolk</string> - <string name="verification_emoji_fire">Vuur</string> - <string name="verification_emoji_banana">Banaan</string> - <string name="verification_emoji_apple">Appel</string> - <string name="verification_emoji_strawberry">Aardbei</string> - <string name="verification_emoji_corn">Maïs</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Taart</string> - <string name="verification_emoji_heart">Hart</string> - <string name="verification_emoji_smiley">Smiley</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Hoed</string> - <string name="verification_emoji_glasses">Bril</string> - <string name="verification_emoji_wrench">Moersleutel</string> - <string name="verification_emoji_santa">Kerstman</string> - <string name="verification_emoji_thumbsup">Duim omhoog</string> - <string name="verification_emoji_umbrella">Paraplu</string> - <string name="verification_emoji_hourglass">Zandloper</string> - <string name="verification_emoji_clock">Klok</string> - <string name="verification_emoji_gift">Cadeau</string> - <string name="verification_emoji_lightbulb">Gloeilamp</string> - <string name="verification_emoji_book">Boek</string> - <string name="verification_emoji_pencil">Potlood</string> - <string name="verification_emoji_paperclip">Paperclip</string> - <string name="verification_emoji_scissors">Schaar</string> - <string name="verification_emoji_lock">Slot</string> - <string name="verification_emoji_key">Sleutel</string> - <string name="verification_emoji_hammer">Hamer</string> - <string name="verification_emoji_telephone">Telefoon</string> - <string name="verification_emoji_flag">Vlag</string> - <string name="verification_emoji_train">Trein</string> - <string name="verification_emoji_bicycle">Fiets</string> - <string name="verification_emoji_airplane">Vliegtuig</string> - <string name="verification_emoji_rocket">Raket</string> - <string name="verification_emoji_trophy">Trofee</string> - <string name="verification_emoji_ball">Bal</string> - <string name="verification_emoji_guitar">Gitaar</string> - <string name="verification_emoji_trumpet">Trompet</string> - <string name="verification_emoji_bell">Bel</string> - <string name="verification_emoji_anchor">Anker</string> - <string name="verification_emoji_headphone">Koptelefoon</string> - <string name="verification_emoji_folder">Map</string> - <string name="verification_emoji_pin">Speld</string> <string name="initial_sync_start_importing_account">Initiële synchronisatie: \nAccount wordt geïmporteerd…</string> diff --git a/matrix-sdk-android/src/main/res/values-nl/strings_sas.xml b/matrix-sdk-android/src/main/res/values-nl/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..077244232ae525a966f3bfbdb59027f96e9fa95f --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-nl/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hond</string> + <string name="verification_emoji_cat">Kat</string> + <string name="verification_emoji_lion">Leeuw</string> + <string name="verification_emoji_horse">Paard</string> + <string name="verification_emoji_unicorn">Eenhoorn</string> + <string name="verification_emoji_pig">Varken</string> + <string name="verification_emoji_elephant">Olifant</string> + <string name="verification_emoji_rabbit">Konijn</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Haan</string> + <string name="verification_emoji_penguin">Pinguïn</string> + <string name="verification_emoji_turtle">Schildpad</string> + <string name="verification_emoji_fish">Vis</string> + <string name="verification_emoji_octopus">Octopus</string> + <string name="verification_emoji_butterfly">Vlinder</string> + <string name="verification_emoji_flower">Bloem</string> + <string name="verification_emoji_tree">Boom</string> + <string name="verification_emoji_cactus">Cactus</string> + <string name="verification_emoji_mushroom">Paddenstoel</string> + <string name="verification_emoji_globe">Wereldbol</string> + <string name="verification_emoji_moon">Maan</string> + <string name="verification_emoji_cloud">Wolk</string> + <string name="verification_emoji_fire">Vuur</string> + <string name="verification_emoji_banana">Banaan</string> + <string name="verification_emoji_apple">Appel</string> + <string name="verification_emoji_strawberry">Aardbei</string> + <string name="verification_emoji_corn">Maïs</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Taart</string> + <string name="verification_emoji_heart">Hart</string> + <string name="verification_emoji_smiley">Smiley</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Hoed</string> + <string name="verification_emoji_glasses">Bril</string> + <string name="verification_emoji_spanner">Moersleutel</string> + <string name="verification_emoji_santa">Kerstman</string> + <string name="verification_emoji_thumbs_up">Duim omhoog</string> + <string name="verification_emoji_umbrella">Paraplu</string> + <string name="verification_emoji_hourglass">Zandloper</string> + <string name="verification_emoji_clock">Wekker</string> + <string name="verification_emoji_gift">Geschenk</string> + <string name="verification_emoji_light_bulb">Gloeilamp</string> + <string name="verification_emoji_book">Boek</string> + <string name="verification_emoji_pencil">Potlood</string> + <string name="verification_emoji_paperclip">Papierklemmetje</string> + <string name="verification_emoji_scissors">Schaar</string> + <string name="verification_emoji_lock">Slot</string> + <string name="verification_emoji_key">Sleutel</string> + <string name="verification_emoji_hammer">Hamer</string> + <string name="verification_emoji_telephone">Telefoon</string> + <string name="verification_emoji_flag">Vlag</string> + <string name="verification_emoji_train">Trein</string> + <string name="verification_emoji_bicycle">Fiets</string> + <string name="verification_emoji_aeroplane">Vliegtuig</string> + <string name="verification_emoji_rocket">Raket</string> + <string name="verification_emoji_trophy">Trofee</string> + <string name="verification_emoji_ball">Bal</string> + <string name="verification_emoji_guitar">Gitaar</string> + <string name="verification_emoji_trumpet">Trompet</string> + <string name="verification_emoji_bell">Bel</string> + <string name="verification_emoji_anchor">Anker</string> + <string name="verification_emoji_headphones">Koptelefoon</string> + <string name="verification_emoji_folder">Map</string> + <string name="verification_emoji_pin">Duimspijker</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-nn/strings.xml b/matrix-sdk-android/src/main/res/values-nn/strings.xml index 601cf4c9df01185f96ac7291cd453a31b5302ec7..d986e697ad6c981e3c345b369f95dba593f52ce1 100644 --- a/matrix-sdk-android/src/main/res/values-nn/strings.xml +++ b/matrix-sdk-android/src/main/res/values-nn/strings.xml @@ -77,70 +77,6 @@ <string name="notice_event_redacted_by">%1$s strauk meldingi</string> <string name="notice_event_redacted_with_reason">Meldingi vart stroki [av di: %1$s]</string> <string name="notice_event_redacted_by_with_reason">%1$s strauk meldingi [av di: %2$s]</string> - <string name="verification_emoji_dog">Hund</string> - <string name="verification_emoji_cat">Katt</string> - <string name="verification_emoji_lion">Løva</string> - <string name="verification_emoji_horse">Hest</string> - <string name="verification_emoji_unicorn">Einhyrning</string> - <string name="verification_emoji_pig">Gris</string> - <string name="verification_emoji_elephant">Elefant</string> - <string name="verification_emoji_rabbit">Hare</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Hane</string> - <string name="verification_emoji_penguin">Pingvin</string> - <string name="verification_emoji_turtle">Skjoldpadda</string> - <string name="verification_emoji_fish">Fisk</string> - <string name="verification_emoji_octopus">Blekksprut</string> - <string name="verification_emoji_butterfly">Fivrelde</string> - <string name="verification_emoji_flower">Blome</string> - <string name="verification_emoji_tree">Tre</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Sopp</string> - <string name="verification_emoji_globe">Klote</string> - <string name="verification_emoji_moon">MÃ¥ne</string> - <string name="verification_emoji_cloud">Sky</string> - <string name="verification_emoji_fire">Eld</string> - <string name="verification_emoji_banana">Banan</string> - <string name="verification_emoji_apple">Eple</string> - <string name="verification_emoji_strawberry">Jordbær</string> - <string name="verification_emoji_corn">Mais</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Kaka</string> - <string name="verification_emoji_heart">Hjarta</string> - <string name="verification_emoji_smiley">Smilandlit</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Hatt</string> - <string name="verification_emoji_glasses">Brillor</string> - <string name="verification_emoji_wrench">Skiftenykel</string> - <string name="verification_emoji_santa">Nissen</string> - <string name="verification_emoji_thumbsup">Tumalen Upp</string> - <string name="verification_emoji_umbrella">Regnskjold</string> - <string name="verification_emoji_hourglass">Timeglas</string> - <string name="verification_emoji_clock">Ur</string> - <string name="verification_emoji_gift">GÃ¥va</string> - <string name="verification_emoji_lightbulb">Ljospera</string> - <string name="verification_emoji_book">Bok</string> - <string name="verification_emoji_pencil">Blyant</string> - <string name="verification_emoji_paperclip">Binders</string> - <string name="verification_emoji_scissors">Saks</string> - <string name="verification_emoji_lock">LÃ¥s</string> - <string name="verification_emoji_key">Nykel</string> - <string name="verification_emoji_hammer">Hamar</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Flagg</string> - <string name="verification_emoji_train">Tog</string> - <string name="verification_emoji_bicycle">Sykkel</string> - <string name="verification_emoji_airplane">Flyg</string> - <string name="verification_emoji_rocket">Rakett</string> - <string name="verification_emoji_trophy">Pokal</string> - <string name="verification_emoji_ball">Ball</string> - <string name="verification_emoji_guitar">Gitar</string> - <string name="verification_emoji_trumpet">Trompet</string> - <string name="verification_emoji_bell">Klokka</string> - <string name="verification_emoji_anchor">Ankar</string> - <string name="verification_emoji_headphone">Hodetelefon</string> - <string name="verification_emoji_folder">Mappa</string> - <string name="verification_emoji_pin">NÃ¥l</string> <string name="notice_room_update">%s oppgraderte rommet.</string> diff --git a/matrix-sdk-android/src/main/res/values-pl/strings.xml b/matrix-sdk-android/src/main/res/values-pl/strings.xml index dc380516b75e7ab6aa6ebae1a6131b1eb00d5ade..0d79edc658242cb1bd9586039185a3ef35ad0219 100644 --- a/matrix-sdk-android/src/main/res/values-pl/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pl/strings.xml @@ -79,73 +79,8 @@ <string name="notice_event_redacted_by">Wiadomość usuniÄ™ta przez %1$s</string> <string name="notice_event_redacted_with_reason">Wiadomość usuniÄ™ta [powód: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Wiadomość usuniÄ™ta przez %1$s [powód: %2$s]</string> - <string name="verification_emoji_dog">Pies</string> - <string name="verification_emoji_cat">Kot</string> - <string name="verification_emoji_lion">Lew</string> - <string name="verification_emoji_horse">KoÅ„</string> - <string name="verification_emoji_unicorn">Jednorożec</string> - <string name="verification_emoji_pig">Åšwinia</string> - <string name="verification_emoji_elephant">SÅ‚oÅ„</string> - <string name="verification_emoji_rabbit">Królik</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Kogut</string> - <string name="verification_emoji_penguin">Pingwin</string> - <string name="verification_emoji_turtle">Żółw</string> - <string name="verification_emoji_fish">Ryba</string> - <string name="verification_emoji_octopus">OÅ›miornica</string> - <string name="verification_emoji_butterfly">Motyl</string> - <string name="verification_emoji_flower">Kwiat</string> - <string name="verification_emoji_tree">Drzewo</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Grzyb</string> - <string name="verification_emoji_moon">Księżyc</string> - <string name="verification_emoji_cloud">Chmura</string> - <string name="verification_emoji_fire">OgieÅ„</string> - <string name="verification_emoji_banana">Banan</string> - <string name="verification_emoji_apple">JabÅ‚ko</string> - <string name="verification_emoji_strawberry">Truskawka</string> - <string name="verification_emoji_corn">Kukurydza</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Ciasto</string> - <string name="verification_emoji_heart">Serce</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Kapelusz</string> - <string name="verification_emoji_glasses">Okulary</string> - <string name="verification_emoji_umbrella">Parasol</string> - <string name="verification_emoji_hourglass">Klepsydra</string> - <string name="verification_emoji_clock">Zegar</string> - <string name="verification_emoji_lightbulb">Å»arówka</string> - <string name="verification_emoji_book">Książka</string> - <string name="verification_emoji_pencil">Ołówek</string> - <string name="verification_emoji_paperclip">Spinacz</string> - <string name="verification_emoji_scissors">Nożyczki</string> - <string name="verification_emoji_key">Klucz</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Flaga</string> - <string name="verification_emoji_train">PociÄ…g</string> - <string name="verification_emoji_bicycle">Rower</string> - <string name="verification_emoji_airplane">Samolot</string> - <string name="verification_emoji_rocket">Rakieta</string> - <string name="verification_emoji_trophy">Trofeum</string> - <string name="verification_emoji_guitar">Gitara</string> - <string name="verification_emoji_trumpet">TrÄ…bka</string> - <string name="verification_emoji_bell">Dzwonek</string> - <string name="verification_emoji_anchor">Kotwica</string> - <string name="verification_emoji_headphone">SÅ‚uchawki</string> - <string name="verification_emoji_folder">Folder</string> - <string name="verification_emoji_pin">Pinezka</string> - - <string name="verification_emoji_globe">Ziemia</string> - <string name="verification_emoji_smiley">UÅ›miech</string> - <string name="verification_emoji_wrench">Klucz francuski</string> - <string name="verification_emoji_santa">MikoÅ‚aj</string> - <string name="verification_emoji_gift">Prezent</string> - <string name="verification_emoji_hammer">MÅ‚otek</string> <string name="notice_room_update">%s zakutalizowaÅ‚(a) ten pokój.</string> - <string name="verification_emoji_thumbsup">Kciuk w górÄ™</string> - <string name="verification_emoji_lock">Zamek</string> - <string name="verification_emoji_ball">PiÅ‚ka</string> <string name="initial_sync_start_importing_account">Synchronizacja poczÄ…tkowa: \nImportowanie konta…</string> <string name="initial_sync_start_importing_account_crypto">Synchronizacja poczÄ…tkowa: diff --git a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml index e1b99506c87d44da57f922043f11a1cfe5162df6..2ba369b93ae34956ffbe6cd70abc344c6a833806 100644 --- a/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml +++ b/matrix-sdk-android/src/main/res/values-pt-rBR/strings.xml @@ -25,9 +25,9 @@ <string name="notice_answered_call">%s aceitou a chamada.</string> <string name="notice_ended_call">%s encerrou a chamada.</string> <string name="notice_made_future_room_visibility">%1$s deixou o histórico futuro da sala visÃvel para %2$s</string> - <string name="notice_room_visibility_invited">todos os membros da sala, a partir do momento em que foram convidados.</string> - <string name="notice_room_visibility_joined">todos os membros da sala, a partir do momento em que entraram nela.</string> - <string name="notice_room_visibility_shared">todos os membros da sala.</string> + <string name="notice_room_visibility_invited">todos os participantes da sala, a partir do momento em que foram convidados.</string> + <string name="notice_room_visibility_joined">todos os participantes da sala, a partir do momento em que entraram nela.</string> + <string name="notice_room_visibility_shared">todos os participantes da sala.</string> <string name="notice_room_visibility_world_readable">qualquer pessoa.</string> <string name="notice_room_visibility_unknown">desconhecido (%s).</string> <string name="notice_end_to_end">%1$s ativou a criptografia de ponta a ponta (%2$s)</string> @@ -124,10 +124,10 @@ <string name="notice_room_topic_removed_by_you">Você removeu a descrição da sala</string> <string name="notice_room_avatar_removed">%1$s removeu a foto da sala</string> <string name="notice_room_avatar_removed_by_you">Você removeu a foto da sala</string> - <string name="notice_event_redacted">Mensagem removida</string> - <string name="notice_event_redacted_by">Mensagem removida por %1$s</string> - <string name="notice_event_redacted_with_reason">Mensagem removida [motivo: %1$s]</string> - <string name="notice_event_redacted_by_with_reason">Mensagem removida por %1$s [motivo: %2$s]</string> + <string name="notice_event_redacted">Mensagem apagada</string> + <string name="notice_event_redacted_by">Mensagem apagada por %1$s</string> + <string name="notice_event_redacted_with_reason">Mensagem apagada [motivo: %1$s]</string> + <string name="notice_event_redacted_by_with_reason">Mensagem apagada por %1$s [motivo: %2$s]</string> <string name="notice_profile_change_redacted_by_you">Você atualizou o seu perfil %1$s</string> <string name="notice_room_third_party_invite_by_you">Você enviou um convite para %1$s entrar na sala</string> <string name="notice_room_third_party_revoked_invite">%1$s cancelou o convite a %2$s para entrar na sala</string> @@ -151,71 +151,6 @@ <string name="notice_power_level_changed">%1$s alterou o nÃvel de permissão de %2$s.</string> <string name="notice_power_level_diff">%1$s de %2$s para %3$s</string> - <string name="verification_emoji_dog">Cachorro</string> - <string name="verification_emoji_cat">Gato</string> - <string name="verification_emoji_lion">Leão</string> - <string name="verification_emoji_horse">Cavalo</string> - <string name="verification_emoji_unicorn">Unicórnio</string> - <string name="verification_emoji_pig">Porco</string> - <string name="verification_emoji_elephant">Elefante</string> - <string name="verification_emoji_rabbit">Coelho</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Galo</string> - <string name="verification_emoji_penguin">Pinguim</string> - <string name="verification_emoji_turtle">Tartaruga</string> - <string name="verification_emoji_fish">Peixe</string> - <string name="verification_emoji_octopus">Polvo</string> - <string name="verification_emoji_butterfly">Borboleta</string> - <string name="verification_emoji_flower">Flor</string> - <string name="verification_emoji_tree">Ãrvore</string> - <string name="verification_emoji_cactus">Cacto</string> - <string name="verification_emoji_mushroom">Cogumelo</string> - <string name="verification_emoji_globe">Globo</string> - <string name="verification_emoji_moon">Lua</string> - <string name="verification_emoji_cloud">Nuvem</string> - <string name="verification_emoji_fire">Fogo</string> - <string name="verification_emoji_banana">Banana</string> - <string name="verification_emoji_apple">Maçã</string> - <string name="verification_emoji_strawberry">Morango</string> - <string name="verification_emoji_corn">Milho</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Bolo</string> - <string name="verification_emoji_heart">Coração</string> - <string name="verification_emoji_smiley">Sorriso</string> - <string name="verification_emoji_robot">Robô</string> - <string name="verification_emoji_hat">Chapéu</string> - <string name="verification_emoji_glasses">Óculos</string> - <string name="verification_emoji_wrench">Chave inglesa</string> - <string name="verification_emoji_santa">Papai-noel</string> - <string name="verification_emoji_thumbsup">Joinha</string> - <string name="verification_emoji_umbrella">Guarda-chuva</string> - <string name="verification_emoji_hourglass">Ampulheta</string> - <string name="verification_emoji_clock">Relógio</string> - <string name="verification_emoji_gift">Presente</string> - <string name="verification_emoji_lightbulb">Lâmpada</string> - <string name="verification_emoji_book">Livro</string> - <string name="verification_emoji_pencil">Lápis</string> - <string name="verification_emoji_paperclip">Clipe de papel</string> - <string name="verification_emoji_scissors">Tesoura</string> - <string name="verification_emoji_lock">Cadeado</string> - <string name="verification_emoji_key">Chave</string> - <string name="verification_emoji_hammer">Martelo</string> - <string name="verification_emoji_telephone">Telefone</string> - <string name="verification_emoji_flag">Bandeira</string> - <string name="verification_emoji_train">Trem</string> - <string name="verification_emoji_bicycle">Bicicleta</string> - <string name="verification_emoji_airplane">Avião</string> - <string name="verification_emoji_rocket">Foguete</string> - <string name="verification_emoji_trophy">Troféu</string> - <string name="verification_emoji_ball">Bola</string> - <string name="verification_emoji_guitar">Guitarra</string> - <string name="verification_emoji_trumpet">Trombeta</string> - <string name="verification_emoji_bell">Sino</string> - <string name="verification_emoji_anchor">Âncora</string> - <string name="verification_emoji_headphone">Fones de ouvido</string> - <string name="verification_emoji_folder">Pasta</string> - <string name="verification_emoji_pin">Alfinete</string> - <string name="initial_sync_start_importing_account">Primeira sincronização:↵ \nImportando a conta…</string> <string name="initial_sync_start_importing_account_crypto">Primeira sincronização:↵ @@ -302,8 +237,4 @@ <string name="key_verification_request_fallback_message">%s deseja confirmar a sua chave, mas o seu aplicativo não suporta a confirmação da chave da conversa. Você precisará usar a confirmação tradicional de chaves para confirmar chaves.</string> - <string name="call_notification_answer">Aceitar</string> - <string name="call_notification_reject">Recusar</string> - <string name="call_notification_hangup">Encerrar</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-ru/strings.xml b/matrix-sdk-android/src/main/res/values-ru/strings.xml index 1657d80f1c1369a3370c5c37e513974827768681..a4d752782ed8b84bd159b448df62eb011fd67e4c 100644 --- a/matrix-sdk-android/src/main/res/values-ru/strings.xml +++ b/matrix-sdk-android/src/main/res/values-ru/strings.xml @@ -91,70 +91,6 @@ <string name="notice_event_redacted_by">%1$s удалил(а) Ñообщение</string> <string name="notice_event_redacted_with_reason">Сообщение удалено [причина: %1$s]</string> <string name="notice_event_redacted_by_with_reason">%1$s удалил(а) Ñообщение [причина: %2$s]</string> - <string name="verification_emoji_dog">Собака</string> - <string name="verification_emoji_cat">Кошка</string> - <string name="verification_emoji_lion">Лев</string> - <string name="verification_emoji_horse">Лошадь</string> - <string name="verification_emoji_unicorn">Единорог</string> - <string name="verification_emoji_pig">ПороÑёнок</string> - <string name="verification_emoji_elephant">Слон</string> - <string name="verification_emoji_rabbit">Кролик</string> - <string name="verification_emoji_panda">Панда</string> - <string name="verification_emoji_rooster">Петух</string> - <string name="verification_emoji_penguin">Пингвин</string> - <string name="verification_emoji_turtle">Черепаха</string> - <string name="verification_emoji_fish">Рыба</string> - <string name="verification_emoji_octopus">ОÑьминог</string> - <string name="verification_emoji_butterfly">Бабочка</string> - <string name="verification_emoji_flower">Цветок</string> - <string name="verification_emoji_tree">Дерево</string> - <string name="verification_emoji_cactus">КактуÑ</string> - <string name="verification_emoji_mushroom">Гриб</string> - <string name="verification_emoji_globe">ЗемлÑ</string> - <string name="verification_emoji_moon">Луна</string> - <string name="verification_emoji_cloud">Облако</string> - <string name="verification_emoji_fire">Огонь</string> - <string name="verification_emoji_banana">Банан</string> - <string name="verification_emoji_apple">Яблоко</string> - <string name="verification_emoji_strawberry">Клубника</string> - <string name="verification_emoji_corn">Кукуруза</string> - <string name="verification_emoji_pizza">Пицца</string> - <string name="verification_emoji_cake">Пирожное</string> - <string name="verification_emoji_heart">Сердце</string> - <string name="verification_emoji_smiley">Смайлик</string> - <string name="verification_emoji_robot">Робот</string> - <string name="verification_emoji_hat">ШлÑпа</string> - <string name="verification_emoji_glasses">Очки</string> - <string name="verification_emoji_wrench">Гаечный ключ</string> - <string name="verification_emoji_santa">Санта</string> - <string name="verification_emoji_thumbsup">Большой палец вверх</string> - <string name="verification_emoji_umbrella">Зонтик</string> - <string name="verification_emoji_hourglass">ПеÑочные чаÑÑ‹</string> - <string name="verification_emoji_clock">ЧаÑÑ‹</string> - <string name="verification_emoji_gift">Подарок</string> - <string name="verification_emoji_lightbulb">Лампочка</string> - <string name="verification_emoji_book">Книга</string> - <string name="verification_emoji_pencil">Карандаш</string> - <string name="verification_emoji_paperclip">Скрепка Ð´Ð»Ñ Ð±ÑƒÐ¼Ð°Ð³</string> - <string name="verification_emoji_scissors">Ðожницы</string> - <string name="verification_emoji_lock">Замок</string> - <string name="verification_emoji_key">Ключ</string> - <string name="verification_emoji_hammer">Молоток</string> - <string name="verification_emoji_telephone">Телефон</string> - <string name="verification_emoji_flag">Флаг</string> - <string name="verification_emoji_train">Поезд</string> - <string name="verification_emoji_bicycle">ВелоÑипед</string> - <string name="verification_emoji_airplane">Самолёт</string> - <string name="verification_emoji_rocket">Ракета</string> - <string name="verification_emoji_trophy">Трофей</string> - <string name="verification_emoji_ball">ÐœÑч</string> - <string name="verification_emoji_guitar">Гитара</string> - <string name="verification_emoji_trumpet">Труба</string> - <string name="verification_emoji_bell">Колокол</string> - <string name="verification_emoji_anchor">Якорь</string> - <string name="verification_emoji_headphone">Ðаушники</string> - <string name="verification_emoji_folder">Папка</string> - <string name="verification_emoji_pin">Булавка</string> <string name="initial_sync_start_importing_account">ÐÐ°Ñ‡Ð°Ð»ÑŒÐ½Ð°Ñ ÑинхронизациÑ: \nИмпорт учетной запиÑи…</string> @@ -313,8 +249,5 @@ <string name="notice_call_candidates_by_you">Ð’Ñ‹ отправили данные Ð´Ð»Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° звонка.</string> <string name="notice_room_avatar_removed">%1$s удалил(а) аватар комнаты</string> <string name="notice_room_avatar_removed_by_you">Ð’Ñ‹ удалили аватар комнаты</string> - <string name="call_notification_answer">ПринÑÑ‚ÑŒ</string> - <string name="call_notification_reject">Отклонить</string> - <string name="call_notification_hangup">Завершить звонок</string> </resources> diff --git a/matrix-sdk-android/src/main/res/values-ru/strings_sas.xml b/matrix-sdk-android/src/main/res/values-ru/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..f60d7026b64f77b5bab1892f6f16ff794ae5a803 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-ru/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Собака</string> + <string name="verification_emoji_cat">Кошка</string> + <string name="verification_emoji_lion">Лев</string> + <string name="verification_emoji_horse">Лошадь</string> + <string name="verification_emoji_unicorn">Единорог</string> + <string name="verification_emoji_pig">СвиньÑ</string> + <string name="verification_emoji_elephant">Слон</string> + <string name="verification_emoji_rabbit">Кролик</string> + <string name="verification_emoji_panda">Панда</string> + <string name="verification_emoji_rooster">Петух</string> + <string name="verification_emoji_penguin">Пингвин</string> + <string name="verification_emoji_turtle">Черепаха</string> + <string name="verification_emoji_fish">Рыба</string> + <string name="verification_emoji_octopus">ОÑьминог</string> + <string name="verification_emoji_butterfly">Бабочка</string> + <string name="verification_emoji_flower">Цветок</string> + <string name="verification_emoji_tree">Дерево</string> + <string name="verification_emoji_cactus">КактуÑ</string> + <string name="verification_emoji_mushroom">Гриб</string> + <string name="verification_emoji_globe">ГлобуÑ</string> + <string name="verification_emoji_moon">Луна</string> + <string name="verification_emoji_cloud">Облако</string> + <string name="verification_emoji_fire">Огонь</string> + <string name="verification_emoji_banana">Банан</string> + <string name="verification_emoji_apple">Яблоко</string> + <string name="verification_emoji_strawberry">Клубника</string> + <string name="verification_emoji_corn">Кукуруза</string> + <string name="verification_emoji_pizza">Пицца</string> + <string name="verification_emoji_cake">Торт</string> + <string name="verification_emoji_heart">Сердце</string> + <string name="verification_emoji_smiley">Улыбка</string> + <string name="verification_emoji_robot">Робот</string> + <string name="verification_emoji_hat">ШлÑпа</string> + <string name="verification_emoji_glasses">Очки</string> + <string name="verification_emoji_spanner">Ключ</string> + <string name="verification_emoji_santa">Санта</string> + <string name="verification_emoji_thumbs_up">Большой палец вверх</string> + <string name="verification_emoji_umbrella">Зонт</string> + <string name="verification_emoji_hourglass">ПеÑочные чаÑÑ‹</string> + <string name="verification_emoji_clock">ЧаÑÑ‹</string> + <string name="verification_emoji_gift">Подарок</string> + <string name="verification_emoji_light_bulb">Лампочка</string> + <string name="verification_emoji_book">Книга</string> + <string name="verification_emoji_pencil">Карандаш</string> + <string name="verification_emoji_paperclip">Скрепка</string> + <string name="verification_emoji_scissors">Ðожницы</string> + <string name="verification_emoji_lock">Замок</string> + <string name="verification_emoji_key">Ключ</string> + <string name="verification_emoji_hammer">Молоток</string> + <string name="verification_emoji_telephone">Телефон</string> + <string name="verification_emoji_flag">Флаг</string> + <string name="verification_emoji_train">Поезд</string> + <string name="verification_emoji_bicycle">ВелоÑипед</string> + <string name="verification_emoji_aeroplane">Самолет</string> + <string name="verification_emoji_rocket">Ракета</string> + <string name="verification_emoji_trophy">Кубок</string> + <string name="verification_emoji_ball">ÐœÑч</string> + <string name="verification_emoji_guitar">Гитара</string> + <string name="verification_emoji_trumpet">Труба</string> + <string name="verification_emoji_bell">Колокол</string> + <string name="verification_emoji_anchor">Якорь</string> + <string name="verification_emoji_headphones">Ðаушники</string> + <string name="verification_emoji_folder">Папка</string> + <string name="verification_emoji_pin">Булавка</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-sk/strings.xml b/matrix-sdk-android/src/main/res/values-sk/strings.xml index 70e3a6ebd0c376f2c41121bd09592e7a57b1d987..da869eacc2da8893d06845139be78b51be54e23b 100644 --- a/matrix-sdk-android/src/main/res/values-sk/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sk/strings.xml @@ -81,70 +81,6 @@ <string name="notice_event_redacted_by">Odstránená správa použÃvateľom %1$s</string> <string name="notice_event_redacted_with_reason">Odstránená správa [dôvod: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Odstránená správa použÃvateľom %1$s [dôvod: %2$s]</string> - <string name="verification_emoji_dog">Hlava psa</string> - <string name="verification_emoji_cat">Hlava maÄky</string> - <string name="verification_emoji_lion">Hlava leva</string> - <string name="verification_emoji_horse">Kôň</string> - <string name="verification_emoji_unicorn">Hlava jednorožca</string> - <string name="verification_emoji_pig">Hlava prasaÅ¥a</string> - <string name="verification_emoji_elephant">Slon</string> - <string name="verification_emoji_rabbit">Hlava zajaca</string> - <string name="verification_emoji_panda">Hlava pandy</string> - <string name="verification_emoji_rooster">Kohút</string> - <string name="verification_emoji_penguin">TuÄniak</string> - <string name="verification_emoji_turtle">KorytnaÄka</string> - <string name="verification_emoji_fish">Ryba</string> - <string name="verification_emoji_octopus">Chobotnica</string> - <string name="verification_emoji_butterfly">Motýľ</string> - <string name="verification_emoji_flower">Tulipán</string> - <string name="verification_emoji_tree">Listnatý strom</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Huba</string> - <string name="verification_emoji_globe">Zemeguľa</string> - <string name="verification_emoji_moon">Polmesiac</string> - <string name="verification_emoji_cloud">Oblak</string> - <string name="verification_emoji_fire">Oheň</string> - <string name="verification_emoji_banana">Banán</string> - <string name="verification_emoji_apple">ÄŒervené jablko</string> - <string name="verification_emoji_strawberry">Jahoda</string> - <string name="verification_emoji_corn">KukuriÄný klas</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Narodeninová torta</string> - <string name="verification_emoji_heart">ÄŒervené srdce</string> - <string name="verification_emoji_smiley">Å keriaca sa tvár</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Cylinder</string> - <string name="verification_emoji_glasses">Okuliare</string> - <string name="verification_emoji_wrench">Francúzsky kľúÄ</string> - <string name="verification_emoji_santa">Santa Claus</string> - <string name="verification_emoji_thumbsup">Palec nahor</string> - <string name="verification_emoji_umbrella">Dáždnik</string> - <string name="verification_emoji_hourglass">Presýpacie hodiny</string> - <string name="verification_emoji_clock">BudÃk</string> - <string name="verification_emoji_gift">Zabalený darÄek</string> - <string name="verification_emoji_lightbulb">Žiarovka</string> - <string name="verification_emoji_book">Zatvorená kniha</string> - <string name="verification_emoji_pencil">Ceruzka</string> - <string name="verification_emoji_paperclip">Sponka na papier</string> - <string name="verification_emoji_scissors">Nožnice</string> - <string name="verification_emoji_lock">Zatvorená zámka</string> - <string name="verification_emoji_key">KľúÄ</string> - <string name="verification_emoji_hammer">Kladivo</string> - <string name="verification_emoji_telephone">Telefón</string> - <string name="verification_emoji_flag">Kockovaná zástava</string> - <string name="verification_emoji_train">RuÅ¡eň</string> - <string name="verification_emoji_bicycle">Bicykel</string> - <string name="verification_emoji_airplane">Lietadlo</string> - <string name="verification_emoji_rocket">Raketa</string> - <string name="verification_emoji_trophy">Trofej</string> - <string name="verification_emoji_ball">Futbal</string> - <string name="verification_emoji_guitar">Gitara</string> - <string name="verification_emoji_trumpet">Trúbka</string> - <string name="verification_emoji_bell">Zvon</string> - <string name="verification_emoji_anchor">Kotva</string> - <string name="verification_emoji_headphone">Slúchadlá</string> - <string name="verification_emoji_folder">Fascikel</string> - <string name="verification_emoji_pin">Å pendlÃk</string> <string name="initial_sync_start_importing_account">Úvodná synchronizácia: \nPrebieha import úÄtu…</string> @@ -299,8 +235,4 @@ <string name="key_verification_request_fallback_message">%s požaduje overenie vaÅ¡ich Å¡ifrovacÃch kľúÄov, ale váš klient nepodporuje overenie kľúÄov v konverzácii. Budete musieÅ¥ použiÅ¥ zastaralú metódu overenia.</string> - <string name="call_notification_answer">PrijaÅ¥</string> - <string name="call_notification_reject">OdmietnuÅ¥</string> - <string name="call_notification_hangup">ZavesiÅ¥</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-sk/strings_sas.xml b/matrix-sdk-android/src/main/res/values-sk/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..72fd9cc2a3967036ca911dc4cdb89fc80af2f15c --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-sk/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hlava psa</string> + <string name="verification_emoji_cat">Hlava maÄky</string> + <string name="verification_emoji_lion">Hlava leva</string> + <string name="verification_emoji_horse">Kôň</string> + <string name="verification_emoji_unicorn">Hlava jednorožca</string> + <string name="verification_emoji_pig">Hlava prasaÅ¥a</string> + <string name="verification_emoji_elephant">Slon</string> + <string name="verification_emoji_rabbit">Hlava zajaca</string> + <string name="verification_emoji_panda">Hlava pandy</string> + <string name="verification_emoji_rooster">Kohút</string> + <string name="verification_emoji_penguin">TuÄniak</string> + <string name="verification_emoji_turtle">KorytnaÄka</string> + <string name="verification_emoji_fish">Ryba</string> + <string name="verification_emoji_octopus">Chobotnica</string> + <string name="verification_emoji_butterfly">Motýľ</string> + <string name="verification_emoji_flower">Tulipán</string> + <string name="verification_emoji_tree">Listnatý strom</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Huba</string> + <string name="verification_emoji_globe">Zemeguľa</string> + <string name="verification_emoji_moon">Polmesiac</string> + <string name="verification_emoji_cloud">Oblak</string> + <string name="verification_emoji_fire">Oheň</string> + <string name="verification_emoji_banana">Banán</string> + <string name="verification_emoji_apple">ÄŒervené jablko</string> + <string name="verification_emoji_strawberry">Jahoda</string> + <string name="verification_emoji_corn">KukuriÄný klas</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Narodeninová torta</string> + <string name="verification_emoji_heart">Äervené srdce</string> + <string name="verification_emoji_smiley">Å keriaca sa tvár</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Cilinder</string> + <string name="verification_emoji_glasses">Okuliare</string> + <string name="verification_emoji_spanner">Francúzsky kľúÄ</string> + <string name="verification_emoji_santa">Santa Claus</string> + <string name="verification_emoji_thumbs_up">Palec nahor</string> + <string name="verification_emoji_umbrella">Dáždnik</string> + <string name="verification_emoji_hourglass">Presýpacie hodiny</string> + <string name="verification_emoji_clock">BudÃk</string> + <string name="verification_emoji_gift">Zabalený darÄek</string> + <string name="verification_emoji_light_bulb">Žiarovka</string> + <string name="verification_emoji_book">Zatvorená kniha</string> + <string name="verification_emoji_pencil">Ceruzka</string> + <string name="verification_emoji_paperclip">Sponka na papier</string> + <string name="verification_emoji_scissors">Nožnice</string> + <string name="verification_emoji_lock">Zatvorená zámka</string> + <string name="verification_emoji_key">KľúÄ</string> + <string name="verification_emoji_hammer">Kladivo</string> + <string name="verification_emoji_telephone">Telefón</string> + <string name="verification_emoji_flag">Kockovaná zástava</string> + <string name="verification_emoji_train">RuÅ¡eň</string> + <string name="verification_emoji_bicycle">Bicykel</string> + <string name="verification_emoji_aeroplane">Lietadlo</string> + <string name="verification_emoji_rocket">Raketa</string> + <string name="verification_emoji_trophy">Trofej</string> + <string name="verification_emoji_ball">Futbal</string> + <string name="verification_emoji_guitar">Gitara</string> + <string name="verification_emoji_trumpet">Trúbka</string> + <string name="verification_emoji_bell">Zvon</string> + <string name="verification_emoji_anchor">Kotva</string> + <string name="verification_emoji_headphones">Slúchadlá</string> + <string name="verification_emoji_folder">Fascikel</string> + <string name="verification_emoji_pin">Å pendlÃk</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-sq/strings.xml b/matrix-sdk-android/src/main/res/values-sq/strings.xml index e63e28288fb0835c304d3c13754b83f13b690618..14a7c61bbc878d8c040b771eb0bd20b71af8f17c 100644 --- a/matrix-sdk-android/src/main/res/values-sq/strings.xml +++ b/matrix-sdk-android/src/main/res/values-sq/strings.xml @@ -77,68 +77,6 @@ <string name="notice_event_redacted_by">Mesazhi u hoq nga %1$s</string> <string name="notice_event_redacted_with_reason">Mesazh i hequr [arsye: %1$s]</string> <string name="notice_event_redacted_by_with_reason">Mesazh i hequr nga %1$s [arsye: %2$s]</string> - <string name="verification_emoji_dog">Qen</string> - <string name="verification_emoji_cat">Mace</string> - <string name="verification_emoji_lion">Luan</string> - <string name="verification_emoji_horse">Kalë</string> - <string name="verification_emoji_unicorn">Njëbrirësh</string> - <string name="verification_emoji_pig">Derr</string> - <string name="verification_emoji_elephant">Elefant</string> - <string name="verification_emoji_rabbit">Lepur</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Këndes</string> - <string name="verification_emoji_penguin">Pinguin</string> - <string name="verification_emoji_turtle">Breshkë</string> - <string name="verification_emoji_fish">Peshk</string> - <string name="verification_emoji_octopus">Oktapod</string> - <string name="verification_emoji_butterfly">Flutur</string> - <string name="verification_emoji_flower">Lule</string> - <string name="verification_emoji_tree">Pemë</string> - <string name="verification_emoji_cactus">Kaktus</string> - <string name="verification_emoji_mushroom">Kërpudhë</string> - <string name="verification_emoji_globe">Rruzull</string> - <string name="verification_emoji_moon">Hëna</string> - <string name="verification_emoji_cloud">Re</string> - <string name="verification_emoji_fire">Zjarr</string> - <string name="verification_emoji_banana">Banane</string> - <string name="verification_emoji_apple">Mollë</string> - <string name="verification_emoji_strawberry">Luleshtrydhe</string> - <string name="verification_emoji_corn">Misër</string> - <string name="verification_emoji_pizza">Picë</string> - <string name="verification_emoji_cake">Tortë</string> - <string name="verification_emoji_heart">Zemër</string> - <string name="verification_emoji_smiley">Emotikon</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Kapë</string> - <string name="verification_emoji_glasses">Syze</string> - <string name="verification_emoji_wrench">Çelës</string> - <string name="verification_emoji_santa">Babagjyshi i Vitit të Ri</string> - <string name="verification_emoji_umbrella">Ombrellë</string> - <string name="verification_emoji_hourglass">Klepsidër</string> - <string name="verification_emoji_clock">Sahat</string> - <string name="verification_emoji_gift">Dhuratë</string> - <string name="verification_emoji_lightbulb">Llambë</string> - <string name="verification_emoji_book">Libër</string> - <string name="verification_emoji_pencil">Laps</string> - <string name="verification_emoji_paperclip">Kapëse</string> - <string name="verification_emoji_scissors">Gërshërë</string> - <string name="verification_emoji_lock">Dry</string> - <string name="verification_emoji_key">Kyç</string> - <string name="verification_emoji_hammer">Çekiç</string> - <string name="verification_emoji_telephone">Telefon</string> - <string name="verification_emoji_flag">Flamur</string> - <string name="verification_emoji_train">Tren</string> - <string name="verification_emoji_bicycle">Biçikletë</string> - <string name="verification_emoji_airplane">Aeroplan</string> - <string name="verification_emoji_rocket">Raketë</string> - <string name="verification_emoji_trophy">Trofe</string> - <string name="verification_emoji_ball">Top</string> - <string name="verification_emoji_guitar">Kitarë</string> - <string name="verification_emoji_trumpet">Trombë</string> - <string name="verification_emoji_bell">Kambanë</string> - <string name="verification_emoji_anchor">Spirancë</string> - <string name="verification_emoji_headphone">Kufje</string> - <string name="verification_emoji_folder">Dosje</string> <string name="notice_room_update">%s e përmirësoi këtë dhomë.</string> <string name="initial_sync_start_importing_account">Njëkohësimi Fillestar: @@ -200,6 +138,4 @@ <string name="key_verification_request_fallback_message">%s po kërkon të verifikojë kyçin tuaj, por klienti juaj nuk mbulon verifikim kyçesh brenda fjalosjeje. Që të verifikoni kyça, do t’ju duhet të përdorni verifikim të dikurshëm kyçesh.</string> <string name="notice_room_created">%1$s krijo dhomën</string> - <string name="verification_emoji_pin">Fiksoje</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-sv/strings.xml b/matrix-sdk-android/src/main/res/values-sv/strings.xml new file mode 100644 index 0000000000000000000000000000000000000000..491eb0bc49d50419cd0d857056ce8cefa2ba3278 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-sv/strings.xml @@ -0,0 +1,224 @@ +<?xml version='1.0' encoding='UTF-8'?> +<resources> + <string name="summary_message">%1$s: %2$s</string> + <string name="summary_user_sent_image">%1$s skickade en bild.</string> + <string name="summary_you_sent_image">Du skickade en bild.</string> + <string name="summary_user_sent_sticker">%1$s skickade en dekal.</string> + <string name="summary_you_sent_sticker">Du skickade en dekal.</string> + + <string name="notice_room_invite_no_invitee">Inbjudan frÃ¥n %s</string> + <string name="notice_room_invite_no_invitee_by_you">Inbjudan frÃ¥n dig</string> + <string name="notice_room_created">%1$s skapade rummet</string> + <string name="notice_room_created_by_you">Du skapade rummet</string> + <string name="notice_room_invite">%1$s bjöd in %2$s</string> + <string name="notice_room_invite_by_you">Du bjöd in %1$s</string> + <string name="notice_room_invite_you">%1$s bjöd in dig</string> + <string name="notice_room_join">%1$s gick med i rummet</string> + <string name="notice_room_join_by_you">Du gick med i rummet</string> + <string name="notice_room_leave">%1$s lämnade rummet</string> + <string name="notice_room_leave_by_you">Du lämnade rummet</string> + <string name="notice_room_reject">%1$s avböjde inbjudan</string> + <string name="notice_room_reject_by_you">Du avböjde inbjudan</string> + <string name="notice_room_kick">%1$s kickade %2$s</string> + <string name="notice_room_kick_by_you">Du kickade %1$s</string> + <string name="notice_room_unban">%1$s avbannade %2$s</string> + <string name="notice_room_unban_by_you">Du avbannade %1$s</string> + <string name="notice_room_ban">%1$s avbannade %2$s</string> + <string name="notice_room_ban_by_you">Du bannade %1$s</string> + <string name="notice_room_withdraw">%1$s drog tillbaka inbjudan för %2$s</string> + <string name="notice_room_withdraw_by_you">Du drog tillbaka inbjudan för %1$s</string> + <string name="notice_avatar_url_changed">%1$s ändrade sin avatar</string> + <string name="notice_avatar_url_changed_by_you">Du ändrade din avatar</string> + <string name="notice_display_name_set">%1$s satte sitt visningsnamn till %2$s</string> + <string name="notice_display_name_set_by_you">Du satte ditt visningsnamn till %1$s</string> + <string name="notice_display_name_changed_from">%1$s bytte sitt visningsnamn frÃ¥n %2$s till %3$s</string> + <string name="notice_display_name_changed_from_by_you">Du bytte ditt visningsnamn frÃ¥n %1$s till %2$s</string> + <string name="notice_display_name_removed">%1$s tog bort sitt visningsnamn (det var %2$s)</string> + <string name="notice_display_name_removed_by_you">Du tog bort ditt visningsnamn (det var %1$s)</string> + <string name="notice_room_topic_changed">%1$s bytte ämnet till: %2$s</string> + <string name="notice_room_topic_changed_by_you">Du bytte ämnet till: %1$s</string> + <string name="notice_room_avatar_changed">%1$s bytte rummets avatar</string> + <string name="notice_room_avatar_changed_by_you">Du bytte rummets avatar</string> + <string name="notice_room_name_changed">%1$s bytte rummets namn till: %2$s</string> + <string name="notice_room_name_changed_by_you">Du bytte rummets namnet till: %1$s</string> + <string name="notice_placed_video_call">%s startade ett videosamtal.</string> + <string name="notice_placed_video_call_by_you">Du startade ett videosamtal.</string> + <string name="notice_placed_voice_call">%s startade ett röstsamtal.</string> + <string name="notice_placed_voice_call_by_you">Du startade ett röstsamtal.</string> + <string name="notice_call_candidates">%s skickade data för att sätta upp samtalet.</string> + <string name="notice_call_candidates_by_you">Du skickade data för att sätta upp samtalet.</string> + <string name="notice_answered_call">%s svarade pÃ¥ samtalet.</string> + <string name="notice_answered_call_by_you">Du svarade pÃ¥ samtalet.</string> + <string name="notice_ended_call">%s avslutade samtalet.</string> + <string name="notice_ended_call_by_you">Du avslutade samtalet.</string> + <string name="notice_made_future_room_visibility">%1$s gjorde framtida rumshistorik synlig för %2$s</string> + <string name="notice_made_future_room_visibility_by_you">Du gjorde framtida rumshistorik synlig för %1$s</string> + <string name="notice_room_visibility_invited">alla rumsmedlemmar, frÃ¥n tiden de bjöds in.</string> + <string name="notice_room_visibility_joined">alla rumsmedlemmar, frÃ¥n tiden de gick med.</string> + <string name="notice_room_visibility_shared">alla rumsmedlemmar.</string> + <string name="notice_room_visibility_world_readable">vem som helst.</string> + <string name="notice_room_visibility_unknown">okänt (%s).</string> + <string name="notice_end_to_end">%1$s aktiverade totalsträckskryptering (%2$s)</string> + <string name="notice_end_to_end_by_you">Du aktiverade totalsträckskryptering (%1$s)</string> + <string name="notice_room_update">%s uppgraderade det här rummet.</string> + <string name="notice_room_update_by_you">Du uppgraderade det här rummet.</string> + + <string name="notice_requested_voip_conference">%1$s begärde ett VoIP-gruppsamtal</string> + <string name="notice_requested_voip_conference_by_you">Du begärde ett VoIP-gruppsamtal</string> + <string name="notice_voip_started">VoIP-gruppsamtal startat</string> + <string name="notice_voip_finished">VoIP-gruppsamtal avslutat</string> + + <string name="notice_avatar_changed_too">(avataren blev även bytt)</string> + <string name="notice_room_name_removed">%1$s tog bort rummets namn</string> + <string name="notice_room_name_removed_by_you">Du tog bort rummets namn</string> + <string name="notice_room_topic_removed">%1$s tog bort rummets ämne</string> + <string name="notice_room_topic_removed_by_you">Du tog bort rummets ämne</string> + <string name="notice_room_avatar_removed">%1$s tog bort rummets avatar</string> + <string name="notice_room_avatar_removed_by_you">Du tog bort rummets avatar</string> + <string name="notice_event_redacted">Meddelande borttaget</string> + <string name="notice_event_redacted_by">Meddelande borttaget av %1$s</string> + <string name="notice_event_redacted_with_reason">Meddelande borttaget [anledning: %1$s]</string> + <string name="notice_event_redacted_by_with_reason">Meddelande borttaget av %1$s [anledning: %2$s]</string> + <string name="notice_profile_change_redacted">%1$s uppdaterade sim profil %2$s</string> + <string name="notice_profile_change_redacted_by_you">Du uppdaterade din profil %1$s</string> + <string name="notice_room_third_party_invite">%1$s bjöd in %2$s att gÃ¥ med i rummet</string> + <string name="notice_room_third_party_invite_by_you">Du bjöd in %1$s att gÃ¥ med i rummet</string> + <string name="notice_room_third_party_revoked_invite">%1$s drog tillbaka inbjudan för %2$s att gÃ¥ med i rummet</string> + <string name="notice_room_third_party_revoked_invite_by_you">Du drog tillbaka inbjudan för %1$s att gÃ¥ med i rummet</string> + <string name="notice_room_third_party_registered_invite">%1$s accepterade inbjudan för %2$s</string> + <string name="notice_room_third_party_registered_invite_by_you">Du accepterade inbjudan för %1$s</string> + + <string name="notice_widget_added">%1$s lade till %2$s-widget</string> + <string name="notice_widget_added_by_you">Du lade till %1$s-widget</string> + <string name="notice_widget_removed">%1$s tog bort %2$s-widget</string> + <string name="notice_widget_removed_by_you">Du tog bort %1$s-widget</string> + <string name="notice_widget_modified">%1$s modifierade %2$s-widget</string> + <string name="notice_widget_modified_by_you">Du modifierade %1$s-widget</string> + + <string name="power_level_admin">Admin</string> + <string name="power_level_moderator">Moderator</string> + <string name="power_level_default">Standard</string> + <string name="power_level_custom">Anpassad (%1$d)</string> + <string name="power_level_custom_no_value">Anpassad</string> + + <string name="notice_power_level_changed_by_you">Du ändrade behörighetsnivÃ¥ för %1$s.</string> + <string name="notice_power_level_changed">%1$s ändrade behörighetsnivÃ¥ för %2$s.</string> + <string name="notice_power_level_diff">%1$s frÃ¥n %2$s till %3$s</string> + + <string name="notice_crypto_unable_to_decrypt">** Kan inte avkryptera: %s **</string> + <string name="notice_crypto_error_unkwown_inbound_session_id">Avsändarens enhet har inte gett oss nycklarna för det här meddelandet.</string> + + <string name="could_not_redact">Kunde inte dölja</string> + <string name="unable_to_send_message">Kunde inte skicka meddelandet</string> + + <string name="message_failed_to_upload">Misslyckades att ladda upp bilden</string> + + <string name="network_error">Nätverksfel</string> + <string name="matrix_error">Matrixfel</string> + + <string name="room_error_join_failed_empty_room">Det gÃ¥r för närvarande inte att gÃ¥ med i ett tomt rum igen.</string> + + <string name="encrypted_message">Krypterat meddelande</string> + + <string name="medium_email">E-postadress</string> + <string name="medium_phone_number">Telefonnummer</string> + + <string name="room_displayname_invite_from">Inbjudan frÃ¥n %s</string> + <string name="room_displayname_room_invite">Rumsinbjudan</string> + + <string name="room_displayname_two_members">%1$s och %2$s</string> + + <plurals name="room_displayname_three_and_more_members"> + <item quantity="one">%1$s och en till</item> + <item quantity="other">%1$s och %2$d till</item> + </plurals> + + <string name="room_displayname_empty_room">Tomt rum</string> + + <string name="initial_sync_start_importing_account">Inledande synk: +\nImporterar konto…</string> + <string name="initial_sync_start_importing_account_crypto">Inledande synk: +\nImporterar krypto</string> + <string name="initial_sync_start_importing_account_rooms">Inledande synk: +\nImporterar rum</string> + <string name="initial_sync_start_importing_account_joined_rooms">Inledande synk: +\nImporterar anslutna rum</string> + <string name="initial_sync_start_importing_account_invited_rooms">Inledande synk: +\nImporterar inbjudna rum</string> + <string name="initial_sync_start_importing_account_left_rooms">Inledande synk: +\nImporterar lämnade rum</string> + <string name="initial_sync_start_importing_account_groups">Inledande synk: +\nImporterar gemenskaper</string> + <string name="initial_sync_start_importing_account_data">Inledande synk: +\nImporterar kontodata</string> + + <string name="event_status_sending_message">Skickar meddelande…</string> + <string name="clear_timeline_send_queue">Rensa sändningskö</string> + + <string name="notice_room_invite_no_invitee_with_reason">Inbjudan frÃ¥n %1$s. Anledning: %2$s</string> + <string name="notice_room_invite_no_invitee_with_reason_by_you">Inbjudan frÃ¥n dig. Anledning: %1$s</string> + <string name="notice_room_invite_with_reason">%1$s bjöd in %2$s. Anledning: %3$s</string> + <string name="notice_room_invite_with_reason_by_you">Du bjöd in %1$s. Anledning: %2$s</string> + <string name="notice_room_invite_you_with_reason">%1$s bjöd in dig. Anledning: %2$s</string> + <string name="notice_room_join_with_reason">%1$s gick med i rummet. Anledning: %2$s</string> + <string name="notice_room_join_with_reason_by_you">Du gick med i rummet. Anledning: %1$s</string> + <string name="notice_room_leave_with_reason">%1$s lämnade rummet. Anledning: %2$s</string> + <string name="notice_room_leave_with_reason_by_you">Du lämnade rummet. Anledning: %1$s</string> + <string name="notice_room_reject_with_reason">%1$s avböjde inbjudan. Anledning: %2$s</string> + <string name="notice_room_reject_with_reason_by_you">Du avböjde inbjudan. Anledning: %1$s</string> + <string name="notice_room_kick_with_reason">%1$s kickade %2$s. Anledning: %3$s</string> + <string name="notice_room_kick_with_reason_by_you">Du kickade %1$s. Anledning: %2$s</string> + <string name="notice_room_unban_with_reason">%1$s avbannade %2$s. Anledning: %3$s</string> + <string name="notice_room_unban_with_reason_by_you">Du avbannade %1$s. Anledning: %2$s</string> + <string name="notice_room_ban_with_reason">%1$s bannade %2$s. Anledning: %3$s</string> + <string name="notice_room_ban_with_reason_by_you">Du bannade %1$s. Anledning: %2$s</string> + <string name="notice_room_third_party_invite_with_reason">%1$s bjöd in %2$s att gÃ¥ med i rummet. Anledning: %3$s</string> + <string name="notice_room_third_party_invite_with_reason_by_you">Du bjöd in %1$s att gÃ¥ med i rummet. Anledning: %2$s</string> + <string name="notice_room_third_party_revoked_invite_with_reason">%1$s drog tillbaka inbjudan för %2$s att gÃ¥ med i rummet. Anledning: %3$s</string> + <string name="notice_room_third_party_revoked_invite_with_reason_by_you">Du drog tillbaka inbjudan för %1$s att gÃ¥ med i rummet. Anledning: %2$s</string> + <string name="notice_room_third_party_registered_invite_with_reason">%1$s accepterade inbjudan för %2$s. Anledning: %3$s</string> + <string name="notice_room_third_party_registered_invite_with_reason_by_you">Du accepterade inbjudan för %1$s. Anledning: %2$s</string> + <string name="notice_room_withdraw_with_reason">%1$s drog tillbaka inbjudan för %2$s. Anledning: %3$s</string> + <string name="notice_room_withdraw_with_reason_by_you">Du drog tillbaka inbjudan för %1$s. Anledning: %2$s</string> + + <plurals name="notice_room_aliases_added"> + <item quantity="one">%1$s lade till %2$s som en adress för det här rummet.</item> + <item quantity="other">%1$s lade till %2$s som adresser för det här rummet.</item> + </plurals> + + <plurals name="notice_room_aliases_added_by_you"> + <item quantity="one">Du lade till %1$s som en adress för det här rummet.</item> + <item quantity="other">Du lade till %1$s som adresser för det här rummet.</item> + </plurals> + + <plurals name="notice_room_aliases_removed"> + <item quantity="one">%1$s tog bort %2$s som en adress för det här rummet.</item> + <item quantity="other">%1$s tog bort %2$s som adresser för det här rummet.</item> + </plurals> + + <plurals name="notice_room_aliases_removed_by_you"> + <item quantity="one">Du tog bort %1$s som en adress för det här rummet.</item> + <item quantity="other">Du tog bort %2$s som adresser för det här rummet.</item> + </plurals> + + <string name="notice_room_aliases_added_and_removed">%1$s lade till %2$s och tog bort %3$s som adresser för det här rummet.</string> + <string name="notice_room_aliases_added_and_removed_by_you">Du lade till %1$s och tog bort %2$s som adresser för det här rummet.</string> + + <string name="notice_room_canonical_alias_set">%1$s satta huvudadressen för det här rummet till %2$s.</string> + <string name="notice_room_canonical_alias_set_by_you">Du satta huvudadressen för det här rummet till %1$s.</string> + <string name="notice_room_canonical_alias_unset">%1$s tog bort huvudadressen för det här rummet.</string> + <string name="notice_room_canonical_alias_unset_by_you">Du tog bort huvudadressen för det här rummet.</string> + + <string name="notice_room_guest_access_can_join">%1$s tillät gäster att gÃ¥ med i rummet.</string> + <string name="notice_room_guest_access_can_join_by_you">Du tillät gäster att gÃ¥ med i rummet.</string> + <string name="notice_room_guest_access_forbidden">%1$s hindrade gäster frÃ¥n att gÃ¥ med i rummet.</string> + <string name="notice_room_guest_access_forbidden_by_you">Du hindrade gäster frÃ¥n att gÃ¥ med i rummet.</string> + + <string name="notice_end_to_end_ok">%1$s aktiverade totalsträckskryptering.</string> + <string name="notice_end_to_end_ok_by_you">Du aktiverade totalsträckskryptering.</string> + <string name="notice_end_to_end_unknown_algorithm">%1$s aktiverade totalsträckskryptering (okänd algoritm %2$s).</string> + <string name="notice_end_to_end_unknown_algorithm_by_you">Du aktiverade totalsträckskryptering (okänd algoritm %1$s).</string> + + <string name="key_verification_request_fallback_message">%s begär att verifiera din nyckel, men din klient stöder inte nyckelverifiering i chatten. Du behöver använda legacynyckelverifiering för att verifiera nycklar.</string> + +</resources> diff --git a/matrix-sdk-android/src/main/res/values-sv/strings_sas.xml b/matrix-sdk-android/src/main/res/values-sv/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..1e06452ba5278a1b4da42f8cdb782fbd4c87a4f8 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-sv/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Hund</string> + <string name="verification_emoji_cat">Katt</string> + <string name="verification_emoji_lion">Lejon</string> + <string name="verification_emoji_horse">Häst</string> + <string name="verification_emoji_unicorn">Enhörning</string> + <string name="verification_emoji_pig">Gris</string> + <string name="verification_emoji_elephant">Elefant</string> + <string name="verification_emoji_rabbit">Kanin</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Tupp</string> + <string name="verification_emoji_penguin">Pingvin</string> + <string name="verification_emoji_turtle">Sköldpadda</string> + <string name="verification_emoji_fish">Fisk</string> + <string name="verification_emoji_octopus">Bläckfisk</string> + <string name="verification_emoji_butterfly">Fjäril</string> + <string name="verification_emoji_flower">Blomma</string> + <string name="verification_emoji_tree">Träd</string> + <string name="verification_emoji_cactus">Kaktus</string> + <string name="verification_emoji_mushroom">Svamp</string> + <string name="verification_emoji_globe">Jordklot</string> + <string name="verification_emoji_moon">MÃ¥ne</string> + <string name="verification_emoji_cloud">Moln</string> + <string name="verification_emoji_fire">Eld</string> + <string name="verification_emoji_banana">Banan</string> + <string name="verification_emoji_apple">Äpple</string> + <string name="verification_emoji_strawberry">Jordgubbe</string> + <string name="verification_emoji_corn">Majskolv</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">TÃ¥rta</string> + <string name="verification_emoji_heart">Hjärta</string> + <string name="verification_emoji_smiley">Smiley</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Hatt</string> + <string name="verification_emoji_glasses">Glasögon</string> + <string name="verification_emoji_spanner">Skruvnyckel</string> + <string name="verification_emoji_santa">Tomte</string> + <string name="verification_emoji_thumbs_up">Tummen upp</string> + <string name="verification_emoji_umbrella">Paraply</string> + <string name="verification_emoji_hourglass">Timglas</string> + <string name="verification_emoji_clock">Klocka</string> + <string name="verification_emoji_gift">Paket</string> + <string name="verification_emoji_light_bulb">Lampa</string> + <string name="verification_emoji_book">Bok</string> + <string name="verification_emoji_pencil">Penna</string> + <string name="verification_emoji_paperclip">Gem</string> + <string name="verification_emoji_scissors">Sax</string> + <string name="verification_emoji_lock">LÃ¥s</string> + <string name="verification_emoji_key">Nyckel</string> + <string name="verification_emoji_hammer">Hammare</string> + <string name="verification_emoji_telephone">Telefon</string> + <string name="verification_emoji_flag">Flagga</string> + <string name="verification_emoji_train">Ã…nglok</string> + <string name="verification_emoji_bicycle">Cykel</string> + <string name="verification_emoji_aeroplane">Flygplan</string> + <string name="verification_emoji_rocket">Raket</string> + <string name="verification_emoji_trophy">Trofé</string> + <string name="verification_emoji_ball">Boll</string> + <string name="verification_emoji_guitar">Gitarr</string> + <string name="verification_emoji_trumpet">Trumpet</string> + <string name="verification_emoji_bell">Bjällra</string> + <string name="verification_emoji_anchor">Ankare</string> + <string name="verification_emoji_headphones">Hörlurar</string> + <string name="verification_emoji_folder">Mapp</string> + <string name="verification_emoji_pin">Häftstift</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-uk/strings_sas.xml b/matrix-sdk-android/src/main/res/values-uk/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..f979f77250cf9b04f2f83016aba61d06faddcfc9 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-uk/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">ПеÑ</string> + <string name="verification_emoji_cat">Кіт</string> + <string name="verification_emoji_lion">Лев</string> + <string name="verification_emoji_horse">Кінь</string> + <string name="verification_emoji_unicorn">Єдиноріг</string> + <string name="verification_emoji_pig">СвинÑ</string> + <string name="verification_emoji_elephant">Слон</string> + <string name="verification_emoji_rabbit">Кріль</string> + <string name="verification_emoji_panda">Панда</string> + <string name="verification_emoji_rooster">Когут</string> + <string name="verification_emoji_penguin">Пінгвін</string> + <string name="verification_emoji_turtle">Черепаха</string> + <string name="verification_emoji_fish">Риба</string> + <string name="verification_emoji_octopus">ВоÑьминіг</string> + <string name="verification_emoji_butterfly">Метелик</string> + <string name="verification_emoji_flower">Квітка</string> + <string name="verification_emoji_tree">Дерево</string> + <string name="verification_emoji_cactus">КактуÑ</string> + <string name="verification_emoji_mushroom">Гриб</string> + <string name="verification_emoji_globe">ГлобуÑ</string> + <string name="verification_emoji_moon">МіÑÑць</string> + <string name="verification_emoji_cloud">Хмара</string> + <string name="verification_emoji_fire">Вогонь</string> + <string name="verification_emoji_banana">Банан</string> + <string name="verification_emoji_apple">Яблуко</string> + <string name="verification_emoji_strawberry">ПолуницÑ</string> + <string name="verification_emoji_corn">Кукурудза</string> + <string name="verification_emoji_pizza">Піца</string> + <string name="verification_emoji_cake">Пиріг</string> + <string name="verification_emoji_heart">Серце</string> + <string name="verification_emoji_smiley">ПоÑмішка</string> + <string name="verification_emoji_robot">Робот</string> + <string name="verification_emoji_hat">Капелюх</string> + <string name="verification_emoji_glasses">ОкулÑри</string> + <string name="verification_emoji_spanner">Гайковий ключ</string> + <string name="verification_emoji_santa">Санта КлауÑ</string> + <string name="verification_emoji_thumbs_up">Великий палець вгору</string> + <string name="verification_emoji_umbrella">ПараÑолька</string> + <string name="verification_emoji_hourglass">ПіÑковий годинник</string> + <string name="verification_emoji_clock">Годинник</string> + <string name="verification_emoji_gift">Подарунок</string> + <string name="verification_emoji_light_bulb">Лампочка</string> + <string name="verification_emoji_book">Книга</string> + <string name="verification_emoji_pencil">Олівець</string> + <string name="verification_emoji_paperclip">Спиначка</string> + <string name="verification_emoji_scissors">Ðожиці</string> + <string name="verification_emoji_lock">Замок</string> + <string name="verification_emoji_key">Ключ</string> + <string name="verification_emoji_hammer">Молоток</string> + <string name="verification_emoji_telephone">Телефон</string> + <string name="verification_emoji_flag">Прапор</string> + <string name="verification_emoji_train">ПотÑг</string> + <string name="verification_emoji_bicycle">ВелоÑипед</string> + <string name="verification_emoji_aeroplane">Літак</string> + <string name="verification_emoji_rocket">Ракета</string> + <string name="verification_emoji_trophy">Приз</string> + <string name="verification_emoji_ball">Ðœ\'Ñч</string> + <string name="verification_emoji_guitar">Гітара</string> + <string name="verification_emoji_trumpet">Труба</string> + <string name="verification_emoji_bell">Дзвін</string> + <string name="verification_emoji_anchor">Якір</string> + <string name="verification_emoji_headphones">Ðавушники</string> + <string name="verification_emoji_folder">Тека</string> + <string name="verification_emoji_pin">Кнопка</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-vls/strings.xml b/matrix-sdk-android/src/main/res/values-vls/strings.xml index 5c9132ed35a6c07dc01de3f21f337479ff313d98..f0f2287a8d7f3cf44cfa6a55d435adf9d4f8f597 100644 --- a/matrix-sdk-android/src/main/res/values-vls/strings.xml +++ b/matrix-sdk-android/src/main/res/values-vls/strings.xml @@ -77,73 +77,7 @@ <string name="room_displayname_empty_room">Leeg gesprek</string> - - <string name="verification_emoji_dog">Hound</string> - <string name="verification_emoji_cat">Katte</string> - <string name="verification_emoji_lion">Leeuw</string> - <string name="verification_emoji_horse">Peird</string> - <string name="verification_emoji_unicorn">Eenhoorn</string> - <string name="verification_emoji_pig">Zwyn</string> - <string name="verification_emoji_elephant">Olifant</string> - <string name="verification_emoji_rabbit">Keun</string> - <string name="verification_emoji_panda">Panda</string> - <string name="verification_emoji_rooster">Hoane</string> - <string name="verification_emoji_penguin">Pinguin</string> - <string name="verification_emoji_turtle">Schildpadde</string> - <string name="verification_emoji_fish">Vis</string> - <string name="verification_emoji_octopus">Octopus</string> - <string name="verification_emoji_butterfly">Beutervlieg</string> - <string name="verification_emoji_flower">Bloem</string> - <string name="verification_emoji_tree">Boom</string> - <string name="verification_emoji_cactus">Cactus</string> - <string name="verification_emoji_mushroom">Paddestoel</string> - <string name="verification_emoji_globe">Eirdbol</string> - <string name="verification_emoji_moon">Moane</string> - <string name="verification_emoji_cloud">Wolk</string> - <string name="verification_emoji_fire">Vier</string> - <string name="verification_emoji_banana">Banoan</string> - <string name="verification_emoji_apple">Appel</string> - <string name="verification_emoji_strawberry">Freize</string> - <string name="verification_emoji_corn">Mais</string> - <string name="verification_emoji_pizza">Pizza</string> - <string name="verification_emoji_cake">Toarte</string> - <string name="verification_emoji_heart">Erte</string> - <string name="verification_emoji_smiley">Smiley</string> - <string name="verification_emoji_robot">Robot</string> - <string name="verification_emoji_hat">Hoed</string> - <string name="verification_emoji_glasses">Bril</string> - <string name="verification_emoji_wrench">Moersleutel</string> - <string name="verification_emoji_santa">Kestman</string> - <string name="verification_emoji_thumbsup">Duum omhooge</string> - <string name="verification_emoji_umbrella">Paraplu</string> - <string name="verification_emoji_hourglass">Zandloper</string> - <string name="verification_emoji_clock">Klok</string> - <string name="verification_emoji_gift">Cadeau</string> - <string name="verification_emoji_lightbulb">Gloeilampe</string> - <string name="verification_emoji_book">Boek</string> - <string name="verification_emoji_pencil">Potlood</string> - <string name="verification_emoji_paperclip">Paperclip</string> - <string name="verification_emoji_scissors">Schoar</string> - <string name="verification_emoji_lock">Hangslot</string> - <string name="verification_emoji_key">Sleutel</string> - <string name="verification_emoji_hammer">Oamer</string> - <string name="verification_emoji_telephone">Telefong</string> - <string name="verification_emoji_flag">Vlagge</string> - <string name="verification_emoji_train">Tring</string> - <string name="verification_emoji_bicycle">Veloo</string> - <string name="verification_emoji_airplane">Vlieger</string> - <string name="verification_emoji_rocket">Rakette</string> - <string name="verification_emoji_trophy">Trofee</string> - <string name="verification_emoji_ball">Bolle</string> - <string name="verification_emoji_guitar">Gitoar</string> - <string name="verification_emoji_trumpet">Trompette</string> - <string name="verification_emoji_bell">Belle</string> - <string name="verification_emoji_anchor">Anker</string> - <string name="verification_emoji_headphone">Koptelefong</string> - <string name="verification_emoji_folder">Mappe</string> - <string name="verification_emoji_pin">Pinne</string> - - <string name="initial_sync_start_importing_account">Initiële synchronisoasje: + <string name="initial_sync_start_importing_account">Initiële synchronisoasje: \nAccount wor geïmporteerd…</string> <string name="initial_sync_start_importing_account_crypto">Initiële synchronisoasje: \nCrypto wor geïmporteerd</string> diff --git a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml index ef080e8357cdaf6ef6f58c0f72370ec152d44e1d..60322821d4932b7140eeb807a1a721b321c0a968 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rCN/strings.xml @@ -75,69 +75,6 @@ <string name="notice_event_redacted_by">消æ¯å·²è¢« %1$s 移除</string> <string name="notice_event_redacted_with_reason">消æ¯å·²è¢«ç§»é™¤ [åŽŸå› : %1$s]</string> <string name="notice_event_redacted_by_with_reason">消æ¯å·²è¢« %1$s 移除 [åŽŸå› : %2$s]</string> - <string name="verification_emoji_dog">ç‹—</string> - <string name="verification_emoji_cat">猫</string> - <string name="verification_emoji_lion">ç‹®å</string> - <string name="verification_emoji_horse">马</string> - <string name="verification_emoji_unicorn">独角兽</string> - <string name="verification_emoji_pig">猪</string> - <string name="verification_emoji_elephant">大象</string> - <string name="verification_emoji_rabbit">å…”å</string> - <string name="verification_emoji_panda">熊猫</string> - <string name="verification_emoji_rooster">公鸡</string> - <string name="verification_emoji_penguin">ä¼é¹…</string> - <string name="verification_emoji_turtle">乌龟</string> - <string name="verification_emoji_fish">é±¼</string> - <string name="verification_emoji_octopus">ç« é±¼</string> - <string name="verification_emoji_butterfly">è´è¶</string> - <string name="verification_emoji_flower">花</string> - <string name="verification_emoji_tree">æ ‘</string> - <string name="verification_emoji_cactus">仙人掌</string> - <string name="verification_emoji_mushroom">蘑è‡</string> - <string name="verification_emoji_globe">地çƒ</string> - <string name="verification_emoji_moon">月亮</string> - <string name="verification_emoji_cloud">云</string> - <string name="verification_emoji_fire">ç«</string> - <string name="verification_emoji_banana">香蕉</string> - <string name="verification_emoji_apple">苹果</string> - <string name="verification_emoji_strawberry">è‰èŽ“</string> - <string name="verification_emoji_corn">玉米</string> - <string name="verification_emoji_pizza">披è¨</string> - <string name="verification_emoji_cake">蛋糕</string> - <string name="verification_emoji_heart">心</string> - <string name="verification_emoji_smiley">微笑</string> - <string name="verification_emoji_robot">机器人</string> - <string name="verification_emoji_hat">帽å</string> - <string name="verification_emoji_glasses">眼镜</string> - <string name="verification_emoji_wrench">扳手</string> - <string name="verification_emoji_santa">圣诞è€äºº</string> - <string name="verification_emoji_thumbsup">点赞</string> - <string name="verification_emoji_umbrella">雨伞</string> - <string name="verification_emoji_hourglass">æ²™æ¼</string> - <string name="verification_emoji_clock">é’Ÿ</string> - <string name="verification_emoji_gift">礼物</string> - <string name="verification_emoji_lightbulb">ç¯æ³¡</string> - <string name="verification_emoji_book">书</string> - <string name="verification_emoji_pencil">铅笔</string> - <string name="verification_emoji_paperclip">回形针</string> - <string name="verification_emoji_scissors">剪刀</string> - <string name="verification_emoji_lock">é”</string> - <string name="verification_emoji_key">钥匙</string> - <string name="verification_emoji_hammer">锤å</string> - <string name="verification_emoji_telephone">电è¯</string> - <string name="verification_emoji_flag">æ——å</string> - <string name="verification_emoji_train">ç«è½¦</string> - <string name="verification_emoji_bicycle">自行车</string> - <string name="verification_emoji_airplane">飞机</string> - <string name="verification_emoji_rocket">ç«ç®</string> - <string name="verification_emoji_trophy">奖æ¯</string> - <string name="verification_emoji_ball">çƒ</string> - <string name="verification_emoji_guitar">å‰ä»–</string> - <string name="verification_emoji_trumpet">å–‡å</string> - <string name="verification_emoji_bell">铃铛</string> - <string name="verification_emoji_anchor">锚</string> - <string name="verification_emoji_headphone">耳机</string> - <string name="verification_emoji_folder">文件夹</string> <string name="initial_sync_start_importing_account">åˆå§‹åŒ–åŒæ¥ï¼š \næ£åœ¨å¯¼å…¥è´¦å·â€¦</string> <string name="initial_sync_start_importing_account_crypto">åˆå§‹åŒ–åŒæ¥ï¼š @@ -161,7 +98,6 @@ <string name="clear_timeline_send_queue">清除æ£åœ¨å‘é€é˜Ÿåˆ—</string> <string name="notice_room_third_party_revoked_invite">%1$s 撤回了对 %2$s åŠ å…¥èŠå¤©å®¤çš„邀请</string> - <string name="verification_emoji_pin">置顶</string> <string name="notice_room_invite_no_invitee_with_reason">%1$s 的邀请。ç†ç”±ï¼š%2$s</string> <string name="notice_room_invite_with_reason">%1$s 邀请了 %2$s。ç†ç”±ï¼š%3$s</string> @@ -289,8 +225,4 @@ <string name="notice_end_to_end_ok_by_you">您已开å¯ç«¯åˆ°ç«¯åŠ 密。</string> <string name="notice_end_to_end_unknown_algorithm_by_you">您已开å¯ç«¯åˆ°ç«¯åŠ å¯†ï¼ˆæ— æ³•è¯†åˆ«çš„ç®—æ³• %1$s)。</string> - <string name="call_notification_answer">接å—</string> - <string name="call_notification_reject">æ‹’ç»</string> - <string name="call_notification_hangup">挂æ–</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values-zh-rCN/strings_sas.xml b/matrix-sdk-android/src/main/res/values-zh-rCN/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..439615735ade5f0822de9555cc54bb0a079d9b34 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values-zh-rCN/strings_sas.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">ç‹—</string> + <string name="verification_emoji_cat">猫</string> + <string name="verification_emoji_lion">ç‹®å</string> + <string name="verification_emoji_horse">马</string> + <string name="verification_emoji_unicorn">独角兽</string> + <string name="verification_emoji_pig">猪</string> +</resources> diff --git a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml index ee2662f143488cd301ffdafc0517e38a7ff09242..355890923cd445b872f6dfee732e8fbb2e1c77cb 100644 --- a/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml +++ b/matrix-sdk-android/src/main/res/values-zh-rTW/strings.xml @@ -71,75 +71,10 @@ <item quantity="other">%1$s å’Œ 和其他 %2$d 個人</item> </plurals> - <string name="notice_event_redacted">訊æ¯å·²ç§»é™¤</string> <string name="notice_event_redacted_by">訊æ¯å·²è¢« %1$s 移除</string> <string name="notice_event_redacted_with_reason">訊æ¯å·²ç§»é™¤ [ç†ç”±ï¼š%1$s]</string> <string name="notice_event_redacted_by_with_reason">訊æ¯å·²è¢« %1$s 移除 [ç†ç”±ï¼š%2$s]</string> - <string name="verification_emoji_dog">ç‹—</string> - <string name="verification_emoji_cat">貓</string> - <string name="verification_emoji_lion">ç…</string> - <string name="verification_emoji_horse">馬</string> - <string name="verification_emoji_unicorn">ç¨è§’ç¸</string> - <string name="verification_emoji_pig">豬</string> - <string name="verification_emoji_elephant">象</string> - <string name="verification_emoji_rabbit">å…”</string> - <string name="verification_emoji_panda">貓熊</string> - <string name="verification_emoji_rooster">公雞</string> - <string name="verification_emoji_penguin">ä¼éµ</string> - <string name="verification_emoji_turtle">龜</string> - <string name="verification_emoji_fish">éš</string> - <string name="verification_emoji_octopus">ç« éš</string> - <string name="verification_emoji_butterfly">è¶</string> - <string name="verification_emoji_flower">花</string> - <string name="verification_emoji_tree">樹</string> - <string name="verification_emoji_cactus">仙人掌</string> - <string name="verification_emoji_mushroom">蘑è‡</string> - <string name="verification_emoji_globe">地çƒ</string> - <string name="verification_emoji_moon">月亮</string> - <string name="verification_emoji_cloud">雲</string> - <string name="verification_emoji_fire">ç«</string> - <string name="verification_emoji_banana">香蕉</string> - <string name="verification_emoji_apple">蘋果</string> - <string name="verification_emoji_strawberry">è‰èŽ“</string> - <string name="verification_emoji_corn">玉米</string> - <string name="verification_emoji_pizza">披薩</string> - <string name="verification_emoji_cake">蛋糕</string> - <string name="verification_emoji_heart">心</string> - <string name="verification_emoji_smiley">微笑</string> - <string name="verification_emoji_robot">機器人</string> - <string name="verification_emoji_hat">帽å</string> - <string name="verification_emoji_glasses">眼é¡</string> - <string name="verification_emoji_wrench">扳手</string> - <string name="verification_emoji_santa">è–誕è€äºº</string> - <string name="verification_emoji_thumbsup">讚</string> - <string name="verification_emoji_umbrella">雨傘</string> - <string name="verification_emoji_hourglass">æ²™æ¼</string> - <string name="verification_emoji_clock">時é˜</string> - <string name="verification_emoji_gift">禮物</string> - <string name="verification_emoji_lightbulb">燈泡</string> - <string name="verification_emoji_book">書</string> - <string name="verification_emoji_pencil">鉛ç†</string> - <string name="verification_emoji_paperclip">è¿´ç´‹é‡</string> - <string name="verification_emoji_scissors">剪刀</string> - <string name="verification_emoji_lock">鎖</string> - <string name="verification_emoji_key">鑰匙</string> - <string name="verification_emoji_hammer">鎚å</string> - <string name="verification_emoji_telephone">電話</string> - <string name="verification_emoji_flag">æ——å</string> - <string name="verification_emoji_train">ç«è»Š</string> - <string name="verification_emoji_bicycle">è…³è¸è»Š</string> - <string name="verification_emoji_airplane">飛機</string> - <string name="verification_emoji_rocket">ç«ç®</string> - <string name="verification_emoji_trophy">çŽç›ƒ</string> - <string name="verification_emoji_ball">çƒ</string> - <string name="verification_emoji_guitar">å‰ä»–</string> - <string name="verification_emoji_trumpet">å–‡å</string> - <string name="verification_emoji_bell">鈴</string> - <string name="verification_emoji_anchor">錨</string> - <string name="verification_emoji_headphone">耳機</string> - <string name="verification_emoji_folder">資料夾</string> - <string name="verification_emoji_pin">別é‡</string> <string name="initial_sync_start_importing_account">åˆå§‹åŒ–åŒæ¥ï¼š \næ£åœ¨åŒ¯å…¥å¸³è™Ÿâ€¦â€¦</string> @@ -290,8 +225,4 @@ <string name="notice_end_to_end_ok_by_you">æ‚¨é–‹å•Ÿäº†ç«¯åˆ°ç«¯åŠ å¯†ã€‚</string> <string name="notice_end_to_end_unknown_algorithm_by_you">æ‚¨é–‹å•Ÿäº†ç«¯åˆ°ç«¯åŠ å¯†ï¼ˆç„¡æ³•è˜åˆ¥çš„演算法 %1$s)。</string> - <string name="call_notification_answer">接å—</string> - <string name="call_notification_reject">拒絕</string> - <string name="call_notification_hangup">掛斷</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values/strings.xml b/matrix-sdk-android/src/main/res/values/strings.xml index 0dc64c1b4b9d5f15f4bcdbd1ce0eafaaee900dc6..f64ec9926e13d7f417a72d6163761b8d6eec7a5b 100644 --- a/matrix-sdk-android/src/main/res/values/strings.xml +++ b/matrix-sdk-android/src/main/res/values/strings.xml @@ -152,137 +152,6 @@ <string name="room_displayname_empty_room">Empty room</string> - - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_dog">Dog</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_cat">Cat</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_lion">Lion</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_horse">Horse</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_unicorn">Unicorn</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_pig">Pig</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_elephant">Elephant</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_rabbit">Rabbit</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_panda">Panda</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_rooster">Rooster</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_penguin">Penguin</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_turtle">Turtle</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_fish">Fish</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_octopus">Octopus</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_butterfly">Butterfly</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_flower">Flower</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_tree">Tree</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_cactus">Cactus</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_mushroom">Mushroom</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_globe">Globe</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_moon">Moon</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_cloud">Cloud</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_fire">Fire</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_banana">Banana</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_apple">Apple</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_strawberry">Strawberry</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_corn">Corn</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_pizza">Pizza</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_cake">Cake</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_heart">Heart</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_smiley">Smiley</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_robot">Robot</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_hat">Hat</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_glasses">Glasses</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_wrench">Wrench</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_santa">Santa</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_thumbsup">Thumbs Up</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_umbrella">Umbrella</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_hourglass">Hourglass</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_clock">Clock</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_gift">Gift</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_lightbulb">Light Bulb</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_book">Book</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_pencil">Pencil</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_paperclip">Paperclip</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_scissors">Scissors</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_lock">Lock</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_key">Key</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_hammer">Hammer</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_telephone">Telephone</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_flag">Flag</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_train">Train</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_bicycle">Bicycle</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_airplane">Airplane</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_rocket">Rocket</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_trophy">Trophy</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_ball">Ball</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_guitar">Guitar</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_trumpet">Trumpet</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_bell">Bell</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_anchor">Anchor</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_headphone">Headphones</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_folder">Folder</string> - <!-- All translations should be the same across all Riot clients, please use the same translation than RiotWeb --> - <string name="verification_emoji_pin">Pin</string> - - <!-- Strings for RiotX --> <string name="initial_sync_start_importing_account">Initial Sync:\nImporting account…</string> <string name="initial_sync_start_importing_account_crypto">Initial Sync:\nImporting crypto</string> <string name="initial_sync_start_importing_account_rooms">Initial Sync:\nImporting Rooms</string> @@ -361,8 +230,4 @@ <string name="key_verification_request_fallback_message">%s is requesting to verify your key, but your client does not support in-chat key verification. You will need to use legacy key verification to verify keys.</string> - <string name="call_notification_answer">Accept</string> - <string name="call_notification_reject">Decline</string> - <string name="call_notification_hangup">Hang Up</string> - </resources> diff --git a/matrix-sdk-android/src/main/res/values/strings_sas.xml b/matrix-sdk-android/src/main/res/values/strings_sas.xml new file mode 100644 index 0000000000000000000000000000000000000000..8a366a22e56d8de0fd3dc93c4c44087bca3cf286 --- /dev/null +++ b/matrix-sdk-android/src/main/res/values/strings_sas.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <!-- Generated file, do not edit --> + <string name="verification_emoji_dog">Dog</string> + <string name="verification_emoji_cat">Cat</string> + <string name="verification_emoji_lion">Lion</string> + <string name="verification_emoji_horse">Horse</string> + <string name="verification_emoji_unicorn">Unicorn</string> + <string name="verification_emoji_pig">Pig</string> + <string name="verification_emoji_elephant">Elephant</string> + <string name="verification_emoji_rabbit">Rabbit</string> + <string name="verification_emoji_panda">Panda</string> + <string name="verification_emoji_rooster">Rooster</string> + <string name="verification_emoji_penguin">Penguin</string> + <string name="verification_emoji_turtle">Turtle</string> + <string name="verification_emoji_fish">Fish</string> + <string name="verification_emoji_octopus">Octopus</string> + <string name="verification_emoji_butterfly">Butterfly</string> + <string name="verification_emoji_flower">Flower</string> + <string name="verification_emoji_tree">Tree</string> + <string name="verification_emoji_cactus">Cactus</string> + <string name="verification_emoji_mushroom">Mushroom</string> + <string name="verification_emoji_globe">Globe</string> + <string name="verification_emoji_moon">Moon</string> + <string name="verification_emoji_cloud">Cloud</string> + <string name="verification_emoji_fire">Fire</string> + <string name="verification_emoji_banana">Banana</string> + <string name="verification_emoji_apple">Apple</string> + <string name="verification_emoji_strawberry">Strawberry</string> + <string name="verification_emoji_corn">Corn</string> + <string name="verification_emoji_pizza">Pizza</string> + <string name="verification_emoji_cake">Cake</string> + <string name="verification_emoji_heart">Heart</string> + <string name="verification_emoji_smiley">Smiley</string> + <string name="verification_emoji_robot">Robot</string> + <string name="verification_emoji_hat">Hat</string> + <string name="verification_emoji_glasses">Glasses</string> + <string name="verification_emoji_spanner">Spanner</string> + <string name="verification_emoji_santa">Santa</string> + <string name="verification_emoji_thumbs_up">Thumbs Up</string> + <string name="verification_emoji_umbrella">Umbrella</string> + <string name="verification_emoji_hourglass">Hourglass</string> + <string name="verification_emoji_clock">Clock</string> + <string name="verification_emoji_gift">Gift</string> + <string name="verification_emoji_light_bulb">Light Bulb</string> + <string name="verification_emoji_book">Book</string> + <string name="verification_emoji_pencil">Pencil</string> + <string name="verification_emoji_paperclip">Paperclip</string> + <string name="verification_emoji_scissors">Scissors</string> + <string name="verification_emoji_lock">Lock</string> + <string name="verification_emoji_key">Key</string> + <string name="verification_emoji_hammer">Hammer</string> + <string name="verification_emoji_telephone">Telephone</string> + <string name="verification_emoji_flag">Flag</string> + <string name="verification_emoji_train">Train</string> + <string name="verification_emoji_bicycle">Bicycle</string> + <string name="verification_emoji_aeroplane">Aeroplane</string> + <string name="verification_emoji_rocket">Rocket</string> + <string name="verification_emoji_trophy">Trophy</string> + <string name="verification_emoji_ball">Ball</string> + <string name="verification_emoji_guitar">Guitar</string> + <string name="verification_emoji_trumpet">Trumpet</string> + <string name="verification_emoji_bell">Bell</string> + <string name="verification_emoji_anchor">Anchor</string> + <string name="verification_emoji_headphones">Headphones</string> + <string name="verification_emoji_folder">Folder</string> + <string name="verification_emoji_pin">Pin</string> +</resources> diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushrulesConditionTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushrulesConditionTest.kt index be5aeaaf0f908bdb03911e6edd5a0ed5cc18ca7c..b2c8d3bda8972c08c72ab3b577aff858e101c750 100644 --- a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushrulesConditionTest.kt +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/api/pushrules/PushrulesConditionTest.kt @@ -16,6 +16,12 @@ package org.matrix.android.sdk.api.pushrules +import io.mockk.every +import io.mockk.mockk +import org.amshove.kluent.shouldBe +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test import org.matrix.android.sdk.MatrixTest import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toContent @@ -24,28 +30,26 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomMemberContent import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent import org.matrix.android.sdk.internal.session.room.RoomGetter -import io.mockk.every -import io.mockk.mockk -import org.amshove.kluent.shouldBe -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Test -class PushrulesConditionTest: MatrixTest { +class PushRulesConditionTest : MatrixTest { /* ========================================================================================== * Test EventMatchCondition * ========================================================================================== */ - @Test - fun test_eventmatch_type_condition() { - val condition = EventMatchCondition("type", "m.room.message") - - val simpleTextEvent = Event( + private fun createSimpleTextEvent(text: String): Event { + return Event( type = "m.room.message", eventId = "mx0", - content = MessageTextContent("m.text", "Yo wtf?").toContent(), + content = MessageTextContent("m.text", text).toContent(), originServerTs = 0) + } + + @Test + fun test_eventmatch_type_condition() { + val condition = EventMatchCondition("type", "m.room.message", false) + + val simpleTextEvent = createSimpleTextEvent("Yo wtf?") val rm = RoomMemberContent( Membership.INVITE, @@ -65,13 +69,9 @@ class PushrulesConditionTest: MatrixTest { @Test fun test_eventmatch_path_condition() { - val condition = EventMatchCondition("content.msgtype", "m.text") + val condition = EventMatchCondition("content.msgtype", "m.text", false) - val simpleTextEvent = Event( - type = "m.room.message", - eventId = "mx0", - content = MessageTextContent("m.text", "Yo wtf?").toContent(), - originServerTs = 0) + val simpleTextEvent = createSimpleTextEvent("Yo wtf?") assert(condition.isSatisfied(simpleTextEvent)) @@ -86,49 +86,44 @@ class PushrulesConditionTest: MatrixTest { ).toContent(), originServerTs = 0 ).apply { - assert(EventMatchCondition("content.membership", "invite").isSatisfied(this)) + assert(EventMatchCondition("content.membership", "invite", false).isSatisfied(this)) } } @Test fun test_eventmatch_cake_condition() { - val condition = EventMatchCondition("content.body", "cake") + val condition = EventMatchCondition("content.body", "cake", false) - Event( - type = "m.room.message", - eventId = "mx0", - content = MessageTextContent("m.text", "How was the cake?").toContent(), - originServerTs = 0 - ).apply { - assert(condition.isSatisfied(this)) - } - - Event( - type = "m.room.message", - eventId = "mx0", - content = MessageTextContent("m.text", "Howwasthecake?").toContent(), - originServerTs = 0 - ).apply { - assert(condition.isSatisfied(this)) - } + assert(condition.isSatisfied(createSimpleTextEvent("How was the cake?"))) + assert(condition.isSatisfied(createSimpleTextEvent("Howwasthecake?"))) } @Test fun test_eventmatch_cakelie_condition() { - val condition = EventMatchCondition("content.body", "cake*lie") + val condition = EventMatchCondition("content.body", "cake*lie", false) - val simpleTextEvent = Event( - type = "m.room.message", - eventId = "mx0", - content = MessageTextContent("m.text", "How was the cakeisalie?").toContent(), - originServerTs = 0) + assert(condition.isSatisfied(createSimpleTextEvent("How was the cakeisalie?"))) + } - assert(condition.isSatisfied(simpleTextEvent)) + @Test + fun test_eventmatch_words_only_condition() { + val condition = EventMatchCondition("content.body", "ben", true) + + assertFalse(condition.isSatisfied(createSimpleTextEvent("benoit"))) + assertFalse(condition.isSatisfied(createSimpleTextEvent("Hello benoit"))) + assertFalse(condition.isSatisfied(createSimpleTextEvent("superben"))) + + assert(condition.isSatisfied(createSimpleTextEvent("ben"))) + assert(condition.isSatisfied(createSimpleTextEvent("hello ben"))) + assert(condition.isSatisfied(createSimpleTextEvent("ben is there"))) + assert(condition.isSatisfied(createSimpleTextEvent("hello ben!"))) + assert(condition.isSatisfied(createSimpleTextEvent("hello Ben!"))) + assert(condition.isSatisfied(createSimpleTextEvent("BEN"))) } @Test fun test_notice_condition() { - val conditionEqual = EventMatchCondition("content.msgtype", "m.notice") + val conditionEqual = EventMatchCondition("content.msgtype", "m.notice", false) Event( type = "m.room.message",