Merge branch 'develop' into feature/fix_share_image
|
@ -81,7 +81,7 @@ steps:
|
||||||
|
|
||||||
- label: "ktlint"
|
- label: "ktlint"
|
||||||
command:
|
command:
|
||||||
- "curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.34.2/ktlint && chmod a+x ktlint"
|
- "curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.36.0/ktlint && chmod a+x ktlint"
|
||||||
- "./ktlint --android --experimental -v"
|
- "./ktlint --android --experimental -v"
|
||||||
plugins:
|
plugins:
|
||||||
- docker#v3.1.0:
|
- docker#v3.1.0:
|
||||||
|
|
3
.idea/codeStyles/Project.xml
generated
|
@ -1,9 +1,6 @@
|
||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
<option name="RIGHT_MARGIN" value="160" />
|
<option name="RIGHT_MARGIN" value="160" />
|
||||||
<AndroidXmlCodeStyleSettings>
|
|
||||||
<option name="ARRANGEMENT_SETTINGS_MIGRATED_TO_191" value="true" />
|
|
||||||
</AndroidXmlCodeStyleSettings>
|
|
||||||
<JetCodeStyleSettings>
|
<JetCodeStyleSettings>
|
||||||
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
|
||||||
<value>
|
<value>
|
||||||
|
|
|
@ -6,6 +6,9 @@ Features ✨:
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Share image and other media from e2e rooms (#677)
|
- Share image and other media from e2e rooms (#677)
|
||||||
|
- Add support for `/plain` command (#12)
|
||||||
|
- Detect spaces in password if user fail to login (#1038)
|
||||||
|
- FTUE: do not display a different color when encrypting message when not in developer mode.
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Fix crash on attachment preview screen (#1088)
|
- Fix crash on attachment preview screen (#1088)
|
||||||
|
@ -19,10 +22,11 @@ SDK API changes ⚠️:
|
||||||
-
|
-
|
||||||
|
|
||||||
Build 🧱:
|
Build 🧱:
|
||||||
-
|
- Upgrade ktlint to version 0.36.0
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
-
|
- Restore availability to Chromebooks (#932)
|
||||||
|
- Add a [documentation](./docs/integration_tests.md) to run integration tests
|
||||||
|
|
||||||
Changes in RiotX 0.17.0 (2020-02-27)
|
Changes in RiotX 0.17.0 (2020-02-27)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
|
@ -82,6 +82,8 @@ Make sure the following commands execute without any error:
|
||||||
RiotX is currently supported on Android KitKat (API 19+): please test your change on an Android device (or Android emulator) running with API 19. Many issues can happen (including crashes) on older devices.
|
RiotX is currently supported on Android KitKat (API 19+): please test your change on an Android device (or Android emulator) running with API 19. Many issues can happen (including crashes) on older devices.
|
||||||
Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient.
|
Also, if possible, please test your change on a real device. Testing on Android emulator may not be sufficient.
|
||||||
|
|
||||||
|
You should consider adding Unit tests with your PR, and also integration tests (AndroidTest). Please refer to [this document](./docs/integration_tests.md) to install and run the integration test environment.
|
||||||
|
|
||||||
### Internationalisation
|
### Internationalisation
|
||||||
|
|
||||||
When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators with a specific tool named [Weblate](https://translate.riot.im/projects/riot-android/).
|
When adding new string resources, please only add new entries in file `value/strings.xml`. Translations will be added later by the community of translators with a specific tool named [Weblate](https://translate.riot.im/projects/riot-android/).
|
||||||
|
|
97
docs/integration_tests.md
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
# Integration tests
|
||||||
|
|
||||||
|
Integration tests are useful to ensure that the code works well for any use cases.
|
||||||
|
|
||||||
|
They can also be used as sample on how to use the Matrix SDK.
|
||||||
|
|
||||||
|
In a ideal world, every API of the SDK should be covered by integration tests. For the moment, we have test mainly for the Crypto part, which is the tricky part. But it covers quite a lot of features: accounts creation, login to existing account, send encrypted messages, keys backup, verification, etc.
|
||||||
|
|
||||||
|
The Matrix SDK is able to open multiple sessions, for the same user, of for different users. This way we can test communication between several sessions on a single device.
|
||||||
|
|
||||||
|
## Pre requirements
|
||||||
|
|
||||||
|
Integration tests need a homeserver running on localhost.
|
||||||
|
|
||||||
|
The documentation describes what we do to have one, using [Synapse](https://github.com/matrix-org/synapse/), which is the Matrix reference homeserver.
|
||||||
|
|
||||||
|
## Install and run Synapse
|
||||||
|
|
||||||
|
Steps:
|
||||||
|
|
||||||
|
- Install virtualenv
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m pip install virtualenv
|
||||||
|
```
|
||||||
|
|
||||||
|
- Clone Synapse repository
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone -b develop https://github.com/matrix-org/synapse.git
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```bash
|
||||||
|
git clone -b develop git@github.com:matrix-org/synapse.git
|
||||||
|
```
|
||||||
|
|
||||||
|
You should have the develop branch cloned by default.
|
||||||
|
|
||||||
|
- Run synapse, from the Synapse folder you just cloned
|
||||||
|
|
||||||
|
```bash
|
||||||
|
virtualenv -p python3 env
|
||||||
|
source env/bin/activate
|
||||||
|
pip install -e .
|
||||||
|
demo/start.sh --no-rate-limit
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, to install the latest Synapse release package (and not a cloned branch) you can run the following instead of `pip install -e .`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install matrix-synapse
|
||||||
|
```
|
||||||
|
|
||||||
|
You should now have 3 running federated Synapse instances 🎉, at http://127.0.0.1:8080/, http://127.0.0.1:8081/ and http://127.0.0.1:8082/, which should display a "It Works! Synapse is running" message.
|
||||||
|
|
||||||
|
## Run the test
|
||||||
|
|
||||||
|
It's recommended to run tests using an Android Emulator and not a real device. First reason for that is that the tests will use http://10.0.2.2:8080 to connect to Synapse, which run locally on your machine.
|
||||||
|
|
||||||
|
You can run all the tests in the `androidTest` folders.
|
||||||
|
|
||||||
|
## Stop Synapse
|
||||||
|
|
||||||
|
To stop Synapse, you can run the following commands:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./demo/stop.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
And you can deactivate the virtualenv:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshoot
|
||||||
|
|
||||||
|
You'll need python3 to be able to run synapse
|
||||||
|
|
||||||
|
### Android Emulator does cannot reach the homeserver
|
||||||
|
|
||||||
|
Try on the Emulator browser to open "http://10.0.2.2:8080". You should see the "Synapse is running" message.
|
||||||
|
|
||||||
|
### virtualenv command fails
|
||||||
|
|
||||||
|
You can try using
|
||||||
|
```bash
|
||||||
|
python3 -m venv env
|
||||||
|
```
|
||||||
|
or
|
||||||
|
```bash
|
||||||
|
python3 -m virtualenv env
|
||||||
|
```
|
||||||
|
instead of
|
||||||
|
```bash
|
||||||
|
virtualenv -p python3 env
|
||||||
|
```
|
|
@ -6,6 +6,11 @@
|
||||||
<issue id="MissingTranslation" severity="warning" />
|
<issue id="MissingTranslation" severity="warning" />
|
||||||
<issue id="TypographyEllipsis" severity="error" />
|
<issue id="TypographyEllipsis" severity="error" />
|
||||||
<issue id="ImpliedQuantity" severity="warning" />
|
<issue id="ImpliedQuantity" severity="warning" />
|
||||||
|
<issue id="IconXmlAndPng" severity="error" />
|
||||||
|
<issue id="IconDipSize" severity="error" />
|
||||||
|
<issue id="IconDuplicatesConfig" severity="error" />
|
||||||
|
<issue id="IconDuplicates" severity="error" />
|
||||||
|
<issue id="IconExpectedSize" severity="error" />
|
||||||
|
|
||||||
<!-- UX -->
|
<!-- UX -->
|
||||||
<issue id="ButtonOrder" severity="error" />
|
<issue id="ButtonOrder" severity="error" />
|
||||||
|
@ -19,6 +24,7 @@
|
||||||
<issue id="InefficientWeight" severity="error" />
|
<issue id="InefficientWeight" severity="error" />
|
||||||
<issue id="DisableBaselineAlignment" severity="error" />
|
<issue id="DisableBaselineAlignment" severity="error" />
|
||||||
<issue id="ScrollViewSize" severity="error" />
|
<issue id="ScrollViewSize" severity="error" />
|
||||||
|
<issue id="NegativeMargin" severity="error" />
|
||||||
|
|
||||||
<!-- RTL -->
|
<!-- RTL -->
|
||||||
<issue id="RtlEnabled" severity="error" />
|
<issue id="RtlEnabled" severity="error" />
|
||||||
|
@ -30,9 +36,14 @@
|
||||||
<issue id="SetTextI18n" severity="error" />
|
<issue id="SetTextI18n" severity="error" />
|
||||||
<issue id="ViewConstructor" severity="error" />
|
<issue id="ViewConstructor" severity="error" />
|
||||||
<issue id="UseValueOf" severity="error" />
|
<issue id="UseValueOf" severity="error" />
|
||||||
|
<issue id="Recycle" severity="error" />
|
||||||
|
<issue id="KotlinPropertyAccess" severity="error" />
|
||||||
|
|
||||||
<!-- Ignore error from HtmlCompressor lib -->
|
<!-- Ignore error from HtmlCompressor lib -->
|
||||||
<issue id="InvalidPackage">
|
<issue id="InvalidPackage">
|
||||||
<ignore path="**/htmlcompressor-1.4.jar"/>
|
<ignore path="**/htmlcompressor-1.4.jar" />
|
||||||
</issue>
|
</issue>
|
||||||
|
|
||||||
|
<!-- Manifest -->
|
||||||
|
<issue id="PermissionImpliesUnsupportedChromeOsHardware" severity="error" />
|
||||||
</lint>
|
</lint>
|
||||||
|
|
|
@ -9,6 +9,15 @@
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
|
<!-- Adding CAMERA permission prevents Chromebooks to see the application on the PlayStore -->
|
||||||
|
<!-- Tell that the Camera is not mandatory to install the application -->
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera.autofocus"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".VectorApplication"
|
android:name=".VectorApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("DEPRECATION")
|
||||||
|
|
||||||
|
package im.vector.riotx.core.hardware
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.hardware.Camera
|
||||||
|
import android.hardware.camera2.CameraCharacteristics
|
||||||
|
import android.hardware.camera2.CameraManager
|
||||||
|
import android.os.Build
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class HardwareInfo @Inject constructor(
|
||||||
|
private val context: Context
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Tell if the device has a back (or external) camera
|
||||||
|
*/
|
||||||
|
fun hasBackCamera(): Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
return Camera.getNumberOfCameras() > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val manager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager? ?: return Camera.getNumberOfCameras() > 0
|
||||||
|
|
||||||
|
return manager.cameraIdList.any {
|
||||||
|
val lensFacing = manager.getCameraCharacteristics(it).get(CameraCharacteristics.LENS_FACING)
|
||||||
|
lensFacing == CameraCharacteristics.LENS_FACING_BACK || lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -129,7 +129,7 @@ class BadgeFloatingActionButton @JvmOverloads constructor(
|
||||||
attrs?.let { initAttrs(attrs) }
|
attrs?.let { initAttrs(attrs) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ResourceType", "Recycle")
|
@SuppressWarnings("Recycle")
|
||||||
private fun initAttrs(attrs: AttributeSet) {
|
private fun initAttrs(attrs: AttributeSet) {
|
||||||
context.obtainStyledAttributes(attrs, R.styleable.BadgeFloatingActionButton).use {
|
context.obtainStyledAttributes(attrs, R.styleable.BadgeFloatingActionButton).use {
|
||||||
counterBackgroundColor = it.getColor(R.styleable.BadgeFloatingActionButton_badgeBackgroundColor, 0)
|
counterBackgroundColor = it.getColor(R.styleable.BadgeFloatingActionButton_badgeBackgroundColor, 0)
|
||||||
|
|
|
@ -43,6 +43,7 @@ enum class Command(val command: String, val parameters: String, @StringRes val d
|
||||||
SPOILER("/spoiler", "<message>", R.string.command_description_spoiler),
|
SPOILER("/spoiler", "<message>", R.string.command_description_spoiler),
|
||||||
POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll),
|
POLL("/poll", "Question | Option 1 | Option 2 ...", R.string.command_description_poll),
|
||||||
SHRUG("/shrug", "<message>", R.string.command_description_shrug),
|
SHRUG("/shrug", "<message>", R.string.command_description_shrug),
|
||||||
|
PLAIN("/plain", "<message>", R.string.command_description_plain),
|
||||||
// TODO temporary command
|
// TODO temporary command
|
||||||
VERIFY_USER("/verify", "<user-id>", R.string.command_description_verify);
|
VERIFY_USER("/verify", "<user-id>", R.string.command_description_verify);
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,15 @@ object CommandParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
return when (val slashCommand = messageParts.first()) {
|
return when (val slashCommand = messageParts.first()) {
|
||||||
|
Command.PLAIN.command -> {
|
||||||
|
val text = textMessage.substring(Command.PLAIN.command.length).trim()
|
||||||
|
|
||||||
|
if (text.isNotEmpty()) {
|
||||||
|
ParsedCommand.SendPlainText(text)
|
||||||
|
} else {
|
||||||
|
ParsedCommand.ErrorSyntax(Command.PLAIN)
|
||||||
|
}
|
||||||
|
}
|
||||||
Command.CHANGE_DISPLAY_NAME.command -> {
|
Command.CHANGE_DISPLAY_NAME.command -> {
|
||||||
val newDisplayName = textMessage.substring(Command.CHANGE_DISPLAY_NAME.command.length).trim()
|
val newDisplayName = textMessage.substring(Command.CHANGE_DISPLAY_NAME.command.length).trim()
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ sealed class ParsedCommand {
|
||||||
|
|
||||||
// Valid commands:
|
// Valid commands:
|
||||||
|
|
||||||
|
class SendPlainText(val message: CharSequence) : ParsedCommand()
|
||||||
class SendEmote(val message: CharSequence) : ParsedCommand()
|
class SendEmote(val message: CharSequence) : ParsedCommand()
|
||||||
class SendRainbow(val message: CharSequence) : ParsedCommand()
|
class SendRainbow(val message: CharSequence) : ParsedCommand()
|
||||||
class SendRainbowEmote(val message: CharSequence) : ParsedCommand()
|
class SendRainbowEmote(val message: CharSequence) : ParsedCommand()
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2020 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package im.vector.riotx.features.crypto.verification
|
|
||||||
|
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
|
|
||||||
|
|
||||||
val supportedVerificationMethods =
|
|
||||||
listOf(
|
|
||||||
// RiotX supports SAS verification
|
|
||||||
VerificationMethod.SAS,
|
|
||||||
// RiotX is able to show QR codes
|
|
||||||
VerificationMethod.QR_CODE_SHOW,
|
|
||||||
// RiotX is able to scan QR codes
|
|
||||||
VerificationMethod.QR_CODE_SCAN
|
|
||||||
)
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.crypto.verification
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
|
||||||
|
import im.vector.riotx.core.hardware.HardwareInfo
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class SupportedVerificationMethodsProvider @Inject constructor(
|
||||||
|
private val hardwareInfo: HardwareInfo
|
||||||
|
) {
|
||||||
|
/**
|
||||||
|
* Provide the list of supported method by RiotX, with or without the QR_CODE_SCAN, depending if a back camera
|
||||||
|
* is available
|
||||||
|
*/
|
||||||
|
fun provide(): List<VerificationMethod> {
|
||||||
|
return mutableListOf(
|
||||||
|
// RiotX supports SAS verification
|
||||||
|
VerificationMethod.SAS,
|
||||||
|
// RiotX is able to show QR codes
|
||||||
|
VerificationMethod.QR_CODE_SHOW)
|
||||||
|
.apply {
|
||||||
|
if (hardwareInfo.hasBackCamera()) {
|
||||||
|
// RiotX is able to scan QR codes, and a Camera is available
|
||||||
|
add(VerificationMethod.QR_CODE_SCAN)
|
||||||
|
} else {
|
||||||
|
// This quite uncommon
|
||||||
|
Timber.w("No back Camera detected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,9 +63,11 @@ data class VerificationBottomSheetViewState(
|
||||||
val isMe: Boolean = false
|
val isMe: Boolean = false
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted initialState: VerificationBottomSheetViewState,
|
class VerificationBottomSheetViewModel @AssistedInject constructor(
|
||||||
@Assisted args: VerificationBottomSheet.VerificationArgs,
|
@Assisted initialState: VerificationBottomSheetViewState,
|
||||||
private val session: Session)
|
@Assisted args: VerificationBottomSheet.VerificationArgs,
|
||||||
|
private val session: Session,
|
||||||
|
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider)
|
||||||
: VectorViewModel<VerificationBottomSheetViewState, VerificationAction, VerificationBottomSheetViewEvents>(initialState),
|
: VectorViewModel<VerificationBottomSheetViewState, VerificationAction, VerificationBottomSheetViewEvents>(initialState),
|
||||||
VerificationService.Listener {
|
VerificationService.Listener {
|
||||||
|
|
||||||
|
@ -116,9 +118,11 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
||||||
if (autoReady) {
|
if (autoReady) {
|
||||||
// TODO, can I be here in DM mode? in this case should test if roomID is null?
|
// TODO, can I be here in DM mode? in this case should test if roomID is null?
|
||||||
session.cryptoService().verificationService()
|
session.cryptoService().verificationService()
|
||||||
.readyPendingVerification(supportedVerificationMethods,
|
.readyPendingVerification(
|
||||||
|
supportedVerificationMethodsProvider.provide(),
|
||||||
pr!!.otherUserId,
|
pr!!.otherUserId,
|
||||||
pr.transactionId ?: "")
|
pr.transactionId ?: ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +177,12 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
||||||
session
|
session
|
||||||
.cryptoService()
|
.cryptoService()
|
||||||
.verificationService()
|
.verificationService()
|
||||||
.requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, data, pendingLocalId)
|
.requestKeyVerificationInDMs(
|
||||||
|
supportedVerificationMethodsProvider.provide(),
|
||||||
|
otherUserId,
|
||||||
|
data,
|
||||||
|
pendingLocalId
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -191,7 +200,7 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
||||||
pendingRequest = Success(session
|
pendingRequest = Success(session
|
||||||
.cryptoService()
|
.cryptoService()
|
||||||
.verificationService()
|
.verificationService()
|
||||||
.requestKeyVerificationInDMs(supportedVerificationMethods, otherUserId, roomId)
|
.requestKeyVerificationInDMs(supportedVerificationMethodsProvider.provide(), otherUserId, roomId)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -294,8 +303,6 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage))
|
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage))
|
||||||
}
|
}
|
||||||
|
|
||||||
Unit
|
|
||||||
}
|
}
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
|
@ -362,9 +369,11 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(@Assisted ini
|
||||||
// auto ready in this case, as we are waiting
|
// auto ready in this case, as we are waiting
|
||||||
// TODO, can I be here in DM mode? in this case should test if roomID is null?
|
// TODO, can I be here in DM mode? in this case should test if roomID is null?
|
||||||
session.cryptoService().verificationService()
|
session.cryptoService().verificationService()
|
||||||
.readyPendingVerification(supportedVerificationMethods,
|
.readyPendingVerification(
|
||||||
|
supportedVerificationMethodsProvider.provide(),
|
||||||
pr.otherUserId,
|
pr.otherUserId,
|
||||||
pr.transactionId ?: "")
|
pr.transactionId ?: ""
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use this one!
|
// Use this one!
|
||||||
|
|
|
@ -65,7 +65,7 @@ import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
import im.vector.riotx.core.utils.subscribeLogError
|
import im.vector.riotx.core.utils.subscribeLogError
|
||||||
import im.vector.riotx.features.command.CommandParser
|
import im.vector.riotx.features.command.CommandParser
|
||||||
import im.vector.riotx.features.command.ParsedCommand
|
import im.vector.riotx.features.command.ParsedCommand
|
||||||
import im.vector.riotx.features.crypto.verification.supportedVerificationMethods
|
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||||
import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator
|
import im.vector.riotx.features.home.room.detail.composer.rainbow.RainbowGenerator
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
import im.vector.riotx.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
||||||
import im.vector.riotx.features.home.room.typing.TypingHelper
|
import im.vector.riotx.features.home.room.typing.TypingHelper
|
||||||
|
@ -81,13 +81,15 @@ import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.concurrent.atomic.AtomicBoolean
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: RoomDetailViewState,
|
class RoomDetailViewModel @AssistedInject constructor(
|
||||||
userPreferencesProvider: UserPreferencesProvider,
|
@Assisted initialState: RoomDetailViewState,
|
||||||
private val vectorPreferences: VectorPreferences,
|
userPreferencesProvider: UserPreferencesProvider,
|
||||||
private val stringProvider: StringProvider,
|
private val vectorPreferences: VectorPreferences,
|
||||||
private val typingHelper: TypingHelper,
|
private val stringProvider: StringProvider,
|
||||||
private val rainbowGenerator: RainbowGenerator,
|
private val typingHelper: TypingHelper,
|
||||||
private val session: Session
|
private val rainbowGenerator: RainbowGenerator,
|
||||||
|
private val session: Session,
|
||||||
|
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider
|
||||||
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
|
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
|
||||||
|
|
||||||
private val room = session.getRoom(initialState.roomId)!!
|
private val room = session.getRoom(initialState.roomId)!!
|
||||||
|
@ -340,6 +342,12 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||||
is ParsedCommand.ErrorUnknownSlashCommand -> {
|
is ParsedCommand.ErrorUnknownSlashCommand -> {
|
||||||
_viewEvents.post(RoomDetailViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand))
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandUnknown(slashCommandResult.slashCommand))
|
||||||
}
|
}
|
||||||
|
is ParsedCommand.SendPlainText -> {
|
||||||
|
// Send the text message to the room, without markdown
|
||||||
|
room.sendTextMessage(slashCommandResult.message, autoMarkdown = false)
|
||||||
|
_viewEvents.post(RoomDetailViewEvents.MessageSent)
|
||||||
|
popDraft()
|
||||||
|
}
|
||||||
is ParsedCommand.Invite -> {
|
is ParsedCommand.Invite -> {
|
||||||
handleInviteSlashCommand(slashCommandResult)
|
handleInviteSlashCommand(slashCommandResult)
|
||||||
popDraft()
|
popDraft()
|
||||||
|
@ -421,7 +429,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||||
session
|
session
|
||||||
.cryptoService()
|
.cryptoService()
|
||||||
.verificationService()
|
.verificationService()
|
||||||
.requestKeyVerificationInDMs(supportedVerificationMethods, slashCommandResult.userId, room.roomId)
|
.requestKeyVerificationInDMs(supportedVerificationMethodsProvider.provide(), slashCommandResult.userId, room.roomId)
|
||||||
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
_viewEvents.post(RoomDetailViewEvents.SlashCommandHandled())
|
||||||
popDraft()
|
popDraft()
|
||||||
}
|
}
|
||||||
|
@ -828,7 +836,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
|
||||||
private fun handleAcceptVerification(action: RoomDetailAction.AcceptVerificationRequest) {
|
private fun handleAcceptVerification(action: RoomDetailAction.AcceptVerificationRequest) {
|
||||||
Timber.v("## SAS handleAcceptVerification ${action.otherUserId}, roomId:${room.roomId}, txId:${action.transactionId}")
|
Timber.v("## SAS handleAcceptVerification ${action.otherUserId}, roomId:${room.roomId}, txId:${action.transactionId}")
|
||||||
if (session.cryptoService().verificationService().readyPendingVerificationInDMs(
|
if (session.cryptoService().verificationService().readyPendingVerificationInDMs(
|
||||||
supportedVerificationMethods,
|
supportedVerificationMethodsProvider.provide(),
|
||||||
action.otherUserId,
|
action.otherUserId,
|
||||||
room.roomId,
|
room.roomId,
|
||||||
action.transactionId)) {
|
action.transactionId)) {
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.home.room.detail.timeline
|
||||||
|
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.resources.ColorProvider
|
||||||
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class MessageColorProvider @Inject constructor(
|
||||||
|
private val colorProvider: ColorProvider,
|
||||||
|
private val vectorPreferences: VectorPreferences) {
|
||||||
|
|
||||||
|
@ColorInt
|
||||||
|
fun getMessageTextColor(sendState: SendState): Int {
|
||||||
|
return if (vectorPreferences.developerMode()) {
|
||||||
|
when (sendState) {
|
||||||
|
// SendStates, in the classical order they will occur
|
||||||
|
SendState.UNKNOWN,
|
||||||
|
SendState.UNSENT -> colorProvider.getColorFromAttribute(R.attr.vctr_sending_message_text_color)
|
||||||
|
SendState.ENCRYPTING -> colorProvider.getColorFromAttribute(R.attr.vctr_encrypting_message_text_color)
|
||||||
|
SendState.SENDING -> colorProvider.getColorFromAttribute(R.attr.vctr_sending_message_text_color)
|
||||||
|
SendState.SENT,
|
||||||
|
SendState.SYNCED -> colorProvider.getColorFromAttribute(R.attr.vctr_message_text_color)
|
||||||
|
SendState.UNDELIVERED,
|
||||||
|
SendState.FAILED_UNKNOWN_DEVICES -> colorProvider.getColorFromAttribute(R.attr.vctr_unsent_message_text_color)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// When not in developer mode, we do not use special color for the encrypting state
|
||||||
|
when (sendState) {
|
||||||
|
SendState.UNKNOWN,
|
||||||
|
SendState.UNSENT,
|
||||||
|
SendState.ENCRYPTING,
|
||||||
|
SendState.SENDING -> colorProvider.getColorFromAttribute(R.attr.vctr_sending_message_text_color)
|
||||||
|
SendState.SENT,
|
||||||
|
SendState.SYNCED -> colorProvider.getColorFromAttribute(R.attr.vctr_message_text_color)
|
||||||
|
SendState.UNDELIVERED,
|
||||||
|
SendState.FAILED_UNKNOWN_DEVICES -> colorProvider.getColorFromAttribute(R.attr.vctr_unsent_message_text_color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -222,7 +222,7 @@ class MessageItemFactory @Inject constructor(
|
||||||
referenceId = informationData.eventId,
|
referenceId = informationData.eventId,
|
||||||
informationData = informationData,
|
informationData = informationData,
|
||||||
avatarRenderer = attributes.avatarRenderer,
|
avatarRenderer = attributes.avatarRenderer,
|
||||||
colorProvider = attributes.colorProvider,
|
messageColorProvider = attributes.messageColorProvider,
|
||||||
itemLongClickListener = attributes.itemLongClickListener,
|
itemLongClickListener = attributes.itemLongClickListener,
|
||||||
itemClickListener = attributes.itemClickListener,
|
itemClickListener = attributes.itemClickListener,
|
||||||
reactionPillCallback = attributes.reactionPillCallback,
|
reactionPillCallback = attributes.reactionPillCallback,
|
||||||
|
|
|
@ -27,8 +27,8 @@ import im.vector.matrix.android.api.session.room.model.message.MessageVerificati
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.internal.session.room.VerificationState
|
import im.vector.matrix.android.internal.session.room.VerificationState
|
||||||
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.resources.UserPreferencesProvider
|
import im.vector.riotx.core.resources.UserPreferencesProvider
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
import im.vector.riotx.features.home.room.detail.timeline.helper.AvatarSizeProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.MessageInformationDataFactory
|
import im.vector.riotx.features.home.room.detail.timeline.helper.MessageInformationDataFactory
|
||||||
|
@ -43,7 +43,7 @@ import javax.inject.Inject
|
||||||
* several checks are made to see if this conclusion is attached to a known request
|
* several checks are made to see if this conclusion is attached to a known request
|
||||||
*/
|
*/
|
||||||
class VerificationItemFactory @Inject constructor(
|
class VerificationItemFactory @Inject constructor(
|
||||||
private val colorProvider: ColorProvider,
|
private val messageColorProvider: MessageColorProvider,
|
||||||
private val messageInformationDataFactory: MessageInformationDataFactory,
|
private val messageInformationDataFactory: MessageInformationDataFactory,
|
||||||
private val messageItemAttributesFactory: MessageItemAttributesFactory,
|
private val messageItemAttributesFactory: MessageItemAttributesFactory,
|
||||||
private val avatarSizeProvider: AvatarSizeProvider,
|
private val avatarSizeProvider: AvatarSizeProvider,
|
||||||
|
@ -97,7 +97,7 @@ class VerificationItemFactory @Inject constructor(
|
||||||
isPositive = false,
|
isPositive = false,
|
||||||
informationData = informationData,
|
informationData = informationData,
|
||||||
avatarRenderer = attributes.avatarRenderer,
|
avatarRenderer = attributes.avatarRenderer,
|
||||||
colorProvider = colorProvider,
|
messageColorProvider = messageColorProvider,
|
||||||
emojiTypeFace = attributes.emojiTypeFace,
|
emojiTypeFace = attributes.emojiTypeFace,
|
||||||
itemClickListener = attributes.itemClickListener,
|
itemClickListener = attributes.itemClickListener,
|
||||||
itemLongClickListener = attributes.itemLongClickListener,
|
itemLongClickListener = attributes.itemLongClickListener,
|
||||||
|
@ -130,7 +130,7 @@ class VerificationItemFactory @Inject constructor(
|
||||||
isPositive = true,
|
isPositive = true,
|
||||||
informationData = informationData,
|
informationData = informationData,
|
||||||
avatarRenderer = attributes.avatarRenderer,
|
avatarRenderer = attributes.avatarRenderer,
|
||||||
colorProvider = colorProvider,
|
messageColorProvider = messageColorProvider,
|
||||||
emojiTypeFace = attributes.emojiTypeFace,
|
emojiTypeFace = attributes.emojiTypeFace,
|
||||||
itemClickListener = attributes.itemClickListener,
|
itemClickListener = attributes.itemClickListener,
|
||||||
itemLongClickListener = attributes.itemLongClickListener,
|
itemLongClickListener = attributes.itemLongClickListener,
|
||||||
|
|
|
@ -27,14 +27,13 @@ import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.di.ActiveSessionHolder
|
import im.vector.riotx.core.di.ActiveSessionHolder
|
||||||
import im.vector.riotx.core.di.ScreenScope
|
import im.vector.riotx.core.di.ScreenScope
|
||||||
import im.vector.riotx.core.error.ErrorFormatter
|
import im.vector.riotx.core.error.ErrorFormatter
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.utils.TextUtils
|
import im.vector.riotx.core.utils.TextUtils
|
||||||
import im.vector.riotx.features.ui.getMessageTextColor
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ScreenScope
|
@ScreenScope
|
||||||
class ContentUploadStateTrackerBinder @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
|
class ContentUploadStateTrackerBinder @Inject constructor(private val activeSessionHolder: ActiveSessionHolder,
|
||||||
private val colorProvider: ColorProvider,
|
private val messageColorProvider: MessageColorProvider,
|
||||||
private val errorFormatter: ErrorFormatter) {
|
private val errorFormatter: ErrorFormatter) {
|
||||||
|
|
||||||
private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>()
|
private val updateListeners = mutableMapOf<String, ContentUploadStateTracker.UpdateListener>()
|
||||||
|
@ -44,7 +43,7 @@ class ContentUploadStateTrackerBinder @Inject constructor(private val activeSess
|
||||||
progressLayout: ViewGroup) {
|
progressLayout: ViewGroup) {
|
||||||
activeSessionHolder.getSafeActiveSession()?.also { session ->
|
activeSessionHolder.getSafeActiveSession()?.also { session ->
|
||||||
val uploadStateTracker = session.contentUploadProgressTracker()
|
val uploadStateTracker = session.contentUploadProgressTracker()
|
||||||
val updateListener = ContentMediaProgressUpdater(progressLayout, isLocalFile, colorProvider, errorFormatter)
|
val updateListener = ContentMediaProgressUpdater(progressLayout, isLocalFile, messageColorProvider, errorFormatter)
|
||||||
updateListeners[eventId] = updateListener
|
updateListeners[eventId] = updateListener
|
||||||
uploadStateTracker.track(eventId, updateListener)
|
uploadStateTracker.track(eventId, updateListener)
|
||||||
}
|
}
|
||||||
|
@ -68,7 +67,7 @@ class ContentUploadStateTrackerBinder @Inject constructor(private val activeSess
|
||||||
|
|
||||||
private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
private val isLocalFile: Boolean,
|
private val isLocalFile: Boolean,
|
||||||
private val colorProvider: ColorProvider,
|
private val messageColorProvider: MessageColorProvider,
|
||||||
private val errorFormatter: ErrorFormatter) : ContentUploadStateTracker.UpdateListener {
|
private val errorFormatter: ErrorFormatter) : ContentUploadStateTracker.UpdateListener {
|
||||||
|
|
||||||
override fun onUpdate(state: ContentUploadStateTracker.State) {
|
override fun onUpdate(state: ContentUploadStateTracker.State) {
|
||||||
|
@ -92,7 +91,7 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
progressBar?.isIndeterminate = true
|
progressBar?.isIndeterminate = true
|
||||||
progressBar?.progress = 0
|
progressBar?.progress = 0
|
||||||
progressTextView?.text = progressLayout.context.getString(R.string.send_file_step_idle)
|
progressTextView?.text = progressLayout.context.getString(R.string.send_file_step_idle)
|
||||||
progressTextView?.setTextColor(colorProvider.getMessageTextColor(SendState.UNSENT))
|
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNSENT))
|
||||||
} else {
|
} else {
|
||||||
progressLayout.isVisible = false
|
progressLayout.isVisible = false
|
||||||
}
|
}
|
||||||
|
@ -120,7 +119,7 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
||||||
progressBar?.isIndeterminate = true
|
progressBar?.isIndeterminate = true
|
||||||
progressTextView?.text = progressLayout.context.getString(resId)
|
progressTextView?.text = progressLayout.context.getString(resId)
|
||||||
progressTextView?.setTextColor(colorProvider.getMessageTextColor(SendState.ENCRYPTING))
|
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.ENCRYPTING))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doHandleProgress(resId: Int, current: Long, total: Long) {
|
private fun doHandleProgress(resId: Int, current: Long, total: Long) {
|
||||||
|
@ -134,7 +133,7 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
progressTextView?.text = progressLayout.context.getString(resId,
|
progressTextView?.text = progressLayout.context.getString(resId,
|
||||||
TextUtils.formatFileSize(progressLayout.context, current, true),
|
TextUtils.formatFileSize(progressLayout.context, current, true),
|
||||||
TextUtils.formatFileSize(progressLayout.context, total, true))
|
TextUtils.formatFileSize(progressLayout.context, total, true))
|
||||||
progressTextView?.setTextColor(colorProvider.getMessageTextColor(SendState.SENDING))
|
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.SENDING))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleFailure(state: ContentUploadStateTracker.State.Failure) {
|
private fun handleFailure(state: ContentUploadStateTracker.State.Failure) {
|
||||||
|
@ -143,7 +142,7 @@ private class ContentMediaProgressUpdater(private val progressLayout: ViewGroup,
|
||||||
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
val progressTextView = progressLayout.findViewById<TextView>(R.id.mediaProgressTextView)
|
||||||
progressBar?.isVisible = false
|
progressBar?.isVisible = false
|
||||||
progressTextView?.text = errorFormatter.toHumanReadable(state.throwable)
|
progressTextView?.text = errorFormatter.toHumanReadable(state.throwable)
|
||||||
progressTextView?.setTextColor(colorProvider.getMessageTextColor(SendState.UNDELIVERED))
|
progressTextView?.setTextColor(messageColorProvider.getMessageTextColor(SendState.UNDELIVERED))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSuccess() {
|
private fun handleSuccess() {
|
||||||
|
|
|
@ -20,9 +20,9 @@ package im.vector.riotx.features.home.room.detail.timeline.helper
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||||
import im.vector.riotx.EmojiCompatFontProvider
|
import im.vector.riotx.EmojiCompatFontProvider
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.AbsMessageItem
|
import im.vector.riotx.features.home.room.detail.timeline.item.AbsMessageItem
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
||||||
|
@ -30,7 +30,7 @@ import javax.inject.Inject
|
||||||
|
|
||||||
class MessageItemAttributesFactory @Inject constructor(
|
class MessageItemAttributesFactory @Inject constructor(
|
||||||
private val avatarRenderer: AvatarRenderer,
|
private val avatarRenderer: AvatarRenderer,
|
||||||
private val colorProvider: ColorProvider,
|
private val messageColorProvider: MessageColorProvider,
|
||||||
private val avatarSizeProvider: AvatarSizeProvider,
|
private val avatarSizeProvider: AvatarSizeProvider,
|
||||||
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
|
private val emojiCompatFontProvider: EmojiCompatFontProvider) {
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class MessageItemAttributesFactory @Inject constructor(
|
||||||
avatarSize = avatarSizeProvider.avatarSize,
|
avatarSize = avatarSizeProvider.avatarSize,
|
||||||
informationData = informationData,
|
informationData = informationData,
|
||||||
avatarRenderer = avatarRenderer,
|
avatarRenderer = avatarRenderer,
|
||||||
colorProvider = colorProvider,
|
messageColorProvider = messageColorProvider,
|
||||||
itemLongClickListener = View.OnLongClickListener { view ->
|
itemLongClickListener = View.OnLongClickListener { view ->
|
||||||
callback?.onEventLongClicked(informationData, messageContent, view) ?: false
|
callback?.onEventLongClicked(informationData, messageContent, view) ?: false
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,12 +24,11 @@ import androidx.annotation.IdRes
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import im.vector.matrix.android.api.session.room.send.SendState
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.reactions.widget.ReactionButton
|
import im.vector.riotx.features.reactions.widget.ReactionButton
|
||||||
import im.vector.riotx.features.ui.getMessageTextColor
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base timeline item with reactions and read receipts.
|
* Base timeline item with reactions and read receipts.
|
||||||
|
@ -105,7 +104,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
||||||
protected open fun renderSendState(root: View, textView: TextView?, failureIndicator: ImageView? = null) {
|
protected open fun renderSendState(root: View, textView: TextView?, failureIndicator: ImageView? = null) {
|
||||||
root.isClickable = baseAttributes.informationData.sendState.isSent()
|
root.isClickable = baseAttributes.informationData.sendState.isSent()
|
||||||
val state = if (baseAttributes.informationData.hasPendingEdits) SendState.UNSENT else baseAttributes.informationData.sendState
|
val state = if (baseAttributes.informationData.hasPendingEdits) SendState.UNSENT else baseAttributes.informationData.sendState
|
||||||
textView?.setTextColor(baseAttributes.colorProvider.getMessageTextColor(state))
|
textView?.setTextColor(baseAttributes.messageColorProvider.getMessageTextColor(state))
|
||||||
failureIndicator?.isVisible = baseAttributes.informationData.sendState.hasFailed()
|
failureIndicator?.isVisible = baseAttributes.informationData.sendState.hasFailed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +119,7 @@ abstract class AbsBaseMessageItem<H : AbsBaseMessageItem.Holder> : BaseEventItem
|
||||||
// val avatarSize: Int,
|
// val avatarSize: Int,
|
||||||
val informationData: MessageInformationData
|
val informationData: MessageInformationData
|
||||||
val avatarRenderer: AvatarRenderer
|
val avatarRenderer: AvatarRenderer
|
||||||
val colorProvider: ColorProvider
|
val messageColorProvider: MessageColorProvider
|
||||||
val itemLongClickListener: View.OnLongClickListener?
|
val itemLongClickListener: View.OnLongClickListener?
|
||||||
val itemClickListener: View.OnClickListener?
|
val itemClickListener: View.OnClickListener?
|
||||||
// val memberClickListener: View.OnClickListener?
|
// val memberClickListener: View.OnClickListener?
|
||||||
|
|
|
@ -23,9 +23,9 @@ import android.widget.TextView
|
||||||
import androidx.annotation.IdRes
|
import androidx.annotation.IdRes
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +88,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : AbsBaseMessageItem<H>
|
||||||
val avatarSize: Int,
|
val avatarSize: Int,
|
||||||
override val informationData: MessageInformationData,
|
override val informationData: MessageInformationData,
|
||||||
override val avatarRenderer: AvatarRenderer,
|
override val avatarRenderer: AvatarRenderer,
|
||||||
override val colorProvider: ColorProvider,
|
override val messageColorProvider: MessageColorProvider,
|
||||||
override val itemLongClickListener: View.OnLongClickListener? = null,
|
override val itemLongClickListener: View.OnLongClickListener? = null,
|
||||||
override val itemClickListener: View.OnClickListener? = null,
|
override val itemClickListener: View.OnClickListener? = null,
|
||||||
val memberClickListener: View.OnClickListener? = null,
|
val memberClickListener: View.OnClickListener? = null,
|
||||||
|
|
|
@ -73,11 +73,11 @@ class PollResultLineView @JvmOverloads constructor(
|
||||||
orientation = HORIZONTAL
|
orientation = HORIZONTAL
|
||||||
ButterKnife.bind(this)
|
ButterKnife.bind(this)
|
||||||
|
|
||||||
val typedArray = context.obtainStyledAttributes(attrs,
|
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PollResultLineView, 0, 0)
|
||||||
R.styleable.PollResultLineView, 0, 0)
|
|
||||||
label = typedArray.getString(R.styleable.PollResultLineView_optionName) ?: ""
|
label = typedArray.getString(R.styleable.PollResultLineView_optionName) ?: ""
|
||||||
percent = typedArray.getString(R.styleable.PollResultLineView_optionCount) ?: ""
|
percent = typedArray.getString(R.styleable.PollResultLineView_optionCount) ?: ""
|
||||||
optionSelected = typedArray.getBoolean(R.styleable.PollResultLineView_optionSelected, false)
|
optionSelected = typedArray.getBoolean(R.styleable.PollResultLineView_optionSelected, false)
|
||||||
isWinner = typedArray.getBoolean(R.styleable.PollResultLineView_optionIsWinner, false)
|
isWinner = typedArray.getBoolean(R.styleable.PollResultLineView_optionIsWinner, false)
|
||||||
|
typedArray.recycle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ import androidx.core.view.updateLayoutParams
|
||||||
import com.airbnb.epoxy.EpoxyAttribute
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
import com.airbnb.epoxy.EpoxyModelClass
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_state)
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_state)
|
||||||
|
@ -80,7 +80,7 @@ abstract class VerificationRequestConclusionItem : AbsBaseMessageItem<Verificati
|
||||||
val isPositive: Boolean,
|
val isPositive: Boolean,
|
||||||
override val informationData: MessageInformationData,
|
override val informationData: MessageInformationData,
|
||||||
override val avatarRenderer: AvatarRenderer,
|
override val avatarRenderer: AvatarRenderer,
|
||||||
override val colorProvider: ColorProvider,
|
override val messageColorProvider: MessageColorProvider,
|
||||||
override val itemLongClickListener: View.OnLongClickListener? = null,
|
override val itemLongClickListener: View.OnLongClickListener? = null,
|
||||||
override val itemClickListener: View.OnClickListener? = null,
|
override val itemClickListener: View.OnClickListener? = null,
|
||||||
override val reactionPillCallback: TimelineEventController.ReactionPillCallback? = null,
|
override val reactionPillCallback: TimelineEventController.ReactionPillCallback? = null,
|
||||||
|
|
|
@ -32,10 +32,10 @@ import im.vector.matrix.android.api.session.crypto.verification.VerificationServ
|
||||||
import im.vector.matrix.android.internal.session.room.VerificationState
|
import im.vector.matrix.android.internal.session.room.VerificationState
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import im.vector.riotx.core.extensions.exhaustive
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
import im.vector.riotx.core.utils.DebouncedClickListener
|
import im.vector.riotx.core.utils.DebouncedClickListener
|
||||||
import im.vector.riotx.features.home.AvatarRenderer
|
import im.vector.riotx.features.home.AvatarRenderer
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailAction
|
import im.vector.riotx.features.home.room.detail.RoomDetailAction
|
||||||
|
import im.vector.riotx.features.home.room.detail.timeline.MessageColorProvider
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
|
|
||||||
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_state)
|
@EpoxyModelClass(layout = R.layout.item_timeline_event_base_state)
|
||||||
|
@ -166,7 +166,7 @@ abstract class VerificationRequestItem : AbsBaseMessageItem<VerificationRequestI
|
||||||
// val avatarSize: Int,
|
// val avatarSize: Int,
|
||||||
override val informationData: MessageInformationData,
|
override val informationData: MessageInformationData,
|
||||||
override val avatarRenderer: AvatarRenderer,
|
override val avatarRenderer: AvatarRenderer,
|
||||||
override val colorProvider: ColorProvider,
|
override val messageColorProvider: MessageColorProvider,
|
||||||
override val itemLongClickListener: View.OnLongClickListener? = null,
|
override val itemLongClickListener: View.OnLongClickListener? = null,
|
||||||
override val itemClickListener: View.OnClickListener? = null,
|
override val itemClickListener: View.OnClickListener? = null,
|
||||||
// val memberClickListener: View.OnClickListener? = null,
|
// val memberClickListener: View.OnClickListener? = null,
|
||||||
|
|
|
@ -209,7 +209,14 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||||
} else {
|
} else {
|
||||||
// Trick to display the error without text.
|
// Trick to display the error without text.
|
||||||
loginFieldTil.error = " "
|
loginFieldTil.error = " "
|
||||||
passwordFieldTil.error = errorFormatter.toHumanReadable(state.asyncLoginAction.error)
|
if (error is Failure.ServerError
|
||||||
|
&& error.error.code == MatrixError.M_FORBIDDEN
|
||||||
|
&& error.error.message == "Invalid password"
|
||||||
|
&& spaceInPassword()) {
|
||||||
|
passwordFieldTil.error = getString(R.string.auth_invalid_login_param_space_in_password)
|
||||||
|
} else {
|
||||||
|
passwordFieldTil.error = errorFormatter.toHumanReadable(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Success is handled by the LoginActivity
|
// Success is handled by the LoginActivity
|
||||||
|
@ -226,4 +233,9 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() {
|
||||||
is Success -> Unit
|
is Success -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if password ends or starts with spaces
|
||||||
|
*/
|
||||||
|
private fun spaceInPassword() = passwordField.text.toString().let { it.trim() != it }
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import androidx.core.app.ActivityOptionsCompat
|
||||||
import androidx.core.app.TaskStackBuilder
|
import androidx.core.app.TaskStackBuilder
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction
|
import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction
|
||||||
import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod
|
|
||||||
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import im.vector.matrix.android.api.util.MatrixItem
|
import im.vector.matrix.android.api.util.MatrixItem
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
|
@ -35,6 +34,7 @@ import im.vector.riotx.core.utils.toast
|
||||||
import im.vector.riotx.features.createdirect.CreateDirectRoomActivity
|
import im.vector.riotx.features.createdirect.CreateDirectRoomActivity
|
||||||
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||||
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupActivity
|
||||||
|
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||||
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
import im.vector.riotx.features.crypto.verification.VerificationBottomSheet
|
||||||
import im.vector.riotx.features.debug.DebugMenuActivity
|
import im.vector.riotx.features.debug.DebugMenuActivity
|
||||||
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
import im.vector.riotx.features.home.room.detail.RoomDetailActivity
|
||||||
|
@ -56,7 +56,8 @@ import javax.inject.Singleton
|
||||||
@Singleton
|
@Singleton
|
||||||
class DefaultNavigator @Inject constructor(
|
class DefaultNavigator @Inject constructor(
|
||||||
private val sessionHolder: ActiveSessionHolder,
|
private val sessionHolder: ActiveSessionHolder,
|
||||||
private val vectorPreferences: VectorPreferences
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider
|
||||||
) : Navigator {
|
) : Navigator {
|
||||||
|
|
||||||
override fun openRoom(context: Context, roomId: String, eventId: String?, buildTask: Boolean) {
|
override fun openRoom(context: Context, roomId: String, eventId: String?, buildTask: Boolean) {
|
||||||
|
@ -85,9 +86,10 @@ class DefaultNavigator @Inject constructor(
|
||||||
override fun requestSessionVerification(context: Context) {
|
override fun requestSessionVerification(context: Context) {
|
||||||
val session = sessionHolder.getSafeActiveSession() ?: return
|
val session = sessionHolder.getSafeActiveSession() ?: return
|
||||||
val pr = session.cryptoService().verificationService().requestKeyVerification(
|
val pr = session.cryptoService().verificationService().requestKeyVerification(
|
||||||
listOf(VerificationMethod.SAS, VerificationMethod.QR_CODE_SCAN, VerificationMethod.QR_CODE_SHOW),
|
supportedVerificationMethodsProvider.provide(),
|
||||||
session.myUserId,
|
session.myUserId,
|
||||||
session.cryptoService().getUserDevices(session.myUserId).map { it.deviceId })
|
session.cryptoService().getUserDevices(session.myUserId).map { it.deviceId }
|
||||||
|
)
|
||||||
if (context is VectorBaseActivity) {
|
if (context is VectorBaseActivity) {
|
||||||
VerificationBottomSheet.withArgs(
|
VerificationBottomSheet.withArgs(
|
||||||
roomId = null,
|
roomId = null,
|
||||||
|
|
|
@ -40,7 +40,7 @@ import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
|
||||||
import im.vector.matrix.rx.rx
|
import im.vector.matrix.rx.rx
|
||||||
import im.vector.riotx.core.platform.VectorViewModel
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
import im.vector.riotx.features.crypto.verification.supportedVerificationMethods
|
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
|
||||||
|
|
||||||
data class DevicesViewState(
|
data class DevicesViewState(
|
||||||
val myDeviceId: String = "",
|
val myDeviceId: String = "",
|
||||||
|
@ -50,8 +50,10 @@ data class DevicesViewState(
|
||||||
val request: Async<Unit> = Uninitialized
|
val request: Async<Unit> = Uninitialized
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
|
||||||
class DevicesViewModel @AssistedInject constructor(@Assisted initialState: DevicesViewState,
|
class DevicesViewModel @AssistedInject constructor(
|
||||||
private val session: Session)
|
@Assisted initialState: DevicesViewState,
|
||||||
|
private val session: Session,
|
||||||
|
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider)
|
||||||
: VectorViewModel<DevicesViewState, DevicesAction, DevicesViewEvents>(initialState), VerificationService.Listener {
|
: VectorViewModel<DevicesViewState, DevicesAction, DevicesViewEvents>(initialState), VerificationService.Listener {
|
||||||
|
|
||||||
@AssistedInject.Factory
|
@AssistedInject.Factory
|
||||||
|
@ -172,7 +174,9 @@ class DevicesViewModel @AssistedInject constructor(@Assisted initialState: Devic
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleVerify(action: DevicesAction.VerifyMyDevice) {
|
private fun handleVerify(action: DevicesAction.VerifyMyDevice) {
|
||||||
val txID = session.cryptoService().verificationService().requestKeyVerification(supportedVerificationMethods, session.myUserId, listOf(action.deviceId))
|
val txID = session.cryptoService()
|
||||||
|
.verificationService()
|
||||||
|
.requestKeyVerification(supportedVerificationMethodsProvider.provide(), session.myUserId, listOf(action.deviceId))
|
||||||
_viewEvents.post(DevicesViewEvents.ShowVerifyDevice(
|
_viewEvents.post(DevicesViewEvents.ShowVerifyDevice(
|
||||||
session.myUserId,
|
session.myUserId,
|
||||||
txID.transactionId
|
txID.transactionId
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2019 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package im.vector.riotx.features.ui
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt
|
|
||||||
import im.vector.matrix.android.api.session.room.send.SendState
|
|
||||||
import im.vector.riotx.R
|
|
||||||
import im.vector.riotx.core.resources.ColorProvider
|
|
||||||
|
|
||||||
@ColorInt
|
|
||||||
fun ColorProvider.getMessageTextColor(sendState: SendState): Int {
|
|
||||||
return when (sendState) {
|
|
||||||
// SendStates, in the classical order they will occur
|
|
||||||
SendState.UNKNOWN,
|
|
||||||
SendState.UNSENT -> getColorFromAttribute(R.attr.vctr_sending_message_text_color)
|
|
||||||
SendState.ENCRYPTING -> getColorFromAttribute(R.attr.vctr_encrypting_message_text_color)
|
|
||||||
SendState.SENDING -> getColorFromAttribute(R.attr.vctr_sending_message_text_color)
|
|
||||||
SendState.SENT,
|
|
||||||
SendState.SYNCED -> getColorFromAttribute(R.attr.vctr_message_text_color)
|
|
||||||
SendState.UNDELIVERED,
|
|
||||||
SendState.FAILED_UNKNOWN_DEVICES -> getColorFromAttribute(R.attr.vctr_unsent_message_text_color)
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 269 B |
Before Width: | Height: | Size: 539 B |
Before Width: | Height: | Size: 545 B |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 399 B |
Before Width: | Height: | Size: 224 B |
Before Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 574 B |
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 432 B |
Before Width: | Height: | Size: 684 B |
Before Width: | Height: | Size: 307 B |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 240 B |
Before Width: | Height: | Size: 539 B |
Before Width: | Height: | Size: 545 B |
Before Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 712 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 3 KiB |
Before Width: | Height: | Size: 240 B |
Before Width: | Height: | Size: 428 B |
Before Width: | Height: | Size: 428 B |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 399 B |
Before Width: | Height: | Size: 224 B |
Before Width: | Height: | Size: 298 B |
Before Width: | Height: | Size: 574 B |
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 432 B |
Before Width: | Height: | Size: 684 B |
Before Width: | Height: | Size: 565 B |
|
@ -21,6 +21,7 @@
|
||||||
android:layout_marginLeft="-5dp"
|
android:layout_marginLeft="-5dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
tools:ignore="NegativeMargin"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
android:layout_marginLeft="-5dp"
|
android:layout_marginLeft="-5dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
tools:ignore="NegativeMargin"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -41,6 +43,7 @@
|
||||||
android:layout_marginLeft="-5dp"
|
android:layout_marginLeft="-5dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
tools:ignore="NegativeMargin"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -51,6 +54,7 @@
|
||||||
android:layout_marginLeft="-5dp"
|
android:layout_marginLeft="-5dp"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
tools:ignore="NegativeMargin"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -1,7 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_select_remove_group"
|
|
||||||
android:icon="@drawable/vector_leave_room_black"
|
|
||||||
android:title="@string/leave" />
|
|
||||||
</menu>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context="org.matrix.vector.activity.RoomActivity">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_search_in_room"
|
|
||||||
android:icon="@drawable/ic_material_search_white"
|
|
||||||
android:title="@string/room_menu_search"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_matrix_apps"
|
|
||||||
android:icon="@drawable/apps_icon"
|
|
||||||
android:title="@string/room_add_matrix_apps"
|
|
||||||
app:showAsAction="collapseActionView" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_room_resend_unsent"
|
|
||||||
android:icon="@drawable/ic_material_send_black"
|
|
||||||
android:title="@string/room_resend_unsent_messages"
|
|
||||||
app:showAsAction="collapseActionView" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_room_delete_unsent"
|
|
||||||
android:icon="@drawable/ic_material_delete"
|
|
||||||
android:title="@string/room_delete_unsent_messages"
|
|
||||||
app:showAsAction="collapseActionView" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_room_settings"
|
|
||||||
android:icon="@drawable/ic_material_settings_small"
|
|
||||||
android:title="@string/room_details_title"
|
|
||||||
app:showAsAction="collapseActionView" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_room_leave"
|
|
||||||
android:icon="@drawable/vector_leave_room_black"
|
|
||||||
android:title="@string/leave"
|
|
||||||
app:showAsAction="collapseActionView" />
|
|
||||||
|
|
||||||
</menu>
|
|
|
@ -1,18 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
tools:context="org.matrix.vector.activity.RoomActivity">
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_speak_to_search"
|
|
||||||
android:icon="@drawable/vector_micro_green"
|
|
||||||
android:title="@string/speak"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/ic_action_clear_search"
|
|
||||||
android:icon="@drawable/vector_clear_edittext_green"
|
|
||||||
android:title="@string/clear"
|
|
||||||
app:showAsAction="always" />
|
|
||||||
</menu>
|
|
|
@ -26,7 +26,8 @@
|
||||||
|
|
||||||
|
|
||||||
<!-- BEGIN Strings added by Others -->
|
<!-- BEGIN Strings added by Others -->
|
||||||
|
<string name="command_description_plain">Sends a message as plain text, without interpreting it as markdown</string>
|
||||||
<!-- END Strings added by Others -->
|
<!-- END Strings added by Others -->
|
||||||
|
|
||||||
|
<string name="auth_invalid_login_param_space_in_password">Incorrect username and/or password. The entered password starts or ends with spaces, please check it.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|