diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt index 3ea61119ac..63fd6a34e1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt @@ -53,7 +53,6 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo @Inject internal lateinit var backgroundDetectionObserver: BackgroundDetectionObserver @Inject internal lateinit var olmManager: OlmManager @Inject internal lateinit var sessionManager: SessionManager - var currentSession: Session? = null init { Monarchy.init(context) @@ -63,12 +62,6 @@ class Matrix private constructor(context: Context, matrixConfiguration: MatrixCo } ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) userAgentHolder.setApplicationFlavor(matrixConfiguration.applicationFlavor) - authenticator.getLastActiveSession()?.also { - currentSession = it - it.open() - it.setFilter(FilterService.FilterPreset.RiotFilter) - it.startSync() - } } fun getUserAgent() = userAgentHolder.userAgent diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt index 633d262e8a..2ca6d0a22b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/auth/Authenticator.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.api.auth import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig +import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.util.Cancelable @@ -40,14 +41,24 @@ interface Authenticator { * Check if there is an active [Session]. * @return true if there is at least one active session. */ - fun hasActiveSessions(): Boolean + fun hasAuthenticatedSessions(): Boolean //TODO remove this method. Shouldn't be managed like that. /** * Get the last active [Session], if there is an active session. * @return the lastActive session if any, or null */ - fun getLastActiveSession(): Session? + fun getLastAuthenticatedSession(): Session? + + /** + * Get an authenticated session. You should at least call authenticate one time before. + * If you logout, this session will no longer be valid. + * + * @param sessionParams the sessionParams to open with. + * @return the associated session if any, or null + */ + fun getSession(sessionParams: SessionParams): Session? + } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt index d70052ef7f..7e0a67a4f2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/SessionManager.kt @@ -20,6 +20,7 @@ package im.vector.matrix.android.internal import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.di.MatrixComponent import im.vector.matrix.android.internal.di.MatrixScope import im.vector.matrix.android.internal.session.DaggerSessionComponent @@ -27,27 +28,18 @@ import im.vector.matrix.android.internal.session.SessionComponent import javax.inject.Inject @MatrixScope -internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent) { +internal class SessionManager @Inject constructor(private val matrixComponent: MatrixComponent, + private val sessionParamsStore: SessionParamsStore) { private val sessionComponents = HashMap() fun getSessionComponent(userId: String): SessionComponent? { - return sessionComponents[userId] + val sessionParams = sessionParamsStore.get(userId) ?: return null + return getOrCreateSessionComponent(sessionParams) } - fun createSession(sessionParams: SessionParams): Session { - val userId = sessionParams.credentials.userId - if (sessionComponents.containsKey(userId)) { - throw RuntimeException("You already have a session for the user $userId") - } - return DaggerSessionComponent - .factory() - .create(matrixComponent, sessionParams) - .also { - sessionComponents[userId] = it - }.let { - it.session() - } + fun getOrCreateSession(sessionParams: SessionParams): Session { + return getOrCreateSessionComponent(sessionParams).session() } fun releaseSession(userId: String) { @@ -59,5 +51,17 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M } } + private fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent { + val userId = sessionParams.credentials.userId + if (sessionComponents.containsKey(userId)) { + return sessionComponents[userId]!! + } + return DaggerSessionComponent + .factory() + .create(matrixComponent, sessionParams) + .also { + sessionComponents[sessionParams.credentials.userId] = it + } + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt index 71e7d37199..472d653dee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt @@ -49,6 +49,8 @@ internal abstract class AuthModule { } } + + @Binds abstract fun bindSessionParamsStore(sessionParamsStore: RealmSessionParamsStore): SessionParamsStore diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt index c19ec00568..3eb8f113d3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/DefaultAuthenticator.kt @@ -28,32 +28,41 @@ import im.vector.matrix.android.internal.SessionManager import im.vector.matrix.android.internal.auth.data.PasswordLoginParams import im.vector.matrix.android.internal.auth.data.ThreePidMedium import im.vector.matrix.android.internal.di.MatrixScope +import im.vector.matrix.android.internal.di.Unauthenticated +import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.util.CancelableCoroutine import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import okhttp3.OkHttpClient import retrofit2.Retrofit import javax.inject.Inject -internal class DefaultAuthenticator @Inject constructor(private val retrofitBuilder: Retrofit.Builder, +internal class DefaultAuthenticator @Inject constructor(@Unauthenticated + private val okHttpClient: OkHttpClient, + private val retrofitFactory: RetrofitFactory, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val sessionParamsStore: SessionParamsStore, private val sessionManager: SessionManager ) : Authenticator { - override fun hasActiveSessions(): Boolean { - return sessionParamsStore.get() != null + override fun hasAuthenticatedSessions(): Boolean { + return sessionParamsStore.getLast() != null } - override fun getLastActiveSession(): Session? { - val sessionParams = sessionParamsStore.get() + override fun getLastAuthenticatedSession(): Session? { + val sessionParams = sessionParamsStore.getLast() return sessionParams?.let { - sessionManager.createSession(it) + sessionManager.getOrCreateSession(it) } } + override fun getSession(sessionParams: SessionParams): Session? { + return sessionManager.getOrCreateSession(sessionParams) + } + override fun authenticate(homeServerConnectionConfig: HomeServerConnectionConfig, login: String, password: String, @@ -84,13 +93,13 @@ internal class DefaultAuthenticator @Inject constructor(private val retrofitBuil sessionParamsStore.save(sessionParams) sessionParams }.map { - sessionManager.createSession(it) + sessionManager.getOrCreateSession(it) } } private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI { - val retrofit = retrofitBuilder.baseUrl(homeServerConnectionConfig.homeServerUri.toString()).build() + val retrofit = retrofitFactory.create(okHttpClient, homeServerConnectionConfig.homeServerUri.toString()) return retrofit.create(AuthAPI::class.java) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt index df8b71e48d..e7729d3728 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/SessionParamsStore.kt @@ -21,9 +21,15 @@ import im.vector.matrix.android.api.auth.data.SessionParams internal interface SessionParamsStore { - fun get(): SessionParams? + fun get(userId: String): SessionParams? + + fun getLast(): SessionParams? + + fun getAll(): List fun save(sessionParams: SessionParams): Try - fun delete(): Try + fun delete(userId: String): Try + + fun deleteAll(): Try } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt index 4a202e3ad4..1bb27d20fc 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/RealmSessionParamsStore.kt @@ -20,15 +20,48 @@ import arrow.core.Try import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.di.AuthDatabase -import im.vector.matrix.android.internal.di.MatrixScope import io.realm.Realm import io.realm.RealmConfiguration import javax.inject.Inject internal class RealmSessionParamsStore @Inject constructor(private val mapper: SessionParamsMapper, - @AuthDatabase private val realmConfiguration: RealmConfiguration + @AuthDatabase + private val realmConfiguration: RealmConfiguration ) : SessionParamsStore { + override fun getLast(): SessionParams? { + val realm = Realm.getInstance(realmConfiguration) + val sessionParams = realm + .where(SessionParamsEntity::class.java) + .findAll() + .map { mapper.map(it) } + .lastOrNull() + realm.close() + return sessionParams + } + + override fun get(userId: String): SessionParams? { + val realm = Realm.getInstance(realmConfiguration) + val sessionParams = realm + .where(SessionParamsEntity::class.java) + .equalTo(SessionParamsEntityFields.USER_ID, userId) + .findAll() + .map { mapper.map(it) } + .firstOrNull() + realm.close() + return sessionParams + } + + override fun getAll(): List { + val realm = Realm.getInstance(realmConfiguration) + val sessionParams = realm + .where(SessionParamsEntity::class.java) + .findAll() + .mapNotNull { mapper.map(it) } + realm.close() + return sessionParams + } + override fun save(sessionParams: SessionParams): Try { return Try { val entity = mapper.map(sessionParams) @@ -43,18 +76,20 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S } } - override fun get(): SessionParams? { - val realm = Realm.getInstance(realmConfiguration) - val sessionParams = realm - .where(SessionParamsEntity::class.java) - .findAll() - .map { mapper.map(it) } - .lastOrNull() - realm.close() - return sessionParams + override fun delete(userId: String): Try { + return Try { + val realm = Realm.getInstance(realmConfiguration) + realm.executeTransaction { + it.where(SessionParamsEntity::class.java) + .equalTo(SessionParamsEntityFields.USER_ID, userId) + .findAll() + .deleteAllFromRealm() + } + realm.close() + } } - override fun delete(): Try { + override fun deleteAll(): Try { return Try { val realm = Realm.getInstance(realmConfiguration) realm.executeTransaction { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt index 7ebfbcc46d..e6569d28ea 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsEntity.kt @@ -17,8 +17,10 @@ package im.vector.matrix.android.internal.auth.db import io.realm.RealmObject +import io.realm.annotations.PrimaryKey internal open class SessionParamsEntity( + @PrimaryKey var userId: String = "", var credentialsJson: String = "", var homeServerConnectionConfigJson: String = "" ) : RealmObject() \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt index a8738cb41c..64303ea03d 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/db/SessionParamsMapper.kt @@ -49,7 +49,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) { if (credentialsJson == null || homeServerConnectionConfigJson == null) { return null } - return SessionParamsEntity(credentialsJson, homeServerConnectionConfigJson) + return SessionParamsEntity(sessionParams.credentials.userId, credentialsJson, homeServerConnectionConfigJson) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt new file mode 100644 index 0000000000..e89d8b8ea6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/AuthQualifiers.kt @@ -0,0 +1,29 @@ +/* + * + * * 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.di + +import javax.inject.Qualifier + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class Authenticated + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class Unauthenticated \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt index 30471d5766..ad03bbca4e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixComponent.kt @@ -23,9 +23,11 @@ import dagger.BindsInstance import dagger.Component import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.auth.Authenticator +import im.vector.matrix.android.internal.SessionManager import im.vector.matrix.android.internal.auth.AuthModule import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.network.NetworkConnectivityChecker +import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers @@ -42,8 +44,7 @@ internal interface MatrixComponent { fun moshi(): Moshi - fun retrofitBuilder(): Retrofit.Builder - + @Unauthenticated fun okHttpClient(): OkHttpClient fun authenticator(): Authenticator @@ -62,6 +63,8 @@ internal interface MatrixComponent { fun backgroundDetectionObserver(): BackgroundDetectionObserver + fun sessionManager(): SessionManager + fun inject(matrix: Matrix) @Component.Factory diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt index b6a3242d53..2f9e8c6939 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt @@ -66,9 +66,9 @@ internal object NetworkModule { @MatrixScope @Provides @JvmStatic + @Unauthenticated fun providesOkHttpClient(stethoInterceptor: StethoInterceptor, userAgentInterceptor: UserAgentInterceptor, - accessTokenInterceptor: AccessTokenInterceptor, httpLoggingInterceptor: HttpLoggingInterceptor, curlLoggingInterceptor: CurlLoggingInterceptor, okReplayInterceptor: OkReplayInterceptor): OkHttpClient { @@ -78,7 +78,6 @@ internal object NetworkModule { .writeTimeout(30, TimeUnit.SECONDS) .addNetworkInterceptor(stethoInterceptor) .addInterceptor(userAgentInterceptor) - .addInterceptor(accessTokenInterceptor) .addInterceptor(httpLoggingInterceptor) .apply { if (BuildConfig.LOG_PRIVATE_DATA) { @@ -94,15 +93,4 @@ internal object NetworkModule { fun providesMoshi(): Moshi { return MoshiProvider.providesMoshi() } - - @Provides - @JvmStatic - fun providesRetrofitBuilder(okHttpClient: OkHttpClient, - moshi: Moshi): Retrofit.Builder { - return Retrofit.Builder() - .client(okHttpClient) - .addConverterFactory(UnitConverterFactory) - .addConverterFactory(MoshiConverterFactory.create(moshi)) - } - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt index 5c2f9d8cb3..0f723d41e8 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/AccessTokenInterceptor.kt @@ -16,22 +16,19 @@ package im.vector.matrix.android.internal.network -import im.vector.matrix.android.internal.auth.SessionParamsStore -import im.vector.matrix.android.internal.di.MatrixScope +import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.internal.session.SessionScope import okhttp3.Interceptor import okhttp3.Response import javax.inject.Inject -internal class AccessTokenInterceptor @Inject constructor(private val sessionParamsStore: SessionParamsStore) : Interceptor { +internal class AccessTokenInterceptor @Inject constructor(private val credentials: Credentials) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() val newRequestBuilder = request.newBuilder() // Add the access token to all requests if it is set - val sessionParams = sessionParamsStore.get() - sessionParams?.let { - newRequestBuilder.addHeader(HttpHeaders.Authorization, "Bearer " + it.credentials.accessToken) - } + newRequestBuilder.addHeader(HttpHeaders.Authorization, "Bearer " + credentials.accessToken) request = newRequestBuilder.build() return chain.proceed(request) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt new file mode 100644 index 0000000000..1338c36e77 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitFactory.kt @@ -0,0 +1,39 @@ +/* + * + * * 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.network + +import com.squareup.moshi.Moshi +import okhttp3.Interceptor +import okhttp3.OkHttpClient +import retrofit2.Retrofit +import retrofit2.converter.moshi.MoshiConverterFactory +import javax.inject.Inject + +class RetrofitFactory @Inject constructor(private val moshi: Moshi) { + + fun create(okHttpClient: OkHttpClient, baseUrl: String): Retrofit { + return Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .addConverterFactory(UnitConverterFactory) + .addConverterFactory(MoshiConverterFactory.create(moshi)) + .build() + } + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 3ae65b909f..cff657ae03 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -28,13 +28,18 @@ import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.model.SessionRealmModule +import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.di.Unauthenticated +import im.vector.matrix.android.internal.network.AccessTokenInterceptor +import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater import im.vector.matrix.android.internal.session.room.prune.EventsPruner import im.vector.matrix.android.internal.session.user.UserEntityUpdater import im.vector.matrix.android.internal.util.md5 import io.realm.RealmConfiguration +import okhttp3.OkHttpClient import retrofit2.Retrofit import java.io.File @@ -86,13 +91,26 @@ internal abstract class SessionModule { @JvmStatic @Provides @SessionScope - fun providesRetrofit(sessionParams: SessionParams, retrofitBuilder: Retrofit.Builder): Retrofit { - return retrofitBuilder - .baseUrl(sessionParams.homeServerConnectionConfig.homeServerUri.toString()) + @Authenticated + fun providesOkHttpClient(@Unauthenticated okHttpClient: OkHttpClient, + accessTokenInterceptor: AccessTokenInterceptor): OkHttpClient { + return okHttpClient.newBuilder() + .addInterceptor(accessTokenInterceptor) .build() } + + @JvmStatic + @Provides + @SessionScope + fun providesRetrofit(@Authenticated okHttpClient: OkHttpClient, + sessionParams: SessionParams, + retrofitFactory: RetrofitFactory): Retrofit { + return retrofitFactory + .create(okHttpClient, sessionParams.homeServerConnectionConfig.homeServerUri.toString()) + } } + @Binds abstract fun bindSession(session: DefaultSession): Session diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt index 217c06ba4a..dac85cb24f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/content/FileUploader.kt @@ -20,7 +20,9 @@ import arrow.core.Try import arrow.core.Try.Companion.raise import com.squareup.moshi.Moshi import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.di.MoshiProvider +import im.vector.matrix.android.internal.di.Unauthenticated import im.vector.matrix.android.internal.network.ProgressRequestBody import im.vector.matrix.android.internal.session.SessionScope import okhttp3.* @@ -29,7 +31,8 @@ import java.io.IOException import javax.inject.Inject -internal class FileUploader @Inject constructor(private val okHttpClient: OkHttpClient, +internal class FileUploader @Inject constructor(@Authenticated + private val okHttpClient: OkHttpClient, private val sessionParams: SessionParams, private val moshi: Moshi) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt index 56bf71f596..209e5f3831 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt @@ -31,6 +31,7 @@ import im.vector.matrix.android.internal.database.query.where import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery +import timber.log.Timber import javax.inject.Inject internal class SenderRoomMemberExtractor @Inject constructor(private val roomId: String) { @@ -46,9 +47,8 @@ internal class SenderRoomMemberExtractor @Inject constructor(private val roomId: event.stateIndex <= 0 -> baseQuery(chunkEntity.events, sender, unlinked).next(from = event.stateIndex)?.prevContent else -> baseQuery(chunkEntity.events, sender, unlinked).prev(since = event.stateIndex)?.content } - val fallbackContent = content - ?: baseQuery(roomEntity.untimelinedStateEvents, sender, unlinked).prev(since = event.stateIndex)?.content + ?: baseQuery(roomEntity.untimelinedStateEvents, sender, unlinked).prev(since = event.stateIndex)?.content return ContentMapper.map(fallbackContent).toModel() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt index 2b240ff933..f24e7b46c1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/DefaultSignOutService.kt @@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.signout import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.signout.SignOutService +import im.vector.matrix.android.internal.SessionManager import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt index b627ebd61e..baf671916e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/signout/SignOutTask.kt @@ -17,6 +17,9 @@ package im.vector.matrix.android.internal.session.signout import arrow.core.Try +import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.internal.SessionManager import im.vector.matrix.android.internal.auth.SessionParamsStore import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.SessionScope @@ -25,14 +28,20 @@ import javax.inject.Inject internal interface SignOutTask : Task -internal class DefaultSignOutTask @Inject constructor(private val signOutAPI: SignOutAPI, +internal class DefaultSignOutTask @Inject constructor(private val credentials: Credentials, + private val signOutAPI: SignOutAPI, + private val sessionManager: SessionManager, private val sessionParamsStore: SessionParamsStore) : SignOutTask { override suspend fun execute(params: Unit): Try { return executeRequest { apiCall = signOutAPI.signOut() }.flatMap { - sessionParamsStore.delete() + sessionParamsStore.delete(credentials.userId) + }.flatMap { + Try { + sessionManager.releaseSession(credentials.userId) + } } } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt index 6acd82c9de..35f0775bce 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncTask.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.sync import arrow.core.Try import arrow.core.failure import arrow.core.recoverWith +import im.vector.matrix.android.api.auth.data.Credentials import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.internal.auth.SessionParamsStore @@ -36,6 +37,7 @@ internal interface SyncTask : Task { } internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, + private val credentials: Credentials, private val filterRepository: FilterRepository, private val syncResponseHandler: SyncResponseHandler, private val sessionParamsStore: SessionParamsStore @@ -58,7 +60,7 @@ internal class DefaultSyncTask @Inject constructor(private val syncAPI: SyncAPI, // Intercept 401 if (throwable is Failure.ServerError && throwable.error.code == MatrixError.UNKNOWN_TOKEN) { - sessionParamsStore.delete() + sessionParamsStore.delete(credentials.userId) } // Transmit the throwable diff --git a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt index b2ce3c8a78..52267e9986 100644 --- a/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt +++ b/vector/src/main/java/im/vector/riotredesign/VectorApplication.kt @@ -32,51 +32,55 @@ import com.github.piasy.biv.loader.glide.GlideImageLoader import com.jakewharton.threetenabp.AndroidThreeTen import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.MatrixConfiguration -import im.vector.riotredesign.core.di.DaggerVectorComponent -import im.vector.riotredesign.core.di.HasInjector -import im.vector.riotredesign.core.di.VectorComponent +import im.vector.riotredesign.core.di.* import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.riotredesign.features.rageshake.VectorFileLogger import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler import timber.log.Timber import javax.inject.Inject +import kotlin.system.measureTimeMillis -class VectorApplication : Application(), HasInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider { +class VectorApplication : Application(), HasVectorInjector, MatrixConfiguration.Provider, androidx.work.Configuration.Provider { lateinit var appContext: Context //font thread handler @Inject lateinit var vectorConfiguration: VectorConfiguration @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider + @Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler + @Inject lateinit var activeSessionHolder: ActiveSessionHolder lateinit var vectorComponent: VectorComponent private var fontThreadHandler: Handler? = null override fun onCreate() { - super.onCreate() - appContext = this - vectorComponent = DaggerVectorComponent.factory().create(this) - vectorComponent.inject(this) - VectorUncaughtExceptionHandler.activate(this) - // Log - VectorFileLogger.init(this) - Timber.plant(Timber.DebugTree(), VectorFileLogger) - if (BuildConfig.DEBUG) { - Stetho.initializeWithDefaults(this) + val time = measureTimeMillis { + super.onCreate() + appContext = this + vectorComponent = DaggerVectorComponent.factory().create(this) + vectorComponent.inject(this) + vectorUncaughtExceptionHandler.activate(this) + // Log + VectorFileLogger.init(this) + Timber.plant(Timber.DebugTree(), VectorFileLogger) + if (BuildConfig.DEBUG) { + Stetho.initializeWithDefaults(this) + } + AndroidThreeTen.init(this) + BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) + EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() + EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() + registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks()) + val fontRequest = FontRequest( + "com.google.android.gms.fonts", + "com.google.android.gms", + "Noto Color Emoji Compat", + R.array.com_google_android_gms_fonts_certs + ) + FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) + vectorConfiguration.initConfiguration() } - AndroidThreeTen.init(this) - BigImageViewer.initialize(GlideImageLoader.with(applicationContext)) - EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() - EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler() - registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks()) - val fontRequest = FontRequest( - "com.google.android.gms.fonts", - "com.google.android.gms", - "Noto Color Emoji Compat", - R.array.com_google_android_gms_fonts_certs - ) - FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) - vectorConfiguration.initConfiguration() + Timber.v("On create took $time ms") } override fun providesMatrixConfiguration() = MatrixConfiguration(BuildConfig.FLAVOR_DESCRIPTION) diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ActiveSessionHolder.kt new file mode 100644 index 0000000000..176021264e --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ActiveSessionHolder.kt @@ -0,0 +1,57 @@ +/* + * + * * 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.riotredesign.core.di + +import im.vector.matrix.android.api.auth.Authenticator +import im.vector.matrix.android.api.auth.data.SessionParams +import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.sync.FilterService +import java.lang.IllegalStateException +import java.util.concurrent.atomic.AtomicReference +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ActiveSessionHolder @Inject constructor(private val authenticator: Authenticator) { + + private var activeSession: AtomicReference = AtomicReference() + + fun setActiveSession(session: Session){ + activeSession.set(session) + } + + fun clearActiveSession(){ + activeSession.set(null) + } + + fun hasActiveSession(): Boolean { + return activeSession.get() != null + } + + fun getActiveSession(): Session { + return activeSession.get() ?: throw IllegalStateException("You should authenticate before using this") + } + + //TODO: Stop sync ? + fun switchToSession(sessionParams: SessionParams) { + val newActiveSession = authenticator.getSession(sessionParams) + activeSession.set(newActiveSession) + } + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt b/vector/src/main/java/im/vector/riotredesign/core/di/HasScreenInjector.kt similarity index 90% rename from vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt rename to vector/src/main/java/im/vector/riotredesign/core/di/HasScreenInjector.kt index ca2e27ab68..746c0c186f 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/HasInjector.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/HasScreenInjector.kt @@ -16,8 +16,8 @@ package im.vector.riotredesign.core.di -interface HasInjector { +interface HasScreenInjector { - fun injector(): C + fun injector(): ScreenComponent } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/HasVectorInjector.kt b/vector/src/main/java/im/vector/riotredesign/core/di/HasVectorInjector.kt new file mode 100644 index 0000000000..e8301c736a --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/di/HasVectorInjector.kt @@ -0,0 +1,25 @@ +/* + * + * * 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.riotredesign.core.di + +interface HasVectorInjector { + + fun injector(): VectorComponent + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt index 901940748a..47b92a9f2a 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/ScreenComponent.kt @@ -31,10 +31,7 @@ import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupSt import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupStep2Fragment import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupStep3Fragment import im.vector.riotredesign.features.crypto.verification.SASVerificationIncomingFragment -import im.vector.riotredesign.features.home.HomeActivity -import im.vector.riotredesign.features.home.HomeDetailFragment -import im.vector.riotredesign.features.home.HomeDrawerFragment -import im.vector.riotredesign.features.home.HomeModule +import im.vector.riotredesign.features.home.* import im.vector.riotredesign.features.home.group.GroupListFragment import im.vector.riotredesign.features.home.room.detail.RoomDetailFragment import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageActionsBottomSheet @@ -42,7 +39,13 @@ import im.vector.riotredesign.features.home.room.detail.timeline.action.MessageM import im.vector.riotredesign.features.home.room.detail.timeline.action.QuickReactionFragment import im.vector.riotredesign.features.home.room.detail.timeline.action.ViewReactionBottomSheet import im.vector.riotredesign.features.home.room.list.RoomListFragment +import im.vector.riotredesign.features.invite.VectorInviteView import im.vector.riotredesign.features.login.LoginActivity +import im.vector.riotredesign.features.media.ImageMediaViewerActivity +import im.vector.riotredesign.features.media.VideoMediaViewerActivity +import im.vector.riotredesign.features.rageshake.BugReportActivity +import im.vector.riotredesign.features.rageshake.BugReporter +import im.vector.riotredesign.features.rageshake.RageShake import im.vector.riotredesign.features.reactions.EmojiReactionPickerActivity import im.vector.riotredesign.features.roomdirectory.PublicRoomsFragment import im.vector.riotredesign.features.roomdirectory.RoomDirectoryActivity @@ -60,6 +63,10 @@ interface ScreenComponent { fun viewModelFactory(): ViewModelProvider.Factory + fun bugReporter(): BugReporter + + fun rageShake(): RageShake + fun inject(activity: HomeActivity) fun inject(roomDetailFragment: RoomDetailFragment) @@ -118,6 +125,15 @@ interface ScreenComponent { fun inject(roomDirectoryActivity: RoomDirectoryActivity) + fun inject(bugReportActivity: BugReportActivity) + + fun inject(imageMediaViewerActivity: ImageMediaViewerActivity) + + fun inject(vectorInviteView: VectorInviteView) + + fun inject(videoMediaViewerActivity: VideoMediaViewerActivity) + + @Component.Factory interface Factory { fun create(vectorComponent: VectorComponent, diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt index 3e21cbac54..54321160f0 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorComponent.kt @@ -28,17 +28,23 @@ import im.vector.riotredesign.VectorApplication import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.crypto.keysrequest.KeyRequestHandler import im.vector.riotredesign.features.crypto.verification.IncomingVerificationRequestHandler +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.HomeNavigator import im.vector.riotredesign.features.home.HomeRoomListObservableStore import im.vector.riotredesign.features.home.group.SelectedGroupStore import im.vector.riotredesign.features.navigation.Navigator import im.vector.riotredesign.features.notifications.NotificationDrawerManager +import im.vector.riotredesign.features.rageshake.BugReporter +import im.vector.riotredesign.features.rageshake.RageShake +import im.vector.riotredesign.features.rageshake.VectorUncaughtExceptionHandler import javax.inject.Singleton @Component(modules = [VectorModule::class]) @Singleton interface VectorComponent { + fun inject(vectorApplication: VectorApplication) + fun matrix(): Matrix fun currentSession(): Session @@ -51,6 +57,8 @@ interface VectorComponent { fun vectorConfiguration(): VectorConfiguration + fun activeSessionHolder(): ActiveSessionHolder + fun emojiCompatFontProvider(): EmojiCompatFontProvider fun navigator(): Navigator @@ -65,10 +73,12 @@ interface VectorComponent { fun incomingKeyRequestHandler(): KeyRequestHandler - fun inject(vectorApplication: VectorApplication) - fun authenticator(): Authenticator + fun bugReporter(): BugReporter + + fun vectorUncaughtExceptionHandler(): VectorUncaughtExceptionHandler + @Component.Factory interface Factory { fun create(@BindsInstance context: Context): VectorComponent diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt index ec8db244d5..b1c6c7e743 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/VectorModule.kt @@ -55,9 +55,9 @@ abstract class VectorModule { @Provides @JvmStatic - fun providesCurrentSession(matrix: Matrix): Session { + fun providesCurrentSession(activeSessionHolder: ActiveSessionHolder): Session { //TODO: handle session injection better - return matrix.currentSession!! + return activeSessionHolder.getActiveSession() } @Provides diff --git a/vector/src/main/java/im/vector/riotredesign/core/extensions/Session.kt b/vector/src/main/java/im/vector/riotredesign/core/extensions/Session.kt new file mode 100644 index 0000000000..03766cf062 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/extensions/Session.kt @@ -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.riotredesign.core.extensions + +import im.vector.matrix.android.api.session.Session +import im.vector.matrix.android.api.session.sync.FilterService + +fun Session.openAndStartSync(){ + open() + setFilter(FilterService.FilterPreset.RiotFilter) + startSync() +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt index 7296b7d5d2..440a4eca69 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseActivity.kt @@ -32,40 +32,32 @@ import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.view.isVisible import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProviders import butterknife.BindView import butterknife.ButterKnife import butterknife.Unbinder import com.airbnb.mvrx.BaseMvRxActivity -import com.airbnb.mvrx.MvRxState import com.bumptech.glide.util.Util import com.google.android.material.snackbar.Snackbar import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.R -import im.vector.riotredesign.core.di.DaggerScreenComponent -import im.vector.riotredesign.core.di.HasInjector -import im.vector.riotredesign.core.di.ScreenComponent -import im.vector.riotredesign.core.di.VectorComponent +import im.vector.riotredesign.core.di.* import im.vector.riotredesign.core.utils.toast import im.vector.riotredesign.features.configuration.VectorConfiguration import im.vector.riotredesign.features.rageshake.BugReportActivity import im.vector.riotredesign.features.rageshake.BugReporter import im.vector.riotredesign.features.rageshake.RageShake -import im.vector.riotredesign.features.roomdirectory.PublicRoomsViewState -import im.vector.riotredesign.features.roomdirectory.RoomDirectoryViewModel import im.vector.riotredesign.features.themes.ActivityOtherThemes import im.vector.riotredesign.features.themes.ThemeUtils import im.vector.riotredesign.receivers.DebugReceiver import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable import timber.log.Timber -import javax.inject.Provider -import kotlin.reflect.KClass +import kotlin.system.measureTimeMillis -abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector { +abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector { /* ========================================================================================== * UI * ========================================================================================== */ @@ -81,6 +73,8 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector() - private var rageShake: RageShake? = null private lateinit var screenComponent: ScreenComponent override fun attachBaseContext(base: Context) { @@ -125,9 +118,14 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector).injector() + return (application as HasVectorInjector).injector() } /** diff --git a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt index f1fa25f7b7..d0f8214eab 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/platform/VectorBaseFragment.kt @@ -35,14 +35,14 @@ import com.airbnb.mvrx.BaseMvRxFragment import com.airbnb.mvrx.MvRx import com.bumptech.glide.util.Util.assertMainThread import im.vector.riotredesign.core.di.DaggerScreenComponent -import im.vector.riotredesign.core.di.HasInjector +import im.vector.riotredesign.core.di.HasScreenInjector import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.features.navigation.Navigator import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable import timber.log.Timber -abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed, HasInjector { +abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed, HasScreenInjector { // Butterknife unbinder private var mUnBinder: Unbinder? = null diff --git a/vector/src/main/java/im/vector/riotredesign/features/MainActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/MainActivity.kt index a87753e67b..be5a7d5135 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/MainActivity.kt @@ -22,7 +22,9 @@ import android.os.Bundle import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.auth.Authenticator +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.di.ScreenComponent +import im.vector.riotredesign.core.extensions.openAndStartSync import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.features.home.HomeActivity import im.vector.riotredesign.features.login.LoginActivity @@ -49,6 +51,7 @@ class MainActivity : VectorBaseActivity() { @Inject lateinit var matrix: Matrix @Inject lateinit var authenticator: Authenticator + @Inject lateinit var sessionHolder: ActiveSessionHolder override fun injectWith(injector: ScreenComponent) { injector.inject(this) @@ -58,30 +61,31 @@ class MainActivity : VectorBaseActivity() { super.onCreate(savedInstanceState) val clearCache = intent.getBooleanExtra(EXTRA_CLEAR_CACHE, false) val clearCredentials = intent.getBooleanExtra(EXTRA_CLEAR_CREDENTIALS, false) - val session = matrix.currentSession - if (session == null) { - start() - } else { - // Handle some wanted cleanup - when { - clearCredentials -> session.signOut(object : MatrixCallback { - override fun onSuccess(data: Unit) { - Timber.w("SIGN_OUT: success, start app") - start() - } - }) - clearCache -> session.clearCache(object : MatrixCallback { - override fun onSuccess(data: Unit) { - start() - } - }) - else -> start() - } + // Handle some wanted cleanup + when { + clearCredentials -> sessionHolder.getActiveSession().signOut(object : MatrixCallback { + override fun onSuccess(data: Unit) { + Timber.w("SIGN_OUT: success, start app") + sessionHolder.clearActiveSession() + start() + } + }) + clearCache -> sessionHolder.getActiveSession().clearCache(object : MatrixCallback { + override fun onSuccess(data: Unit) { + start() + } + }) + else -> start() } } private fun start() { - val intent = if (authenticator.hasActiveSessions()) { + val intent = if (authenticator.hasAuthenticatedSessions()) { + if (!sessionHolder.hasActiveSession()) { + val lastAuthenticatedSession = authenticator.getLastAuthenticatedSession()!! + sessionHolder.setActiveSession(lastAuthenticatedSession) + lastAuthenticatedSession.openAndStartSync() + } HomeActivity.newIntent(this) } else { LoginActivity.newIntent(this) diff --git a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt index 576947253e..17cbde66c5 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/autocomplete/user/AutocompleteUserItem.kt @@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_autocomplete_user) abstract class AutocompleteUserItem : VectorEpoxyModel() { + @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute var name: String? = null @EpoxyAttribute var userId: String = "" @EpoxyAttribute var avatarUrl: String? = null @@ -37,7 +38,7 @@ abstract class AutocompleteUserItem : VectorEpoxyModel { //Add a notification for every incoming request - val session = Matrix.getInstance(context).currentSession!! + val session = activeSessionHolder.getActiveSession() val name = session.getUser(tx.otherUserId)?.displayName ?: tx.otherUserId diff --git a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt index b8549995fa..6acbad5512 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/crypto/verification/SASVerificationIncomingFragment.kt @@ -27,6 +27,7 @@ import im.vector.riotredesign.R import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.features.home.AvatarRenderer +import javax.inject.Inject class SASVerificationIncomingFragment : VectorBaseFragment() { @@ -48,6 +49,7 @@ class SASVerificationIncomingFragment : VectorBaseFragment() { override fun getLayoutResId() = R.layout.fragment_sas_verification_incoming_request + @Inject lateinit var avatarRenderer: AvatarRenderer private lateinit var viewModel: SasVerificationViewModel override fun injectWith(injector: ScreenComponent) { @@ -66,10 +68,10 @@ class SASVerificationIncomingFragment : VectorBaseFragment() { otherDeviceTextView.text = viewModel.otherDeviceId viewModel.otherUser?.let { - AvatarRenderer.render(it, avatarImageView) + avatarRenderer.render(it, avatarImageView) } ?: run { // Fallback to what we know - AvatarRenderer.render(null, viewModel.otherUserId ?: "", viewModel.otherUserId, avatarImageView) + avatarRenderer.render(null, viewModel.otherUserId ?: "", viewModel.otherUserId, avatarImageView) } viewModel.transactionState.observe(this, Observer { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt index 451a49c2f2..a9943a6e29 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/AvatarRenderer.kt @@ -26,29 +26,32 @@ import com.amulyakhare.textdrawable.TextDrawable import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.DrawableImageViewTarget import com.bumptech.glide.request.target.Target -import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.MatrixPatterns import im.vector.matrix.android.api.session.content.ContentUrlResolver import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.glide.GlideRequest import im.vector.riotredesign.core.glide.GlideRequests +import javax.inject.Inject /** * This helper centralise ways to retrieve avatar into ImageView or even generic Target */ -object AvatarRenderer { +class AvatarRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder){ - private const val THUMBNAIL_SIZE = 250 + companion object { + private const val THUMBNAIL_SIZE = 250 - private val AVATAR_COLOR_LIST = listOf( - R.color.riotx_avatar_fill_1, - R.color.riotx_avatar_fill_2, - R.color.riotx_avatar_fill_3 - ) + private val AVATAR_COLOR_LIST = listOf( + R.color.riotx_avatar_fill_1, + R.color.riotx_avatar_fill_2, + R.color.riotx_avatar_fill_3 + ) + } @UiThread fun render(roomSummary: RoomSummary, imageView: ImageView) { @@ -78,7 +81,7 @@ object AvatarRenderer { name } val placeholder = getPlaceholderDrawable(context, identifier, displayName) - buildGlideRequest(context, glideRequest, avatarUrl) + buildGlideRequest(glideRequest, avatarUrl) .placeholder(placeholder) .into(target) } @@ -115,8 +118,8 @@ object AvatarRenderer { // return AVATAR_COLOR_LIST[colorIndex.toInt()] // } - private fun buildGlideRequest(context: Context, glideRequest: GlideRequests, avatarUrl: String?): GlideRequest { - val resolvedUrl = Matrix.getInstance(context).currentSession!!.contentUrlResolver() + private fun buildGlideRequest(glideRequest: GlideRequests, avatarUrl: String?): GlideRequest { + val resolvedUrl = activeSessionHolder.getActiveSession().contentUrlResolver() .resolveThumbnail(avatarUrl, THUMBNAIL_SIZE, THUMBNAIL_SIZE, ContentUrlResolver.ThumbnailMethod.SCALE) return glideRequest diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt index d0e05f871c..ca5c6c5249 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt @@ -31,6 +31,7 @@ import androidx.lifecycle.ViewModelProviders import com.airbnb.mvrx.viewModel import im.vector.matrix.android.api.Matrix import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.extensions.hideKeyboard import im.vector.riotredesign.core.extensions.observeEvent @@ -57,8 +58,10 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { private val homeActivityViewModel: HomeActivityViewModel by viewModel() private lateinit var navigationViewModel: HomeNavigationViewModel + @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var homeActivityViewModelFactory: HomeActivityViewModel.Factory @Inject lateinit var homeNavigator: HomeNavigator + @Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler // TODO Move this elsewhere @Inject lateinit var incomingVerificationRequestHandler: IncomingVerificationRequestHandler // TODO Move this elsewhere @@ -119,14 +122,14 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { override fun onResume() { super.onResume() - if (VectorUncaughtExceptionHandler.didAppCrash(this)) { - VectorUncaughtExceptionHandler.clearAppCrashStatus(this) + if (vectorUncaughtExceptionHandler.didAppCrash(this)) { + vectorUncaughtExceptionHandler.clearAppCrashStatus(this) AlertDialog.Builder(this) .setMessage(R.string.send_bug_report_app_crashed) .setCancelable(false) - .setPositiveButton(R.string.yes) { _, _ -> BugReporter.openBugReportScreen(this) } - .setNegativeButton(R.string.no) { _, _ -> BugReporter.deleteCrashFile(this) } + .setPositiveButton(R.string.yes) { _, _ -> bugReporter.openBugReportScreen(this) } + .setNegativeButton(R.string.no) { _, _ -> bugReporter.deleteCrashFile(this) } .show() } } @@ -140,7 +143,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.sliding_menu_sign_out -> { - SignOutUiWorker(this).perform(Matrix.getInstance(this).currentSession!!) + SignOutUiWorker(this).perform(activeSessionHolder.getActiveSession()) return true } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt index 23eb943dfc..4ea3df5dc4 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDetailFragment.kt @@ -70,6 +70,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate { @Inject lateinit var session: Session @Inject lateinit var homeDetailViewModelFactory: HomeDetailViewModel.Factory + @Inject lateinit var avatarRenderer: AvatarRenderer override fun getLayoutResId(): Int { return R.layout.fragment_home_detail @@ -138,7 +139,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate { parentActivity.configure(groupToolbar) } groupToolbar.title = "" - AvatarRenderer.render( + avatarRenderer.render( params.groupAvatar, params.groupId, params.groupName, diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt index 28b8cf20fc..378b6a1b00 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt @@ -37,6 +37,7 @@ class HomeDrawerFragment : VectorBaseFragment() { } @Inject lateinit var session: Session + @Inject lateinit var avatarRenderer: AvatarRenderer override fun getLayoutResId() = R.layout.fragment_home_drawer @@ -53,7 +54,7 @@ class HomeDrawerFragment : VectorBaseFragment() { session.observeUser(session.sessionParams.credentials.userId).observeK(this) { user -> if (user != null) { - AvatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView) + avatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView) homeDrawerUsernameView.text = user.displayName homeDrawerUserIdView.text = user.userId } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt index e82afb5409..02904be3be 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryController.kt @@ -18,9 +18,10 @@ package im.vector.riotredesign.features.home.group import com.airbnb.epoxy.TypedEpoxyController import im.vector.matrix.android.api.session.group.model.GroupSummary +import im.vector.riotredesign.features.home.AvatarRenderer import javax.inject.Inject -class GroupSummaryController @Inject constructor(): TypedEpoxyController() { +class GroupSummaryController @Inject constructor(private val avatarRenderer: AvatarRenderer): TypedEpoxyController() { var callback: Callback? = null @@ -35,6 +36,7 @@ class GroupSummaryController @Inject constructor(): TypedEpoxyController val isSelected = groupSummary.groupId == selected?.groupId groupSummaryItem { + avatarRenderer(avatarRenderer) id(groupSummary.groupId) groupId(groupSummary.groupId) groupName(groupSummary.displayName) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt index 167498493e..1abb59bd2a 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt @@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_group) abstract class GroupSummaryItem : VectorEpoxyModel() { + @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute lateinit var groupName: CharSequence @EpoxyAttribute lateinit var groupId: String @EpoxyAttribute var avatarUrl: String? = null @@ -40,7 +41,7 @@ abstract class GroupSummaryItem : VectorEpoxyModel() { holder.rootView.setOnClickListener { listener?.invoke() } holder.groupNameView.text = groupName holder.rootView.isChecked = selected - AvatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView) + avatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView) } class Holder : VectorEpoxyHolder() { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index f2eeaa99d6..11c4a30ddb 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -174,6 +174,7 @@ class RoomDetailFragment : private val textComposerViewModel: TextComposerViewModel by fragmentViewModel() @Inject lateinit var session: Session + @Inject lateinit var avatarRenderer: AvatarRenderer @Inject lateinit var timelineEventController: TimelineEventController @Inject lateinit var commandAutocompletePolicy: CommandAutocompletePolicy @Inject lateinit var autocompleteCommandPresenter: AutocompleteCommandPresenter @@ -183,6 +184,7 @@ class RoomDetailFragment : @Inject lateinit var textComposerViewModelFactory: TextComposerViewModel.Factory private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback + override fun getLayoutResId() = R.layout.fragment_room_detail private lateinit var actionViewModel: ActionsHandler @@ -223,7 +225,7 @@ class RoomDetailFragment : commandAutocompletePolicy.enabled = true val uid = session.sessionParams.credentials.userId val meMember = session.getRoom(roomId)?.getRoomMember(uid) - AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) + avatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) composerLayout.collapse() } SendMode.EDIT, @@ -270,7 +272,7 @@ class RoomDetailFragment : composerLayout.composerRelatedMessageActionIcon.setImageDrawable(ContextCompat.getDrawable(requireContext(), R.drawable.ic_reply)) } - AvatarRenderer.render(event.senderAvatar, event.root.sender + avatarRenderer.render(event.senderAvatar, event.root.sender ?: "", event.senderName, composerLayout.composerRelatedMessageAvatar) composerLayout.composerEditText.setSelection(composerLayout.composerEditText.text.length) @@ -378,7 +380,7 @@ class RoomDetailFragment : // Add the span val user = session.getUser(item.userId) - val span = PillImageSpan(glideRequests, requireContext(), item.userId, user) + val span = PillImageSpan(glideRequests, avatarRenderer, requireContext(), item.userId, user) span.bind(composerLayout.composerEditText) editable.setSpan(span, startIndex, startIndex + displayName.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) @@ -487,7 +489,7 @@ class RoomDetailFragment : val uid = session.sessionParams.credentials.userId val meMember = session.getRoom(state.roomId)?.getRoomMember(uid) - AvatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) + avatarRenderer.render(meMember?.avatarUrl, uid, meMember?.displayName, composerLayout.composerAvatarImageView) } else if (summary?.membership == Membership.INVITE && inviter != null) { inviteView.visibility = View.VISIBLE @@ -500,7 +502,7 @@ class RoomDetailFragment : private fun renderRoomSummary(state: RoomDetailViewState) { state.asyncRoomSummary()?.let { roomToolbarTitleView.text = it.displayName - AvatarRenderer.render(it, roomToolbarAvatarImageView) + avatarRenderer.render(it, roomToolbarAvatarImageView) if (it.topic.isNotEmpty()) { roomToolbarSubtitleView.visibility = View.VISIBLE roomToolbarSubtitleView.text = it.topic diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index d4505b4008..d46272322f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -25,25 +25,14 @@ import androidx.recyclerview.widget.RecyclerView import com.airbnb.epoxy.EpoxyController import com.airbnb.epoxy.EpoxyModel import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary -import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent -import im.vector.matrix.android.api.session.room.model.message.MessageContent -import im.vector.matrix.android.api.session.room.model.message.MessageFileContent -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent -import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent +import im.vector.matrix.android.api.session.room.model.message.* import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.core.epoxy.LoadingItem_ import im.vector.riotredesign.core.extensions.localDateTime +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineEventDiffUtilCallback -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider -import im.vector.riotredesign.features.home.room.detail.timeline.helper.canBeMerged -import im.vector.riotredesign.features.home.room.detail.timeline.helper.nextDisplayableEvent -import im.vector.riotredesign.features.home.room.detail.timeline.helper.prevSameTypeEvents -import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar -import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName +import im.vector.riotredesign.features.home.room.detail.timeline.helper.* import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem import im.vector.riotredesign.features.home.room.detail.timeline.item.DaySeparatorItem_ import im.vector.riotredesign.features.home.room.detail.timeline.item.MergedHeaderItem @@ -56,7 +45,9 @@ import javax.inject.Inject class TimelineEventController @Inject constructor(private val dateFormatter: TimelineDateFormatter, private val timelineItemFactory: TimelineItemFactory, private val timelineMediaSizeProvider: TimelineMediaSizeProvider, - @TimelineEventControllerHandler private val backgroundHandler: Handler + private val avatarRenderer: AvatarRenderer, + @TimelineEventControllerHandler + private val backgroundHandler: Handler ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { interface Callback : ReactionPillCallback, AvatarCallback, BaseCallback { @@ -188,8 +179,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim // Should be build if not cached or if cached but contains mergedHeader or formattedDay // We then are sure we always have items up to date. if (modelCache[position] == null - || modelCache[position]?.mergedHeaderModel != null - || modelCache[position]?.formattedDayModel != null) { + || modelCache[position]?.mergedHeaderModel != null + || modelCache[position]?.formattedDayModel != null) { modelCache[position] = buildItemModels(position, currentSnapshot) } } @@ -261,7 +252,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim // => handle case where paginating from mergeable events and we get more val previousCollapseStateKey = mergedEventIds.intersect(mergeItemCollapseStates.keys).firstOrNull() val initialCollapseState = mergeItemCollapseStates.remove(previousCollapseStateKey) - ?: true + ?: true val isCollapsed = mergeItemCollapseStates.getOrPut(event.localId) { initialCollapseState } if (isCollapsed) { collapsedEventIds.addAll(mergedEventIds) @@ -269,7 +260,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim collapsedEventIds.removeAll(mergedEventIds) } val mergeId = mergedEventIds.joinToString(separator = "_") { it } - MergedHeaderItem(isCollapsed, mergeId, mergedData) { + MergedHeaderItem(isCollapsed, mergeId, mergedData, avatarRenderer) { mergeItemCollapseStates[event.localId] = it requestModelBuild() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt index d32e83a61d..ef440c9ec6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/action/MessageActionsBottomSheet.kt @@ -46,6 +46,7 @@ import javax.inject.Inject class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() { @Inject lateinit var messageActionViewModelFactory: MessageActionsViewModel.Factory + @Inject lateinit var avatarRenderer: AvatarRenderer private val viewModel: MessageActionsViewModel by fragmentViewModel(MessageActionsViewModel::class) private lateinit var actionHandlerModel: ActionsHandler @@ -127,7 +128,7 @@ class MessageActionsBottomSheet : VectorBaseBottomSheetDialogFragment() { senderNameTextView.text = it.senderName messageBodyTextView.text = it.messageBody messageTimestampText.text = it.ts - AvatarRenderer.render(it.senderAvatarPath, it.userId, it.senderName, senderAvatarImageView) + avatarRenderer.render(it.senderAvatarPath, it.userId, it.senderName, senderAvatarImageView) } else { bottom_sheet_message_preview.isVisible = false } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt index 46f5b7eb16..fb6c398b96 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptedItemFactory.kt @@ -26,6 +26,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.R import im.vector.riotredesign.core.epoxy.VectorEpoxyModel import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData @@ -33,7 +34,8 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem import javax.inject.Inject // This class handles timeline event who haven't been successfully decrypted -class EncryptedItemFactory @Inject constructor(private val stringProvider: StringProvider) { +class EncryptedItemFactory @Inject constructor(private val stringProvider: StringProvider, + private val avatarRenderer: AvatarRenderer) { fun create(timelineEvent: TimelineEvent): VectorEpoxyModel<*>? { return when { @@ -59,6 +61,7 @@ class EncryptedItemFactory @Inject constructor(private val stringProvider: Strin showInformation = false ) return NoticeItem_() + .avatarRenderer(avatarRenderer) .noticeText(spannableStr) .informationData(informationData) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt index cd8f34d58e..835dd46b20 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/EncryptionItemFactory.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.android.internal.crypto.model.event.EncryptionEventContent import im.vector.riotredesign.R import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderName import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData @@ -30,7 +31,8 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ import javax.inject.Inject -class EncryptionItemFactory @Inject constructor(private val stringProvider: StringProvider) { +class EncryptionItemFactory @Inject constructor(private val stringProvider: StringProvider, + private val avatarRenderer: AvatarRenderer) { fun create(event: TimelineEvent): NoticeItem? { val text = buildNoticeText(event.root, event.senderName) ?: return null @@ -43,6 +45,7 @@ class EncryptionItemFactory @Inject constructor(private val stringProvider: Stri showInformation = false ) return NoticeItem_() + .avatarRenderer(avatarRenderer) .noticeText(text) .informationData(informationData) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt index 9ddd4d34f4..9774a85594 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/MessageItemFactory.kt @@ -29,14 +29,7 @@ import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.RelationType import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary -import im.vector.matrix.android.api.session.room.model.message.MessageAudioContent -import im.vector.matrix.android.api.session.room.model.message.MessageContent -import im.vector.matrix.android.api.session.room.model.message.MessageEmoteContent -import im.vector.matrix.android.api.session.room.model.message.MessageFileContent -import im.vector.matrix.android.api.session.room.model.message.MessageImageContent -import im.vector.matrix.android.api.session.room.model.message.MessageNoticeContent -import im.vector.matrix.android.api.session.room.model.message.MessageTextContent -import im.vector.matrix.android.api.session.room.model.message.MessageVideoContent +import im.vector.matrix.android.api.session.room.model.message.* import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.EmojiCompatFontProvider @@ -47,23 +40,13 @@ import im.vector.riotredesign.core.linkify.VectorLinkify import im.vector.riotredesign.core.resources.ColorProvider import im.vector.riotredesign.core.resources.StringProvider import im.vector.riotredesign.core.utils.DebouncedClickListener +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.getColorFromUserId import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController +import im.vector.riotredesign.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider -import im.vector.riotredesign.features.home.room.detail.timeline.item.BlankItem_ -import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem -import im.vector.riotredesign.features.home.room.detail.timeline.item.DefaultItem_ -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageFileItem -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageFileItem_ -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageImageVideoItem_ -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_ -import im.vector.riotredesign.features.home.room.detail.timeline.item.ReactionInfoData -import im.vector.riotredesign.features.home.room.detail.timeline.item.RedactedMessageItem -import im.vector.riotredesign.features.home.room.detail.timeline.item.RedactedMessageItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.* import im.vector.riotredesign.features.html.EventHtmlRenderer import im.vector.riotredesign.features.media.ImageContentRenderer import im.vector.riotredesign.features.media.VideoContentRenderer @@ -71,12 +54,15 @@ import me.gujun.android.span.span import javax.inject.Inject class MessageItemFactory @Inject constructor( + private val avatarRenderer: AvatarRenderer, private val colorProvider: ColorProvider, private val timelineMediaSizeProvider: TimelineMediaSizeProvider, private val timelineDateFormatter: TimelineDateFormatter, private val htmlRenderer: EventHtmlRenderer, private val stringProvider: StringProvider, - private val emojiCompatFontProvider: EmojiCompatFontProvider) { + private val emojiCompatFontProvider: EmojiCompatFontProvider, + private val imageContentRenderer: ImageContentRenderer, + private val contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder) { fun create(event: TimelineEvent, nextEvent: TimelineEvent?, @@ -89,33 +75,33 @@ class MessageItemFactory @Inject constructor( val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() val isNextMessageReceivedMoreThanOneHourAgo = nextDate?.isBefore(date.minusMinutes(60)) - ?: false + ?: false val showInformation = addDaySeparator - || event.senderAvatar != nextEvent?.senderAvatar - || event.senderName != nextEvent?.senderName - || nextEvent?.root?.getClearType() != EventType.MESSAGE - || isNextMessageReceivedMoreThanOneHourAgo + || event.senderAvatar != nextEvent?.senderAvatar + || event.senderName != nextEvent?.senderName + || nextEvent?.root?.getClearType() != EventType.MESSAGE + || isNextMessageReceivedMoreThanOneHourAgo val time = timelineDateFormatter.formatMessageHour(date) val avatarUrl = event.senderAvatar val memberName = event.senderName ?: event.root.sender ?: "" val formattedMemberName = span(memberName) { textColor = colorProvider.getColor(getColorFromUserId(event.root.sender - ?: "")) + ?: "")) } val hasBeenEdited = event.annotations?.editSummary != null val informationData = MessageInformationData(eventId = eventId, - senderId = event.root.sender ?: "", - sendState = event.sendState, - time = time, - avatarUrl = avatarUrl, - memberName = formattedMemberName, - showInformation = showInformation, - orderedReactionList = event.annotations?.reactionsSummary?.map { - ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty()) - }, - hasBeenEdited = hasBeenEdited + senderId = event.root.sender ?: "", + sendState = event.sendState, + time = time, + avatarUrl = avatarUrl, + memberName = formattedMemberName, + showInformation = showInformation, + orderedReactionList = event.annotations?.reactionsSummary?.map { + ReactionInfoData(it.key, it.count, it.addedByMe, it.localEchoEvents.isEmpty()) + }, + hasBeenEdited = hasBeenEdited ) if (event.root.unsignedData?.redactedEvent != null) { @@ -125,9 +111,9 @@ class MessageItemFactory @Inject constructor( val messageContent: MessageContent = event.annotations?.editSummary?.aggregatedContent?.toModel() - ?: event.root.getClearContent().toModel() - ?: //Malformed content, we should echo something on screen - return DefaultItem_().text(stringProvider.getString(R.string.malformed_message)) + ?: event.root.getClearContent().toModel() + ?: //Malformed content, we should echo something on screen + return DefaultItem_().text(stringProvider.getString(R.string.malformed_message)) if (messageContent.relatesTo?.type == RelationType.REPLACE) { // ignore replace event, the targeted id is already edited @@ -137,16 +123,16 @@ class MessageItemFactory @Inject constructor( // val ev = all.toModel() return when (messageContent) { is MessageEmoteContent -> buildEmoteMessageItem(messageContent, - informationData, - hasBeenEdited, - event.annotations?.editSummary, - callback) + informationData, + hasBeenEdited, + event.annotations?.editSummary, + callback) is MessageTextContent -> buildTextMessageItem(event.sendState, - messageContent, - informationData, - hasBeenEdited, - event.annotations?.editSummary, - callback + messageContent, + informationData, + hasBeenEdited, + event.annotations?.editSummary, + callback ) is MessageImageContent -> buildImageMessageItem(messageContent, informationData, callback) is MessageNoticeContent -> buildNoticeMessageItem(messageContent, informationData, callback) @@ -161,6 +147,7 @@ class MessageItemFactory @Inject constructor( informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() + .avatarRenderer(avatarRenderer) .informationData(informationData) .avatarCallback(callback) .filename(messageContent.body) @@ -177,7 +164,7 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -185,6 +172,7 @@ class MessageItemFactory @Inject constructor( informationData: MessageInformationData, callback: TimelineEventController.Callback?): MessageFileItem? { return MessageFileItem_() + .avatarRenderer(avatarRenderer) .informationData(informationData) .avatarCallback(callback) .filename(messageContent.body) @@ -197,7 +185,7 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } .clickListener( DebouncedClickListener(View.OnClickListener { _ -> @@ -226,6 +214,9 @@ class MessageItemFactory @Inject constructor( rotation = messageContent.info?.rotation ) return MessageImageVideoItem_() + .avatarRenderer(avatarRenderer) + .imageContentRenderer(imageContentRenderer) + .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder) .playable(messageContent.info?.mimeType == "image/gif") .informationData(informationData) .avatarCallback(callback) @@ -242,7 +233,7 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -267,6 +258,9 @@ class MessageItemFactory @Inject constructor( ) return MessageImageVideoItem_() + .imageContentRenderer(imageContentRenderer) + .contentUploadStateTrackerBinder(contentUploadStateTrackerBinder) + .avatarRenderer(avatarRenderer) .playable(true) .informationData(informationData) .avatarCallback(callback) @@ -280,7 +274,7 @@ class MessageItemFactory @Inject constructor( .clickListener { view -> callback?.onVideoMessageClicked(messageContent, videoData, view) } .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -306,6 +300,7 @@ class MessageItemFactory @Inject constructor( message(linkifiedBody) } } + .avatarRenderer(avatarRenderer) .informationData(informationData) .avatarCallback(callback) .reactionPillCallback(callback) @@ -317,7 +312,7 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -349,9 +344,9 @@ class MessageItemFactory @Inject constructor( //nop } }, - editStart, - editEnd, - Spanned.SPAN_INCLUSIVE_EXCLUSIVE) + editStart, + editEnd, + Spanned.SPAN_INCLUSIVE_EXCLUSIVE) return spannable } @@ -368,6 +363,7 @@ class MessageItemFactory @Inject constructor( linkifyBody(formattedBody, callback) } return MessageTextItem_() + .avatarRenderer(avatarRenderer) .message(message) .informationData(informationData) .avatarCallback(callback) @@ -383,7 +379,7 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } @@ -406,6 +402,7 @@ class MessageItemFactory @Inject constructor( message(message) } } + .avatarRenderer(avatarRenderer) .informationData(informationData) .avatarCallback(callback) .reactionPillCallback(callback) @@ -416,13 +413,14 @@ class MessageItemFactory @Inject constructor( })) .longClickListener { view -> return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false + ?: false } } private fun buildRedactedItem(informationData: MessageInformationData, callback: TimelineEventController.Callback?): RedactedMessageItem? { return RedactedMessageItem_() + .avatarRenderer(avatarRenderer) .informationData(informationData) .avatarCallback(callback) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt index 00d8070f34..e1349feff4 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/NoticeItemFactory.kt @@ -17,6 +17,7 @@ package im.vector.riotredesign.features.home.room.detail.timeline.factory import im.vector.matrix.android.api.session.room.timeline.TimelineEvent +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar @@ -26,7 +27,8 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ import javax.inject.Inject -class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter) { +class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEventFormatter, + private val avatarRenderer: AvatarRenderer) { fun create(event: TimelineEvent, callback: TimelineEventController.Callback?): NoticeItem? { @@ -41,6 +43,7 @@ class NoticeItemFactory @Inject constructor(private val eventFormatter: NoticeEv ) return NoticeItem_() + .avatarRenderer(avatarRenderer) .noticeText(formattedText) .informationData(informationData) .baseCallback(callback) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt index 93b567b147..e72dc9dc52 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/ContentUploadStateTrackerBinder.kt @@ -25,10 +25,12 @@ import android.widget.TextView import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.session.content.ContentUploadStateTracker import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.features.media.ImageContentRenderer import java.io.File +import javax.inject.Inject -object ContentUploadStateTrackerBinder { +class ContentUploadStateTrackerBinder @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) { private val updateListeners = mutableMapOf() @@ -36,7 +38,7 @@ object ContentUploadStateTrackerBinder { mediaData: ImageContentRenderer.Data, progressLayout: ViewGroup) { - Matrix.getInstance(progressLayout.context).currentSession?.also { session -> + activeSessionHolder.getActiveSession().also { session -> val uploadStateTracker = session.contentUploadProgressTracker() val updateListener = ContentMediaProgressUpdater(progressLayout, mediaData) updateListeners[eventId] = updateListener @@ -44,8 +46,8 @@ object ContentUploadStateTrackerBinder { } } - fun unbind(eventId: String, progressLayout: ViewGroup) { - Matrix.getInstance(progressLayout.context).currentSession?.also { session -> + fun unbind(eventId: String) { + activeSessionHolder.getActiveSession().also { session -> val uploadStateTracker = session.contentUploadProgressTracker() updateListeners[eventId]?.also { uploadStateTracker.untrack(eventId, it) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt index 8a32396801..ffa6299701 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/AbsMessageItem.kt @@ -40,6 +40,8 @@ abstract class AbsMessageItem : BaseEventItem() { abstract val informationData: MessageInformationData + abstract val avatarRenderer: AvatarRenderer + @EpoxyAttribute var longClickListener: View.OnLongClickListener? = null @@ -96,7 +98,7 @@ abstract class AbsMessageItem : BaseEventItem() { holder.timeView.visibility = View.VISIBLE holder.timeView.text = informationData.time holder.memberNameView.text = informationData.memberName - AvatarRenderer.render(informationData.avatarUrl, informationData.senderId, informationData.memberName?.toString(), holder.avatarImageView) + avatarRenderer.render(informationData.avatarUrl, informationData.senderId, informationData.memberName?.toString(), holder.avatarImageView) holder.view.setOnClickListener(cellClickListener) holder.view.setOnLongClickListener(longClickListener) holder.avatarImageView.setOnLongClickListener(longClickListener) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MergedHeaderItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MergedHeaderItem.kt index 6cdd7e15e1..bd1a08b267 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MergedHeaderItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MergedHeaderItem.kt @@ -30,6 +30,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer data class MergedHeaderItem(private val isCollapsed: Boolean, private val mergeId: String, private val mergeData: List, + private val avatarRenderer: AvatarRenderer, private val onCollapsedStateChanged: (Boolean) -> Unit ) : BaseEventItem() { @@ -63,7 +64,7 @@ data class MergedHeaderItem(private val isCollapsed: Boolean, val data = distinctMergeData.getOrNull(index) if (data != null && view is ImageView) { view.visibility = View.VISIBLE - AvatarRenderer.render(data.avatarUrl, data.userId, data.memberName, view) + avatarRenderer.render(data.avatarUrl, data.userId, data.memberName, view) } else { view.visibility = View.GONE } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageFileItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageFileItem.kt index 66055984cc..9ec8d08bc1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageFileItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageFileItem.kt @@ -25,6 +25,7 @@ import androidx.annotation.DrawableRes import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R +import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_timeline_event_base) abstract class MessageFileItem : AbsMessageItem() { @@ -37,6 +38,8 @@ abstract class MessageFileItem : AbsMessageItem() { @EpoxyAttribute override lateinit var informationData: MessageInformationData @EpoxyAttribute + override lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute var clickListener: View.OnClickListener? = null override fun bind(holder: Holder) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageVideoItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageVideoItem.kt index 25eb8bca19..33bf57326b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageVideoItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/MessageImageVideoItem.kt @@ -22,6 +22,7 @@ import android.widget.ImageView import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.helper.ContentUploadStateTrackerBinder import im.vector.riotredesign.features.media.ImageContentRenderer @@ -33,14 +34,20 @@ abstract class MessageImageVideoItem : AbsMessageItem() { @EpoxyAttribute var message: CharSequence? = null @EpoxyAttribute + override lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute override lateinit var informationData: MessageInformationData val mvmtMethod = BetterLinkMovementMethod.newInstance().also { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt index d190875f20..b5d5acc853 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/NoticeItem.kt @@ -28,6 +28,9 @@ import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventCo @EpoxyModelClass(layout = R.layout.item_timeline_event_base_noinfo) abstract class NoticeItem : BaseEventItem() { + @EpoxyAttribute + lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute var noticeText: CharSequence? = null @@ -46,7 +49,7 @@ abstract class NoticeItem : BaseEventItem() { override fun bind(holder: Holder) { super.bind(holder) holder.noticeTextView.text = noticeText - AvatarRenderer.render( + avatarRenderer.render( informationData.avatarUrl, informationData.senderId, informationData.memberName?.toString() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/RedactedMessageItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/RedactedMessageItem.kt index 7331a6f34b..d690347dae 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/RedactedMessageItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/item/RedactedMessageItem.kt @@ -3,12 +3,15 @@ package im.vector.riotredesign.features.home.room.detail.timeline.item import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.riotredesign.R +import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_timeline_event_base) abstract class RedactedMessageItem : AbsMessageItem() { @EpoxyAttribute override lateinit var informationData: MessageInformationData + @EpoxyAttribute + override lateinit var avatarRenderer: AvatarRenderer override fun getStubType(): Int = STUB_ID diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt index 08f7fdb3b8..992b697ea8 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt @@ -25,13 +25,15 @@ import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.riotredesign.core.extensions.localDateTime import im.vector.riotredesign.core.resources.DateProvider import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter import javax.inject.Inject class RoomSummaryController @Inject constructor(private val stringProvider: StringProvider, private val eventFormatter: NoticeEventFormatter, - private val timelineDateFormatter: TimelineDateFormatter + private val timelineDateFormatter: TimelineDateFormatter, + private val avatarRenderer: AvatarRenderer ) : TypedEpoxyController() { var callback: Callback? = null @@ -110,6 +112,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri } roomSummaryItem { + avatarRenderer(avatarRenderer) id(roomSummary.roomId) roomId(roomSummary.roomId) lastEventTime(lastMessageTime) diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt index bf6fbcaa1c..1207cb13b6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt @@ -30,6 +30,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_room) abstract class RoomSummaryItem : VectorEpoxyModel() { + @EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer @EpoxyAttribute lateinit var roomName: CharSequence @EpoxyAttribute lateinit var roomId: String @EpoxyAttribute lateinit var lastFormattedEvent: CharSequence @@ -47,7 +48,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel() { holder.lastEventTimeView.text = lastEventTime holder.lastEventView.text = lastFormattedEvent holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted)) - AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) + avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) } class Holder : VectorEpoxyHolder() { diff --git a/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt index e57de8d14c..6e26be59fc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/html/EventHtmlRenderer.kt @@ -26,37 +26,25 @@ import im.vector.matrix.android.api.permalinks.PermalinkParser import im.vector.matrix.android.api.session.Session import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.glide.GlideRequests +import im.vector.riotredesign.features.home.AvatarRenderer import org.commonmark.node.BlockQuote import org.commonmark.node.HtmlBlock import org.commonmark.node.HtmlInline import org.commonmark.node.Node -import ru.noties.markwon.AbstractMarkwonPlugin -import ru.noties.markwon.Markwon -import ru.noties.markwon.MarkwonConfiguration -import ru.noties.markwon.MarkwonVisitor -import ru.noties.markwon.SpannableBuilder +import ru.noties.markwon.* import ru.noties.markwon.html.HtmlTag import ru.noties.markwon.html.MarkwonHtmlParserImpl import ru.noties.markwon.html.MarkwonHtmlRenderer import ru.noties.markwon.html.TagHandler -import ru.noties.markwon.html.tag.BlockquoteHandler -import ru.noties.markwon.html.tag.EmphasisHandler -import ru.noties.markwon.html.tag.HeadingHandler -import ru.noties.markwon.html.tag.ImageHandler -import ru.noties.markwon.html.tag.LinkHandler -import ru.noties.markwon.html.tag.ListHandler -import ru.noties.markwon.html.tag.StrikeHandler -import ru.noties.markwon.html.tag.StrongEmphasisHandler -import ru.noties.markwon.html.tag.SubScriptHandler -import ru.noties.markwon.html.tag.SuperScriptHandler -import ru.noties.markwon.html.tag.UnderlineHandler +import ru.noties.markwon.html.tag.* import java.util.Arrays.asList import javax.inject.Inject class EventHtmlRenderer @Inject constructor(context: AppCompatActivity, + val avatarRenderer: AvatarRenderer, session: Session) { private val markwon = Markwon.builder(context) - .usePlugin(MatrixPlugin.create(GlideApp.with(context), context, session)) + .usePlugin(MatrixPlugin.create(GlideApp.with(context), context, avatarRenderer, session)) .build() fun render(text: String): CharSequence { @@ -67,6 +55,7 @@ class EventHtmlRenderer @Inject constructor(context: AppCompatActivity, private class MatrixPlugin private constructor(private val glideRequests: GlideRequests, private val context: Context, + private val avatarRenderer: AvatarRenderer, private val session: Session) : AbstractMarkwonPlugin() { override fun configureConfiguration(builder: MarkwonConfiguration.Builder) { @@ -80,7 +69,7 @@ private class MatrixPlugin private constructor(private val glideRequests: GlideR ImageHandler.create()) .setHandler( "a", - MxLinkHandler(glideRequests, context, session)) + MxLinkHandler(glideRequests, context, avatarRenderer, session)) .setHandler( "blockquote", BlockquoteHandler()) @@ -112,7 +101,7 @@ private class MatrixPlugin private constructor(private val glideRequests: GlideR asList("h1", "h2", "h3", "h4", "h5", "h6"), HeadingHandler()) .setHandler("mx-reply", - MxReplyTagHandler()) + MxReplyTagHandler()) } @@ -135,14 +124,15 @@ private class MatrixPlugin private constructor(private val glideRequests: GlideR companion object { - fun create(glideRequests: GlideRequests, context: Context, session: Session): MatrixPlugin { - return MatrixPlugin(glideRequests, context, session) + fun create(glideRequests: GlideRequests, context: Context, avatarRenderer: AvatarRenderer, session: Session): MatrixPlugin { + return MatrixPlugin(glideRequests, context, avatarRenderer, session) } } } private class MxLinkHandler(private val glideRequests: GlideRequests, private val context: Context, + private val avatarRenderer: AvatarRenderer, private val session: Session) : TagHandler() { private val linkHandler = LinkHandler() @@ -154,7 +144,7 @@ private class MxLinkHandler(private val glideRequests: GlideRequests, when (permalinkData) { is PermalinkData.UserLink -> { val user = session.getUser(permalinkData.userId) - val span = PillImageSpan(glideRequests, context, permalinkData.userId, user) + val span = PillImageSpan(glideRequests, avatarRenderer, context, permalinkData.userId, user) SpannableBuilder.setSpans( visitor.builder(), span, diff --git a/vector/src/main/java/im/vector/riotredesign/features/html/PillImageSpan.kt b/vector/src/main/java/im/vector/riotredesign/features/html/PillImageSpan.kt index e83e20e6b9..c5939e6dd3 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/html/PillImageSpan.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/html/PillImageSpan.kt @@ -37,6 +37,7 @@ import java.lang.ref.WeakReference * It's needed to call [bind] method to start requesting avatar, otherwise only the placeholder icon will be displayed if not already cached. */ class PillImageSpan(private val glideRequests: GlideRequests, + private val avatarRenderer: AvatarRenderer, private val context: Context, private val userId: String, private val user: User?) : ReplacementSpan() { @@ -52,7 +53,7 @@ class PillImageSpan(private val glideRequests: GlideRequests, @UiThread fun bind(textView: TextView) { tv = WeakReference(textView) - AvatarRenderer.render(context, glideRequests, user?.avatarUrl, userId, displayName, target) + avatarRenderer.render(context, glideRequests, user?.avatarUrl, userId, displayName, target) } // ReplacementSpan ***************************************************************************** @@ -105,7 +106,7 @@ class PillImageSpan(private val glideRequests: GlideRequests, textStartPadding = textPadding setChipMinHeightResource(R.dimen.pill_min_height) setChipIconSizeResource(R.dimen.pill_avatar_size) - chipIcon = AvatarRenderer.getPlaceholderDrawable(context, userId, displayName) + chipIcon = avatarRenderer.getPlaceholderDrawable(context, userId, displayName) setBounds(0, 0, intrinsicWidth, intrinsicHeight) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt b/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt index 54b1476ab8..ada994dfad 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/invite/VectorInviteView.kt @@ -24,8 +24,10 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.updateLayoutParams import im.vector.matrix.android.api.session.user.model.User import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.HasScreenInjector import im.vector.riotredesign.features.home.AvatarRenderer import kotlinx.android.synthetic.main.vector_invite_view.view.* +import javax.inject.Inject class VectorInviteView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : ConstraintLayout(context, attrs, defStyle) { @@ -40,9 +42,13 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib SMALL } + @Inject lateinit var avatarRenderer: AvatarRenderer var callback: Callback? = null init { + if(context is HasScreenInjector){ + context.injector().inject(this) + } View.inflate(context, R.layout.vector_invite_view, this) setBackgroundColor(Color.WHITE) inviteRejectView.setOnClickListener { callback?.onRejectInvite() } @@ -52,7 +58,7 @@ class VectorInviteView @JvmOverloads constructor(context: Context, attrs: Attrib fun render(sender: User, mode: Mode = Mode.LARGE) { if (mode == Mode.LARGE) { updateLayoutParams { height = LayoutParams.MATCH_CONSTRAINT } - AvatarRenderer.render(sender.avatarUrl, sender.userId, sender.displayName, inviteAvatarView) + avatarRenderer.render(sender.avatarUrl, sender.userId, sender.displayName, inviteAvatarView) inviteIdentifierView.text = sender.userId inviteNameView.text = sender.displayName inviteLabelView.text = context.getString(R.string.send_you_invite) diff --git a/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt index 5298217c88..12b6a24035 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/login/LoginActivity.kt @@ -30,7 +30,9 @@ import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.sync.FilterService import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.di.ScreenComponent +import im.vector.riotredesign.core.extensions.openAndStartSync import im.vector.riotredesign.core.extensions.showPassword import im.vector.riotredesign.core.platform.VectorBaseActivity import im.vector.riotredesign.features.home.HomeActivity @@ -47,6 +49,7 @@ private const val DEFAULT_ANTIVIRUS_SERVER_URI = "https://matrix.org" class LoginActivity : VectorBaseActivity() { @Inject lateinit var authenticator: Authenticator + @Inject lateinit var activeSessionHolder: ActiveSessionHolder private var passwordShown = false @@ -78,11 +81,8 @@ class LoginActivity : VectorBaseActivity() { progressBar.visibility = View.VISIBLE authenticator.authenticate(homeServerConnectionConfig, login, password, object : MatrixCallback { override fun onSuccess(data: Session) { - Matrix.getInstance(this@LoginActivity).currentSession = data - data.open() - data.setFilter(FilterService.FilterPreset.RiotFilter) - data.startSync() - + activeSessionHolder.setActiveSession(data) + data.openAndStartSync() goToHome() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt index e02536a03f..741ad99506 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/media/ImageContentRenderer.kt @@ -24,12 +24,14 @@ import com.bumptech.glide.load.resource.bitmap.RoundedCorners import com.github.piasy.biv.view.BigImageView import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.session.content.ContentUrlResolver +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.glide.GlideApp import im.vector.riotredesign.core.utils.DimensionUtils.dpToPx import kotlinx.android.parcel.Parcelize import java.io.File +import javax.inject.Inject -object ImageContentRenderer { +class ImageContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder) { @Parcelize data class Data( @@ -57,26 +59,26 @@ object ImageContentRenderer { val (width, height) = processSize(data, mode) imageView.layoutParams.height = height imageView.layoutParams.width = width - val contentUrlResolver = Matrix.getInstance(imageView.context).currentSession!!.contentUrlResolver() + val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() val resolvedUrl = when (mode) { - Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url) - Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE) - } - //Fallback to base url - ?: data.url + Mode.FULL_SIZE -> contentUrlResolver.resolveFullSize(data.url) + Mode.THUMBNAIL -> contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE) + } + //Fallback to base url + ?: data.url GlideApp .with(imageView) .load(resolvedUrl) .dontAnimate() - .transform(RoundedCorners(dpToPx(8,imageView.context))) + .transform(RoundedCorners(dpToPx(8, imageView.context))) .thumbnail(0.3f) .into(imageView) } fun render(data: Data, imageView: BigImageView) { val (width, height) = processSize(data, Mode.THUMBNAIL) - val contentUrlResolver = Matrix.getInstance(imageView.context).currentSession!!.contentUrlResolver() + val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() val fullSize = contentUrlResolver.resolveFullSize(data.url) val thumbnail = contentUrlResolver.resolveThumbnail(data.url, width, height, ContentUrlResolver.ThumbnailMethod.SCALE) imageView.showImage( diff --git a/vector/src/main/java/im/vector/riotredesign/features/media/ImageMediaViewerActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/media/ImageMediaViewerActivity.kt index 902c2f9bc1..4b980ccb23 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/media/ImageMediaViewerActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/media/ImageMediaViewerActivity.kt @@ -24,12 +24,20 @@ import android.os.Bundle import androidx.appcompat.widget.Toolbar import com.github.piasy.biv.indicator.progresspie.ProgressPieIndicator import com.github.piasy.biv.view.GlideImageViewFactory +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.platform.VectorBaseActivity import kotlinx.android.synthetic.main.activity_image_media_viewer.* +import javax.inject.Inject class ImageMediaViewerActivity : VectorBaseActivity() { + @Inject lateinit var imageContentRenderer: ImageContentRenderer + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(im.vector.riotredesign.R.layout.activity_image_media_viewer) @@ -40,7 +48,7 @@ class ImageMediaViewerActivity : VectorBaseActivity() { configureToolbar(imageMediaViewerToolbar, mediaData) imageMediaViewerImageView.setImageViewFactory(GlideImageViewFactory()) imageMediaViewerImageView.setProgressIndicator(ProgressPieIndicator()) - ImageContentRenderer.render(mediaData, imageMediaViewerImageView) + imageContentRenderer.render(mediaData, imageMediaViewerImageView) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/media/VideoContentRenderer.kt b/vector/src/main/java/im/vector/riotredesign/features/media/VideoContentRenderer.kt index 54a91ed507..8fd4b43e46 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/media/VideoContentRenderer.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/media/VideoContentRenderer.kt @@ -20,9 +20,11 @@ import android.os.Parcelable import android.widget.ImageView import android.widget.VideoView import im.vector.matrix.android.api.Matrix +import im.vector.riotredesign.core.di.ActiveSessionHolder import kotlinx.android.parcel.Parcelize +import javax.inject.Inject -object VideoContentRenderer { +class VideoContentRenderer @Inject constructor(private val activeSessionHolder: ActiveSessionHolder){ @Parcelize data class Data( @@ -32,7 +34,7 @@ object VideoContentRenderer { ) : Parcelable fun render(data: Data, thumbnailView: ImageView, videoView: VideoView) { - val contentUrlResolver = Matrix.getInstance(videoView.context).currentSession!!.contentUrlResolver() + val contentUrlResolver = activeSessionHolder.getActiveSession().contentUrlResolver() val resolvedUrl = contentUrlResolver.resolveFullSize(data.videoUrl) videoView.setVideoPath(resolvedUrl) videoView.start() diff --git a/vector/src/main/java/im/vector/riotredesign/features/media/VideoMediaViewerActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/media/VideoMediaViewerActivity.kt index 0630a2cb01..d0b70302cf 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/media/VideoMediaViewerActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/media/VideoMediaViewerActivity.kt @@ -20,12 +20,21 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.appcompat.widget.Toolbar +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.platform.VectorBaseActivity +import im.vector.riotredesign.features.home.AvatarRenderer import kotlinx.android.synthetic.main.activity_video_media_viewer.* +import javax.inject.Inject class VideoMediaViewerActivity : VectorBaseActivity() { + @Inject lateinit var videoContentRenderer: VideoContentRenderer + + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(im.vector.riotredesign.R.layout.activity_video_media_viewer) @@ -34,7 +43,7 @@ class VideoMediaViewerActivity : VectorBaseActivity() { finish() } else { configureToolbar(videoMediaViewerToolbar, mediaData) - VideoContentRenderer.render(mediaData, videoMediaViewerThumbnailView, videoMediaViewerVideoView) + videoContentRenderer.render(mediaData, videoMediaViewerThumbnailView, videoMediaViewerVideoView) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt index 48f8102126..d436013c73 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReportActivity.kt @@ -26,9 +26,11 @@ import butterknife.BindView import butterknife.OnCheckedChanged import butterknife.OnTextChanged import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.platform.VectorBaseActivity import kotlinx.android.synthetic.main.activity_bug_report.* import timber.log.Timber +import javax.inject.Inject /** * Form to send a bug report @@ -66,13 +68,17 @@ class BugReportActivity : VectorBaseActivity() { @BindView(R.id.bug_report_mask_view) lateinit var mMaskView: View + override fun injectWith(injector: ScreenComponent) { + injector.inject(this) + } + override fun getLayoutRes() = R.layout.activity_bug_report override fun initUiAndData() { configureToolbar(bugReportToolbar) - if (BugReporter.screenshot != null) { - mScreenShotPreview.setImageBitmap(BugReporter.screenshot) + if (bugReporter.screenshot != null) { + mScreenShotPreview.setImageBitmap(bugReporter.screenshot) } else { mScreenShotPreview.isVisible = false mIncludeScreenShotButton.isChecked = false @@ -120,7 +126,7 @@ class BugReportActivity : VectorBaseActivity() { mProgressBar.isVisible = true mProgressBar.progress = 0 - BugReporter.sendBugReport(this, + bugReporter.sendBugReport(this, mIncludeLogsButton.isChecked, mIncludeCrashLogsButton.isChecked, mIncludeScreenShotButton.isChecked, @@ -190,12 +196,12 @@ class BugReportActivity : VectorBaseActivity() { @OnCheckedChanged(R.id.bug_report_button_include_screenshot) internal fun onSendScreenshotChanged() { - mScreenShotPreview.isVisible = mIncludeScreenShotButton.isChecked && BugReporter.screenshot != null + mScreenShotPreview.isVisible = mIncludeScreenShotButton.isChecked && bugReporter.screenshot != null } override fun onBackPressed() { // Ensure there is no crash status remaining, which will be sent later on by mistake - BugReporter.deleteCrashFile(this) + bugReporter.deleteCrashFile(this) super.onBackPressed() } diff --git a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReporter.kt index 59bf5c0a2e..778ce5869a 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/rageshake/BugReporter.kt @@ -30,6 +30,7 @@ import android.view.View import im.vector.matrix.android.api.Matrix import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.R +import im.vector.riotredesign.core.di.ActiveSessionHolder import im.vector.riotredesign.core.extensions.toOnOff import im.vector.riotredesign.core.utils.getDeviceLocale import im.vector.riotredesign.features.settings.VectorLocale @@ -42,19 +43,26 @@ import java.io.* import java.net.HttpURLConnection import java.util.* import java.util.zip.GZIPOutputStream +import javax.inject.Inject +import javax.inject.Singleton /** * BugReporter creates and sends the bug reports. */ -object BugReporter { +@Singleton +class BugReporter @Inject constructor(private val activeSessionHolder: ActiveSessionHolder){ var inMultiWindowMode = false - // filenames - private const val LOG_CAT_ERROR_FILENAME = "logcatError.log" - private const val LOG_CAT_FILENAME = "logcat.log" - private const val LOG_CAT_SCREENSHOT_FILENAME = "screenshot.png" - private const val CRASH_FILENAME = "crash.log" + companion object { + // filenames + private const val LOG_CAT_ERROR_FILENAME = "logcatError.log" + private const val LOG_CAT_FILENAME = "logcat.log" + private const val LOG_CAT_SCREENSHOT_FILENAME = "screenshot.png" + private const val CRASH_FILENAME = "crash.log" + private const val BUFFER_SIZE = 1024 * 1024 * 50 + + } // the http client private val mOkHttpClient = OkHttpClient() @@ -74,8 +82,6 @@ object BugReporter { var screenshot: Bitmap? = null private set - private const val BUFFER_SIZE = 1024 * 1024 * 50 - private val LOGCAT_CMD_ERROR = arrayOf("logcat", ///< Run 'logcat' command "-d", ///< Dump the log rather than continue outputting it "-v", // formatting @@ -195,7 +201,7 @@ object BugReporter { var matrixSdkVersion = "undefined" var olmVersion = "undefined" - Matrix.getInstance(context).currentSession?.let { session -> + activeSessionHolder.getActiveSession().let { session -> userId = session.sessionParams.credentials.userId deviceId = session.sessionParams.credentials.deviceId ?: "undefined" // TODO matrixSdkVersion = session.getVersion(true); diff --git a/vector/src/main/java/im/vector/riotredesign/features/rageshake/RageShake.kt b/vector/src/main/java/im/vector/riotredesign/features/rageshake/RageShake.kt index 446d2f4807..4125ac20e1 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/rageshake/RageShake.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/rageshake/RageShake.kt @@ -16,7 +16,6 @@ package im.vector.riotredesign.features.rageshake -import android.app.Activity import android.content.Context import android.hardware.Sensor import android.hardware.SensorManager @@ -26,8 +25,10 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.content.edit import com.squareup.seismic.ShakeDetector import im.vector.riotredesign.R +import javax.inject.Inject -class RageShake(val activity: Activity) : ShakeDetector.Listener { +class RageShake @Inject constructor(private val activity: AppCompatActivity, + private val bugReporter: BugReporter) : ShakeDetector.Listener { private var shakeDetector: ShakeDetector? = null @@ -94,7 +95,7 @@ class RageShake(val activity: Activity) : ShakeDetector.Listener { } private fun openBugReportScreen() { - BugReporter.openBugReportScreen(activity) + bugReporter.openBugReportScreen(activity) } companion object { diff --git a/vector/src/main/java/im/vector/riotredesign/features/rageshake/VectorUncaughtExceptionHandler.kt b/vector/src/main/java/im/vector/riotredesign/features/rageshake/VectorUncaughtExceptionHandler.kt index 609590298e..a7da508e35 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/rageshake/VectorUncaughtExceptionHandler.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/rageshake/VectorUncaughtExceptionHandler.kt @@ -16,7 +16,6 @@ package im.vector.riotredesign.features.rageshake -import android.annotation.SuppressLint import android.content.Context import android.os.Build import androidx.core.content.edit @@ -25,12 +24,16 @@ import im.vector.riotredesign.BuildConfig import timber.log.Timber import java.io.PrintWriter import java.io.StringWriter +import javax.inject.Inject +import javax.inject.Singleton -@SuppressLint("StaticFieldLeak") -object VectorUncaughtExceptionHandler : Thread.UncaughtExceptionHandler { +@Singleton +class VectorUncaughtExceptionHandler @Inject constructor(private val bugReporter: BugReporter) : Thread.UncaughtExceptionHandler { // key to save the crash status - private const val PREFS_CRASH_KEY = "PREFS_CRASH_KEY" + companion object { + private const val PREFS_CRASH_KEY = "PREFS_CRASH_KEY" + } private var vectorVersion: String = "" private var matrixSdkVersion: String = "" @@ -44,9 +47,7 @@ object VectorUncaughtExceptionHandler : Thread.UncaughtExceptionHandler { */ fun activate(context: Context) { this.context = context - previousHandler = Thread.getDefaultUncaughtExceptionHandler() - Thread.setDefaultUncaughtExceptionHandler(this) } @@ -58,15 +59,10 @@ object VectorUncaughtExceptionHandler : Thread.UncaughtExceptionHandler { * @return the exception description */ override fun uncaughtException(thread: Thread, throwable: Throwable) { - if (context == null) { - previousHandler?.uncaughtException(thread, throwable) - return - } - + Timber.v("Uncaught exception: $throwable") PreferenceManager.getDefaultSharedPreferences(context).edit { putBoolean(PREFS_CRASH_KEY, true) } - val b = StringBuilder() val appName = "RiotX" // TODO Matrix.getApplicationName() @@ -114,7 +110,7 @@ object VectorUncaughtExceptionHandler : Thread.UncaughtExceptionHandler { val bugDescription = b.toString() - BugReporter.saveCrashReport(context, bugDescription) + bugReporter.saveCrashReport(context, bugDescription) // Show the classical system popup previousHandler?.uncaughtException(thread, throwable) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt index 8e30809f80..2f46fbce9b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomItem.kt @@ -31,6 +31,9 @@ import im.vector.riotredesign.features.home.AvatarRenderer @EpoxyModelClass(layout = R.layout.item_public_room) abstract class PublicRoomItem : VectorEpoxyModel() { + @EpoxyAttribute + lateinit var avatarRenderer: AvatarRenderer + @EpoxyAttribute var avatarUrl: String? = null @@ -61,7 +64,7 @@ abstract class PublicRoomItem : VectorEpoxyModel() { override fun bind(holder: Holder) { holder.rootView.setOnClickListener { globalListener?.invoke() } - AvatarRenderer.render(avatarUrl, roomId!!, roomName, holder.avatarView) + avatarRenderer.render(avatarUrl, roomId!!, roomName, holder.avatarView) holder.nameView.text = roomName holder.aliasView.setTextOrHide(roomAlias) holder.topicView.setTextOrHide(roomTopic) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt index bf39586830..b9bf30e776 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/PublicRoomsController.kt @@ -28,9 +28,11 @@ import im.vector.riotredesign.core.epoxy.loadingItem import im.vector.riotredesign.core.epoxy.noResultItem import im.vector.riotredesign.core.error.ErrorFormatter import im.vector.riotredesign.core.resources.StringProvider +import im.vector.riotredesign.features.home.AvatarRenderer import javax.inject.Inject class PublicRoomsController @Inject constructor(private val stringProvider: StringProvider, + private val avatarRenderer: AvatarRenderer, private val errorFormatter: ErrorFormatter) : TypedEpoxyController() { var callback: Callback? = null @@ -79,6 +81,7 @@ class PublicRoomsController @Inject constructor(private val stringProvider: Stri private fun buildPublicRoom(publicRoom: PublicRoom, viewState: PublicRoomsViewState) { publicRoomItem { + avatarRenderer(avatarRenderer) id(publicRoom.roomId) roomId(publicRoom.roomId) avatarUrl(publicRoom.avatarUrl) diff --git a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt index d94503a15c..95f9027cf6 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt @@ -47,6 +47,7 @@ class RoomPreviewNoPreviewFragment : VectorBaseFragment() { @Inject lateinit var errorFormatter: ErrorFormatter @Inject lateinit var roomPreviewViewModelFactory: RoomPreviewViewModel.Factory + @Inject lateinit var avatarRenderer: AvatarRenderer private val roomPreviewViewModel: RoomPreviewViewModel by fragmentViewModel() private val roomPreviewData: RoomPreviewData by args() @@ -65,11 +66,11 @@ class RoomPreviewNoPreviewFragment : VectorBaseFragment() { super.onViewCreated(view, savedInstanceState) // Toolbar - AvatarRenderer.render(roomPreviewData.avatarUrl, roomPreviewData.roomId, roomPreviewData.roomName, roomPreviewNoPreviewToolbarAvatar) + avatarRenderer.render(roomPreviewData.avatarUrl, roomPreviewData.roomId, roomPreviewData.roomName, roomPreviewNoPreviewToolbarAvatar) roomPreviewNoPreviewToolbarTitle.text = roomPreviewData.roomName // Screen - AvatarRenderer.render(roomPreviewData.avatarUrl, roomPreviewData.roomId, roomPreviewData.roomName, roomPreviewNoPreviewAvatar) + avatarRenderer.render(roomPreviewData.avatarUrl, roomPreviewData.roomId, roomPreviewData.roomName, roomPreviewNoPreviewAvatar) roomPreviewNoPreviewName.text = roomPreviewData.roomName roomPreviewNoPreviewTopic.setTextOrHide(roomPreviewData.topic) diff --git a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt index b176362ae2..700fd24432 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt @@ -55,6 +55,7 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() { private var testManager: NotificationTroubleshootTestManager? = null // members @Inject lateinit var session: Session + @Inject lateinit var bugReporter: BugReporter override fun getLayoutResId() = R.layout.fragment_settings_notifications_troubleshoot @@ -78,7 +79,7 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() { mSummaryButton.setOnClickListener { - BugReporter.openBugReportScreen(activity!!) + bugReporter.openBugReportScreen(activity!!) } mRunButton.setOnClickListener { diff --git a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt index f420a2ac82..ff66800a18 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/workers/signout/SignOutBottomSheetDialogFragment.kt @@ -41,8 +41,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState import im.vector.riotredesign.R -import im.vector.riotredesign.core.di.HasInjector -import im.vector.riotredesign.core.di.ScreenComponent import im.vector.riotredesign.core.utils.toast import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity import im.vector.riotredesign.features.crypto.keysbackup.setup.KeysBackupSetupActivity