Merge branch 'develop' into feature/fix_widget

This commit is contained in:
ganfra 2020-06-22 10:21:39 +02:00
commit 8de0bdca93
32 changed files with 126 additions and 82 deletions

View File

@ -5,10 +5,11 @@ Features ✨:
-
Improvements 🙌:
-
- "Add Matrix app" menu is now always visible (#1495)
Bugfix 🐛:
-
- Fix dark theme issue on login screen (#1097)
- Incomplete predicate in RealmCryptoStore#getOutgoingRoomKeyRequest (#1519)
Translations 🗣:
-
@ -18,6 +19,7 @@ SDK API changes ⚠️:
Build 🧱:
- Enable code optimization (Proguard)
- SDK is now API level 21 minimum, and so RiotX (#405)
Other changes:
-

View File

@ -19,7 +19,11 @@ An Android Studio template has been added to the project to help creating all fi
To install the template (to be done only once):
- Go to folder `./tools/template`.
- Run the script `./configure.sh`.
- Mac OSX: Run the script `./configure.sh`.
Linux: Run `ANDROID_STUDIO=/path/to/android-studio ./configure`
- e.g. `ANDROID_STUDIO=/usr/local/android-studio ./configure`
- Restart Android Studio.
To create a new screen:

View File

@ -11,8 +11,8 @@ RiotX is an Android Matrix Client currently in beta but in active development.
It is a total rewrite of [Riot-Android](https://github.com/vector-im/riot-android) with a new user experience. RiotX will become the official replacement as soon as all features are implemented.
[<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.riotx)
[<img src="https://f-droid.org/badge/get-it-on.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/app/im.vector.riotx)
[<img src="resources/img/google-play-badge.png" alt="Get it on Google Play" height="60">](https://play.google.com/store/apps/details?id=im.vector.riotx)
[<img src="resources/img/f-droid-badge.png" alt="Get it on F-Droid" height="60">](https://f-droid.org/app/im.vector.riotx)
Nightly build: [![Buildkite](https://badge.buildkite.com/657d3db27364448d69d54f66c690f7788bc6aa80a7628e37f3.svg?branch=develop)](https://buildkite.com/matrix-dot-org/riotx-android/builds?branch=develop)

View File

@ -6,7 +6,7 @@ android {
compileSdkVersion 29
defaultConfig {
minSdkVersion 16
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"

View File

@ -23,7 +23,7 @@ android {
testOptions.unitTests.includeAndroidResources = true
defaultConfig {
minSdkVersion 16
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "0.0.1"

View File

@ -90,7 +90,7 @@ class KeyShareTests : InstrumentedTest {
} catch (failure: Throwable) {
}
val outgoingRequestBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
val outgoingRequestsBefore = aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
// Try to request
aliceSession2.cryptoService().requestRoomKeyForEvent(receivedEvent.root)
@ -100,10 +100,10 @@ class KeyShareTests : InstrumentedTest {
var outGoingRequestId: String? = null
mTestHelper.retryPeriodicallyWithLatch(waitLatch) {
aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
.filter { req ->
// filter out request that was known before
!outgoingRequestBefore.any { req.requestId == it.requestId }
!outgoingRequestsBefore.any { req.requestId == it.requestId }
}
.let {
val outgoing = it.firstOrNull { it.sessionId == eventMegolmSessionId }
@ -115,10 +115,10 @@ class KeyShareTests : InstrumentedTest {
Log.v("TEST", "=======> Outgoing requet Id is $outGoingRequestId")
val outgoingRequestAfter = aliceSession2.cryptoService().getOutgoingRoomKeyRequest()
val outgoingRequestAfter = aliceSession2.cryptoService().getOutgoingRoomKeyRequests()
// We should have a new request
Assert.assertTrue(outgoingRequestAfter.size > outgoingRequestBefore.size)
Assert.assertTrue(outgoingRequestAfter.size > outgoingRequestsBefore.size)
Assert.assertNotNull(outgoingRequestAfter.first { it.sessionId == eventMegolmSessionId })
// The first session should see an incoming request
@ -126,7 +126,7 @@ class KeyShareTests : InstrumentedTest {
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
// DEBUG LOGS
aliceSession.cryptoService().getIncomingRoomKeyRequest().let {
aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
Log.v("TEST", "Incoming request Session 1 (looking for $outGoingRequestId)")
Log.v("TEST", "=========================")
it.forEach { keyRequest ->
@ -135,7 +135,7 @@ class KeyShareTests : InstrumentedTest {
Log.v("TEST", "=========================")
}
val incoming = aliceSession.cryptoService().getIncomingRoomKeyRequest().firstOrNull { it.requestId == outGoingRequestId }
val incoming = aliceSession.cryptoService().getIncomingRoomKeyRequests().firstOrNull { it.requestId == outGoingRequestId }
incoming?.state == GossipingRequestState.REJECTED
}
}
@ -155,7 +155,7 @@ class KeyShareTests : InstrumentedTest {
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
aliceSession.cryptoService().getIncomingRoomKeyRequest().let {
aliceSession.cryptoService().getIncomingRoomKeyRequests().let {
Log.v("TEST", "Incoming request Session 1")
Log.v("TEST", "=========================")
it.forEach {
@ -171,7 +171,7 @@ class KeyShareTests : InstrumentedTest {
Thread.sleep(6_000)
mTestHelper.waitWithLatch { latch ->
mTestHelper.retryPeriodicallyWithLatch(latch) {
aliceSession2.cryptoService().getOutgoingRoomKeyRequest().let {
aliceSession2.cryptoService().getOutgoingRoomKeyRequests().let {
it.any { it.requestBody?.sessionId == eventMegolmSessionId && it.state == OutgoingGossipingRequestState.CANCELLED }
}
}

View File

@ -138,7 +138,9 @@ interface CryptoService {
fun removeSessionListener(listener: NewSessionListener)
fun getOutgoingRoomKeyRequest(): List<OutgoingRoomKeyRequest>
fun getIncomingRoomKeyRequest(): List<IncomingRoomKeyRequest>
fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest>
fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest>
fun getGossipingEventsTrail(): List<Event>
}

View File

@ -21,6 +21,9 @@ import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.util.JsonDict
/**
* Ref: https://github.com/matrix-org/matrix-doc/issues/1236
*/
@JsonClass(generateAdapter = true)
data class WidgetContent(
@Json(name = "creatorUserId") val creatorUserId: String? = null,

View File

@ -32,6 +32,9 @@ private val DEFINED_TYPES by lazy {
)
}
/**
* Ref: https://github.com/matrix-org/matrix-doc/issues/1236
*/
sealed class WidgetType(open val preferred: String, open val legacy: String = preferred) {
object Jitsi : WidgetType("m.jitsi", "jitsi")
object TradingView : WidgetType("m.tradingview")

View File

@ -1262,11 +1262,11 @@ internal class DefaultCryptoService @Inject constructor(
return "DefaultCryptoService of $userId ($deviceId)"
}
override fun getOutgoingRoomKeyRequest(): List<OutgoingRoomKeyRequest> {
override fun getOutgoingRoomKeyRequests(): List<OutgoingRoomKeyRequest> {
return cryptoStore.getOutgoingRoomKeyRequests()
}
override fun getIncomingRoomKeyRequest(): List<IncomingRoomKeyRequest> {
override fun getIncomingRoomKeyRequests(): List<IncomingRoomKeyRequest> {
return cryptoStore.getIncomingRoomKeyRequests()
}

View File

@ -897,9 +897,9 @@ internal class RealmCryptoStore @Inject constructor(
it.toOutgoingGossipingRequest() as? OutgoingRoomKeyRequest
}.firstOrNull {
it.requestBody?.algorithm == requestBody.algorithm
it.requestBody?.roomId == requestBody.roomId
it.requestBody?.senderKey == requestBody.senderKey
it.requestBody?.sessionId == requestBody.sessionId
&& it.requestBody?.roomId == requestBody.roomId
&& it.requestBody?.senderKey == requestBody.senderKey
&& it.requestBody?.sessionId == requestBody.sessionId
}
}
@ -1266,7 +1266,7 @@ internal class RealmCryptoStore @Inject constructor(
deviceInfoEntity.trustLevelEntity = it
}
} else {
locallyVerified?.let { trustEntity.locallyVerified = it }
locallyVerified?.let { trustEntity.locallyVerified = it }
trustEntity.crossSignedVerified = crossSignedVerified
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -17,8 +17,9 @@
#
echo "Configure RiotX Template..."
if [ -z ${ANDROID_STUDIO+x} ]; then ANDROID_STUDIO="/Applications/Android Studio.app/Contents"; fi
{
ln -s $(pwd)/RiotXFeature /Applications/Android\ Studio.app/Contents/plugins/android/lib/templates/other
ln -s $(pwd)/RiotXFeature "${ANDROID_STUDIO%/}/plugins/android/lib/templates/other"
} && {
echo "Please restart Android Studio."
}

View File

@ -107,9 +107,8 @@ android {
compileSdkVersion 29
defaultConfig {
applicationId "im.vector.riotx"
// Set to API 19 because motionLayout is min API 18.
// In the future we may consider using an alternative of MotionLayout to support API 16. But for security reason, maybe not.
minSdkVersion 19
// Set to API 21: see #405
minSdkVersion 21
targetSdkVersion 29
multiDexEnabled true

View File

@ -315,7 +315,7 @@ class RoomDetailFragment @Inject constructor(
is RoomDetailViewEvents.SendMessageResult -> renderSendMessageResult(it)
RoomDetailViewEvents.DisplayPromptForIntegrationManager -> displayPromptForIntegrationManager()
is RoomDetailViewEvents.OpenStickerPicker -> openStickerPicker(it)
is RoomDetailViewEvents.DisplayEnableIntegrationsWarning -> displayEnableIntegrationsWarning()
is RoomDetailViewEvents.DisplayEnableIntegrationsWarning -> displayDisabledIntegrationDialog()
is RoomDetailViewEvents.OpenIntegrationManager -> openIntegrationManager()
}.exhaustive
}
@ -354,17 +354,6 @@ class RoomDetailFragment @Inject constructor(
.show()
}
private fun displayEnableIntegrationsWarning() {
AlertDialog.Builder(requireContext())
.setTitle(R.string.integration_manager_not_enabled_title)
.setMessage(R.string.integration_manager_not_enabled_msg)
.setPositiveButton(R.string.open_settings) { _, _ ->
navigator.openSettings(requireContext(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_GENERAL)
}
.setNegativeButton(R.string.cancel, null)
.show()
}
private fun handleJoinedToAnotherRoom(action: RoomDetailViewEvents.JoinRoomCommandSuccess) {
updateComposerText("")
lockSendButton = false
@ -496,6 +485,17 @@ class RoomDetailFragment @Inject constructor(
}
}
private fun displayDisabledIntegrationDialog() {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.disabled_integration_dialog_title)
.setMessage(R.string.disabled_integration_dialog_content)
.setPositiveButton(R.string.settings) { _, _ ->
navigator.openSettings(requireActivity(), VectorSettingsActivity.EXTRA_DIRECT_ACCESS_GENERAL)
}
.setNegativeButton(R.string.cancel, null)
.show()
}
private fun renderRegularMode(text: String) {
autoCompleter.exitSpecialMode()
composerLayout.collapse()

View File

@ -21,17 +21,17 @@ import android.os.Parcelable
import android.view.View
import butterknife.OnClick
import com.airbnb.mvrx.args
import im.vector.matrix.android.internal.auth.registration.LocalizedFlowDataLoginTerms
import im.vector.riotx.R
import im.vector.riotx.core.extensions.cleanup
import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.toReducedUrl
import im.vector.riotx.core.utils.openUrlInExternalBrowser
import im.vector.riotx.core.utils.openUrlInChromeCustomTab
import im.vector.riotx.features.login.AbstractLoginFragment
import im.vector.riotx.features.login.LoginAction
import im.vector.riotx.features.login.LoginViewState
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_login_terms.*
import im.vector.matrix.android.internal.auth.registration.LocalizedFlowDataLoginTerms
import javax.inject.Inject
@Parcelize
@ -95,7 +95,7 @@ class LoginTermsFragment @Inject constructor(
localizedFlowDataLoginTerms.localizedUrl
?.takeIf { it.isNotBlank() }
?.let {
openUrlInExternalBrowser(requireContext(), it)
openUrlInChromeCustomTab(requireContext(), null, it)
}
}

View File

@ -59,7 +59,7 @@ class VectorSettingsActivity : VectorBaseActivity(),
if (isFirstCreation()) {
// display the fragment
when (intent.getIntExtra(EXTRA_DIRECT_ACCESS, EXTRA_DIRECT_ACCESS_ROOT)) {
EXTRA_DIRECT_ACCESS_GENERAL ->
EXTRA_DIRECT_ACCESS_GENERAL ->
replaceFragment(R.id.vector_settings_page, VectorSettingsGeneralFragment::class.java, null, FRAGMENT_TAG)
EXTRA_DIRECT_ACCESS_ADVANCED_SETTINGS ->
replaceFragment(R.id.vector_settings_page, VectorSettingsAdvancedSettingsFragment::class.java, null, FRAGMENT_TAG)

View File

@ -179,7 +179,7 @@ class GossipingEventsEpoxyController @Inject constructor(
}
private fun buildOutgoing(data: KeyRequestListViewState?) {
data?.outgoingRoomKeyRequest?.let { async ->
data?.outgoingRoomKeyRequests?.let { async ->
when (async) {
is Uninitialized,
is Loading -> {

View File

@ -107,7 +107,7 @@ class KeyRequestEpoxyController @Inject constructor(
}
private fun buildOutgoing(data: KeyRequestListViewState?) {
data?.outgoingRoomKeyRequest?.let { async ->
data?.outgoingRoomKeyRequests?.let { async ->
when (async) {
is Uninitialized,
is Loading -> {

View File

@ -36,7 +36,7 @@ import kotlinx.coroutines.launch
data class KeyRequestListViewState(
val incomingRequests: Async<List<IncomingRoomKeyRequest>> = Uninitialized,
val outgoingRoomKeyRequest: Async<List<OutgoingRoomKeyRequest>> = Uninitialized
val outgoingRoomKeyRequests: Async<List<OutgoingRoomKeyRequest>> = Uninitialized
) : MvRxState
class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState: KeyRequestListViewState,
@ -49,14 +49,14 @@ class KeyRequestListViewModel @AssistedInject constructor(@Assisted initialState
fun refresh() {
viewModelScope.launch {
session.cryptoService().getOutgoingRoomKeyRequest().let {
session.cryptoService().getOutgoingRoomKeyRequests().let {
setState {
copy(
outgoingRoomKeyRequest = Success(it)
outgoingRoomKeyRequests = Success(it)
)
}
}
session.cryptoService().getIncomingRoomKeyRequest().let {
session.cryptoService().getIncomingRoomKeyRequests().let {
setState {
copy(
incomingRequests = Success(it)

View File

@ -30,7 +30,7 @@ import im.vector.riotx.core.extensions.configureWith
import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.openUrlInExternalBrowser
import im.vector.riotx.core.utils.openUrlInChromeCustomTab
import kotlinx.android.synthetic.main.fragment_review_terms.*
import javax.inject.Inject
@ -106,6 +106,6 @@ class ReviewTermsFragment @Inject constructor(
}
override fun review(term: Term) {
openUrlInExternalBrowser(requireContext(), term.url)
openUrlInChromeCustomTab(requireContext(), null, term.url)
}
}

View File

@ -7,6 +7,6 @@
android:width="1.2dp"
android:color="#E7E7E7" />
<solid android:color="@color/white" />
<solid android:color="?riotx_background" />
</shape>

View File

@ -7,6 +7,6 @@
android:width="1.2dp"
android:color="@color/riotx_accent" />
<solid android:color="@color/white" />
<solid android:color="?riotx_background" />
</shape>

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="16dp"
android:viewportWidth="14"
android:viewportHeight="16">
<path
android:strokeWidth="1"
android:pathData="M13,11.1915V9.9086L8,5.6517C8,3.2856 8,1.8893 8,1.7728C8,1.2731 7.5522,0.6667 7,0.6667C6.4478,0.6667 6,1.2731 6,1.7728C6,1.9784 6,3.3376 6,5.6517L1,9.9086V11.1915L6,8.8416C6,10.3353 6,12.3168 6,13.0103L3.963,14.7439V15.3334L7,14.7508L10.037,15.3334V14.7439L8,13.0103C8,12.3168 8,10.3353 8,8.8416L13,11.1915Z"
android:strokeLineJoin="round"
android:fillColor="#00000000"
android:strokeColor="#2E2F32"
android:strokeLineCap="round"/>
</vector>

View File

@ -25,6 +25,7 @@
android:id="@+id/loginServerIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tint="?riotx_text_primary"
tools:src="@drawable/ic_logo_matrix_org" />
<TextView

View File

@ -63,6 +63,7 @@
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/ic_logo_matrix_org"
android:tint="?riotx_text_primary"
app:layout_constraintBottom_toTopOf="@+id/loginServerChoiceMatrixOrgText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -103,6 +104,7 @@
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/ic_logo_modular"
android:tint="?riotx_text_primary"
app:layout_constraintBottom_toTopOf="@+id/loginServerChoiceModularText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

View File

@ -26,7 +26,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:src="@drawable/ic_logo_modular" />
android:src="@drawable/ic_logo_modular"
android:tint="?riotx_text_primary" />
<TextView
android:id="@+id/loginServerUrlFormTitle"

View File

@ -23,6 +23,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:importantForAccessibility="no"
android:tint="?riotx_text_primary"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<merge 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -36,16 +37,26 @@
tools:layout_marginTop="10dp"
tools:visibility="visible" />
<TextView
<FrameLayout
android:id="@+id/syncStateNoNetworkAirplane"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/notification_accent_color"
android:gravity="center"
android:text="@string/no_connectivity_to_the_server_indicator_airplane"
android:textColor="@color/white"
android:visibility="gone"
tools:layout_marginTop="10dp"
tools:visibility="visible" />
tools:visibility="visible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawablePadding="4dp"
android:gravity="center"
android:text="@string/no_connectivity_to_the_server_indicator_airplane"
android:textColor="@color/white"
app:drawableStartCompat="@drawable/ic_airplane_16dp"
app:drawableTint="@color/white" />
</FrameLayout>
</merge>

View File

@ -862,6 +862,9 @@
<string name="settings_integration_allow">Allow integrations</string>
<string name="settings_integration_manager">Integration Manager</string>
<string name="disabled_integration_dialog_title">Integrations are disabled</string>
<string name="disabled_integration_dialog_content">"Enable 'Allow integrations' in Settings to do this."</string>
<string name="settings_user_interface">User interface</string>
<string name="settings_interface_language">Language</string>
<string name="settings_select_language">Choose language</string>
@ -1162,8 +1165,6 @@
<string name="room_widget_webview_read_protected_media">Read DRM protected Media</string>
<!-- Widget Integration Manager -->
<string name="integration_manager_not_enabled_title">Integrations are disabled</string>
<string name="integration_manager_not_enabled_msg">Enable integrations in settings to allow this action.</string>
<string name="widget_integration_unable_to_create">Unable to create widget.</string>
<string name="widget_integration_failed_to_send_request">Failed to send request.</string>

View File

@ -68,6 +68,26 @@
</im.vector.riotx.core.preference.VectorPreferenceCategory>
<im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_integrations">
<im.vector.riotx.core.preference.VectorPreference
android:focusable="false"
android:persistent="false"
android:summary="@string/settings_integrations_summary" />
<im.vector.riotx.core.preference.VectorSwitchPreference
android:key="SETTINGS_ALLOW_INTEGRATIONS_KEY"
android:persistent="false"
android:title="@string/settings_integration_allow" />
<im.vector.riotx.core.preference.VectorPreference
android:dependency="SETTINGS_ALLOW_INTEGRATIONS_KEY"
android:key="SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY"
android:persistent="false"
android:title="@string/settings_integration_manager" />
</im.vector.riotx.core.preference.VectorPreferenceCategory>
<im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_advanced">
<im.vector.riotx.core.preference.VectorPreference
@ -96,26 +116,6 @@
</im.vector.riotx.core.preference.VectorPreferenceCategory>
<im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/settings_integrations">
<im.vector.riotx.core.preference.VectorPreference
android:focusable="false"
android:persistent="false"
android:summary="@string/settings_integrations_summary" />
<im.vector.riotx.core.preference.VectorSwitchPreference
android:key="SETTINGS_ALLOW_INTEGRATIONS_KEY"
android:persistent="false"
android:title="@string/settings_integration_allow" />
<im.vector.riotx.core.preference.VectorPreference
android:dependency="SETTINGS_ALLOW_INTEGRATIONS_KEY"
android:key="SETTINGS_INTEGRATION_MANAGER_UI_URL_KEY"
android:persistent="false"
android:title="@string/settings_integration_manager" />
</im.vector.riotx.core.preference.VectorPreferenceCategory>
<im.vector.riotx.core.preference.VectorPreferenceCategory android:title="@string/action_sign_out">
<im.vector.riotx.core.preference.VectorPreference