Merge remote-tracking branch 'upstream/develop' into direct_share

This commit is contained in:
Constantin Wartenburger 2020-10-13 20:26:07 +02:00
commit afe55ae57e
No known key found for this signature in database
GPG Key ID: 7439D96D8E1DB894
376 changed files with 2926 additions and 1433 deletions

View File

@ -4,16 +4,7 @@
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS"> <option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value> <value>
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" /> <package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value> </value>
</option> </option>
<option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" /> <option name="ALIGN_IN_COLUMNS_CASE_BRANCH" value="true" />

View File

@ -18,8 +18,10 @@ Improvements 🙌:
- Filter room member (and banned users) by name (#2184) - Filter room member (and banned users) by name (#2184)
- Implement "Jump to read receipt" and "Mention" actions on the room member profile screen - Implement "Jump to read receipt" and "Mention" actions on the room member profile screen
- Direct share (#2029) - Direct share (#2029)
- Add FAB to room members list (#2226)
- Add Sygnal API implementation to test is Push are correctly received - Add Sygnal API implementation to test is Push are correctly received
- Add PushGateway API implementation to test if Push are correctly received - Add PushGateway API implementation to test if Push are correctly received
- Cross signing: shouldn't offer to verify with other session when there is not. (#2227)
Bugfix 🐛: Bugfix 🐛:
- Improve support for image/audio/video/file selection with intent changes (#1376) - Improve support for image/audio/video/file selection with intent changes (#1376)
@ -27,9 +29,10 @@ Bugfix 🐛:
- Invalid popup when pressing back (#1635) - Invalid popup when pressing back (#1635)
- Simplifies draft management and should fix bunch of draft issues (#952, #683) - Simplifies draft management and should fix bunch of draft issues (#952, #683)
- Very long topic cannot be fully visible (#1957) - Very long topic cannot be fully visible (#1957)
- Properly detect cross signing keys reset
Translations 🗣: Translations 🗣:
- - Move store data to `/fastlane/metadata/android` (#812)
SDK API changes ⚠️: SDK API changes ⚠️:
- Search messages in a room by using Session.searchService() or Room.search() - Search messages in a room by using Session.searchService() or Room.search()

View File

@ -0,0 +1 @@
Element (o novo Riot.im)

View File

@ -13,7 +13,7 @@ Element здатен забезпечити усе це завдяки тому,
Element надає вам повний контроль, дозволяючи обирати з-поміж надавачів послуг, що обслуговують сервери з вашими бесідами. Ви вільні обрати будь-який спосіб розміщення прямо з застосунку Element: Element надає вам повний контроль, дозволяючи обирати з-поміж надавачів послуг, що обслуговують сервери з вашими бесідами. Ви вільні обрати будь-який спосіб розміщення прямо з застосунку Element:
1. Отримати безкоштовний обліковий запис на загальнодоступному сервері matrix.org 1. Отримати безкоштовний обліковий запис на загальнодоступному сервері matrix.org, який обслуговують розробники Matrix, чи на одному з тисяч публічних серверів, які обслуговують волонтери
2. Розмістити свій обліковий запис на власному сервері 2. Розмістити свій обліковий запис на власному сервері
3. Зареєструватись на індивідуальному сервері, просто підписавшись на послуги платформи Element Matrix Services 3. Зареєструватись на індивідуальному сервері, просто підписавшись на послуги платформи Element Matrix Services

View File

@ -17,6 +17,8 @@
package org.matrix.android.sdk.api package org.matrix.android.sdk.api
import android.content.Context import android.content.Context
import android.os.Handler
import android.os.Looper
import androidx.lifecycle.ProcessLifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner
import androidx.work.Configuration import androidx.work.Configuration
import androidx.work.WorkManager import androidx.work.WorkManager
@ -48,14 +50,18 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo
@Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var olmManager: OlmManager
@Inject internal lateinit var sessionManager: SessionManager @Inject internal lateinit var sessionManager: SessionManager
private val uiHandler = Handler(Looper.getMainLooper())
init { init {
Monarchy.init(context) Monarchy.init(context)
DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this) DaggerTestMatrixComponent.factory().create(context, matrixConfiguration).inject(this)
if (context.applicationContext !is Configuration.Provider) { if (context.applicationContext !is Configuration.Provider) {
WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build()) WorkManager.initialize(context, Configuration.Builder().setExecutor(Executors.newCachedThreadPool()).build())
} }
uiHandler.post {
ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver)
} }
}
fun getUserAgent() = userAgentHolder.userAgent fun getUserAgent() = userAgentHolder.userAgent

View File

@ -16,7 +16,6 @@
package org.matrix.android.sdk.internal.crypto package org.matrix.android.sdk.internal.crypto
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStore
import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule import org.matrix.android.sdk.internal.crypto.store.db.RealmCryptoStoreModule
@ -34,14 +33,8 @@ internal class CryptoStoreHelper {
.modules(RealmCryptoStoreModule()) .modules(RealmCryptoStoreModule())
.build(), .build(),
crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()), crossSigningKeysMapper = CrossSigningKeysMapper(MoshiProvider.providesMoshi()),
credentials = createCredential())
}
fun createCredential() = Credentials(
userId = "userId_" + Random.nextInt(), userId = "userId_" + Random.nextInt(),
homeServer = "http://matrix.org",
accessToken = "access_token",
refreshToken = null,
deviceId = "deviceId_sample" deviceId = "deviceId_sample"
) )
} }
}

View File

@ -0,0 +1,111 @@
/*
* 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.crypto.encryption
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.amshove.kluent.shouldBe
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.NoOpMatrixCallback
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.Room
import org.matrix.android.sdk.api.session.room.send.SendState
import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
import org.matrix.android.sdk.common.CommonTestHelper
import org.matrix.android.sdk.common.CryptoTestHelper
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.internal.crypto.model.event.EncryptionEventContent
import java.util.concurrent.CountDownLatch
@RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
class EncryptionTest : InstrumentedTest {
private val mTestHelper = CommonTestHelper(context())
private val mCryptoTestHelper = CryptoTestHelper(mTestHelper)
@Test
fun test_EncryptionEvent() {
performTest(roomShouldBeEncrypted = false) { room ->
// Send an encryption Event as an Event (and not as a state event)
room.sendEvent(
eventType = EventType.STATE_ROOM_ENCRYPTION,
content = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent()
)
}
}
@Test
fun test_EncryptionStateEvent() {
performTest(roomShouldBeEncrypted = true) { room ->
// Send an encryption Event as a State Event
room.sendStateEvent(
eventType = EventType.STATE_ROOM_ENCRYPTION,
stateKey = null,
body = EncryptionEventContent(algorithm = MXCRYPTO_ALGORITHM_MEGOLM).toContent(),
callback = NoOpMatrixCallback()
)
}
}
private fun performTest(roomShouldBeEncrypted: Boolean, action: (Room) -> Unit) {
val cryptoTestData = mCryptoTestHelper.doE2ETestWithAliceInARoom(encryptedRoom = false)
val aliceSession = cryptoTestData.firstSession
val room = aliceSession.getRoom(cryptoTestData.roomId)!!
room.isEncrypted() shouldBe false
val timeline = room.createTimeline(null, TimelineSettings(10))
val latch = CountDownLatch(1)
val timelineListener = object : Timeline.Listener {
override fun onTimelineFailure(throwable: Throwable) {
}
override fun onNewTimelineEvents(eventIds: List<String>) {
// noop
}
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
val newMessages = snapshot
.filter { it.root.sendState == SendState.SYNCED }
.filter { it.root.getClearType() == EventType.STATE_ROOM_ENCRYPTION }
if (newMessages.isNotEmpty()) {
timeline.removeListener(this)
latch.countDown()
}
}
}
timeline.start()
timeline.addListener(timelineListener)
action.invoke(room)
mTestHelper.await(latch)
timeline.dispose()
room.isEncrypted() shouldBe roomShouldBeEncrypted
cryptoTestData.cleanUp(mTestHelper)
}
}

View File

@ -17,15 +17,14 @@
package org.matrix.android.sdk.internal.crypto.verification.qrcode package org.matrix.android.sdk.internal.crypto.verification.qrcode
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import org.matrix.android.sdk.InstrumentedTest import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeNull import org.amshove.kluent.shouldBeNull
import org.amshove.kluent.shouldEqual
import org.amshove.kluent.shouldEqualTo
import org.amshove.kluent.shouldNotBeNull import org.amshove.kluent.shouldNotBeNull
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
import org.matrix.android.sdk.InstrumentedTest
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@FixMethodOrder(MethodSorters.JVM) @FixMethodOrder(MethodSorters.JVM)
@ -66,32 +65,32 @@ class QrCodeTest : InstrumentedTest {
@Test @Test
fun testEncoding1() { fun testEncoding1() {
qrCode1.toEncodedString() shouldEqual value1 qrCode1.toEncodedString() shouldBeEqualTo value1
} }
@Test @Test
fun testEncoding2() { fun testEncoding2() {
qrCode2.toEncodedString() shouldEqual value2 qrCode2.toEncodedString() shouldBeEqualTo value2
} }
@Test @Test
fun testEncoding3() { fun testEncoding3() {
qrCode3.toEncodedString() shouldEqual value3 qrCode3.toEncodedString() shouldBeEqualTo value3
} }
@Test @Test
fun testSymmetry1() { fun testSymmetry1() {
qrCode1.toEncodedString().toQrCodeData() shouldEqual qrCode1 qrCode1.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode1
} }
@Test @Test
fun testSymmetry2() { fun testSymmetry2() {
qrCode2.toEncodedString().toQrCodeData() shouldEqual qrCode2 qrCode2.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode2
} }
@Test @Test
fun testSymmetry3() { fun testSymmetry3() {
qrCode3.toEncodedString().toQrCodeData() shouldEqual qrCode3 qrCode3.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode3
} }
@Test @Test
@ -102,7 +101,7 @@ class QrCodeTest : InstrumentedTest {
checkHeader(byteArray) checkHeader(byteArray)
// Mode // Mode
byteArray[7] shouldEqualTo 0 byteArray[7] shouldBeEqualTo 0
checkSizeAndTransaction(byteArray) checkSizeAndTransaction(byteArray)
@ -120,7 +119,7 @@ class QrCodeTest : InstrumentedTest {
checkHeader(byteArray) checkHeader(byteArray)
// Mode // Mode
byteArray[7] shouldEqualTo 1 byteArray[7] shouldBeEqualTo 1
checkSizeAndTransaction(byteArray) checkSizeAndTransaction(byteArray)
compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray) compareArray(byteArray.copyOfRange(23, 23 + 32), kte_byteArray)
@ -137,7 +136,7 @@ class QrCodeTest : InstrumentedTest {
checkHeader(byteArray) checkHeader(byteArray)
// Mode // Mode
byteArray[7] shouldEqualTo 2 byteArray[7] shouldBeEqualTo 2
checkSizeAndTransaction(byteArray) checkSizeAndTransaction(byteArray)
compareArray(byteArray.copyOfRange(23, 23 + 32), tlx_byteArray) compareArray(byteArray.copyOfRange(23, 23 + 32), tlx_byteArray)
@ -156,10 +155,10 @@ class QrCodeTest : InstrumentedTest {
val result = qrCode.toEncodedString() val result = qrCode.toEncodedString()
val expected = value1.replace("\u0000\u000DMaTransaction", "\u0007\u00D0$longTransactionId") val expected = value1.replace("\u0000\u000DMaTransaction", "\u0007\u00D0$longTransactionId")
result shouldEqual expected result shouldBeEqualTo expected
// Reverse operation // Reverse operation
expected.toQrCodeData() shouldEqual qrCode expected.toQrCodeData() shouldBeEqualTo qrCode
} }
@Test @Test
@ -170,7 +169,7 @@ class QrCodeTest : InstrumentedTest {
val qrCode = qrCode1.copy(transactionId = longTransactionId) val qrCode = qrCode1.copy(transactionId = longTransactionId)
// Symmetric operation // Symmetric operation
qrCode.toEncodedString().toQrCodeData() shouldEqual qrCode qrCode.toEncodedString().toQrCodeData() shouldBeEqualTo qrCode
} }
} }
@ -218,32 +217,32 @@ class QrCodeTest : InstrumentedTest {
} }
private fun compareArray(actual: ByteArray, expected: ByteArray) { private fun compareArray(actual: ByteArray, expected: ByteArray) {
actual.size shouldEqual expected.size actual.size shouldBeEqualTo expected.size
for (i in actual.indices) { for (i in actual.indices) {
actual[i] shouldEqualTo expected[i] actual[i] shouldBeEqualTo expected[i]
} }
} }
private fun checkHeader(byteArray: ByteArray) { private fun checkHeader(byteArray: ByteArray) {
// MATRIX // MATRIX
byteArray[0] shouldEqualTo 'M'.toByte() byteArray[0] shouldBeEqualTo 'M'.toByte()
byteArray[1] shouldEqualTo 'A'.toByte() byteArray[1] shouldBeEqualTo 'A'.toByte()
byteArray[2] shouldEqualTo 'T'.toByte() byteArray[2] shouldBeEqualTo 'T'.toByte()
byteArray[3] shouldEqualTo 'R'.toByte() byteArray[3] shouldBeEqualTo 'R'.toByte()
byteArray[4] shouldEqualTo 'I'.toByte() byteArray[4] shouldBeEqualTo 'I'.toByte()
byteArray[5] shouldEqualTo 'X'.toByte() byteArray[5] shouldBeEqualTo 'X'.toByte()
// Version // Version
byteArray[6] shouldEqualTo 2 byteArray[6] shouldBeEqualTo 2
} }
private fun checkSizeAndTransaction(byteArray: ByteArray) { private fun checkSizeAndTransaction(byteArray: ByteArray) {
// Size // Size
byteArray[8] shouldEqualTo 0 byteArray[8] shouldBeEqualTo 0
byteArray[9] shouldEqualTo 13 byteArray[9] shouldBeEqualTo 13
// Transaction // Transaction
byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldEqual "MaTransaction" byteArray.copyOfRange(10, 10 + "MaTransaction".length).toString(Charsets.ISO_8859_1) shouldBeEqualTo "MaTransaction"
} }
} }

View File

@ -18,6 +18,14 @@ package org.matrix.android.sdk.session.room.timeline
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.zhuinden.monarchy.Monarchy import com.zhuinden.monarchy.Monarchy
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import org.amshove.kluent.shouldBeEqualTo
import org.amshove.kluent.shouldBeTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.matrix.android.sdk.InstrumentedTest import org.matrix.android.sdk.InstrumentedTest
import org.matrix.android.sdk.api.session.events.model.Event 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.api.session.room.send.SendState
@ -29,14 +37,6 @@ import org.matrix.android.sdk.internal.database.model.SessionRealmModule
import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection import org.matrix.android.sdk.internal.session.room.timeline.PaginationDirection
import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeListOfEvents
import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent import org.matrix.android.sdk.session.room.timeline.RoomDataHelper.createFakeMessageEvent
import io.realm.Realm
import io.realm.RealmConfiguration
import io.realm.kotlin.createObject
import org.amshove.kluent.shouldBeTrue
import org.amshove.kluent.shouldEqual
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
internal class ChunkEntityTest : InstrumentedTest { internal class ChunkEntityTest : InstrumentedTest {
@ -60,10 +60,10 @@ internal class ChunkEntityTest : InstrumentedTest {
val chunk: ChunkEntity = realm.createObject() val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let { val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let {
realm.copyToRealmOrUpdate(it) realm.copyToRealm(it)
} }
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.timelineEvents.size shouldEqual 1 chunk.timelineEvents.size shouldBeEqualTo 1
} }
} }
@ -72,11 +72,11 @@ internal class ChunkEntityTest : InstrumentedTest {
monarchy.runTransactionSync { realm -> monarchy.runTransactionSync { realm ->
val chunk: ChunkEntity = realm.createObject() val chunk: ChunkEntity = realm.createObject()
val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let { val fakeEvent = createFakeMessageEvent().toEntity(ROOM_ID, SendState.SYNCED, System.currentTimeMillis()).let {
realm.copyToRealmOrUpdate(it) realm.copyToRealm(it)
} }
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap()) chunk.addTimelineEvent(ROOM_ID, fakeEvent, PaginationDirection.FORWARDS, emptyMap())
chunk.timelineEvents.size shouldEqual 1 chunk.timelineEvents.size shouldBeEqualTo 1
} }
} }
@ -88,7 +88,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.timelineEvents.size shouldEqual 60 chunk1.timelineEvents.size shouldBeEqualTo 60
} }
} }
@ -104,7 +104,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS) chunk1.addAll(ROOM_ID, eventsForChunk1, PaginationDirection.FORWARDS)
chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, eventsForChunk2, PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.timelineEvents.size shouldEqual 40 chunk1.timelineEvents.size shouldBeEqualTo 40
chunk1.isLastForward.shouldBeTrue() chunk1.isLastForward.shouldBeTrue()
} }
} }
@ -119,7 +119,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.FORWARDS)
chunk1.prevToken shouldEqual prevToken chunk1.prevToken shouldBeEqualTo prevToken
} }
} }
@ -133,7 +133,7 @@ internal class ChunkEntityTest : InstrumentedTest {
chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk1.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS) chunk2.addAll(ROOM_ID, createFakeListOfEvents(30), PaginationDirection.BACKWARDS)
chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS) chunk1.merge(ROOM_ID, chunk2, PaginationDirection.BACKWARDS)
chunk1.nextToken shouldEqual nextToken chunk1.nextToken shouldBeEqualTo nextToken
} }
} }
@ -142,7 +142,7 @@ internal class ChunkEntityTest : InstrumentedTest {
direction: PaginationDirection) { direction: PaginationDirection) {
events.forEach { event -> events.forEach { event ->
val fakeEvent = event.toEntity(roomId, SendState.SYNCED, System.currentTimeMillis()).let { val fakeEvent = event.toEntity(roomId, SendState.SYNCED, System.currentTimeMillis()).let {
realm.copyToRealmOrUpdate(it) realm.copyToRealm(it)
} }
addTimelineEvent(roomId, fakeEvent, direction, emptyMap()) addTimelineEvent(roomId, fakeEvent, direction, emptyMap())
} }

View File

@ -21,7 +21,7 @@ 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.EventType
import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.Membership
import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary 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.api.session.room.model.message.MessageTextContent
import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.MessageType
import kotlin.random.Random import kotlin.random.Random
@ -41,7 +41,7 @@ object RoomDataHelper {
} }
} }
fun createFakeEvent(type: String, private fun createFakeEvent(type: String,
content: Content? = null, content: Content? = null,
prevContent: Content? = null, prevContent: Content? = null,
sender: String = FAKE_TEST_SENDER, sender: String = FAKE_TEST_SENDER,
@ -62,8 +62,8 @@ object RoomDataHelper {
return createFakeEvent(EventType.MESSAGE, message) return createFakeEvent(EventType.MESSAGE, message)
} }
fun createFakeRoomMemberEvent(): Event { private fun createFakeRoomMemberEvent(): Event {
val roomMember = RoomMemberSummary(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent() val roomMember = RoomMemberContent(Membership.JOIN, "Fake name #${Random.nextLong()}").toContent()
return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember) return createFakeEvent(EventType.STATE_ROOM_MEMBER, roomMember)
} }
} }

View File

@ -78,7 +78,7 @@ internal class TimelineTest : InstrumentedTest {
// } // }
// } // }
// latch.await() // latch.await()
// timelineEvents.size shouldEqual initialLoad + paginationCount // timelineEvents.size shouldBeEqualTo initialLoad + paginationCount
// timeline.dispose() // timeline.dispose()
// } // }
} }

View File

@ -2,8 +2,10 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="org.matrix.android.sdk"> package="org.matrix.android.sdk">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.VIBRATE" />
<!-- TODO Is WRITE_EXTERNAL_STORAGE necessary? -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application android:networkSecurityConfig="@xml/network_security_config"> <application android:networkSecurityConfig="@xml/network_security_config">

View File

@ -48,18 +48,25 @@ data class MatrixError(
companion object { companion object {
/** Forbidden access, e.g. joining a room without permission, failed login. */ /** Forbidden access, e.g. joining a room without permission, failed login. */
const val M_FORBIDDEN = "M_FORBIDDEN" const val M_FORBIDDEN = "M_FORBIDDEN"
/** An unknown error has occurred. */ /** An unknown error has occurred. */
const val M_UNKNOWN = "M_UNKNOWN" const val M_UNKNOWN = "M_UNKNOWN"
/** The access token specified was not recognised. */ /** The access token specified was not recognised. */
const val M_UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN" const val M_UNKNOWN_TOKEN = "M_UNKNOWN_TOKEN"
/** No access token was specified for the request. */ /** No access token was specified for the request. */
const val M_MISSING_TOKEN = "M_MISSING_TOKEN" const val M_MISSING_TOKEN = "M_MISSING_TOKEN"
/** Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. */ /** Request contained valid JSON, but it was malformed in some way, e.g. missing required keys, invalid values for keys. */
const val M_BAD_JSON = "M_BAD_JSON" const val M_BAD_JSON = "M_BAD_JSON"
/** Request did not contain valid JSON. */ /** Request did not contain valid JSON. */
const val M_NOT_JSON = "M_NOT_JSON" const val M_NOT_JSON = "M_NOT_JSON"
/** No resource was found for this request. */ /** No resource was found for this request. */
const val M_NOT_FOUND = "M_NOT_FOUND" const val M_NOT_FOUND = "M_NOT_FOUND"
/** Too many requests have been sent in a short period of time. Wait a while then try again. */ /** Too many requests have been sent in a short period of time. Wait a while then try again. */
const val M_LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED" const val M_LIMIT_EXCEEDED = "M_LIMIT_EXCEEDED"
@ -69,68 +76,97 @@ data class MatrixError(
/** Encountered when trying to register a user ID which has been taken. */ /** Encountered when trying to register a user ID which has been taken. */
const val M_USER_IN_USE = "M_USER_IN_USE" const val M_USER_IN_USE = "M_USER_IN_USE"
/** Sent when the room alias given to the createRoom API is already in use. */ /** Sent when the room alias given to the createRoom API is already in use. */
const val M_ROOM_IN_USE = "M_ROOM_IN_USE" const val M_ROOM_IN_USE = "M_ROOM_IN_USE"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_BAD_PAGINATION = "M_BAD_PAGINATION" const val M_BAD_PAGINATION = "M_BAD_PAGINATION"
/** The request was not correctly authorized. Usually due to login failures. */ /** The request was not correctly authorized. Usually due to login failures. */
const val M_UNAUTHORIZED = "M_UNAUTHORIZED" const val M_UNAUTHORIZED = "M_UNAUTHORIZED"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_OLD_VERSION = "M_OLD_VERSION" const val M_OLD_VERSION = "M_OLD_VERSION"
/** The server did not understand the request. */ /** The server did not understand the request. */
const val M_UNRECOGNIZED = "M_UNRECOGNIZED" const val M_UNRECOGNIZED = "M_UNRECOGNIZED"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET" const val M_LOGIN_EMAIL_URL_NOT_YET = "M_LOGIN_EMAIL_URL_NOT_YET"
/** Authentication could not be performed on the third party identifier. */ /** Authentication could not be performed on the third party identifier. */
const val M_THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED" const val M_THREEPID_AUTH_FAILED = "M_THREEPID_AUTH_FAILED"
/** Sent when a threepid given to an API cannot be used because no record matching the threepid was found. */ /** Sent when a threepid given to an API cannot be used because no record matching the threepid was found. */
const val M_THREEPID_NOT_FOUND = "M_THREEPID_NOT_FOUND" const val M_THREEPID_NOT_FOUND = "M_THREEPID_NOT_FOUND"
/** Sent when a threepid given to an API cannot be used because the same threepid is already in use. */ /** Sent when a threepid given to an API cannot be used because the same threepid is already in use. */
const val M_THREEPID_IN_USE = "M_THREEPID_IN_USE" const val M_THREEPID_IN_USE = "M_THREEPID_IN_USE"
/** The client's request used a third party server, eg. identity server, that this server does not trust. */ /** The client's request used a third party server, eg. identity server, that this server does not trust. */
const val M_SERVER_NOT_TRUSTED = "M_SERVER_NOT_TRUSTED" const val M_SERVER_NOT_TRUSTED = "M_SERVER_NOT_TRUSTED"
/** The request or entity was too large. */ /** The request or entity was too large. */
const val M_TOO_LARGE = "M_TOO_LARGE" const val M_TOO_LARGE = "M_TOO_LARGE"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN" const val M_CONSENT_NOT_GIVEN = "M_CONSENT_NOT_GIVEN"
/** The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example, /** The request cannot be completed because the homeserver has reached a resource limit imposed on it. For example,
* a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory * a homeserver held in a shared hosting environment may reach a resource limit if it starts using too much memory
* or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach * or disk space. The error MUST have an admin_contact field to provide the user receiving the error a place to reach
* out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account * out to. Typically, this error will appear on routes which attempt to modify state (eg: sending messages, account
* data, etc) and not routes which only read state (eg: /sync, get account data, etc). */ * data, etc) and not routes which only read state (eg: /sync, get account data, etc). */
const val M_RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED" const val M_RESOURCE_LIMIT_EXCEEDED = "M_RESOURCE_LIMIT_EXCEEDED"
/** The user ID associated with the request has been deactivated. Typically for endpoints that prove authentication, such as /login. */ /** The user ID associated with the request has been deactivated. Typically for endpoints that prove authentication, such as /login. */
const val M_USER_DEACTIVATED = "M_USER_DEACTIVATED" const val M_USER_DEACTIVATED = "M_USER_DEACTIVATED"
/** Encountered when trying to register a user ID which is not valid. */ /** Encountered when trying to register a user ID which is not valid. */
const val M_INVALID_USERNAME = "M_INVALID_USERNAME" const val M_INVALID_USERNAME = "M_INVALID_USERNAME"
/** Sent when the initial state given to the createRoom API is invalid. */ /** Sent when the initial state given to the createRoom API is invalid. */
const val M_INVALID_ROOM_STATE = "M_INVALID_ROOM_STATE" const val M_INVALID_ROOM_STATE = "M_INVALID_ROOM_STATE"
/** The server does not permit this third party identifier. This may happen if the server only permits, /** The server does not permit this third party identifier. This may happen if the server only permits,
* for example, email addresses from a particular domain. */ * for example, email addresses from a particular domain. */
const val M_THREEPID_DENIED = "M_THREEPID_DENIED" const val M_THREEPID_DENIED = "M_THREEPID_DENIED"
/** The client's request to create a room used a room version that the server does not support. */ /** The client's request to create a room used a room version that the server does not support. */
const val M_UNSUPPORTED_ROOM_VERSION = "M_UNSUPPORTED_ROOM_VERSION" const val M_UNSUPPORTED_ROOM_VERSION = "M_UNSUPPORTED_ROOM_VERSION"
/** The client attempted to join a room that has a version the server does not support. /** The client attempted to join a room that has a version the server does not support.
* Inspect the room_version property of the error response for the room's version. */ * Inspect the room_version property of the error response for the room's version. */
const val M_INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION" const val M_INCOMPATIBLE_ROOM_VERSION = "M_INCOMPATIBLE_ROOM_VERSION"
/** The state change requested cannot be performed, such as attempting to unban a user who is not banned. */ /** The state change requested cannot be performed, such as attempting to unban a user who is not banned. */
const val M_BAD_STATE = "M_BAD_STATE" const val M_BAD_STATE = "M_BAD_STATE"
/** The room or resource does not permit guests to access it. */ /** The room or resource does not permit guests to access it. */
const val M_GUEST_ACCESS_FORBIDDEN = "M_GUEST_ACCESS_FORBIDDEN" const val M_GUEST_ACCESS_FORBIDDEN = "M_GUEST_ACCESS_FORBIDDEN"
/** A Captcha is required to complete the request. */ /** A Captcha is required to complete the request. */
const val M_CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED" const val M_CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
/** The Captcha provided did not match what was expected. */ /** The Captcha provided did not match what was expected. */
const val M_CAPTCHA_INVALID = "M_CAPTCHA_INVALID" const val M_CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
/** A required parameter was missing from the request. */ /** A required parameter was missing from the request. */
const val M_MISSING_PARAM = "M_MISSING_PARAM" const val M_MISSING_PARAM = "M_MISSING_PARAM"
/** A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. */ /** A parameter that was specified has the wrong value. For example, the server expected an integer and instead received a string. */
const val M_INVALID_PARAM = "M_INVALID_PARAM" const val M_INVALID_PARAM = "M_INVALID_PARAM"
/** The resource being requested is reserved by an application service, or the application service making the request has not created the resource. */ /** The resource being requested is reserved by an application service, or the application service making the request has not created the resource. */
const val M_EXCLUSIVE = "M_EXCLUSIVE" const val M_EXCLUSIVE = "M_EXCLUSIVE"
/** The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. */ /** The user is unable to reject an invite to join the server notices room. See the Server Notices module for more information. */
const val M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM" const val M_CANNOT_LEAVE_SERVER_NOTICE_ROOM = "M_CANNOT_LEAVE_SERVER_NOTICE_ROOM"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION" const val M_WRONG_ROOM_KEYS_VERSION = "M_WRONG_ROOM_KEYS_VERSION"
/** (Not documented yet) */ /** (Not documented yet) */
const val M_WEAK_PASSWORD = "M_WEAK_PASSWORD" const val M_WEAK_PASSWORD = "M_WEAK_PASSWORD"

View File

@ -33,6 +33,7 @@ interface MxCallDetail {
interface MxCall : MxCallDetail { interface MxCall : MxCallDetail {
var state: CallState var state: CallState
/** /**
* Pick Up the incoming call * Pick Up the incoming call
* It has no effect on outgoing call * It has no effect on outgoing call

View File

@ -53,23 +53,31 @@ package org.matrix.android.sdk.api.session.crypto.keysbackup
enum class KeysBackupState { enum class KeysBackupState {
// Need to check the current backup version on the homeserver // Need to check the current backup version on the homeserver
Unknown, Unknown,
// Checking if backup is enabled on home server // Checking if backup is enabled on home server
CheckingBackUpOnHomeserver, CheckingBackUpOnHomeserver,
// Backup has been stopped because a new backup version has been detected on the homeserver // Backup has been stopped because a new backup version has been detected on the homeserver
WrongBackUpVersion, WrongBackUpVersion,
// Backup from this device is not enabled // Backup from this device is not enabled
Disabled, Disabled,
// There is a backup available on the homeserver but it is not trusted. // There is a backup available on the homeserver but it is not trusted.
// It is not trusted because the signature is invalid or the device that created it is not verified // It is not trusted because the signature is invalid or the device that created it is not verified
// Use [KeysBackup.getKeysBackupTrust()] to get trust details. // Use [KeysBackup.getKeysBackupTrust()] to get trust details.
// Consequently, the backup from this device is not enabled. // Consequently, the backup from this device is not enabled.
NotTrusted, NotTrusted,
// Backup is being enabled: the backup version is being created on the homeserver // Backup is being enabled: the backup version is being created on the homeserver
Enabling, Enabling,
// Backup is enabled and ready to send backup to the homeserver // Backup is enabled and ready to send backup to the homeserver
ReadyToBackUp, ReadyToBackUp,
// e2e keys are going to be sent to the homeserver // e2e keys are going to be sent to the homeserver
WillBackUp, WillBackUp,
// e2e keys are being sent to the homeserver // e2e keys are being sent to the homeserver
BackingUp BackingUp
} }

View File

@ -22,8 +22,10 @@ package org.matrix.android.sdk.api.session.crypto.verification
enum class VerificationMethod { enum class VerificationMethod {
// Use it when your application supports the SAS verification method // Use it when your application supports the SAS verification method
SAS, SAS,
// Use it if your application is able to display QR codes // Use it if your application is able to display QR codes
QR_CODE_SHOW, QR_CODE_SHOW,
// Use it if your application is able to scan QR codes // Use it if your application is able to scan QR codes
QR_CODE_SCAN QR_CODE_SCAN
} }

View File

@ -253,6 +253,7 @@ fun Event.isFileMessage(): Boolean {
else -> false else -> false
} }
} }
fun Event.isAttachmentMessage(): Boolean { fun Event.isAttachmentMessage(): Boolean {
return getClearType() == EventType.MESSAGE return getClearType() == EventType.MESSAGE
&& when (getClearContent()?.toModel<MessageContent>()?.msgType) { && when (getClearContent()?.toModel<MessageContent>()?.msgType) {

View File

@ -21,10 +21,13 @@ package org.matrix.android.sdk.api.session.events.model
object RelationType { object RelationType {
/** Lets you define an event which annotates an existing event.*/ /** Lets you define an event which annotates an existing event.*/
const val ANNOTATION = "m.annotation" const val ANNOTATION = "m.annotation"
/** Lets you define an event which replaces an existing event.*/ /** Lets you define an event which replaces an existing event.*/
const val REPLACE = "m.replace" const val REPLACE = "m.replace"
/** Lets you define an event which references an existing event.*/ /** Lets you define an event which references an existing event.*/
const val REFERENCE = "m.reference" const val REFERENCE = "m.reference"
/** Lets you define an event which adds a response to an existing event.*/ /** Lets you define an event which adds a response to an existing event.*/
const val RESPONSE = "org.matrix.response" const val RESPONSE = "org.matrix.response"
} }

View File

@ -33,10 +33,12 @@ data class IntegrationManagerConfig(
* Defined in UserAccountData * Defined in UserAccountData
*/ */
ACCOUNT, ACCOUNT,
/** /**
* Defined in Wellknown * Defined in Wellknown
*/ */
HOMESERVER, HOMESERVER,
/** /**
* Fallback value, hardcoded by the SDK * Fallback value, hardcoded by the SDK
*/ */

View File

@ -16,7 +16,7 @@
package org.matrix.android.sdk.api.session.room.members package org.matrix.android.sdk.api.session.room.members
sealed class ChangeMembershipState() { sealed class ChangeMembershipState {
object Unknown : ChangeMembershipState() object Unknown : ChangeMembershipState()
object Joining : ChangeMembershipState() object Joining : ChangeMembershipState()
data class FailedJoining(val throwable: Throwable) : ChangeMembershipState() data class FailedJoining(val throwable: Throwable) : ChangeMembershipState()

View File

@ -33,6 +33,7 @@ data class RoomGuestAccessContent(
enum class GuestAccess(val value: String) { enum class GuestAccess(val value: String) {
@Json(name = "can_join") @Json(name = "can_join")
CanJoin("can_join"), CanJoin("can_join"),
@Json(name = "forbidden") @Json(name = "forbidden")
Forbidden("forbidden") Forbidden("forbidden")
} }

View File

@ -29,16 +29,19 @@ enum class RoomHistoryVisibility {
* participating homeserver with anyone, regardless of whether they have ever joined the room. * participating homeserver with anyone, regardless of whether they have ever joined the room.
*/ */
@Json(name = "world_readable") WORLD_READABLE, @Json(name = "world_readable") WORLD_READABLE,
/** /**
* Previous events are always accessible to newly joined members. All events in the * Previous events are always accessible to newly joined members. All events in the
* room are accessible, even those sent when the member was not a part of the room. * room are accessible, even those sent when the member was not a part of the room.
*/ */
@Json(name = "shared") SHARED, @Json(name = "shared") SHARED,
/** /**
* Events are accessible to newly joined members from the point they were invited onwards. * Events are accessible to newly joined members from the point they were invited onwards.
* Events stop being accessible when the member's state changes to something other than invite or join. * Events stop being accessible when the member's state changes to something other than invite or join.
*/ */
@Json(name = "invited") INVITED, @Json(name = "invited") INVITED,
/** /**
* Events are accessible to newly joined members from the point they joined the room onwards. * Events are accessible to newly joined members from the point they joined the room onwards.
* Events stop being accessible when the member's state changes to something other than join. * Events stop being accessible when the member's state changes to something other than join.

View File

@ -29,6 +29,7 @@ object MessageType {
const val MSGTYPE_RESPONSE = "org.matrix.response" const val MSGTYPE_RESPONSE = "org.matrix.response"
const val MSGTYPE_POLL_CLOSED = "org.matrix.poll_closed" const val MSGTYPE_POLL_CLOSED = "org.matrix.poll_closed"
const val MSGTYPE_VERIFICATION_REQUEST = "m.key.verification.request" const val MSGTYPE_VERIFICATION_REQUEST = "m.key.verification.request"
// Add, in local, a fake message type in order to StickerMessage can inherit Message class // Add, in local, a fake message type in order to StickerMessage can inherit Message class
// Because sticker isn't a message type but a event type without msgtype field // Because sticker isn't a message type but a event type without msgtype field
const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker" const val MSGTYPE_STICKER_LOCAL = "org.matrix.android.sdk.sticker"

View File

@ -18,18 +18,25 @@ package org.matrix.android.sdk.api.session.room.send
enum class SendState { enum class SendState {
UNKNOWN, UNKNOWN,
// the event has not been sent // the event has not been sent
UNSENT, UNSENT,
// the event is encrypting // the event is encrypting
ENCRYPTING, ENCRYPTING,
// the event is currently sending // the event is currently sending
SENDING, SENDING,
// the event has been sent // the event has been sent
SENT, SENT,
// the event has been received from server // the event has been received from server
SYNCED, SYNCED,
// The event failed to be sent // The event failed to be sent
UNDELIVERED, UNDELIVERED,
// the event failed to be sent because some unknown devices have been found while encrypting it // the event failed to be sent because some unknown devices have been found while encrypting it
FAILED_UNKNOWN_DEVICES; FAILED_UNKNOWN_DEVICES;

View File

@ -128,6 +128,7 @@ interface Timeline {
* It represents future events. * It represents future events.
*/ */
FORWARDS, FORWARDS,
/** /**
* It represents past events. * It represents past events.
*/ */

View File

@ -20,6 +20,7 @@ interface FilterService {
enum class FilterPreset { enum class FilterPreset {
NoFilter, NoFilter,
/** /**
* Filter for Riot, will include only known event type * Filter for Riot, will include only known event type
*/ */

View File

@ -35,6 +35,7 @@ const val MXCRYPTO_ALGORITHM_MEGOLM_BACKUP = "m.megolm_backup.v1.curve25519-aes-
* Secured Shared Storage algorithm constant * Secured Shared Storage algorithm constant
*/ */
const val SSSS_ALGORITHM_CURVE25519_AES_SHA2 = "m.secret_storage.v1.curve25519-aes-sha2" const val SSSS_ALGORITHM_CURVE25519_AES_SHA2 = "m.secret_storage.v1.curve25519-aes-sha2"
/* Secrets are encrypted using AES-CTR-256 and MACed using HMAC-SHA-256. **/ /* Secrets are encrypted using AES-CTR-256 and MACed using HMAC-SHA-256. **/
const val SSSS_ALGORITHM_AES_HMAC_SHA2 = "m.secret_storage.v1.aes-hmac-sha2" const val SSSS_ALGORITHM_AES_HMAC_SHA2 = "m.secret_storage.v1.aes-hmac-sha2"

View File

@ -194,18 +194,18 @@ internal class DefaultCryptoService @Inject constructor(
private val lastNewSessionForcedDates = MXUsersDevicesMap<Long>() private val lastNewSessionForcedDates = MXUsersDevicesMap<Long>()
fun onStateEvent(roomId: String, event: Event) { fun onStateEvent(roomId: String, event: Event) {
when { when (event.getClearType()) {
event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} }
} }
fun onLiveEvent(roomId: String, event: Event) { fun onLiveEvent(roomId: String, event: Event) {
when { when (event.getClearType()) {
event.getClearType() == EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event) EventType.STATE_ROOM_ENCRYPTION -> onRoomEncryptionEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event) EventType.STATE_ROOM_MEMBER -> onRoomMembershipEvent(roomId, event)
event.getClearType() == EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event) EventType.STATE_ROOM_HISTORY_VISIBILITY -> onRoomHistoryVisibilityEvent(roomId, event)
} }
} }
@ -615,6 +615,7 @@ internal class DefaultCryptoService @Inject constructor(
val encryptionEvent = monarchy.fetchCopied { realm -> val encryptionEvent = monarchy.fetchCopied { realm ->
EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION) EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
.isNotNull(EventEntityFields.STATE_KEY)
.findFirst() .findFirst()
} }
return encryptionEvent != null return encryptionEvent != null
@ -915,6 +916,11 @@ internal class DefaultCryptoService @Inject constructor(
* @param event the encryption event. * @param event the encryption event.
*/ */
private fun onRoomEncryptionEvent(roomId: String, event: Event) { private fun onRoomEncryptionEvent(roomId: String, event: Event) {
if (!event.isStateEvent()) {
// Ignore
Timber.w("Invalid encryption event")
return
}
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
val params = LoadRoomMembersTask.Params(roomId) val params = LoadRoomMembersTask.Params(roomId)
try { try {

View File

@ -359,7 +359,6 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM
cryptoStore.storeUserDevices(userId, workingCopy) cryptoStore.storeUserDevices(userId, workingCopy)
} }
// Handle cross signing keys update
val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also { val masterKey = response.masterKeys?.get(userId)?.toCryptoModel().also {
Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}") Timber.v("## CRYPTO | CrossSigning : Got keys for $userId : MSK ${it?.unpaddedBase64PublicKey}")
} }

View File

@ -28,6 +28,7 @@ enum class GossipingRequestState {
ACCEPTING, ACCEPTING,
ACCEPTED, ACCEPTED,
FAILED_TO_ACCEPTED, FAILED_TO_ACCEPTED,
// USER_REJECTED, // USER_REJECTED,
UNABLE_TO_PROCESS, UNABLE_TO_PROCESS,
CANCELLED_BY_REQUESTER, CANCELLED_BY_REQUESTER,

View File

@ -36,6 +36,7 @@ import kotlin.math.min
object MXMegolmExportEncryption { object MXMegolmExportEncryption {
private const val HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----" private const val HEADER_LINE = "-----BEGIN MEGOLM SESSION DATA-----"
private const val TRAILER_LINE = "-----END MEGOLM SESSION DATA-----" private const val TRAILER_LINE = "-----END MEGOLM SESSION DATA-----"
// we split into lines before base64ing, because encodeBase64 doesn't deal // we split into lines before base64ing, because encodeBase64 doesn't deal
// terribly well with large arrays. // terribly well with large arrays.
private const val LINE_LENGTH = 72 * 4 / 3 private const val LINE_LENGTH = 72 * 4 / 3

View File

@ -70,7 +70,9 @@ internal class OutgoingGossipingRequestManager @Inject constructor(
delay(1500) delay(1500)
cryptoStore.getOrAddOutgoingSecretShareRequest(secretName, recipients)?.let { cryptoStore.getOrAddOutgoingSecretShareRequest(secretName, recipients)?.let {
// TODO check if there is already one that is being sent? // TODO check if there is already one that is being sent?
if (it.state == OutgoingGossipingRequestState.SENDING /**|| it.state == OutgoingGossipingRequestState.SENT*/) { if (it.state == OutgoingGossipingRequestState.SENDING
/**|| it.state == OutgoingGossipingRequestState.SENT*/
) {
Timber.v("## CRYPTO - GOSSIP sendSecretShareRequest() : we are already sending for that session: $it") Timber.v("## CRYPTO - GOSSIP sendSecretShareRequest() : we are already sending for that session: $it")
return@launch return@launch
} }

View File

@ -80,6 +80,7 @@ class OlmInboundGroupSessionWrapper2 : Serializable {
constructor() { constructor() {
// empty // empty
} }
/** /**
* Create a new instance from the provided keys map. * Create a new instance from the provided keys map.
* *

View File

@ -66,19 +66,23 @@ enum class WithHeldCode(val value: String) {
* the user/device was blacklisted * the user/device was blacklisted
*/ */
BLACKLISTED("m.blacklisted"), BLACKLISTED("m.blacklisted"),
/** /**
* the user/devices is unverified * the user/devices is unverified
*/ */
UNVERIFIED("m.unverified"), UNVERIFIED("m.unverified"),
/** /**
* the user/device is not allowed have the key. For example, this would usually be sent in response * the user/device is not allowed have the key. For example, this would usually be sent in response
* to a key request if the user was not in the room when the message was sent * to a key request if the user was not in the room when the message was sent
*/ */
UNAUTHORISED("m.unauthorised"), UNAUTHORISED("m.unauthorised"),
/** /**
* Sent in reply to a key request if the device that the key is requested from does not have the requested key * Sent in reply to a key request if the device that the key is requested from does not have the requested key
*/ */
UNAVAILABLE("m.unavailable"), UNAVAILABLE("m.unavailable"),
/** /**
* An olm session could not be established. * An olm session could not be established.
* This may happen, for example, if the sender was unable to obtain a one-time key from the recipient. * This may happen, for example, if the sender was unable to obtain a one-time key from the recipient.

View File

@ -23,7 +23,6 @@ import io.realm.Realm
import io.realm.RealmConfiguration import io.realm.RealmConfiguration
import io.realm.Sort import io.realm.Sort
import io.realm.kotlin.where import io.realm.kotlin.where
import org.matrix.android.sdk.api.auth.data.Credentials
import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo
import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.LocalEcho import org.matrix.android.sdk.api.session.events.model.LocalEcho
@ -86,7 +85,9 @@ import org.matrix.android.sdk.internal.crypto.store.db.query.getById
import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate import org.matrix.android.sdk.internal.crypto.store.db.query.getOrCreate
import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.ContentMapper
import org.matrix.android.sdk.internal.di.CryptoDatabase import org.matrix.android.sdk.internal.di.CryptoDatabase
import org.matrix.android.sdk.internal.di.DeviceId
import org.matrix.android.sdk.internal.di.MoshiProvider import org.matrix.android.sdk.internal.di.MoshiProvider
import org.matrix.android.sdk.internal.di.UserId
import org.matrix.android.sdk.internal.session.SessionScope import org.matrix.android.sdk.internal.session.SessionScope
import org.matrix.olm.OlmAccount import org.matrix.olm.OlmAccount
import org.matrix.olm.OlmException import org.matrix.olm.OlmException
@ -98,7 +99,9 @@ import kotlin.collections.set
internal class RealmCryptoStore @Inject constructor( internal class RealmCryptoStore @Inject constructor(
@CryptoDatabase private val realmConfiguration: RealmConfiguration, @CryptoDatabase private val realmConfiguration: RealmConfiguration,
private val crossSigningKeysMapper: CrossSigningKeysMapper, private val crossSigningKeysMapper: CrossSigningKeysMapper,
private val credentials: Credentials) : IMXCryptoStore { @UserId private val userId: String,
@DeviceId private val deviceId: String?
) : IMXCryptoStore {
/* ========================================================================================== /* ==========================================================================================
* Memory cache, to correctly release JNI objects * Memory cache, to correctly release JNI objects
@ -141,8 +144,8 @@ internal class RealmCryptoStore @Inject constructor(
// Check credentials // Check credentials
// The device id may not have been provided in credentials. // The device id may not have been provided in credentials.
// Check it only if provided, else trust the stored one. // Check it only if provided, else trust the stored one.
if (currentMetadata.userId != credentials.userId if (currentMetadata.userId != userId
|| (credentials.deviceId != null && credentials.deviceId != currentMetadata.deviceId)) { || (deviceId != null && deviceId != currentMetadata.deviceId)) {
Timber.w("## open() : Credentials do not match, close this store and delete data") Timber.w("## open() : Credentials do not match, close this store and delete data")
deleteAll = true deleteAll = true
currentMetadata = null currentMetadata = null
@ -155,8 +158,8 @@ internal class RealmCryptoStore @Inject constructor(
} }
// Metadata not found, or database cleaned, create it // Metadata not found, or database cleaned, create it
realm.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply { realm.createObject(CryptoMetadataEntity::class.java, userId).apply {
deviceId = credentials.deviceId deviceId = this@RealmCryptoStore.deviceId
} }
} }
} }
@ -302,22 +305,42 @@ internal class RealmCryptoStore @Inject constructor(
userEntity.crossSigningInfoEntity?.deleteFromRealm() userEntity.crossSigningInfoEntity?.deleteFromRealm()
userEntity.crossSigningInfoEntity = null userEntity.crossSigningInfoEntity = null
} else { } else {
var shouldResetMyDevicesLocalTrust = false
CrossSigningInfoEntity.getOrCreate(realm, userId).let { signingInfo -> CrossSigningInfoEntity.getOrCreate(realm, userId).let { signingInfo ->
// What should we do if we detect a change of the keys? // What should we do if we detect a change of the keys?
val existingMaster = signingInfo.getMasterKey() val existingMaster = signingInfo.getMasterKey()
if (existingMaster != null && existingMaster.publicKeyBase64 == masterKey.unpaddedBase64PublicKey) { if (existingMaster != null && existingMaster.publicKeyBase64 == masterKey.unpaddedBase64PublicKey) {
crossSigningKeysMapper.update(existingMaster, masterKey) crossSigningKeysMapper.update(existingMaster, masterKey)
} else { } else {
Timber.d("## CrossSigning MSK change for $userId")
val keyEntity = crossSigningKeysMapper.map(masterKey) val keyEntity = crossSigningKeysMapper.map(masterKey)
signingInfo.setMasterKey(keyEntity) signingInfo.setMasterKey(keyEntity)
if (userId == this.userId) {
shouldResetMyDevicesLocalTrust = true
// my msk has changed! clear my private key
// Could we have some race here? e.g I am the one that did change the keys
// could i get this update to early and clear the private keys?
// -> initializeCrossSigning is guarding for that by storing all at once
realm.where<CryptoMetadataEntity>().findFirst()?.apply {
xSignMasterPrivateKey = null
}
}
} }
val existingSelfSigned = signingInfo.getSelfSignedKey() val existingSelfSigned = signingInfo.getSelfSignedKey()
if (existingSelfSigned != null && existingSelfSigned.publicKeyBase64 == selfSigningKey.unpaddedBase64PublicKey) { if (existingSelfSigned != null && existingSelfSigned.publicKeyBase64 == selfSigningKey.unpaddedBase64PublicKey) {
crossSigningKeysMapper.update(existingSelfSigned, selfSigningKey) crossSigningKeysMapper.update(existingSelfSigned, selfSigningKey)
} else { } else {
Timber.d("## CrossSigning SSK change for $userId")
val keyEntity = crossSigningKeysMapper.map(selfSigningKey) val keyEntity = crossSigningKeysMapper.map(selfSigningKey)
signingInfo.setSelfSignedKey(keyEntity) signingInfo.setSelfSignedKey(keyEntity)
if (userId == this.userId) {
shouldResetMyDevicesLocalTrust = true
// my ssk has changed! clear my private key
realm.where<CryptoMetadataEntity>().findFirst()?.apply {
xSignSelfSignedPrivateKey = null
}
}
} }
// Only for me // Only for me
@ -326,8 +349,27 @@ internal class RealmCryptoStore @Inject constructor(
if (existingUSK != null && existingUSK.publicKeyBase64 == userSigningKey.unpaddedBase64PublicKey) { if (existingUSK != null && existingUSK.publicKeyBase64 == userSigningKey.unpaddedBase64PublicKey) {
crossSigningKeysMapper.update(existingUSK, userSigningKey) crossSigningKeysMapper.update(existingUSK, userSigningKey)
} else { } else {
Timber.d("## CrossSigning USK change for $userId")
val keyEntity = crossSigningKeysMapper.map(userSigningKey) val keyEntity = crossSigningKeysMapper.map(userSigningKey)
signingInfo.setUserSignedKey(keyEntity) signingInfo.setUserSignedKey(keyEntity)
if (userId == this.userId) {
shouldResetMyDevicesLocalTrust = true
// my usk has changed! clear my private key
realm.where<CryptoMetadataEntity>().findFirst()?.apply {
xSignUserPrivateKey = null
}
}
}
}
// When my cross signing keys are reset, we consider clearing all existing device trust
if (shouldResetMyDevicesLocalTrust) {
realm.where<UserEntity>()
.equalTo(UserEntityFields.USER_ID, this.userId)
.findFirst()
?.devices?.forEach {
it?.trustLevelEntity?.crossSignedVerified = false
it?.trustLevelEntity?.locallyVerified = it.deviceId == deviceId
} }
} }
userEntity.crossSigningInfoEntity = signingInfo userEntity.crossSigningInfoEntity = signingInfo
@ -1316,7 +1358,7 @@ internal class RealmCryptoStore @Inject constructor(
.findAll() .findAll()
xInfoEntities?.forEach { info -> xInfoEntities?.forEach { info ->
// Need to ignore mine // Need to ignore mine
if (info.userId != credentials.userId) { if (info.userId != userId) {
info.crossSigningKeys.forEach { info.crossSigningKeys.forEach {
it.trustLevelEntity = null it.trustLevelEntity = null
} }
@ -1331,7 +1373,7 @@ internal class RealmCryptoStore @Inject constructor(
.findAll() .findAll()
xInfoEntities?.forEach { xInfoEntity -> xInfoEntities?.forEach { xInfoEntity ->
// Need to ignore mine // Need to ignore mine
if (xInfoEntity.userId == credentials.userId) return@forEach if (xInfoEntity.userId == userId) return@forEach
val mapped = mapCrossSigningInfoEntity(xInfoEntity) val mapped = mapCrossSigningInfoEntity(xInfoEntity)
val currentTrust = mapped.isTrusted() val currentTrust = mapped.isTrusted()
val newTrust = check(mapped.userId) val newTrust = check(mapped.userId)

View File

@ -68,10 +68,13 @@ internal abstract class SASDefaultVerificationTransaction(
// Deprecated maybe removed later, use V2 // Deprecated maybe removed later, use V2
const val KEY_AGREEMENT_V1 = "curve25519" const val KEY_AGREEMENT_V1 = "curve25519"
const val KEY_AGREEMENT_V2 = "curve25519-hkdf-sha256" const val KEY_AGREEMENT_V2 = "curve25519-hkdf-sha256"
// ordered by preferred order // ordered by preferred order
val KNOWN_AGREEMENT_PROTOCOLS = listOf(KEY_AGREEMENT_V2, KEY_AGREEMENT_V1) val KNOWN_AGREEMENT_PROTOCOLS = listOf(KEY_AGREEMENT_V2, KEY_AGREEMENT_V1)
// ordered by preferred order // ordered by preferred order
val KNOWN_HASHES = listOf("sha256") val KNOWN_HASHES = listOf("sha256")
// ordered by preferred order // ordered by preferred order
val KNOWN_MACS = listOf(SAS_MAC_SHA256, SAS_MAC_SHA256_LONGKDF) val KNOWN_MACS = listOf(SAS_MAC_SHA256, SAS_MAC_SHA256_LONGKDF)
@ -101,6 +104,7 @@ internal abstract class SASDefaultVerificationTransaction(
// Visible for test // Visible for test
var startReq: ValidVerificationInfoStart.SasVerificationInfoStart? = null var startReq: ValidVerificationInfoStart.SasVerificationInfoStart? = null
// Visible for test // Visible for test
var accepted: ValidVerificationInfoAccept? = null var accepted: ValidVerificationInfoAccept? = null
protected var otherKey: String? = null protected var otherKey: String? = null

View File

@ -47,6 +47,7 @@ internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, roomId
} }
return obj return obj
} }
internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity {
return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst()
?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId).apply { this.roomId = roomId } ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId).apply { this.roomId = roomId }

View File

@ -94,6 +94,7 @@ internal class RoomSummaryUpdater @Inject constructor(
// Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room // Don't use current state for this one as we are only interested in having MXCRYPTO_ALGORITHM_MEGOLM event in the room
val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION) val encryptionEvent = EventEntity.whereType(realm, roomId = roomId, type = EventType.STATE_ROOM_ENCRYPTION)
.contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"") .contains(EventEntityFields.CONTENT, "\"algorithm\":\"$MXCRYPTO_ALGORITHM_MEGOLM\"")
.isNotNull(EventEntityFields.STATE_KEY)
.findFirst() .findFirst()
val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId) val latestPreviewableEvent = RoomSummaryEventsHelper.getLatestPreviewableEvent(realm, roomId)

View File

@ -58,6 +58,7 @@ internal class TimelineEventDecryptor @Inject constructor(
// Set of eventIds which are currently decrypting // Set of eventIds which are currently decrypting
private val existingRequests = mutableSetOf<DecryptionRequest>() private val existingRequests = mutableSetOf<DecryptionRequest>()
// sessionId -> list of eventIds // sessionId -> list of eventIds
private val unknownSessionsFailure = mutableMapOf<String, MutableSet<DecryptionRequest>>() private val unknownSessionsFailure = mutableMapOf<String, MutableSet<DecryptionRequest>>()

View File

@ -48,6 +48,7 @@ internal class DefaultTypingService @AssistedInject constructor(
// What the homeserver knows // What the homeserver knows
private var userIsTyping = false private var userIsTyping = false
// Last time the user is typing event has been sent // Last time the user is typing event has been sent
private var lastRequestTimestamp: Long = 0 private var lastRequestTimestamp: Long = 0

View File

@ -67,6 +67,7 @@ internal class DefaultWidgetPostAPIMediator @Inject constructor(private val mosh
Timber.d("BRIDGE onWidgetEvent : $jsonEventData") Timber.d("BRIDGE onWidgetEvent : $jsonEventData")
try { try {
val dataAsDict = jsonAdapter.fromJson(jsonEventData) val dataAsDict = jsonAdapter.fromJson(jsonEventData)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val eventData = (dataAsDict?.get("event.data") as? JsonDict) ?: return val eventData = (dataAsDict?.get("event.data") as? JsonDict) ?: return
onWidgetMessage(eventData) onWidgetMessage(eventData)

View File

@ -4,47 +4,47 @@
<string name="summary_user_sent_image">Uživatel %1$s poslal obrázek.</string> <string name="summary_user_sent_image">Uživatel %1$s poslal obrázek.</string>
<string name="summary_user_sent_sticker">Uživatel %1$s poslal nálepku.</string> <string name="summary_user_sent_sticker">Uživatel %1$s poslal nálepku.</string>
<string name="notice_room_invite_no_invitee">Pozvánka od uživatele %s</string> <string name="notice_room_invite_no_invitee">Pozvání od uživatele %s</string>
<string name="notice_room_invite">Uživatel %1$s pozval uživatele %2$s</string> <string name="notice_room_invite">Uživatel %1$s pozval uživatele %2$s</string>
<string name="notice_room_invite_you">Uživatel %1$s vás pozval</string> <string name="notice_room_invite_you">Uživatel %1$s vás pozval</string>
<string name="notice_room_join">Uživatel %1$s se připojil</string> <string name="notice_room_join">%1$s vstoupil do místnosti</string>
<string name="notice_room_leave">Uživatel %1$s odešel</string> <string name="notice_room_leave">Uživatel %1$s odešel</string>
<string name="notice_room_reject">Uživatel %1$s odmítl pozvání</string> <string name="notice_room_reject">%1$s odmítli pozvání</string>
<string name="notice_room_kick">Uživatel %1$s vykoplivatele %2$s</string> <string name="notice_room_kick">%1$s vykopli %2$s</string>
<string name="notice_room_unban">Uživatel %1$s znovu povolil vstup uživateli %2$s</string> <string name="notice_room_unban">%1$s zrušil vykázání %2$s</string>
<string name="notice_room_ban">Uživatel %1$s vykázalivatele %2$s</string> <string name="notice_room_ban">%1$s vykázali %2$s</string>
<string name="notice_room_withdraw">Uživatel %1$s zrušil pozvání pro uživatele %2$s</string> <string name="notice_room_withdraw">%1$s zrušili pozvání pro %2$s</string>
<string name="notice_avatar_url_changed">Uživatel %1$s změnil svůj profilový obrázek</string> <string name="notice_avatar_url_changed">%1$s změnili svůj profilový obrázek</string>
<string name="notice_display_name_set">Uživatel %1$s nastavil své zobrazované jméno na %2$s</string> <string name="notice_display_name_set">%1$s nastavili své veřejné jméno na %2$s</string>
<string name="notice_display_name_changed_from">Uživatel %1$s změnil své zobrazované jméno z %2$s na %3$s</string> <string name="notice_display_name_changed_from">%1$s změnili své veřejné jméno z %2$s na %3$s</string>
<string name="notice_display_name_removed">Uživatel %1$s odstranil své zobrazované jméno (%2$s)</string> <string name="notice_display_name_removed">%1$s odstranili své veřejné jméno (%2$s)</string>
<string name="notice_room_topic_changed">Uživatel %1$s změnil téma na: %2$s</string> <string name="notice_room_topic_changed">%1$s změnili téma na: %2$s</string>
<string name="notice_room_name_changed">Uživatel %1$s změnil název místnosti na: %2$s</string> <string name="notice_room_name_changed">%1$s změnili název místnosti na: %2$s</string>
<string name="notice_placed_video_call">Uživatel %s uskutečnil videohovor.</string> <string name="notice_placed_video_call">%s uskutečnili videohovor.</string>
<string name="notice_placed_voice_call">Uživatel %s uskutečnil hlasový hovor.</string> <string name="notice_placed_voice_call">%s uskutečnili hlasový hovor.</string>
<string name="notice_answered_call">Uživatel %s přijal hovor.</string> <string name="notice_answered_call">%s přijali hovor.</string>
<string name="notice_ended_call">Uživatel %s ukončil hovor.</string> <string name="notice_ended_call">%s ukončili hovor.</string>
<string name="notice_made_future_room_visibility">Uživatel %1$s nastavit viditelnost budoucích zpráv v místnosti pro %2$s</string> <string name="notice_made_future_room_visibility">%1$s nastavili viditelnost budoucí historie místnosti pro %2$s</string>
<string name="notice_room_visibility_invited">všechny členy místnosti od chvíle, kdy budou pozváni.</string> <string name="notice_room_visibility_invited">všechny členy místnosti od chvíle, kdy budou pozváni.</string>
<string name="notice_room_visibility_joined">všechny členy místnosti od chvíle, kdy se připojí.</string> <string name="notice_room_visibility_joined">všechny členy místnosti od chvíle, kdy se připojí.</string>
<string name="notice_room_visibility_shared">všechny členy místnosti.</string> <string name="notice_room_visibility_shared">všechny členy místnosti.</string>
<string name="notice_room_visibility_world_readable">kohokoliv.</string> <string name="notice_room_visibility_world_readable">kohokoliv.</string>
<string name="notice_room_visibility_unknown">neznámým (%s).</string> <string name="notice_room_visibility_unknown">neznámým (%s).</string>
<string name="notice_end_to_end">Uživatel %1$s zapnul end-to-end šifrování (%2$s)</string> <string name="notice_end_to_end">%1$s zapnuli end-to-end šifrování (%2$s)</string>
<string name="notice_requested_voip_conference">Uživatel %1$s požádal o VoIP konferenci</string> <string name="notice_requested_voip_conference">%1$s požádali o VoIP konferenci</string>
<string name="notice_voip_started">Začala VoIP konference</string> <string name="notice_voip_started">Začala VoIP konference</string>
<string name="notice_voip_finished">VoIP konference skončila</string> <string name="notice_voip_finished">VoIP konference skončila</string>
<string name="notice_avatar_changed_too">(profilový obrázek byl také změněn)</string> <string name="notice_avatar_changed_too">(profilový obrázek byl také změněn)</string>
<string name="notice_room_name_removed">Uživatel %1$s odstranil název místnosti</string> <string name="notice_room_name_removed">%1$s odstranili název místnosti</string>
<string name="notice_room_topic_removed">Uživatel %1$s odstranil téma místnosti</string> <string name="notice_room_topic_removed">%1$s odstranili téma místnosti</string>
<string name="notice_profile_change_redacted">Uživatel %1$s aktualizoval svůj profil %2$s</string> <string name="notice_profile_change_redacted">%1$s aktualizovali svůj profil %2$s</string>
<string name="notice_room_third_party_invite">Uživatel %1$s do této místnosti pozvalivatele %2$s</string> <string name="notice_room_third_party_invite">%1$s do této místnosti pozvali %2$s</string>
<string name="notice_room_third_party_registered_invite">Uživatel %1$s přijal pozvání pro %2$s</string> <string name="notice_room_third_party_registered_invite">%1$s přijali pozvání pro %2$s</string>
<string name="notice_crypto_unable_to_decrypt">** Nelze dešifrovat: %s **</string> <string name="notice_crypto_unable_to_decrypt">** Nelze dešifrovat: %s **</string>
<string name="notice_crypto_error_unkwown_inbound_session_id">Odesílatelovo zařízení neposlalo klíče pro tuto zprávu.</string> <string name="notice_crypto_error_unkwown_inbound_session_id">Odesílatelovo zařízení nám neposlalo klíče pro tuto zprávu.</string>
<string name="could_not_redact">Nelze vymazat</string> <string name="could_not_redact">Nelze vymazat</string>
<string name="unable_to_send_message">Zprávu nelze odeslat</string> <string name="unable_to_send_message">Zprávu nelze odeslat</string>
@ -54,7 +54,7 @@
<string name="network_error">Chyba sítě</string> <string name="network_error">Chyba sítě</string>
<string name="matrix_error">Chyba v Matrixu</string> <string name="matrix_error">Chyba v Matrixu</string>
<string name="room_error_join_failed_empty_room">V současnosti není možné se znovu připojit do prázdné místnosti.</string> <string name="room_error_join_failed_empty_room">V současnosti není možné znovu vstoupit do prázdné místnosti.</string>
<string name="encrypted_message">Šifrovaná zpráva</string> <string name="encrypted_message">Šifrovaná zpráva</string>
@ -74,35 +74,161 @@
<string name="room_displayname_empty_room">Prázdná místnost</string> <string name="room_displayname_empty_room">Prázdná místnost</string>
<string name="notice_room_update">Uživatel %s upgradoval tuto místnost.</string> <string name="notice_room_update">%s povýšili tuto místnost.</string>
<string name="notice_event_redacted_with_reason">Zpráva byla smazána [důvod: %1$s]</string> <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_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="notice_room_third_party_revoked_invite">%1$s zrušili pozvánku do místnosti pro %2$s</string>
<string name="initial_sync_start_importing_account">Úvodní synchronizace: <string name="initial_sync_start_importing_account">Úvodní synchronizace:
\nImport účtu</string> \nImportuji účet…</string>
<string name="initial_sync_start_importing_account_crypto">Úvodní synchronizace: <string name="initial_sync_start_importing_account_crypto">Úvodní synchronizace:
\nImport klíčů</string> \nImportuji klíče</string>
<string name="initial_sync_start_importing_account_rooms">Úvodní synchronizace: <string name="initial_sync_start_importing_account_rooms">Úvodní synchronizace:
\nImport místností</string> \nImportuji místnosti</string>
<string name="initial_sync_start_importing_account_joined_rooms">Úvodní synchronizace: <string name="initial_sync_start_importing_account_joined_rooms">Úvodní synchronizace:
\nImport místností, kterými jste členy</string> \nImportuji místností, jichž jste členy</string>
<string name="initial_sync_start_importing_account_left_rooms">Úvodní synchronizace: <string name="initial_sync_start_importing_account_left_rooms">Úvodní synchronizace:
\nImport opuštěných místností</string> \nImportuji místnost, jež jste opustili</string>
<string name="initial_sync_start_importing_account_groups">Úvodní synchronizace: <string name="initial_sync_start_importing_account_groups">Úvodní synchronizace:
\nImport skupin</string> \nImportuji komunity</string>
<string name="initial_sync_start_importing_account_data">Úvodní synchronizace: <string name="initial_sync_start_importing_account_data">Úvodní synchronizace:
\nImport dat účtu</string> \nImportuji data účtu</string>
<string name="event_status_sending_message">Odesílání zprávy</string> <string name="event_status_sending_message">Odesílám zprávu</string>
<string name="initial_sync_start_importing_account_invited_rooms">Úvodní synchronizace: <string name="initial_sync_start_importing_account_invited_rooms">Úvodní synchronizace:
\nImport pozvánek</string> \nImportuji pozvání</string>
<string name="clear_timeline_send_queue">Vymazat frontu neodeslaných zpráv</string> <string name="clear_timeline_send_queue">Vymazat frontu neodeslaných zpráv</string>
<string name="notice_room_invite_with_reason">Uživatel %1$s pozvalivatele %2$s. Důvod: %3$s</string> <string name="notice_room_invite_with_reason">%1$s pozvali %2$s. Důvod: %3$s</string>
<string name="notice_room_invite_you_with_reason">Uživatel %1$s váš pozval. Důvod: %2$s</string> <string name="notice_room_invite_you_with_reason">%1$s vás pozvali. Důvod: %2$s</string>
<string name="notice_room_leave_with_reason">Uživatel %1$s odešel. Důvod: %2$s</string> <string name="notice_room_leave_with_reason">%1$s opustil místnost. Důvod: %2$s</string>
<string name="notice_event_redacted">Zpráva odstraněna</string> <string name="notice_event_redacted">Zpráva odstraněna</string>
<string name="notice_event_redacted_by">Zprávu odstranil/a %1$s</string> <string name="notice_event_redacted_by">Zprávu odstranil/a %1$s</string>
<string name="summary_you_sent_image">Poslali jste obrázek.</string>
<string name="summary_you_sent_sticker">Poslali jste nálepku.</string>
<string name="notice_room_invite_no_invitee_by_you">Vaše pozvání</string>
<string name="notice_room_created">%1$s založil místnost</string>
<string name="notice_room_created_by_you">Vy jste založili místnost</string>
<string name="notice_room_invite_by_you">Pozvali jste %1$s</string>
<string name="notice_room_join_by_you">Vstoupili jste do místnosti</string>
<string name="notice_room_leave_by_you">Opustili jste místnost</string>
<string name="notice_room_reject_by_you">Odmítli jste pozvání</string>
<string name="notice_room_kick_by_you">Vykopli jste %1$s</string>
<string name="notice_room_unban_by_you">Zrušili jste vykázání pro %1$s</string>
<string name="notice_room_ban_by_you">Vykázali jste %1$s</string>
<string name="notice_room_withdraw_by_you">Stáhli jste pozvánku od %1$s zpět</string>
<string name="notice_avatar_url_changed_by_you">Změnili jste svůj profilový obrázek</string>
<string name="notice_display_name_set_by_you">Změnili jste své veřejné jméno na %1$s</string>
<string name="notice_display_name_changed_from_by_you">Změnili jste své veřejné jméno z %1$s na %2$s</string>
<string name="notice_display_name_removed_by_you">Odstranili jste své veřejné jméno (%1$s)</string>
<string name="notice_room_topic_changed_by_you">Změnili jste téma na: %1$s</string>
<string name="notice_room_avatar_changed">%1$s změnili obrázek místnosti</string>
<string name="notice_room_avatar_changed_by_you">Změnili jste obrázek místnosti</string>
<string name="notice_room_name_changed_by_you">Změnili jste jméno místnosti na: %1$s</string>
<string name="notice_placed_video_call_by_you">Zahájili jste video hovor.</string>
<string name="notice_placed_voice_call_by_you">Zahájili jste hlasový hovor.</string>
<string name="notice_call_candidates">%s poslali data, aby mohli zahájit hovor.</string>
<string name="notice_call_candidates_by_you">Poslali jste data, abyste mohli zahájit hovor.</string>
<string name="notice_answered_call_by_you">Přijali jste hovor.</string>
<string name="notice_ended_call_by_you">Ukončili jste hovor.</string>
<string name="notice_made_future_room_visibility_by_you">Učinili jste budoucí historii místnosti viditelnou pro %1$s</string>
<string name="notice_end_to_end_by_you">Zapnuli jste end-to-end šifrování (%1$s)</string>
<string name="notice_room_update_by_you">Povýšili jste tuto místnost.</string>
<string name="notice_requested_voip_conference_by_you">Požádali jste o VoIP konferenci</string>
<string name="notice_room_name_removed_by_you">Odstranili jste jméno místnosti</string>
<string name="notice_room_topic_removed_by_you">Odstranili jste téma místnosti</string>
<string name="notice_room_avatar_removed">%1$s odstranili obrázek místnosti</string>
<string name="notice_room_avatar_removed_by_you">Odstranili jste obrázek místnosti</string>
<string name="notice_profile_change_redacted_by_you">Aktualizovali jste svů profil %1$s</string>
<string name="notice_room_third_party_invite_by_you">Poslali jste %1$s pozvání ke vstupu do místnosti</string>
<string name="notice_room_third_party_revoked_invite_by_you">Zrušili jste pozvánku ke vstupu do místnosti pro %1$s</string>
<string name="notice_room_third_party_registered_invite_by_you">Přijali jste pozvání pro %1$s</string>
<string name="notice_widget_added">%1$s přidali widget %2$s</string>
<string name="notice_widget_added_by_you">Přidali jste widget %1$s</string>
<string name="notice_widget_removed">%1$s odstranili widget %2$s</string>
<string name="notice_widget_removed_by_you">Odstranili jste widget %1$s</string>
<string name="notice_widget_modified">%1$s změnil widget %2$s</string>
<string name="notice_widget_modified_by_you">Změnili jste widget %1$s</string>
<string name="power_level_admin">Správce</string>
<string name="power_level_moderator">Moderátor</string>
<string name="power_level_default">Výchozí</string>
<string name="power_level_custom">Vlastní (%1$d)</string>
<string name="power_level_custom_no_value">Vlastní</string>
<string name="notice_power_level_changed_by_you">Změnili jste %1$s stupeň oprávnění.</string>
<string name="notice_power_level_changed">%1$s změnili %2$s stupeň oprávnění.</string>
<string name="notice_power_level_diff">%1$s z %2$s na %3$s</string>
<string name="notice_room_invite_no_invitee_with_reason">Pozvání od %1$s. Důvod: %2$s</string>
<string name="notice_room_invite_no_invitee_with_reason_by_you">Vaše pozvání. Důvod: %1$s</string>
<string name="notice_room_invite_with_reason_by_you">Pozvali jste %1$s. Důvod: %2$s</string>
<string name="notice_room_join_with_reason">%1$s vstoupili do místnosti. Důvod: %2$s</string>
<string name="notice_room_join_with_reason_by_you">Vstoupili jste do místnosti. Důvod: %1$s</string>
<string name="notice_room_leave_with_reason_by_you">Opustili jste místnost. Důvod: %1$s</string>
<string name="notice_room_reject_with_reason">%1$s pozvání odmítli. Důvod: %2$s</string>
<string name="notice_room_reject_with_reason_by_you">Odmítli jste pozvání. Důvod: %1$s</string>
<string name="notice_room_kick_with_reason">%1$s vykopnuli %2$s. Důvod: %3$s</string>
<string name="notice_room_kick_with_reason_by_you">Vykopnuli jste %1$s. Důvod: %2$s</string>
<string name="notice_room_unban_with_reason">%1$s zrušili %2$s vykázání. Důvod: %3$s</string>
<string name="notice_room_unban_with_reason_by_you">Zrušili jste %1$s vykázání. Důvod: %2$s</string>
<string name="notice_room_ban_with_reason">%1$s vykázali %2$s. Důvod: %3$s</string>
<string name="notice_room_ban_with_reason_by_you">Vykázali jste %1$s. Důvod: %2$s</string>
<string name="notice_room_third_party_invite_with_reason">%1$s poslali %2$s pozvání, aby vstoupili do místnosti. Důvod: %3$s</string>
<string name="notice_room_third_party_invite_with_reason_by_you">"Poslali jste %1$s pozvání, aby vstoupili do místnosti. Důvod: %2$s"</string>
<string name="notice_room_third_party_revoked_invite_with_reason">%1$s zrušili pozvání do místnosti pro %2$s. Důvod: %3$s</string>
<string name="notice_room_third_party_revoked_invite_with_reason_by_you">Zrušili jste pozvání do místnosti pro %1$s. Důvod: %2$s</string>
<string name="notice_room_third_party_registered_invite_with_reason">%1$s přijali pozvání pro %2$s. Důvod: %3$s</string>
<string name="notice_room_third_party_registered_invite_with_reason_by_you">Přijali jste pozvání pro %1$s. Důvod: %2$s</string>
<string name="notice_room_withdraw_with_reason">%1$s zrušili pozvání pro %2$s. Důvod: %3$s</string>
<string name="notice_room_withdraw_with_reason_by_you">Zrušili jste pozvání od %1$s. Důvod: %2$s</string>
<plurals name="notice_room_aliases_added">
<item quantity="one">%1$s přidali %2$s jako adresu pro tuto místnost.</item>
<item quantity="few">%1$s přidali %2$s jako adresy pro tuto místnost.</item>
<item quantity="other">%1$s přidali %2$s jako adresy pro tuto místnost.</item>
</plurals>
<plurals name="notice_room_aliases_added_by_you">
<item quantity="one">Přidali jste %1$s jako adresu pro tuto místnost.</item>
<item quantity="few">Přidali jste %1$s jako adresy pro tuto místnost.</item>
<item quantity="other">Přidali jste %1$s jako adresy pro tuto místnost.</item>
</plurals>
<plurals name="notice_room_aliases_removed">
<item quantity="one">%1$s odstranili %2$s jako adresu pro tuto místnost.</item>
<item quantity="few">%1$s odstranili %2$s jako adresy pro tuto místnost.</item>
<item quantity="other">%1$s odstranili %2$s jako adresy pro tuto místnost.</item>
</plurals>
<plurals name="notice_room_aliases_removed_by_you">
<item quantity="one">Odstranili jste %2$s jako adresu pro tuto místnost.</item>
<item quantity="few">Odstranili jste %2$s jako adresuy pro tuto místnost.</item>
<item quantity="other">Odstranili jste %2$s jako adresy pro tuto místnost.</item>
</plurals>
<string name="notice_room_aliases_added_and_removed">%1$s přidali %2$ a odstranili %3$s jako adresy pro tuto místnost.</string>
<string name="notice_room_aliases_added_and_removed_by_you">Přidali jste %1$s a odstranili %2$s jako adresy pro tuto místnost.</string>
<string name="notice_room_canonical_alias_set">%1$s nastavili hlavní adresu této místnosti na %2$s.</string>
<string name="notice_room_canonical_alias_set_by_you">Nastavili jste %1$s na hlavní adresu této místnosti.</string>
<string name="notice_room_canonical_alias_unset">%1$s odstranili hlavní adresu této místnosti.</string>
<string name="notice_room_canonical_alias_unset_by_you">Odstranili jste hlavní adresu této místnosti.</string>
<string name="notice_room_guest_access_can_join">"%1$s povolili hostům vstoupit do místnosti."</string>
<string name="notice_room_guest_access_can_join_by_you">Povolili jste hostům vstoupit do místnosti.</string>
<string name="notice_room_guest_access_forbidden">%1$s zamezili hostům vstoupit do místnosti.</string>
<string name="notice_room_guest_access_forbidden_by_you">Zamezili jste hostům vstoupit do místnosti.</string>
<string name="notice_end_to_end_ok">%1$s zapnuli end-to-end šifrování.</string>
<string name="notice_end_to_end_ok_by_you">Zapnuli jste end-to-end šifrování.</string>
<string name="notice_end_to_end_unknown_algorithm">%1$s zapnuli end-to-end šifrování (neznámý algoritmus %2$s).</string>
<string name="notice_end_to_end_unknown_algorithm_by_you">Zapnuli jste end-to-end šifrování (neznámý algoritmus %2$s).</string>
<string name="key_verification_request_fallback_message">%s žádá ověření Vašeho klíče, ale Váš klient nepodporuje ověření klíče v chatu. Budete muset k ověření klíčů použít zastaralý způsob ověření.</string>
</resources> </resources>

View File

@ -40,10 +40,10 @@
<string name="notice_avatar_changed_too">(تصویر هم عوض شد)</string> <string name="notice_avatar_changed_too">(تصویر هم عوض شد)</string>
<string name="notice_room_name_removed">%1$s نام اتاق را پاک کرد</string> <string name="notice_room_name_removed">%1$s نام اتاق را پاک کرد</string>
<string name="notice_room_topic_removed">%1$s موضوع اتاق را پاک کرد</string> <string name="notice_room_topic_removed">%1$s موضوع اتاق را پاک کرد</string>
<string name="notice_event_redacted">پیام پاک شد</string> <string name="notice_event_redacted">پیام برداشته شد</string>
<string name="notice_event_redacted_by">پیام به دست %1$s پاک شد</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_with_reason">پیام برداشته شد [دلیل: %1$s]</string>
<string name="notice_event_redacted_by_with_reason">پیام به دست %1$s پاک شد [دلیل: %2$s]</string> <string name="notice_event_redacted_by_with_reason">پیام به دست %1$s برداشته شد [دلیل: %2$s]</string>
<string name="notice_room_third_party_invite">%1$s دعوتی برای پیوستن %2$s به اتاق فرستاد</string> <string name="notice_room_third_party_invite">%1$s دعوتی برای پیوستن %2$s به اتاق فرستاد</string>
<string name="notice_room_third_party_revoked_invite">%1$s دعوت پیوستن به اتاق %2$s را باطل کرد</string> <string name="notice_room_third_party_revoked_invite">%1$s دعوت پیوستن به اتاق %2$s را باطل کرد</string>
<string name="notice_room_third_party_registered_invite">%1$s دعوت برای %2$s را پذیرفت</string> <string name="notice_room_third_party_registered_invite">%1$s دعوت برای %2$s را پذیرفت</string>
@ -56,7 +56,7 @@
<string name="message_failed_to_upload">شکست در بارگذاری تصویر</string> <string name="message_failed_to_upload">شکست در بارگذاری تصویر</string>
<string name="network_error">خطای شبکه</string> <string name="network_error">خطای شبکه</string>
<string name="matrix_error">خطای ماتریس</string> <string name="matrix_error">خطای ماتریکس</string>
<string name="room_error_join_failed_empty_room">در حال حاضر امکان بازپیوست به اتاقی خالی وجود ندارد‌‌.</string> <string name="room_error_join_failed_empty_room">در حال حاضر امکان بازپیوست به اتاقی خالی وجود ندارد‌‌.</string>
@ -135,6 +135,98 @@
<string name="key_verification_request_fallback_message">%s درخواست تأیید کلیدتان را دارد، ولی کارخواهتان تأیید کلید درون گپ را پشتیبانی نمی‌کند. برای تأیید کلیدها لازم است از تأییدیهٔ کلید قدیمی استفاده کنید.</string> <string name="key_verification_request_fallback_message">%s درخواست تأیید کلیدتان را دارد، ولی کارخواهتان تأیید کلید درون گپ را پشتیبانی نمی‌کند. برای تأیید کلیدها لازم است از تأییدیهٔ کلید قدیمی استفاده کنید.</string>
<string name="notice_room_created">%1$s اتاق را ایجاد کرد</string> <string name="notice_room_created">%1$s اتاق را ایجاد کرد</string>
<string name="notice_profile_change_redacted">%1$s نمایه خود را به‌روز کرد %2$s</string> <string name="notice_profile_change_redacted">%1$s نمایه‌اش را به‌روز کرد %2$s</string>
<string name="could_not_redact">نمی‌توان ویرایش کرد</string> <string name="could_not_redact">نمی‌توان ویرایش کرد</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>
<string name="notice_room_withdraw_by_you">دعوت %1$s را پس‌گرفتید</string>
<string name="notice_avatar_url_changed_by_you">آواتارتان را عوض کردید</string>
<string name="notice_display_name_set_by_you">نام نمایشیتان را به %1$s تغییر دادید</string>
<string name="notice_display_name_changed_from_by_you">نام نمایشیتان را از %1$s به %2$s تغییر دادید</string>
<string name="notice_display_name_removed_by_you">نام نمایشیتان را برداشتید (%1$s بود)</string>
<string name="notice_room_topic_changed_by_you">موضوع را به %1$s تغییر دادید</string>
<string name="notice_room_avatar_changed">%1$s آواتار اتاق را تغییر داد</string>
<string name="notice_room_avatar_changed_by_you">آواتار اتاق را تغییر دادید</string>
<string name="notice_room_name_changed_by_you">نام اتاق را به %1$s تغییر دادید</string>
<string name="notice_placed_video_call_by_you">تماس تصویری گرفتید.</string>
<string name="notice_placed_voice_call_by_you">تماس صوتی گرفتید.</string>
<string name="notice_call_candidates">%s برای برپایی تماس، داده فرستاد.</string>
<string name="notice_call_candidates_by_you">برای برپایی تماس، داده فرستادید.</string>
<string name="notice_answered_call_by_you">تماس را پاسخ دادید.</string>
<string name="notice_ended_call_by_you">به تماس پایان دادید.</string>
<string name="notice_made_future_room_visibility_by_you">تاریخچهٔ آتی اتاق را برای %1$s نمایان کردید</string>
<string name="notice_end_to_end_by_you">رمزنگاری سرتاسری را روشن کردید (%1$s)</string>
<string name="notice_room_update_by_you">این اتاق را ارتقا دادید.</string>
<string name="notice_requested_voip_conference_by_you">دارخواست کنفرانس ویپ دادید</string>
<string name="notice_room_name_removed_by_you">نام اتاق را برداشتید</string>
<string name="notice_room_topic_removed_by_you">موضوع اتاق را برداشتید</string>
<string name="notice_room_avatar_removed">%1$s آواتار اتاق را برداشت</string>
<string name="notice_room_avatar_removed_by_you">آواتار اتاق را برداشتید</string>
<string name="notice_profile_change_redacted_by_you">نمایه‌تان را به‌روز کردید %1$s</string>
<string name="notice_room_third_party_invite_by_you">برای %1$s دعوت پیوستن به اتاق فرستادید</string>
<string name="notice_room_third_party_revoked_invite_by_you">دعوت پیوستن %1$s به اتاق را پس گرفتید</string>
<string name="notice_room_third_party_registered_invite_by_you">دعوت برای %1$s را پذیرفتید</string>
<string name="notice_widget_added">%1$s ابزارک %2$s را افزود</string>
<string name="notice_widget_added_by_you">ابزارک %1$s را افزودید</string>
<string name="notice_widget_removed">%1$s ابزارک %2$s را برداشت</string>
<string name="notice_widget_removed_by_you">ابزارک %1$s را برداشتید</string>
<string name="notice_widget_modified">%1$s ابزارک %2$s را دستکاری کرد</string>
<string name="notice_widget_modified_by_you">ابزارک %1$s را دستکاری کردید</string>
<string name="power_level_admin">مدیر</string>
<string name="power_level_moderator">ناظم</string>
<string name="power_level_default">پیش‌گزیده</string>
<string name="power_level_custom">سفارشی (%1$d)</string>
<string name="power_level_custom_no_value">سفارشی</string>
<string name="notice_power_level_changed_by_you">سطح قدرت %1$s را تغییر دادید.</string>
<string name="notice_power_level_changed">%1$s سطح قدرت %2$s را تغییر داد.</string>
<string name="notice_power_level_diff">%1$s از %2$s به %3$s</string>
<string name="notice_room_invite_no_invitee_with_reason_by_you">دعوتتان. دلیل: %1$s</string>
<string name="notice_room_invite_with_reason_by_you">%1$s را دعوت کردید. دلیل: %2$s</string>
<string name="notice_room_join_with_reason_by_you">به اتاق پیوستید. دلیل: %1$s</string>
<string name="notice_room_leave_with_reason_by_you">اتاق را ترک کردید. دلیل: %1$s</string>
<string name="notice_room_reject_with_reason_by_you">دعوت را رد کردید. دلیل: %1$s</string>
<string name="notice_room_kick_with_reason_by_you">%1$s را اخراج کردید. دلیل: %2$s</string>
<string name="notice_room_unban_with_reason_by_you">تحریم %1$s را برداشتید. دلیل: %2$s</string>
<string name="notice_room_ban_with_reason_by_you">%1$s را تحریم کردید. دلیل: %2$s</string>
<string name="notice_room_third_party_invite_with_reason_by_you">دعوتی به %1$s برای پیوستن به اتاق فرستادید. دلیل: %2$s</string>
<string name="notice_room_third_party_revoked_invite_with_reason_by_you">دعوت %1$s برای پیوستن به اتاق را پس گرفتید. دلیل: %2$s</string>
<string name="notice_room_third_party_registered_invite_with_reason_by_you">دعوت برای %1$s را پذیرفتید. دلیل: %2$s</string>
<string name="notice_room_withdraw_with_reason_by_you">دعوت %1$s را رد کردید. دلیل: %2$s</string>
<plurals name="notice_room_aliases_added_by_you">
<item quantity="one">نشانی %1$s را به این اتاق افزودید.</item>
<item quantity="other">نشانی‌های %1$s را به این اتاق افزودید.</item>
</plurals>
<plurals name="notice_room_aliases_removed_by_you">
<item quantity="one">نشانی %1$s ار از این اتاق برداشتید.</item>
<item quantity="other">نشانی‌های %1$s ار از این اتاق برداشتید.</item>
</plurals>
<string name="notice_room_aliases_added_and_removed_by_you">نشانی %1$s ار افزوده و %2$s را از این اتاق برداشتید.</string>
<string name="notice_room_canonical_alias_set_by_you">نشانی اصلی این اتاق را به %1$s تنظیم کردید.</string>
<string name="notice_room_canonical_alias_unset_by_you">نشانی اصلی این اتاق را برداشتید.</string>
<string name="notice_room_guest_access_can_join_by_you">به میهمانان اجازهٔ پیوستن به گروه دادید.</string>
<string name="notice_room_guest_access_forbidden_by_you">میمهانان را از پیوستن به گروه بازداشتید.</string>
<string name="notice_end_to_end_ok_by_you">رمزنگاری سرتاسری را روشن کردید.</string>
<string name="notice_end_to_end_unknown_algorithm_by_you">رمزنگاری سرتاسری را روشن کردید (الگوریتم ناشناخته %1$s).</string>
</resources> </resources>

View File

@ -201,7 +201,7 @@
<item quantity="other">Tekkseḍ %2$s am tansiwin i texxamt-a.</item> <item quantity="other">Tekkseḍ %2$s am tansiwin i texxamt-a.</item>
</plurals> </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">%1$s yerna %2$s terniḍ tekkseḍ %3$s 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_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">%1$s isbadu %2$s am tansa tagejdant i texxamt-a.</string>

View File

@ -138,4 +138,96 @@
<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 tju duhet të përdorni verifikim të dikurshëm kyçesh.</string> <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 tju duhet të përdorni verifikim të dikurshëm kyçesh.</string>
<string name="notice_room_created">%1$s krijo dhomën</string> <string name="notice_room_created">%1$s krijo dhomën</string>
<string name="summary_you_sent_image">Dërguat një figurë.</string>
<string name="summary_you_sent_sticker">Dërguat një ngjitës.</string>
<string name="notice_room_invite_no_invitee_by_you">Ftesa juaj</string>
<string name="notice_room_created_by_you">Krijuat dhomën</string>
<string name="notice_room_invite_by_you">Ftuat %1$s</string>
<string name="notice_room_join_by_you">Hytë në dhomë</string>
<string name="notice_room_leave_by_you">Dolët nga dhoma</string>
<string name="notice_room_reject_by_you">Hodhët poshtë ftesën</string>
<string name="notice_room_kick_by_you">Përzutë %1$s</string>
<string name="notice_room_unban_by_you">Hoqët dëbimin për %1$s</string>
<string name="notice_room_ban_by_you">Dëbuat %1$s</string>
<string name="notice_room_withdraw_by_you">Tërhoqët mbrapsht ftesën për %1$s</string>
<string name="notice_avatar_url_changed_by_you">Ndryshuat avatarin tuaj</string>
<string name="notice_display_name_set_by_you">Caktuat si emrin tuaj në ekran %1$s</string>
<string name="notice_display_name_changed_from_by_you">E ndryshuat emrin tuaj në ekran nga %1$s në %2$s</string>
<string name="notice_display_name_removed_by_you">Hoqët emrin tuaj në ekran (qe %1$s)</string>
<string name="notice_room_topic_changed_by_you">E ndryshuat temën në: %1$s</string>
<string name="notice_room_avatar_changed">%1$s ndryshoi avatarin e dhomës</string>
<string name="notice_room_avatar_changed_by_you">Ndryshuat avatarin e dhomës</string>
<string name="notice_room_name_changed_by_you">Ndryshuat emrin e dhomës në: %1$s</string>
<string name="notice_placed_video_call_by_you">Filluat një thirrje video.</string>
<string name="notice_placed_voice_call_by_you">Filluat një thirrje zanore.</string>
<string name="notice_call_candidates">%s dërgoi të dhëna për ujdisjen e thirrjes.</string>
<string name="notice_call_candidates_by_you">Dërguat të dhëna për ujdisjen e thirrjes.</string>
<string name="notice_answered_call_by_you">Iu përgjigjët thirrjes.</string>
<string name="notice_ended_call_by_you">E përfunduat thirrjen.</string>
<string name="notice_made_future_room_visibility_by_you">E bëtë historikun e ardhshëm të dhomë të dukshëm për %1$s</string>
<string name="notice_end_to_end_by_you">Aktivizuat fshehtëzim skaj-më-skaj (%1$s)</string>
<string name="notice_room_update_by_you">Përmirësuat këtë dhomë.</string>
<string name="notice_requested_voip_conference_by_you">Kërkuat një konferencë VoIP</string>
<string name="notice_room_name_removed_by_you">Hoqët emrin e dhomës</string>
<string name="notice_room_topic_removed_by_you">Hoqët temën e dhomës</string>
<string name="notice_room_avatar_removed">%1$s hoqi avatarin e dhomës</string>
<string name="notice_room_avatar_removed_by_you">Hoqët avatarin e dhomës</string>
<string name="notice_profile_change_redacted_by_you">Përditësuat profilin tuaj %1$s</string>
<string name="notice_room_third_party_invite_by_you">Dërguat një ftesë te %1$s për të ardhur te dhoma</string>
<string name="notice_room_third_party_revoked_invite_by_you">Shfuqizuat ftesën për ardhjen në dhomë të %1$s</string>
<string name="notice_room_third_party_registered_invite_by_you">Pranuat ftesën për %1$s</string>
<string name="notice_widget_added">%1$s shtoi widget-in %2$s</string>
<string name="notice_widget_added_by_you">Shtuat widget-in %1$s</string>
<string name="notice_widget_removed">%1$s hoqi widget-in %2$s</string>
<string name="notice_widget_removed_by_you">Hoqët widget-in %1$s</string>
<string name="notice_widget_modified">%1$s ndryshoi widget-in %2$s</string>
<string name="notice_widget_modified_by_you">Ndryshuat widget-in %1$s</string>
<string name="power_level_admin">Përgjegjës</string>
<string name="power_level_moderator">Moderator</string>
<string name="power_level_default">Parazgjedhje</string>
<string name="power_level_custom">Vetjake (%1$d)</string>
<string name="power_level_custom_no_value">Vetjake</string>
<string name="notice_power_level_changed_by_you">Ndryshuat shkallën e pushtetit për %1$s.</string>
<string name="notice_power_level_changed">%1$s ndryshoi shkallën e pushtetit për %2$s.</string>
<string name="notice_power_level_diff">%1$s nga %2$s në %3$s</string>
<string name="notice_room_invite_no_invitee_with_reason_by_you">Ftesa juaj. Arsye: %1$s</string>
<string name="notice_room_invite_with_reason_by_you">Ftuat %1$s. Arsye: %2$s</string>
<string name="notice_room_join_with_reason_by_you">Erdhët në dhomë, Arsye: %1$s</string>
<string name="notice_room_leave_with_reason_by_you">Ikët nga dhoma. Arsye: %1$s</string>
<string name="notice_room_reject_with_reason_by_you">Hodhët poshtë ftesën. Arsye: %1$s</string>
<string name="notice_room_kick_with_reason_by_you">Përzutë %1$s. Arsye: %2$s</string>
<string name="notice_room_unban_with_reason_by_you">Hoqët dëbimin për %1$s. Arsye: %2$s</string>
<string name="notice_room_ban_with_reason_by_you">Dëbuat %1$s. Arsye: %2$s</string>
<string name="notice_room_third_party_invite_with_reason_by_you">Dërguat një ftesë për %1$s të vijë në dhomë. Arsye: %2$s</string>
<string name="notice_room_third_party_revoked_invite_with_reason_by_you">Shfuqizuat ftesën për ardhjen në dhomë të %1$s. Arsye: %2$s</string>
<string name="notice_room_third_party_registered_invite_with_reason_by_you">Pranuat ftesën për %1$s. Arsye: %2$s</string>
<string name="notice_room_withdraw_with_reason_by_you">Tërhoqët mbrapsht ftesën për %1$s. Arsye: %2$s</string>
<plurals name="notice_room_aliases_added_by_you">
<item quantity="one">Shtuat %1$s si një adresë për këtë dhomë.</item>
<item quantity="other">Shtuat %1$s si adresa për këtë dhomë.</item>
</plurals>
<plurals name="notice_room_aliases_removed_by_you">
<item quantity="one">Hoqët %1$s si një adresë për këtë dhomë.</item>
<item quantity="other">Hoqët %1$s si adresa për këtë dhomë.</item>
</plurals>
<string name="notice_room_aliases_added_and_removed_by_you">Shtuat %1$s dhe hoqët %2$s si adresa për këtë dhomë.</string>
<string name="notice_room_canonical_alias_set_by_you">Caktuat si adresë kryesore për këtë dhomë %1$s.</string>
<string name="notice_room_canonical_alias_unset_by_you">Hoqët adresën kryesore për këtë dhomë.</string>
<string name="notice_room_guest_access_can_join_by_you">Keni lejuar të vijnë mysafirë në dhomë.</string>
<string name="notice_room_guest_access_forbidden_by_you">U keni penguar mysafirëve të vijnë në dhomë.</string>
<string name="notice_end_to_end_ok_by_you">Aktivizuat fshehtëzimin skaj-më-skaj.</string>
<string name="notice_end_to_end_unknown_algorithm_by_you">Aktivizuat fshehtëzimin skaj-më-skaj (algoritëm %1$s i panjohur).</string>
</resources> </resources>

View File

@ -17,7 +17,7 @@
package org.matrix.android.sdk.internal.crypto.verification.qrcode package org.matrix.android.sdk.internal.crypto.verification.qrcode
import org.matrix.android.sdk.MatrixTest import org.matrix.android.sdk.MatrixTest
import org.amshove.kluent.shouldEqualTo import org.amshove.kluent.shouldBeEqualTo
import org.junit.FixMethodOrder import org.junit.FixMethodOrder
import org.junit.Test import org.junit.Test
import org.junit.runners.MethodSorters import org.junit.runners.MethodSorters
@ -37,17 +37,17 @@ class BinaryStringTest: MatrixTest {
val str = byteArray.toString(Charsets.ISO_8859_1) val str = byteArray.toString(Charsets.ISO_8859_1)
str.length shouldEqualTo 256 str.length shouldBeEqualTo 256
// Ok convert back to bytearray // Ok convert back to bytearray
val result = str.toByteArray(Charsets.ISO_8859_1) val result = str.toByteArray(Charsets.ISO_8859_1)
result.size shouldEqualTo 256 result.size shouldBeEqualTo 256
for (i in 0..255) { for (i in 0..255) {
result[i] shouldEqualTo i.toByte() result[i] shouldBeEqualTo i.toByte()
result[i] shouldEqualTo byteArray[i] result[i] shouldBeEqualTo byteArray[i]
} }
} }
} }

View File

@ -79,9 +79,5 @@ layout_constraintLeft_
### Use im.vector.app.core.preference.VectorPreference to support multiline of the title ### Use im.vector.app.core.preference.VectorPreference to support multiline of the title
<Preference\n <Preference\n
### Will crash on API < 21. Use ?colorAccent instead
\?android:colorAccent
\?android:attr/colorAccent
### Use androidx.recyclerview.widget.RecyclerView because EpoxyRecyclerViews add behavior we do not want to ### Use androidx.recyclerview.widget.RecyclerView because EpoxyRecyclerViews add behavior we do not want to
<com\.airbnb\.epoxy\.EpoxyRecyclerView <com\.airbnb\.epoxy\.EpoxyRecyclerView

View File

@ -96,7 +96,6 @@
<data android:host="element" /> <data android:host="element" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".features.media.ImageMediaViewerActivity" />
<!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite :/ --> <!-- Add tools:ignore="Instantiatable" for the error reported only by Buildkite :/ -->
<activity <activity
@ -112,7 +111,6 @@
android:name=".features.settings.VectorSettingsActivity" android:name=".features.settings.VectorSettingsActivity"
android:label="@string/title_activity_settings" android:label="@string/title_activity_settings"
android:windowSoftInputMode="adjustResize" /> android:windowSoftInputMode="adjustResize" />
<activity android:name=".features.media.VideoMediaViewerActivity" />
<activity <activity
android:name=".features.crypto.keysbackup.restore.KeysBackupRestoreActivity" android:name=".features.crypto.keysbackup.restore.KeysBackupRestoreActivity"
android:label="@string/title_activity_keys_backup_setup" /> android:label="@string/title_activity_keys_backup_setup" />

View File

@ -18,8 +18,8 @@
package im.vector.app package im.vector.app
import arrow.core.Option import arrow.core.Option
import org.matrix.android.sdk.api.session.Session
import im.vector.app.core.utils.BehaviorDataSource import im.vector.app.core.utils.BehaviorDataSource
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton

View File

@ -20,9 +20,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import arrow.core.Option import arrow.core.Option
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID
import im.vector.app.features.grouplist.SelectedGroupDataSource import im.vector.app.features.grouplist.SelectedGroupDataSource
import im.vector.app.features.home.HomeRoomListDataSource import im.vector.app.features.home.HomeRoomListDataSource
@ -32,6 +29,9 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.BiFunction import io.reactivex.functions.BiFunction
import io.reactivex.rxkotlin.addTo import io.reactivex.rxkotlin.addTo
import org.matrix.android.sdk.api.session.group.model.GroupSummary
import org.matrix.android.sdk.api.session.room.model.RoomSummary
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
import org.matrix.android.sdk.rx.rx import org.matrix.android.sdk.rx.rx
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject

View File

@ -51,9 +51,7 @@ import im.vector.app.features.invite.VectorInviteView
import im.vector.app.features.link.LinkHandlerActivity import im.vector.app.features.link.LinkHandlerActivity
import im.vector.app.features.login.LoginActivity import im.vector.app.features.login.LoginActivity
import im.vector.app.features.media.BigImageViewerActivity import im.vector.app.features.media.BigImageViewerActivity
import im.vector.app.features.media.ImageMediaViewerActivity
import im.vector.app.features.media.VectorAttachmentViewerActivity import im.vector.app.features.media.VectorAttachmentViewerActivity
import im.vector.app.features.media.VideoMediaViewerActivity
import im.vector.app.features.navigation.Navigator import im.vector.app.features.navigation.Navigator
import im.vector.app.features.permalink.PermalinkHandlerActivity import im.vector.app.features.permalink.PermalinkHandlerActivity
import im.vector.app.features.pin.PinLocker import im.vector.app.features.pin.PinLocker
@ -125,10 +123,8 @@ interface ScreenComponent {
fun inject(activity: MainActivity) fun inject(activity: MainActivity)
fun inject(activity: RoomDirectoryActivity) fun inject(activity: RoomDirectoryActivity)
fun inject(activity: BugReportActivity) fun inject(activity: BugReportActivity)
fun inject(activity: ImageMediaViewerActivity)
fun inject(activity: FilteredRoomsActivity) fun inject(activity: FilteredRoomsActivity)
fun inject(activity: CreateRoomActivity) fun inject(activity: CreateRoomActivity)
fun inject(activity: VideoMediaViewerActivity)
fun inject(activity: CreateDirectRoomActivity) fun inject(activity: CreateDirectRoomActivity)
fun inject(activity: IncomingShareActivity) fun inject(activity: IncomingShareActivity)
fun inject(activity: SoftLogoutActivity) fun inject(activity: SoftLogoutActivity)

View File

@ -42,18 +42,25 @@ abstract class BottomSheetActionItem : VectorEpoxyModel<BottomSheetActionItem.Ho
@EpoxyAttribute @EpoxyAttribute
@DrawableRes @DrawableRes
var iconRes: Int = 0 var iconRes: Int = 0
@EpoxyAttribute @EpoxyAttribute
var textRes: Int = 0 var textRes: Int = 0
@EpoxyAttribute @EpoxyAttribute
var showExpand = false var showExpand = false
@EpoxyAttribute @EpoxyAttribute
var expanded = false var expanded = false
@EpoxyAttribute @EpoxyAttribute
var selected = false var selected = false
@EpoxyAttribute @EpoxyAttribute
var subMenuItem = false var subMenuItem = false
@EpoxyAttribute @EpoxyAttribute
var destructive = false var destructive = false
@EpoxyAttribute @EpoxyAttribute
lateinit var listener: View.OnClickListener lateinit var listener: View.OnClickListener

View File

@ -37,14 +37,19 @@ abstract class BottomSheetMessagePreviewItem : VectorEpoxyModel<BottomSheetMessa
@EpoxyAttribute @EpoxyAttribute
lateinit var avatarRenderer: AvatarRenderer lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute @EpoxyAttribute
lateinit var matrixItem: MatrixItem lateinit var matrixItem: MatrixItem
@EpoxyAttribute @EpoxyAttribute
lateinit var body: CharSequence lateinit var body: CharSequence
@EpoxyAttribute @EpoxyAttribute
var time: CharSequence? = null var time: CharSequence? = null
@EpoxyAttribute @EpoxyAttribute
var movementMethod: MovementMethod? = null var movementMethod: MovementMethod? = null
@EpoxyAttribute @EpoxyAttribute
var userClicked: (() -> Unit)? = null var userClicked: (() -> Unit)? = null

View File

@ -33,10 +33,13 @@ abstract class BottomSheetQuickReactionsItem : VectorEpoxyModel<BottomSheetQuick
@EpoxyAttribute @EpoxyAttribute
lateinit var fontProvider: EmojiCompatFontProvider lateinit var fontProvider: EmojiCompatFontProvider
@EpoxyAttribute @EpoxyAttribute
lateinit var texts: List<String> lateinit var texts: List<String>
@EpoxyAttribute @EpoxyAttribute
lateinit var selecteds: List<Boolean> lateinit var selecteds: List<Boolean>
@EpoxyAttribute @EpoxyAttribute
var listener: Listener? = null var listener: Listener? = null

View File

@ -34,8 +34,10 @@ abstract class BottomSheetSendStateItem : VectorEpoxyModel<BottomSheetSendStateI
@EpoxyAttribute @EpoxyAttribute
var showProgress: Boolean = false var showProgress: Boolean = false
@EpoxyAttribute @EpoxyAttribute
lateinit var text: CharSequence lateinit var text: CharSequence
@EpoxyAttribute @EpoxyAttribute
@DrawableRes @DrawableRes
var drawableStart: Int = 0 var drawableStart: Int = 0

View File

@ -30,6 +30,7 @@ abstract class BaseProfileMatrixItem<T : ProfileMatrixItem.Holder> : VectorEpoxy
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem @EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute var editable: Boolean = true @EpoxyAttribute var editable: Boolean = true
@EpoxyAttribute @EpoxyAttribute
var userEncryptionTrustLevel: RoomEncryptionTrustLevel? = null var userEncryptionTrustLevel: RoomEncryptionTrustLevel? = null
@EpoxyAttribute var clickListener: View.OnClickListener? = null @EpoxyAttribute var clickListener: View.OnClickListener? = null

View File

@ -38,6 +38,7 @@ abstract class ProfileActionItem : VectorEpoxyModel<ProfileActionItem.Holder>()
@EpoxyAttribute @EpoxyAttribute
lateinit var title: String lateinit var title: String
@EpoxyAttribute @EpoxyAttribute
var subtitle: String? = null var subtitle: String? = null

View File

@ -20,8 +20,8 @@ import android.content.Context
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import im.vector.app.R import im.vector.app.R
import org.matrix.android.sdk.api.failure.MatrixError
import me.gujun.android.span.span import me.gujun.android.span.span
import org.matrix.android.sdk.api.failure.MatrixError
class ResourceLimitErrorFormatter(private val context: Context) { class ResourceLimitErrorFormatter(private val context: Context) {

View File

@ -33,8 +33,6 @@ import timber.log.Timber
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.lang.Exception
import java.lang.IllegalArgumentException
class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessionHolder) class VectorGlideModelLoaderFactory(private val activeSessionHolder: ActiveSessionHolder)
: ModelLoaderFactory<ImageContentRenderer.Data, InputStream> { : ModelLoaderFactory<ImageContentRenderer.Data, InputStream> {

View File

@ -26,11 +26,11 @@ class CheckableFrameLayout : FrameLayout, Checkable {
private var mChecked = false private var mChecked = false
constructor(context: Context) : super(context) {} constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {} constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {} constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun isChecked(): Boolean { override fun isChecked(): Boolean {
return mChecked return mChecked

View File

@ -25,8 +25,8 @@ import butterknife.BindView
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.di.ScreenComponent import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.hideKeyboard import im.vector.app.core.extensions.hideKeyboard
import org.matrix.android.sdk.api.session.Session
import kotlinx.android.synthetic.main.activity.* import kotlinx.android.synthetic.main.activity.*
import org.matrix.android.sdk.api.session.Session
import javax.inject.Inject import javax.inject.Inject
/** /**

View File

@ -177,7 +177,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Timber.i("onCreate Activity ${this.javaClass.simpleName}") Timber.i("onCreate Activity ${javaClass.simpleName}")
val vectorComponent = getVectorComponent() val vectorComponent = getVectorComponent()
screenComponent = DaggerScreenComponent.factory().create(vectorComponent, this) screenComponent = DaggerScreenComponent.factory().create(vectorComponent, this)
val timeForInjection = measureTimeMillis { val timeForInjection = measureTimeMillis {
@ -305,7 +305,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Timber.i("onDestroy Activity ${this.javaClass.simpleName}") Timber.i("onDestroy Activity ${javaClass.simpleName}")
unBinder?.unbind() unBinder?.unbind()
unBinder = null unBinder = null
@ -333,7 +333,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
Timber.i("onResume Activity ${this.javaClass.simpleName}") Timber.i("onResume Activity ${javaClass.simpleName}")
configurationViewModel.onActivityResumed() configurationViewModel.onActivityResumed()
@ -373,7 +373,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
Timber.i("onPause Activity ${this.javaClass.simpleName}") Timber.i("onPause Activity ${javaClass.simpleName}")
rageShake.stop() rageShake.stop()

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