Dagger: prepare for multi session [WIP]
This commit is contained in:
parent
47968c9447
commit
6e7adaec59
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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<String, SessionComponent>()
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -49,6 +49,8 @@ internal abstract class AuthModule {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Binds
|
||||
abstract fun bindSessionParamsStore(sessionParamsStore: RealmSessionParamsStore): SessionParamsStore
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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<SessionParams>
|
||||
|
||||
fun save(sessionParams: SessionParams): Try<SessionParams>
|
||||
|
||||
fun delete(): Try<Unit>
|
||||
fun delete(userId: String): Try<Unit>
|
||||
|
||||
fun deleteAll(): Try<Unit>
|
||||
}
|
|
@ -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<SessionParams> {
|
||||
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<SessionParams> {
|
||||
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<Unit> {
|
||||
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<Unit> {
|
||||
override fun deleteAll(): Try<Unit> {
|
||||
return Try {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
realm.executeTransaction {
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Unit, Unit>
|
||||
|
||||
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<Unit> {
|
||||
return executeRequest<Unit> {
|
||||
apiCall = signOutAPI.signOut()
|
||||
}.flatMap {
|
||||
sessionParamsStore.delete()
|
||||
sessionParamsStore.delete(credentials.userId)
|
||||
}.flatMap {
|
||||
Try {
|
||||
sessionManager.releaseSession(credentials.userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<SyncTask.Params, SyncResponse> {
|
|||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -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<VectorComponent>, 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)
|
||||
|
|
|
@ -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<Session?> = 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)
|
||||
}
|
||||
|
||||
}
|
|
@ -16,8 +16,8 @@
|
|||
|
||||
package im.vector.riotredesign.core.di
|
||||
|
||||
interface HasInjector<C> {
|
||||
interface HasScreenInjector {
|
||||
|
||||
fun injector(): C
|
||||
fun injector(): ScreenComponent
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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<ScreenComponent> {
|
||||
abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
|
||||
/* ==========================================================================================
|
||||
* UI
|
||||
* ========================================================================================== */
|
||||
|
@ -81,6 +73,8 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
|
||||
protected lateinit var viewModelFactory: ViewModelProvider.Factory
|
||||
private lateinit var configurationViewModel: ConfigurationViewModel
|
||||
protected lateinit var bugReporter: BugReporter
|
||||
private lateinit var rageShake: RageShake
|
||||
|
||||
private var unBinder: Unbinder? = null
|
||||
|
||||
|
@ -92,7 +86,6 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
private val uiDisposables = CompositeDisposable()
|
||||
private val restorables = ArrayList<Restorable>()
|
||||
|
||||
private var rageShake: RageShake? = null
|
||||
private lateinit var screenComponent: ScreenComponent
|
||||
|
||||
override fun attachBaseContext(base: Context) {
|
||||
|
@ -125,9 +118,14 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
screenComponent = DaggerScreenComponent.factory().create(getVectorComponent(), this)
|
||||
super.onCreate(savedInstanceState)
|
||||
injectWith(screenComponent)
|
||||
val timeForInjection = measureTimeMillis {
|
||||
injectWith(screenComponent)
|
||||
}
|
||||
Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
|
||||
viewModelFactory = screenComponent.viewModelFactory()
|
||||
configurationViewModel = ViewModelProviders.of(this, viewModelFactory).get(ConfigurationViewModel::class.java)
|
||||
bugReporter = screenComponent.bugReporter()
|
||||
rageShake = screenComponent.rageShake()
|
||||
configurationViewModel.activityRestarter.observe(this, Observer {
|
||||
if (!it.hasBeenHandled) {
|
||||
// Recreate the Activity because configuration has changed
|
||||
|
@ -137,7 +135,6 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
})
|
||||
|
||||
// Shake detector
|
||||
rageShake = RageShake(this)
|
||||
|
||||
ThemeUtils.setActivityTheme(this, getOtherThemes())
|
||||
|
||||
|
@ -215,7 +212,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
super.onMultiWindowModeChanged(isInMultiWindowMode, newConfig)
|
||||
|
||||
Timber.w("onMultiWindowModeChanged. isInMultiWindowMode: $isInMultiWindowMode")
|
||||
BugReporter.inMultiWindowMode = isInMultiWindowMode
|
||||
bugReporter.inMultiWindowMode = isInMultiWindowMode
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,7 +227,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasInjector<ScreenCompon
|
|||
* ========================================================================================== */
|
||||
|
||||
internal fun getVectorComponent(): VectorComponent {
|
||||
return (application as HasInjector<VectorComponent>).injector()
|
||||
return (application as HasVectorInjector).injector()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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<ScreenComponent> {
|
||||
abstract class VectorBaseFragment : BaseMvRxFragment(), OnBackPressed, HasScreenInjector {
|
||||
|
||||
// Butterknife unbinder
|
||||
private var mUnBinder: Unbinder? = null
|
||||
|
|
|
@ -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<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.w("SIGN_OUT: success, start app")
|
||||
start()
|
||||
}
|
||||
})
|
||||
clearCache -> session.clearCache(object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
start()
|
||||
}
|
||||
})
|
||||
else -> start()
|
||||
}
|
||||
// Handle some wanted cleanup
|
||||
when {
|
||||
clearCredentials -> sessionHolder.getActiveSession().signOut(object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
Timber.w("SIGN_OUT: success, start app")
|
||||
sessionHolder.clearActiveSession()
|
||||
start()
|
||||
}
|
||||
})
|
||||
clearCache -> sessionHolder.getActiveSession().clearCache(object : MatrixCallback<Unit> {
|
||||
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)
|
||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
|||
@EpoxyModelClass(layout = R.layout.item_autocomplete_user)
|
||||
abstract class AutocompleteUserItem : VectorEpoxyModel<AutocompleteUserItem.Holder>() {
|
||||
|
||||
@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<AutocompleteUserItem.Hold
|
|||
override fun bind(holder: Holder) {
|
||||
holder.view.setOnClickListener(clickListener)
|
||||
holder.nameView.text = name
|
||||
AvatarRenderer.render(avatarUrl, userId, name, holder.avatarImageView)
|
||||
avatarRenderer.render(avatarUrl, userId, name, holder.avatarImageView)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.matrix.android.api.session.crypto.sas.SasVerificationService
|
|||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTransaction
|
||||
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.di.ActiveSessionHolder
|
||||
import im.vector.riotredesign.features.popup.PopupAlertManager
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
@ -31,11 +32,11 @@ import javax.inject.Singleton
|
|||
*/
|
||||
@Singleton
|
||||
class IncomingVerificationRequestHandler @Inject constructor(val context: Context,
|
||||
private val session: Session
|
||||
private val activeSessionHolder: ActiveSessionHolder
|
||||
) : SasVerificationService.SasVerificationListener {
|
||||
|
||||
init {
|
||||
session.getSasVerificationService().addListener(this)
|
||||
activeSessionHolder.getActiveSession().getSasVerificationService().addListener(this)
|
||||
}
|
||||
|
||||
override fun transactionCreated(tx: SasVerificationTransaction) {}
|
||||
|
@ -44,7 +45,7 @@ class IncomingVerificationRequestHandler @Inject constructor(val context: Contex
|
|||
when (tx.state) {
|
||||
SasVerificationTxState.OnStarted -> {
|
||||
//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
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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<Drawable>
|
||||
*/
|
||||
|
||||
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<Drawable> {
|
||||
val resolvedUrl = Matrix.getInstance(context).currentSession!!.contentUrlResolver()
|
||||
private fun buildGlideRequest(glideRequest: GlideRequests, avatarUrl: String?): GlideRequest<Drawable> {
|
||||
val resolvedUrl = activeSessionHolder.getActiveSession().contentUrlResolver()
|
||||
.resolveThumbnail(avatarUrl, THUMBNAIL_SIZE, THUMBNAIL_SIZE, ContentUrlResolver.ThumbnailMethod.SCALE)
|
||||
|
||||
return glideRequest
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<GroupListViewState>() {
|
||||
class GroupSummaryController @Inject constructor(private val avatarRenderer: AvatarRenderer): TypedEpoxyController<GroupListViewState>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
|
@ -35,6 +36,7 @@ class GroupSummaryController @Inject constructor(): TypedEpoxyController<GroupLi
|
|||
summaries.forEach { groupSummary ->
|
||||
val isSelected = groupSummary.groupId == selected?.groupId
|
||||
groupSummaryItem {
|
||||
avatarRenderer(avatarRenderer)
|
||||
id(groupSummary.groupId)
|
||||
groupId(groupSummary.groupId)
|
||||
groupName(groupSummary.displayName)
|
||||
|
|
|
@ -29,6 +29,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
|||
@EpoxyModelClass(layout = R.layout.item_group)
|
||||
abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
||||
|
||||
@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<GroupSummaryItem.Holder>() {
|
|||
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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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<Event>()
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<String, ContentUploadStateTracker.UpdateListener>()
|
||||
|
||||
|
@ -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)
|
||||
|
|
|
@ -40,6 +40,8 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
|||
|
||||
abstract val informationData: MessageInformationData
|
||||
|
||||
abstract val avatarRenderer: AvatarRenderer
|
||||
|
||||
@EpoxyAttribute
|
||||
var longClickListener: View.OnLongClickListener? = null
|
||||
|
||||
|
@ -96,7 +98,7 @@ abstract class AbsMessageItem<H : AbsMessageItem.Holder> : BaseEventItem<H>() {
|
|||
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)
|
||||
|
|
|
@ -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<Data>,
|
||||
private val avatarRenderer: AvatarRenderer,
|
||||
private val onCollapsedStateChanged: (Boolean) -> Unit
|
||||
) : BaseEventItem<MergedHeaderItem.Holder>() {
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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<MessageFileItem.Holder>() {
|
||||
|
@ -37,6 +38,8 @@ abstract class MessageFileItem : AbsMessageItem<MessageFileItem.Holder>() {
|
|||
@EpoxyAttribute
|
||||
override lateinit var informationData: MessageInformationData
|
||||
@EpoxyAttribute
|
||||
override lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute
|
||||
var clickListener: View.OnClickListener? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
|
|
|
@ -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<MessageImageVideoItem.Hold
|
|||
@EpoxyAttribute
|
||||
override lateinit var informationData: MessageInformationData
|
||||
@EpoxyAttribute
|
||||
override lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute
|
||||
var playable: Boolean = false
|
||||
@EpoxyAttribute
|
||||
var clickListener: View.OnClickListener? = null
|
||||
@EpoxyAttribute
|
||||
lateinit var imageContentRenderer: ImageContentRenderer
|
||||
@EpoxyAttribute
|
||||
lateinit var contentUploadStateTrackerBinder: ContentUploadStateTrackerBinder
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
ImageContentRenderer.render(mediaData, ImageContentRenderer.Mode.THUMBNAIL, holder.imageView)
|
||||
ContentUploadStateTrackerBinder.bind(informationData.eventId, mediaData, holder.progressLayout)
|
||||
imageContentRenderer.render(mediaData, ImageContentRenderer.Mode.THUMBNAIL, holder.imageView)
|
||||
contentUploadStateTrackerBinder.bind(informationData.eventId, mediaData, holder.progressLayout)
|
||||
holder.imageView.setOnClickListener(clickListener)
|
||||
holder.imageView.setOnLongClickListener(longClickListener)
|
||||
holder.mediaContentView.setOnClickListener(cellClickListener)
|
||||
|
@ -50,7 +57,7 @@ abstract class MessageImageVideoItem : AbsMessageItem<MessageImageVideoItem.Hold
|
|||
}
|
||||
|
||||
override fun unbind(holder: Holder) {
|
||||
ContentUploadStateTrackerBinder.unbind(informationData.eventId, holder.progressLayout)
|
||||
contentUploadStateTrackerBinder.unbind(informationData.eventId)
|
||||
super.unbind(holder)
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.airbnb.epoxy.EpoxyAttribute
|
|||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.utils.containsOnlyEmojis
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
import im.vector.riotredesign.features.html.PillImageSpan
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
|
@ -37,6 +38,8 @@ abstract class MessageTextItem : AbsMessageItem<MessageTextItem.Holder>() {
|
|||
@EpoxyAttribute
|
||||
var message: CharSequence? = null
|
||||
@EpoxyAttribute
|
||||
override lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute
|
||||
override lateinit var informationData: MessageInformationData
|
||||
|
||||
val mvmtMethod = BetterLinkMovementMethod.newInstance().also {
|
||||
|
|
|
@ -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<NoticeItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
@EpoxyAttribute
|
||||
var noticeText: CharSequence? = null
|
||||
|
||||
|
@ -46,7 +49,7 @@ abstract class NoticeItem : BaseEventItem<NoticeItem.Holder>() {
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.noticeTextView.text = noticeText
|
||||
AvatarRenderer.render(
|
||||
avatarRenderer.render(
|
||||
informationData.avatarUrl,
|
||||
informationData.senderId,
|
||||
informationData.memberName?.toString()
|
||||
|
|
|
@ -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<RedactedMessageItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
override lateinit var informationData: MessageInformationData
|
||||
@EpoxyAttribute
|
||||
override lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
override fun getStubType(): Int = STUB_ID
|
||||
|
||||
|
|
|
@ -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<RoomListViewState>() {
|
||||
|
||||
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)
|
||||
|
|
|
@ -30,6 +30,7 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
|||
@EpoxyModelClass(layout = R.layout.item_room)
|
||||
abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
||||
|
||||
@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<RoomSummaryItem.Holder>() {
|
|||
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() {
|
||||
|
|
|
@ -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<String>("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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<Session> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -31,6 +31,9 @@ import im.vector.riotredesign.features.home.AvatarRenderer
|
|||
@EpoxyModelClass(layout = R.layout.item_public_room)
|
||||
abstract class PublicRoomItem : VectorEpoxyModel<PublicRoomItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute
|
||||
lateinit var avatarRenderer: AvatarRenderer
|
||||
|
||||
@EpoxyAttribute
|
||||
var avatarUrl: String? = null
|
||||
|
||||
|
@ -61,7 +64,7 @@ abstract class PublicRoomItem : VectorEpoxyModel<PublicRoomItem.Holder>() {
|
|||
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)
|
||||
|
|
|
@ -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<PublicRoomsViewState>() {
|
||||
|
||||
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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue