Skip to content

Commit

Permalink
Merge branch 'release/0.10.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarty committed Dec 10, 2019
2 parents f9c0256 + d91ff87 commit 902a9aa
Show file tree
Hide file tree
Showing 137 changed files with 2,085 additions and 676 deletions.
17 changes: 17 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
Changes in RiotX 0.10.0 (2019-12-10)
===================================================

Features ✨:
- Breadcrumbs: switch from one room to another quickly (#571)

Improvements 🙌:
- Support entering a RiotWeb client URL instead of the homeserver URL during connection (#744)

Other changes:
- Add reason for all membership events (https://github.com/matrix-org/matrix-doc/pull/2367)

Bugfix 🐛:
- When automardown is ON, pills are sent as MD in body (#739)
- "ban" event are not rendered correctly (#716)
- Fix crash when rotating screen in Room timeline

Changes in RiotX 0.9.1 (2019-12-05)
===================================================

Expand Down
2 changes: 1 addition & 1 deletion docs/signup.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Client request the sign-up flows, once the homeserver is chosen by the user and
}
```

We get the flows with a 401, which also means the the registration is possible on this homeserver.
We get the flows with a 401, which also means that the registration is possible on this homeserver.

```json
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ class RxRoom(private val room: Room) {
room.loadRoomMembersIfNeeded(MatrixCallbackSingle(it)).toSingle(it)
}

fun joinRoom(viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
room.join(viaServers, MatrixCallbackSingle(it)).toSingle(it)
fun joinRoom(reason: String? = null,
viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
room.join(reason, viaServers, MatrixCallbackSingle(it)).toSingle(it)
}

fun liveEventReadReceipts(eventId: String): Observable<List<ReadReceipt>> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class RxSession(private val session: Session) {
return session.liveGroupSummaries().asObservable()
}

fun liveBreadcrumbs(): Observable<List<RoomSummary>> {
return session.liveBreadcrumbs().asObservable()
}

fun liveSyncState(): Observable<SyncState> {
return session.syncState().asObservable()
}
Expand Down Expand Up @@ -72,8 +76,10 @@ class RxSession(private val session: Session) {
session.searchUsersDirectory(search, limit, excludedUserIds, MatrixCallbackSingle(it)).toSingle(it)
}

fun joinRoom(roomId: String, viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
session.joinRoom(roomId, viaServers, MatrixCallbackSingle(it)).toSingle(it)
fun joinRoom(roomId: String,
reason: String? = null,
viaServers: List<String> = emptyList()): Single<Unit> = Single.create {
session.joinRoom(roomId, reason, viaServers, MatrixCallbackSingle(it)).toSingle(it)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
sealed class LoginFlowResult {
data class Success(
val loginFlowResponse: LoginFlowResponse,
val isLoginAndRegistrationSupported: Boolean
val isLoginAndRegistrationSupported: Boolean,
val homeServerUrl: String
) : LoginFlowResult()

object OutdatedHomeserver : LoginFlowResult()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ sealed class Failure(cause: Throwable? = null) : Throwable(cause = cause) {
data class ServerError(val error: MatrixError, val httpCode: Int) : Failure(RuntimeException(error.toString()))
object SuccessError : Failure(RuntimeException(RuntimeException("SuccessResult is false")))
// When server send an error, but it cannot be interpreted as a MatrixError
data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException(errorBody))
data class OtherServerError(val errorBody: String, val httpCode: Int) : Failure(RuntimeException("HTTP $httpCode: $errorBody"))

data class RegistrationFlowError(val registrationFlowResponse: RegistrationFlowResponse) : Failure(RuntimeException(registrationFlowResponse.toString()))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ interface ContentUploadStateTracker {

fun untrack(key: String, updateListener: UpdateListener)

fun clear()

interface UpdateListener {
fun onUpdate(state: State)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ interface RoomDirectoryService {
/**
* Get rooms from directory
*/
fun getPublicRooms(server: String?, publicRoomsParams: PublicRoomsParams, callback: MatrixCallback<PublicRoomsResponse>): Cancelable
fun getPublicRooms(server: String?,
publicRoomsParams: PublicRoomsParams,
callback: MatrixCallback<PublicRoomsResponse>): Cancelable

/**
* Join a room by id
*/
fun joinRoom(roomId: String, callback: MatrixCallback<Unit>): Cancelable
fun joinRoom(roomId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable

/**
* Fetches the overall metadata about protocols supported by the homeserver.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,17 @@ interface RoomService {
/**
* Create a room asynchronously
*/
fun createRoom(createRoomParams: CreateRoomParams, callback: MatrixCallback<String>): Cancelable
fun createRoom(createRoomParams: CreateRoomParams,
callback: MatrixCallback<String>): Cancelable

/**
* Join a room by id
* @param roomId the roomId of the room to join
* @param reason optional reason for joining the room
* @param viaServers the servers to attempt to join the room through. One of the servers must be participating in the room.
*/
fun joinRoom(roomId: String,
reason: String? = null,
viaServers: List<String> = emptyList(),
callback: MatrixCallback<Unit>): Cancelable

Expand All @@ -54,8 +57,21 @@ interface RoomService {
*/
fun liveRoomSummaries(): LiveData<List<RoomSummary>>

/**
* Get a live list of Breadcrumbs
* @return the [LiveData] of [RoomSummary]
*/
fun liveBreadcrumbs(): LiveData<List<RoomSummary>>

/**
* Inform the Matrix SDK that a room is displayed.
* The SDK will update the breadcrumbs in the user account data
*/
fun onRoomDisplayed(roomId: String): Cancelable

/**
* Mark all rooms as read
*/
fun markAllAsRead(roomIds: List<String>, callback: MatrixCallback<Unit>): Cancelable
fun markAllAsRead(roomIds: List<String>,
callback: MatrixCallback<Unit>): Cancelable
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,21 @@ interface MembershipService {
/**
* Invite a user in the room
*/
fun invite(userId: String, callback: MatrixCallback<Unit>): Cancelable
fun invite(userId: String,
reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable

/**
* Join the room, or accept an invitation.
*/

fun join(viaServers: List<String> = emptyList(), callback: MatrixCallback<Unit>): Cancelable
fun join(reason: String? = null,
viaServers: List<String> = emptyList(),
callback: MatrixCallback<Unit>): Cancelable

/**
* Leave the room, or reject an invitation.
*/
fun leave(callback: MatrixCallback<Unit>): Cancelable
fun leave(reason: String? = null,
callback: MatrixCallback<Unit>): Cancelable
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ import im.vector.matrix.android.api.session.events.model.UnsignedData
@JsonClass(generateAdapter = true)
data class RoomMember(
@Json(name = "membership") val membership: Membership,
@Json(name = "reason") val reason: String? = null,
@Json(name = "displayname") val displayName: String? = null,
@Json(name = "avatar_url") val avatarUrl: String? = null,
@Json(name = "is_direct") val isDirect: Boolean = false,
@Json(name = "third_party_invite") val thirdPartyInvite: Invite? = null,
@Json(name = "unsigned") val unsignedData: UnsignedData? = null
)
) {
val safeReason
get() = reason?.takeIf { it.isNotBlank() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ interface RelationService {

/**
* Sends a reaction (emoji) to the targetedEvent.
* It has no effect if the user has already added the same reaction to the event.
* @param targetEventId the id of the event being reacted
* @param reaction the reaction (preferably emoji)
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.auth.data.Versions
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
import im.vector.matrix.android.internal.auth.data.PasswordLoginParams
import im.vector.matrix.android.internal.auth.data.RiotConfig
import im.vector.matrix.android.internal.auth.login.ResetPasswordMailConfirmed
import im.vector.matrix.android.internal.auth.registration.*
import im.vector.matrix.android.internal.network.NetworkConstants
Expand All @@ -31,6 +32,12 @@ import retrofit2.http.*
*/
internal interface AuthAPI {

/**
* Get a Riot config file
*/
@GET("config.json")
fun getRiotConfig(): Call<RiotConfig>

/**
* Get the version information of the homeserver
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@

package im.vector.matrix.android.internal.auth

import android.net.Uri
import dagger.Lazy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.AuthenticationService
import im.vector.matrix.android.api.auth.data.*
import im.vector.matrix.android.api.auth.login.LoginWizard
import im.vector.matrix.android.api.auth.registration.RegistrationWizard
import im.vector.matrix.android.api.failure.Failure
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.SessionManager
import im.vector.matrix.android.internal.auth.data.LoginFlowResponse
import im.vector.matrix.android.internal.auth.data.RiotConfig
import im.vector.matrix.android.internal.auth.db.PendingSessionData
import im.vector.matrix.android.internal.auth.login.DefaultLoginWizard
import im.vector.matrix.android.internal.auth.registration.DefaultRegistrationWizard
Expand All @@ -40,6 +43,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import javax.inject.Inject
import javax.net.ssl.HttpsURLConnection

internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
private val okHttpClient: Lazy<OkHttpClient>,
Expand Down Expand Up @@ -84,7 +88,12 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
{
if (it is LoginFlowResult.Success) {
// The homeserver exists and up to date, keep the config
pendingSessionData = PendingSessionData(homeServerConnectionConfig)
// Homeserver url may have been changed, if it was a Riot url
val alteredHomeServerConnectionConfig = homeServerConnectionConfig.copy(
homeServerUri = Uri.parse(it.homeServerUrl)
)

pendingSessionData = PendingSessionData(alteredHomeServerConnectionConfig)
.also { data -> pendingSessionStore.savePendingSessionData(data) }
}
callback.onSuccess(it)
Expand All @@ -97,20 +106,71 @@ internal class DefaultAuthenticationService @Inject constructor(@Unauthenticated
.toCancelable()
}

private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig) = withContext(coroutineDispatchers.io) {
private suspend fun getLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
return withContext(coroutineDispatchers.io) {
val authAPI = buildAuthAPI(homeServerConnectionConfig)

// First check the homeserver version
runCatching {
executeRequest<Versions> {
apiCall = authAPI.versions()
}
}
.map { versions ->
// Ok, it seems that the homeserver url is valid
getLoginFlowResult(authAPI, versions, homeServerConnectionConfig.homeServerUri.toString())
}
.fold(
{
it
},
{
if (it is Failure.OtherServerError
&& it.httpCode == HttpsURLConnection.HTTP_NOT_FOUND /* 404 */) {
// It's maybe a Riot url?
getRiotLoginFlowInternal(homeServerConnectionConfig)
} else {
throw it
}
}
)
}
}

private suspend fun getRiotLoginFlowInternal(homeServerConnectionConfig: HomeServerConnectionConfig): LoginFlowResult {
val authAPI = buildAuthAPI(homeServerConnectionConfig)

// First check the homeserver version
val versions = executeRequest<Versions> {
apiCall = authAPI.versions()
// Ok, try to get the config.json file of a RiotWeb client
val riotConfig = executeRequest<RiotConfig> {
apiCall = authAPI.getRiotConfig()
}

if (versions.isSupportedBySdk()) {
if (riotConfig.defaultHomeServerUrl?.isNotBlank() == true) {
// Ok, good sign, we got a default hs url
val newHomeServerConnectionConfig = homeServerConnectionConfig.copy(
homeServerUri = Uri.parse(riotConfig.defaultHomeServerUrl)
)

val newAuthAPI = buildAuthAPI(newHomeServerConnectionConfig)

val versions = executeRequest<Versions> {
apiCall = newAuthAPI.versions()
}

return getLoginFlowResult(newAuthAPI, versions, riotConfig.defaultHomeServerUrl)
} else {
// Config exists, but there is no default homeserver url (ex: https://riot.im/app)
throw Failure.OtherServerError("", HttpsURLConnection.HTTP_NOT_FOUND /* 404 */)
}
}

private suspend fun getLoginFlowResult(authAPI: AuthAPI, versions: Versions, homeServerUrl: String): LoginFlowResult {
return if (versions.isSupportedBySdk()) {
// Get the login flow
val loginFlowResponse = executeRequest<LoginFlowResponse> {
apiCall = authAPI.getLoginFlows()
}
LoginFlowResult.Success(loginFlowResponse, versions.isLoginAndRegistrationSupportedBySdk())
LoginFlowResult.Success(loginFlowResponse, versions.isLoginAndRegistrationSupportedBySdk(), homeServerUrl)
} else {
// Not supported
LoginFlowResult.OutdatedHomeserver
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* 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.matrix.android.internal.auth.data

import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class RiotConfig(
// There are plenty of other elements in the file config.json of a RiotWeb client, but for the moment only one is interesting
// Ex: "brand", "branding", etc.
@Json(name = "default_hs_url")
val defaultHomeServerUrl: String?
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,14 @@ package im.vector.matrix.android.internal.crypto.store.db.query
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntity
import im.vector.matrix.android.internal.crypto.store.db.model.CryptoRoomEntityFields
import io.realm.Realm
import io.realm.kotlin.createObject
import io.realm.kotlin.where

/**
* Get or create a room
*/
internal fun CryptoRoomEntity.Companion.getOrCreate(realm: Realm, roomId: String): CryptoRoomEntity {
return getById(realm, roomId)
?: let {
realm.createObject(CryptoRoomEntity::class.java, roomId)
}
return getById(realm, roomId) ?: realm.createObject(roomId)
}

/**
Expand Down
Loading

0 comments on commit 902a9aa

Please sign in to comment.