Merge branch 'develop' into feature/room_list_actions

This commit is contained in:
ganfra 2019-11-07 15:43:21 +01:00
commit 61ac250e2b
111 changed files with 1439 additions and 878 deletions

View File

@ -3,6 +3,7 @@ Changes in RiotX 0.8.0 (2019-XX-XX)
Features ✨:
- Handle long click on room in the room list (#395)
- Ignore/UnIgnore users, and display list of ignored users (#542, #617)
Improvements 🙌:
- Search reaction by name or keyword in emoji picker

View File

@ -54,6 +54,10 @@ class RxSession(private val session: Session) {
return session.liveUsers().asObservable()
}
fun liveIgnoredUsers(): Observable<List<User>> {
return session.liveIgnoredUsers().asObservable()
}
fun livePagedUsers(filter: String? = null): Observable<PagedList<User>> {
return session.livePagedUsers(filter).asObservable()
}

View File

@ -19,7 +19,7 @@ package im.vector.matrix.android.api.session.cache
import im.vector.matrix.android.api.MatrixCallback
/**
* This interface defines a method to sign out. It's implemented at the session level.
* This interface defines a method to clear the cache. It's implemented at the session level.
*/
interface CacheService {

View File

@ -64,4 +64,19 @@ interface UserService {
* @return a Livedata of users
*/
fun livePagedUsers(filter: String? = null): LiveData<PagedList<User>>
/**
* Get list of ignored users
*/
fun liveIgnoredUsers(): LiveData<List<User>>
/**
* Ignore users
*/
fun ignoreUserIds(userIds: List<String>, callback: MatrixCallback<Unit>): Cancelable
/**
* Un-ignore some users
*/
fun unIgnoreUserIds(userIds: List<String>, callback: MatrixCallback<Unit>): Cancelable
}

View File

@ -21,4 +21,6 @@ import java.lang.reflect.ParameterizedType
typealias JsonDict = Map<String, @JvmSuppressWildcards Any>
val emptyJsonDict = emptyMap<String, Any>()
internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java)

View File

@ -41,8 +41,7 @@ fun <T> doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T
*/
fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration, action: (Realm) -> T?): T? {
return Realm.getInstance(realmConfiguration).use { realm ->
val result = action.invoke(realm)
result?.let { realm.copyFromRealm(it) }
action.invoke(realm)?.let { realm.copyFromRealm(it) }
}
}
@ -51,8 +50,7 @@ fun <T : RealmObject> doRealmQueryAndCopy(realmConfiguration: RealmConfiguration
*/
fun <T : RealmObject> doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable<T>): Iterable<T> {
return Realm.getInstance(realmConfiguration).use { realm ->
val result = action.invoke(realm)
realm.copyFromRealm(result)
action.invoke(realm).let { realm.copyFromRealm(it) }
}
}

View File

@ -91,7 +91,7 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
realmLocker = Realm.getInstance(realmConfiguration)
// Ensure CryptoMetadataEntity is inserted in DB
doWithRealm(realmConfiguration) { realm ->
doRealmTransaction(realmConfiguration) { realm ->
var currentMetadata = realm.where<CryptoMetadataEntity>().findFirst()
var deleteAll = false
@ -109,15 +109,13 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati
}
if (currentMetadata == null) {
realm.executeTransaction {
if (deleteAll) {
it.deleteAll()
}
if (deleteAll) {
realm.deleteAll()
}
// Metadata not found, or database cleaned, create it
it.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply {
deviceId = credentials.deviceId
}
// Metadata not found, or database cleaned, create it
realm.createObject(CryptoMetadataEntity::class.java, credentials.userId).apply {
deviceId = credentials.deviceId
}
}
}

View File

@ -0,0 +1,24 @@
/*
* 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.database.model
import io.realm.RealmObject
internal open class IgnoredUserEntity(var userId: String = "") : RealmObject() {
companion object
}

View File

@ -35,6 +35,7 @@ import io.realm.annotations.RealmModule
RoomTagEntity::class,
SyncEntity::class,
UserEntity::class,
IgnoredUserEntity::class,
EventAnnotationsSummaryEntity::class,
ReactionAggregatedSummaryEntity::class,
EditAggregatedSummaryEntity::class,

View File

@ -20,10 +20,11 @@ import com.squareup.moshi.Moshi
import im.vector.matrix.android.api.session.room.model.message.*
import im.vector.matrix.android.internal.network.parsing.RuntimeJsonAdapterFactory
import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataFallback
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataDirectMessages
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataFallback
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataIgnoredUsers
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataPushRules
object MoshiProvider {
@ -31,6 +32,7 @@ object MoshiProvider {
.add(UriMoshiAdapter())
.add(RuntimeJsonAdapterFactory.of(UserAccountData::class.java, "type", UserAccountDataFallback::class.java)
.registerSubtype(UserAccountDataDirectMessages::class.java, UserAccountData.TYPE_DIRECT_MESSAGES)
.registerSubtype(UserAccountDataIgnoredUsers::class.java, UserAccountData.TYPE_IGNORED_USER_LIST)
.registerSubtype(UserAccountDataPushRules::class.java, UserAccountData.TYPE_PUSH_RULES)
)
.add(RuntimeJsonAdapterFactory.of(MessageContent::class.java, "msgtype", MessageDefaultContent::class.java)

View File

@ -27,10 +27,9 @@ import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.session.pushers.SavePushRulesTask
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataDirectMessages
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataPushRules
import im.vector.matrix.android.internal.session.sync.model.UserAccountDataSync
import im.vector.matrix.android.internal.session.sync.model.accountdata.*
import im.vector.matrix.android.internal.session.user.accountdata.DirectChatsHelper
import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
import im.vector.matrix.android.internal.session.user.accountdata.UpdateUserAccountDataTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@ -44,6 +43,7 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
private val directChatsHelper: DirectChatsHelper,
private val updateUserAccountDataTask: UpdateUserAccountDataTask,
private val savePushRulesTask: SavePushRulesTask,
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
private val taskExecutor: TaskExecutor) {
suspend fun handle(accountData: UserAccountDataSync?, invites: Map<String, InvitedRoomSync>?) {
@ -51,9 +51,18 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
when (it) {
is UserAccountDataDirectMessages -> handleDirectChatRooms(it)
is UserAccountDataPushRules -> handlePushRules(it)
else -> return@forEach
is UserAccountDataIgnoredUsers -> handleIgnoredUsers(it)
is UserAccountDataFallback -> Timber.d("Receive account data of unhandled type ${it.type}")
else -> error("Missing code here!")
}
}
// TODO Store all account data, app can be interested of it
// accountData?.list?.forEach {
// it.toString()
// MoshiProvider.providesMoshi()
// }
monarchy.doWithRealm { realm ->
synchronizeWithServerIfNeeded(realm, invites)
}
@ -114,4 +123,11 @@ internal class UserAccountDataSyncHandler @Inject constructor(private val monarc
updateUserAccountDataTask.configureWith(updateUserAccountParams).executeBy(taskExecutor)
}
}
private fun handleIgnoredUsers(userAccountDataIgnoredUsers: UserAccountDataIgnoredUsers) {
saveIgnoredUsersTask
.configureWith(SaveIgnoredUsersTask.Params(userAccountDataIgnoredUsers.content.ignoredUsers.keys.toList()))
.executeBy(taskExecutor)
// TODO If not initial sync, we should execute a init sync
}
}

View File

@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.session.sync.model
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountDataSync
// SyncResponse represents the request response for server sync v2.
@JsonClass(generateAdapter = true)

View File

@ -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.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.api.util.emptyJsonDict
@JsonClass(generateAdapter = true)
internal data class IgnoredUsersContent(
/**
* Required. The map of users to ignore. UserId -> empty object for future enhancement
*/
@Json(name = "ignored_users") val ignoredUsers: Map<String, JsonDict>
) {
companion object {
fun createWithUserIds(userIds: List<String>): IgnoredUsersContent {
return IgnoredUsersContent(
ignoredUsers = userIds.associateWith { emptyJsonDict }
)
}
}
}

View File

@ -14,9 +14,13 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.sync.model
package im.vector.matrix.android.internal.session.sync.model.accountdata
internal interface UserAccountData {
import com.squareup.moshi.Json
internal abstract class UserAccountData {
@Json(name = "type") abstract val type: String
companion object {
const val TYPE_IGNORED_USER_LIST = "m.ignored_user_list"

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.sync.model
package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class UserAccountDataDirectMessages(
@Json(name = "type") override val type: String = TYPE_DIRECT_MESSAGES,
@Json(name = "content") val content: Map<String, List<String>>
) : UserAccountData
) : UserAccountData()

View File

@ -14,12 +14,13 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.sync.model
package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class UserAccountDataFallback(
@Json(name = "type") override val type: String,
@Json(name = "content") val content: Map<String, Any>
) : UserAccountData
) : UserAccountData()

View File

@ -0,0 +1,26 @@
/*
* 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.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class UserAccountDataIgnoredUsers(
@Json(name = "type") override val type: String = TYPE_IGNORED_USER_LIST,
@Json(name = "content") val content: IgnoredUsersContent
) : UserAccountData()

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.sync.model
package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@ -22,5 +22,6 @@ import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
@JsonClass(generateAdapter = true)
internal data class UserAccountDataPushRules(
@Json(name = "type") override val type: String = TYPE_PUSH_RULES,
@Json(name = "content") val content: GetPushRulesResponse
) : UserAccountData
) : UserAccountData()

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.sync.model
package im.vector.matrix.android.internal.session.sync.model.accountdata
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

View File

@ -29,9 +29,12 @@ import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.api.util.Optional
import im.vector.matrix.android.api.util.toOptional
import im.vector.matrix.android.internal.database.mapper.asDomain
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
import im.vector.matrix.android.internal.database.model.IgnoredUserEntityFields
import im.vector.matrix.android.internal.database.model.UserEntity
import im.vector.matrix.android.internal.database.model.UserEntityFields
import im.vector.matrix.android.internal.database.query.where
import im.vector.matrix.android.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
import im.vector.matrix.android.internal.session.user.model.SearchUserTask
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
@ -40,8 +43,8 @@ import javax.inject.Inject
internal class DefaultUserService @Inject constructor(private val monarchy: Monarchy,
private val searchUserTask: SearchUserTask,
private val updateIgnoredUserIdsTask: UpdateIgnoredUserIdsTask,
private val taskExecutor: TaskExecutor) : UserService {
private val realmDataSourceFactory: Monarchy.RealmDataSourceFactory<UserEntity> by lazy {
monarchy.createDataSourceFactory { realm ->
realm.where(UserEntity::class.java)
@ -62,7 +65,7 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
override fun getUser(userId: String): User? {
val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() }
?: return null
?: return null
return userEntity.asDomain()
}
@ -117,4 +120,33 @@ internal class DefaultUserService @Inject constructor(private val monarchy: Mona
}
.executeBy(taskExecutor)
}
override fun liveIgnoredUsers(): LiveData<List<User>> {
return monarchy.findAllMappedWithChanges(
{ realm ->
realm.where(IgnoredUserEntity::class.java)
.isNotEmpty(IgnoredUserEntityFields.USER_ID)
.sort(IgnoredUserEntityFields.USER_ID)
},
{ getUser(it.userId) ?: User(userId = it.userId) }
)
}
override fun ignoreUserIds(userIds: List<String>, callback: MatrixCallback<Unit>): Cancelable {
val params = UpdateIgnoredUserIdsTask.Params(userIdsToIgnore = userIds.toList())
return updateIgnoredUserIdsTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
}
override fun unIgnoreUserIds(userIds: List<String>, callback: MatrixCallback<Unit>): Cancelable {
val params = UpdateIgnoredUserIdsTask.Params(userIdsToUnIgnore = userIds.toList())
return updateIgnoredUserIdsTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
}
}

View File

@ -21,6 +21,10 @@ import dagger.Module
import dagger.Provides
import im.vector.matrix.android.api.session.user.UserService
import im.vector.matrix.android.internal.session.SessionScope
import im.vector.matrix.android.internal.session.user.accountdata.DefaultSaveIgnoredUsersTask
import im.vector.matrix.android.internal.session.user.accountdata.DefaultUpdateIgnoredUserIdsTask
import im.vector.matrix.android.internal.session.user.accountdata.SaveIgnoredUsersTask
import im.vector.matrix.android.internal.session.user.accountdata.UpdateIgnoredUserIdsTask
import im.vector.matrix.android.internal.session.user.model.DefaultSearchUserTask
import im.vector.matrix.android.internal.session.user.model.SearchUserTask
import retrofit2.Retrofit
@ -43,4 +47,10 @@ internal abstract class UserModule {
@Binds
abstract fun bindSearchUserTask(searchUserTask: DefaultSearchUserTask): SearchUserTask
@Binds
abstract fun bindSaveIgnoredUsersTask(task: DefaultSaveIgnoredUsersTask): SaveIgnoredUsersTask
@Binds
abstract fun bindUpdateIgnoredUserIdsTask(task: DefaultUpdateIgnoredUserIdsTask): UpdateIgnoredUserIdsTask
}

View File

@ -0,0 +1,46 @@
/*
* 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.session.user.accountdata
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.awaitTransaction
import javax.inject.Inject
/**
* Save the ignored users list in DB
*/
internal interface SaveIgnoredUsersTask : Task<SaveIgnoredUsersTask.Params, Unit> {
data class Params(
val userIds: List<String>
)
}
internal class DefaultSaveIgnoredUsersTask @Inject constructor(private val monarchy: Monarchy) : SaveIgnoredUsersTask {
override suspend fun execute(params: SaveIgnoredUsersTask.Params) {
monarchy.awaitTransaction { realm ->
// clear current ignored users
realm.where(IgnoredUserEntity::class.java)
.findAll()
.deleteAllFromRealm()
// And save the new received list
params.userIds.forEach { realm.createObject(IgnoredUserEntity::class.java).apply { userId = it } }
}
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.session.user.accountdata
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.model.IgnoredUserEntity
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.sync.model.accountdata.IgnoredUsersContent
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
import im.vector.matrix.android.internal.task.Task
import javax.inject.Inject
internal interface UpdateIgnoredUserIdsTask : Task<UpdateIgnoredUserIdsTask.Params, Unit> {
data class Params(
val userIdsToIgnore: List<String> = emptyList(),
val userIdsToUnIgnore: List<String> = emptyList()
)
}
internal class DefaultUpdateIgnoredUserIdsTask @Inject constructor(private val accountDataApi: AccountDataAPI,
private val monarchy: Monarchy,
private val saveIgnoredUsersTask: SaveIgnoredUsersTask,
@UserId private val userId: String) : UpdateIgnoredUserIdsTask {
override suspend fun execute(params: UpdateIgnoredUserIdsTask.Params) {
// Get current list
val ignoredUserIds = monarchy.fetchAllMappedSync(
{ realm -> realm.where(IgnoredUserEntity::class.java) },
{ it.userId }
).toMutableSet()
val original = ignoredUserIds.toList()
ignoredUserIds.removeAll { it in params.userIdsToUnIgnore }
ignoredUserIds.addAll(params.userIdsToIgnore)
if (original == ignoredUserIds) {
// No change
return
}
val list = ignoredUserIds.toList()
val body = IgnoredUsersContent.createWithUserIds(list)
executeRequest<Unit> {
apiCall = accountDataApi.setAccountData(userId, UserAccountData.TYPE_IGNORED_USER_LIST, body)
}
// Update the DB right now (do not wait for the sync to come back with updated data, for a faster UI update)
saveIgnoredUsersTask.execute(SaveIgnoredUsersTask.Params(list))
}
}

View File

@ -18,7 +18,7 @@ package im.vector.matrix.android.internal.session.user.accountdata
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.sync.model.UserAccountData
import im.vector.matrix.android.internal.session.sync.model.accountdata.UserAccountData
import im.vector.matrix.android.internal.task.Task
import javax.inject.Inject
@ -29,6 +29,7 @@ internal interface UpdateUserAccountDataTask : Task<UpdateUserAccountDataTask.Pa
fun getData(): Any
}
// TODO Use [UserAccountDataDirectMessages] class?
data class DirectChatParams(override val type: String = UserAccountData.TYPE_DIRECT_MESSAGES,
private val directMessages: Map<String, List<String>>
) : Params {

View File

@ -217,6 +217,7 @@ android {
dependencies {
def epoxy_version = '3.8.0'
def fragment_version = '1.2.0-rc01'
def arrow_version = "0.8.2"
def coroutines_version = "1.3.2"
def markwon_version = '4.1.2'
@ -234,6 +235,8 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation "androidx.fragment:fragment:$fragment_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"
//Do not use beta2 at the moment, as it breaks things
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1'
implementation 'androidx.core:core-ktx:1.1.0'

View File

@ -0,0 +1,27 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.core.di
import androidx.fragment.app.Fragment
import dagger.MapKey
import kotlin.reflect.KClass
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
annotation class FragmentKey(val value: KClass<out Fragment>)

View File

@ -0,0 +1,197 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.core.di
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
import im.vector.riotx.features.crypto.verification.SASVerificationIncomingFragment
import im.vector.riotx.features.crypto.verification.SASVerificationShortCodeFragment
import im.vector.riotx.features.crypto.verification.SASVerificationStartFragment
import im.vector.riotx.features.crypto.verification.SASVerificationVerifiedFragment
import im.vector.riotx.features.home.HomeDetailFragment
import im.vector.riotx.features.home.HomeDrawerFragment
import im.vector.riotx.features.home.LoadingFragment
import im.vector.riotx.features.home.createdirect.CreateDirectRoomDirectoryUsersFragment
import im.vector.riotx.features.home.createdirect.CreateDirectRoomKnownUsersFragment
import im.vector.riotx.features.home.group.GroupListFragment
import im.vector.riotx.features.home.room.detail.RoomDetailFragment
import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.login.LoginFragment
import im.vector.riotx.features.login.LoginSsoFallbackFragment
import im.vector.riotx.features.reactions.EmojiSearchResultFragment
import im.vector.riotx.features.roomdirectory.PublicRoomsFragment
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomFragment
import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
import im.vector.riotx.features.settings.*
import im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment
import im.vector.riotx.features.settings.push.PushGatewaysFragment
@Module
interface FragmentModule {
/**
* Fragments with @IntoMap will be injected by this factory
*/
@Binds
fun bindFragmentFactory(factory: VectorFragmentFactory): FragmentFactory
@Binds
@IntoMap
@FragmentKey(RoomListFragment::class)
fun bindRoomListFragment(fragment: RoomListFragment): Fragment
@Binds
@IntoMap
@FragmentKey(GroupListFragment::class)
fun bindGroupListFragment(fragment: GroupListFragment): Fragment
@Binds
@IntoMap
@FragmentKey(RoomDetailFragment::class)
fun bindRoomDetailFragment(fragment: RoomDetailFragment): Fragment
@Binds
@IntoMap
@FragmentKey(RoomDirectoryPickerFragment::class)
fun bindRoomDirectoryPickerFragment(fragment: RoomDirectoryPickerFragment): Fragment
@Binds
@IntoMap
@FragmentKey(CreateRoomFragment::class)
fun bindCreateRoomFragment(fragment: CreateRoomFragment): Fragment
@Binds
@IntoMap
@FragmentKey(RoomPreviewNoPreviewFragment::class)
fun bindRoomPreviewNoPreviewFragment(fragment: RoomPreviewNoPreviewFragment): Fragment
@Binds
@IntoMap
@FragmentKey(KeysBackupSettingsFragment::class)
fun bindKeysBackupSettingsFragment(fragment: KeysBackupSettingsFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LoadingFragment::class)
fun bindLoadingFragment(fragment: LoadingFragment): Fragment
@Binds
@IntoMap
@FragmentKey(HomeDrawerFragment::class)
fun bindHomeDrawerFragment(fragment: HomeDrawerFragment): Fragment
@Binds
@IntoMap
@FragmentKey(HomeDetailFragment::class)
fun bindHomeDetailFragment(fragment: HomeDetailFragment): Fragment
@Binds
@IntoMap
@FragmentKey(EmojiSearchResultFragment::class)
fun bindEmojiSearchResultFragment(fragment: EmojiSearchResultFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragment::class)
fun bindLoginFragment(fragment: LoginFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LoginSsoFallbackFragment::class)
fun bindLoginSsoFallbackFragment(fragment: LoginSsoFallbackFragment): Fragment
@Binds
@IntoMap
@FragmentKey(CreateDirectRoomDirectoryUsersFragment::class)
fun bindCreateDirectRoomDirectoryUsersFragment(fragment: CreateDirectRoomDirectoryUsersFragment): Fragment
@Binds
@IntoMap
@FragmentKey(CreateDirectRoomKnownUsersFragment::class)
fun bindCreateDirectRoomKnownUsersFragment(fragment: CreateDirectRoomKnownUsersFragment): Fragment
@Binds
@IntoMap
@FragmentKey(PushGatewaysFragment::class)
fun bindPushGatewaysFragment(fragment: PushGatewaysFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsNotificationsTroubleshootFragment::class)
fun bindVectorSettingsNotificationsTroubleshootFragment(fragment: VectorSettingsNotificationsTroubleshootFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsAdvancedNotificationPreferenceFragment::class)
fun bindVectorSettingsAdvancedNotificationPreferenceFragment(fragment: VectorSettingsAdvancedNotificationPreferenceFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsNotificationPreferenceFragment::class)
fun bindVectorSettingsNotificationPreferenceFragment(fragment: VectorSettingsNotificationPreferenceFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsPreferencesFragment::class)
fun bindVectorSettingsPreferencesFragment(fragment: VectorSettingsPreferencesFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsSecurityPrivacyFragment::class)
fun bindVectorSettingsSecurityPrivacyFragment(fragment: VectorSettingsSecurityPrivacyFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsHelpAboutFragment::class)
fun bindVectorSettingsHelpAboutFragment(fragment: VectorSettingsHelpAboutFragment): Fragment
@Binds
@IntoMap
@FragmentKey(VectorSettingsIgnoredUsersFragment::class)
fun bindVectorSettingsIgnoredUsersFragment(fragment: VectorSettingsIgnoredUsersFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SASVerificationIncomingFragment::class)
fun bindSASVerificationIncomingFragment(fragment: SASVerificationIncomingFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SASVerificationShortCodeFragment::class)
fun bindSASVerificationShortCodeFragment(fragment: SASVerificationShortCodeFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SASVerificationVerifiedFragment::class)
fun bindSASVerificationVerifiedFragment(fragment: SASVerificationVerifiedFragment): Fragment
@Binds
@IntoMap
@FragmentKey(SASVerificationStartFragment::class)
fun bindSASVerificationStartFragment(fragment: SASVerificationStartFragment): Fragment
@Binds
@IntoMap
@FragmentKey(PublicRoomsFragment::class)
fun bindPublicRoomsFragment(fragment: PublicRoomsFragment): Fragment
}

View File

@ -17,42 +17,26 @@
package im.vector.riotx.core.di
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.FragmentFactory
import androidx.lifecycle.ViewModelProvider
import dagger.BindsInstance
import dagger.Component
import im.vector.fragments.keysbackup.restore.KeysBackupRestoreFromPassphraseFragment
import im.vector.riotx.core.preference.UserAvatarPreference
import im.vector.riotx.features.MainActivity
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromKeyFragment
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreSuccessFragment
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupSettingsFragment
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep1Fragment
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep2Fragment
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupStep3Fragment
import im.vector.riotx.features.crypto.verification.SASVerificationIncomingFragment
import im.vector.riotx.features.home.HomeActivity
import im.vector.riotx.features.home.HomeDetailFragment
import im.vector.riotx.features.home.HomeDrawerFragment
import im.vector.riotx.features.home.HomeModule
import im.vector.riotx.features.home.createdirect.CreateDirectRoomActivity
import im.vector.riotx.features.home.createdirect.CreateDirectRoomDirectoryUsersFragment
import im.vector.riotx.features.home.createdirect.CreateDirectRoomKnownUsersFragment
import im.vector.riotx.features.home.group.GroupListFragment
import im.vector.riotx.features.home.room.detail.RoomDetailFragment
import im.vector.riotx.features.home.room.detail.readreceipts.DisplayReadReceiptsBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.action.MessageActionsBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.edithistory.ViewEditHistoryBottomSheet
import im.vector.riotx.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet
import im.vector.riotx.features.home.room.filtered.FilteredRoomsActivity
import im.vector.riotx.features.home.room.list.actions.RoomListQuickActionsBottomSheet
import im.vector.riotx.features.home.room.list.RoomListFragment
import im.vector.riotx.features.home.room.list.RoomListModule
import im.vector.riotx.features.invite.VectorInviteView
import im.vector.riotx.features.link.LinkHandlerActivity
import im.vector.riotx.features.login.LoginActivity
import im.vector.riotx.features.login.LoginFragment
import im.vector.riotx.features.login.LoginSsoFallbackFragment
import im.vector.riotx.features.media.ImageMediaViewerActivity
import im.vector.riotx.features.media.VideoMediaViewerActivity
import im.vector.riotx.features.navigation.Navigator
@ -60,16 +44,10 @@ import im.vector.riotx.features.rageshake.BugReportActivity
import im.vector.riotx.features.rageshake.BugReporter
import im.vector.riotx.features.rageshake.RageShake
import im.vector.riotx.features.reactions.EmojiReactionPickerActivity
import im.vector.riotx.features.reactions.EmojiSearchResultFragment
import im.vector.riotx.features.reactions.widget.ReactionButton
import im.vector.riotx.features.roomdirectory.PublicRoomsFragment
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomFragment
import im.vector.riotx.features.roomdirectory.picker.RoomDirectoryPickerFragment
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewNoPreviewFragment
import im.vector.riotx.features.settings.*
import im.vector.riotx.features.settings.push.PushGatewaysFragment
import im.vector.riotx.features.share.IncomingShareActivity
import im.vector.riotx.features.ui.UiStateRepository
@ -80,6 +58,7 @@ import im.vector.riotx.features.ui.UiStateRepository
modules = [
AssistedInjectModule::class,
ViewModelModule::class,
FragmentModule::class,
HomeModule::class,
RoomListModule::class
]
@ -89,6 +68,8 @@ interface ScreenComponent {
fun activeSessionHolder(): ActiveSessionHolder
fun fragmentFactory(): FragmentFactory
fun viewModelFactory(): ViewModelProvider.Factory
fun bugReporter(): BugReporter
@ -101,22 +82,6 @@ interface ScreenComponent {
fun inject(activity: HomeActivity)
fun inject(roomDetailFragment: RoomDetailFragment)
fun inject(roomListFragment: RoomListFragment)
fun inject(groupListFragment: GroupListFragment)
fun inject(roomDirectoryPickerFragment: RoomDirectoryPickerFragment)
fun inject(roomPreviewNoPreviewFragment: RoomPreviewNoPreviewFragment)
fun inject(keysBackupSettingsFragment: KeysBackupSettingsFragment)
fun inject(homeDrawerFragment: HomeDrawerFragment)
fun inject(homeDetailFragment: HomeDetailFragment)
fun inject(messageActionsBottomSheet: MessageActionsBottomSheet)
fun inject(viewReactionsBottomSheet: ViewReactionsBottomSheet)
@ -125,30 +90,8 @@ interface ScreenComponent {
fun inject(vectorSettingsActivity: VectorSettingsActivity)
fun inject(createRoomFragment: CreateRoomFragment)
fun inject(keysBackupManageActivity: KeysBackupManageActivity)
fun inject(keysBackupRestoreFromKeyFragment: KeysBackupRestoreFromKeyFragment)
fun inject(keysBackupRestoreFromPassphraseFragment: KeysBackupRestoreFromPassphraseFragment)
fun inject(keysBackupRestoreSuccessFragment: KeysBackupRestoreSuccessFragment)
fun inject(keysBackupSetupStep1Fragment: KeysBackupSetupStep1Fragment)
fun inject(keysBackupSetupStep2Fragment: KeysBackupSetupStep2Fragment)
fun inject(keysBackupSetupStep3Fragment: KeysBackupSetupStep3Fragment)
fun inject(publicRoomsFragment: PublicRoomsFragment)
fun inject(loginFragment: LoginFragment)
fun inject(loginSsoFallbackFragment: LoginSsoFallbackFragment)
fun inject(sasVerificationIncomingFragment: SASVerificationIncomingFragment)
fun inject(emojiReactionPickerActivity: EmojiReactionPickerActivity)
fun inject(loginActivity: LoginActivity)
@ -171,26 +114,8 @@ interface ScreenComponent {
fun inject(videoMediaViewerActivity: VideoMediaViewerActivity)
fun inject(vectorSettingsNotificationPreferenceFragment: VectorSettingsNotificationPreferenceFragment)
fun inject(vectorSettingsPreferencesFragment: VectorSettingsPreferencesFragment)
fun inject(vectorSettingsAdvancedNotificationPreferenceFragment: VectorSettingsAdvancedNotificationPreferenceFragment)
fun inject(vectorSettingsSecurityPrivacyFragment: VectorSettingsSecurityPrivacyFragment)
fun inject(vectorSettingsHelpAboutFragment: VectorSettingsHelpAboutFragment)
fun inject(userAvatarPreference: UserAvatarPreference)
fun inject(vectorSettingsNotificationsTroubleshootFragment: VectorSettingsNotificationsTroubleshootFragment)
fun inject(pushGatewaysFragment: PushGatewaysFragment)
fun inject(createDirectRoomKnownUsersFragment: CreateDirectRoomKnownUsersFragment)
fun inject(createDirectRoomDirectoryUsersFragment: CreateDirectRoomDirectoryUsersFragment)
fun inject(createDirectRoomActivity: CreateDirectRoomActivity)
fun inject(displayReadReceiptsBottomSheet: DisplayReadReceiptsBottomSheet)
@ -201,8 +126,6 @@ interface ScreenComponent {
fun inject(roomListActionsBottomSheet: RoomListQuickActionsBottomSheet)
fun inject(emojiSearchResultFragment: EmojiSearchResultFragment)
@Component.Factory
interface Factory {
fun create(vectorComponent: VectorComponent,

View File

@ -0,0 +1,43 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package im.vector.riotx.core.di
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Provider
/**
* FragmentFactory which uses Dagger to create the instances.
*/
class VectorFragmentFactory @Inject constructor(
private val creators: @JvmSuppressWildcards Map<Class<out Fragment>, Provider<Fragment>>
) : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
val fragmentClass = loadFragmentClass(classLoader, className)
val creator: Provider<out Fragment>? = creators[fragmentClass]
return if (creator == null) {
Timber.v("Unknown model class: $className, fallback to default instance")
super.instantiate(classLoader, className)
} else {
creator.get()
}
}
}

View File

@ -16,21 +16,40 @@
package im.vector.riotx.core.extensions
import androidx.appcompat.app.AppCompatActivity
import android.os.Parcelable
import androidx.fragment.app.Fragment
import im.vector.riotx.core.platform.VectorBaseActivity
fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int) {
fun VectorBaseActivity.addFragment(frameId: Int, fragment: Fragment) {
supportFragmentManager.inTransaction { add(frameId, fragment) }
}
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int, tag: String? = null) {
fun <T : Fragment> VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
supportFragmentManager.inTransaction {
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun VectorBaseActivity.replaceFragment(frameId: Int, fragment: Fragment, tag: String? = null) {
supportFragmentManager.inTransaction { replace(frameId, fragment, tag) }
}
fun AppCompatActivity.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
fun <T : Fragment> VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
supportFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
supportFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}
fun AppCompatActivity.hideKeyboard() {
fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
supportFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
}
}
fun VectorBaseActivity.hideKeyboard() {
currentFocus?.hideKeyboard()
}

View File

@ -16,28 +16,66 @@
package im.vector.riotx.core.extensions
import android.os.Parcelable
import androidx.fragment.app.Fragment
import im.vector.riotx.core.platform.VectorBaseFragment
fun Fragment.addFragment(fragment: Fragment, frameId: Int) {
fragmentManager?.inTransaction { add(frameId, fragment) }
fun VectorBaseFragment.addFragment(frameId: Int, fragment: Fragment) {
parentFragmentManager.inTransaction { add(frameId, fragment) }
}
fun Fragment.replaceFragment(fragment: Fragment, frameId: Int) {
fragmentManager?.inTransaction { replace(frameId, fragment) }
fun <T : Fragment> VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
parentFragmentManager.inTransaction {
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
fragmentManager?.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
fun VectorBaseFragment.replaceFragment(frameId: Int, fragment: Fragment) {
parentFragmentManager.inTransaction { replace(frameId, fragment) }
}
fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {
fun <T : Fragment> VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
parentFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
parentFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}
fun <T : Fragment> VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
parentFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
}
}
fun VectorBaseFragment.addChildFragment(frameId: Int, fragment: Fragment) {
childFragmentManager.inTransaction { add(frameId, fragment) }
}
fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) {
fun <T : Fragment> VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
childFragmentManager.inTransaction {
add(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun VectorBaseFragment.replaceChildFragment(frameId: Int, fragment: Fragment) {
childFragmentManager.inTransaction { replace(frameId, fragment) }
}
fun Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
fun <T : Fragment> VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
childFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag)
}
}
fun VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragment: Fragment, tag: String? = null) {
childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
}
fun <T : Fragment> VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class<T>, params: Parcelable? = null, tag: String? = null) {
childFragmentManager.inTransaction {
replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag)
}
}

View File

@ -19,6 +19,7 @@ package im.vector.riotx.core.platform
import android.content.Context
import android.content.res.Configuration
import android.os.Bundle
import android.os.Parcelable
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -34,6 +35,7 @@ import butterknife.BindView
import butterknife.ButterKnife
import butterknife.Unbinder
import com.airbnb.mvrx.BaseMvRxActivity
import com.airbnb.mvrx.MvRx
import com.bumptech.glide.util.Util
import com.google.android.material.snackbar.Snackbar
import im.vector.riotx.BuildConfig
@ -125,7 +127,7 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
}
Timber.v("Injecting dependencies into ${javaClass.simpleName} took $timeForInjection ms")
ThemeUtils.setActivityTheme(this, getOtherThemes())
supportFragmentManager.fragmentFactory = screenComponent.fragmentFactory()
super.onCreate(savedInstanceState)
viewModelFactory = screenComponent.viewModelFactory()
configurationViewModel = ViewModelProviders.of(this, viewModelFactory).get(ConfigurationViewModel::class.java)
@ -331,6 +333,10 @@ abstract class VectorBaseActivity : BaseMvRxActivity(), HasScreenInjector {
}
}
fun Parcelable?.toMvRxBundle(): Bundle? {
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
}
// ==============================================================================================
// Handle loading view (also called waiting view or spinner view)
// ==============================================================================================

View File

@ -63,6 +63,7 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
screenComponent = DaggerScreenComponent.factory().create(vectorBaseActivity.getVectorComponent(), vectorBaseActivity)
navigator = screenComponent.navigator()
viewModelFactory = screenComponent.viewModelFactory()
childFragmentManager.fragmentFactory = screenComponent.fragmentFactory()
injectWith(injector())
super.onAttach(context)
}
@ -134,7 +135,11 @@ abstract class VectorBaseFragment : BaseMvRxFragment(), HasScreenInjector {
}
protected fun setArguments(args: Parcelable? = null) {
arguments = args?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
arguments = args.toMvRxBundle()
}
fun Parcelable?.toMvRxBundle(): Bundle? {
return this?.let { Bundle().apply { putParcelable(MvRx.KEY_ARG, it) } }
}
@MainThread

View File

@ -1,54 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.core.platform
import androidx.annotation.CallSuper
import androidx.preference.PreferenceFragmentCompat
import im.vector.riotx.R
import im.vector.riotx.core.utils.toast
import timber.log.Timber
abstract class VectorPreferenceFragment : PreferenceFragmentCompat() {
val vectorActivity: VectorBaseActivity by lazy {
activity as VectorBaseActivity
}
abstract var titleRes: Int
/* ==========================================================================================
* Life cycle
* ========================================================================================== */
@CallSuper
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(titleRes)
Timber.v("onResume Fragment ${this.javaClass.simpleName}")
}
/* ==========================================================================================
* Protected
* ========================================================================================== */
protected fun notImplemented() {
// Snackbar cannot be display on PreferenceFragment
// Snackbar.make(view!!, R.string.not_implemented, Snackbar.LENGTH_SHORT)
activity?.toast(R.string.not_implemented)
}
}

View File

@ -16,13 +16,21 @@
package im.vector.riotx.core.platform
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.airbnb.mvrx.*
import im.vector.riotx.core.utils.LiveEvent
import io.reactivex.Observable
import io.reactivex.Single
abstract class VectorViewModel<S : MvRxState>(initialState: S)
: BaseMvRxViewModel<S>(initialState, false) {
// Generic handling of any request error
protected val _requestErrorLiveData = MutableLiveData<LiveEvent<Throwable>>()
val requestErrorLiveData: LiveData<LiveEvent<Throwable>>
get() = _requestErrorLiveData
/**
* This method does the same thing as the execute function, but it doesn't subscribe to the stream
* so you can use this in a switchMap or a flatMap

View File

@ -22,9 +22,10 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import im.vector.fragments.keysbackup.restore.KeysBackupRestoreFromPassphraseFragment
import im.vector.riotx.R
import im.vector.riotx.core.extensions.addFragmentToBackstack
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.SimpleFragmentActivity
class KeysBackupRestoreActivity : SimpleFragmentActivity() {
@ -49,13 +50,9 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
if (keyVersion != null && supportFragmentManager.fragments.isEmpty()) {
val isBackupCreatedFromPassphrase = keyVersion.getAuthDataAsMegolmBackupAuthData()?.privateKeySalt != null
if (isBackupCreatedFromPassphrase) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupRestoreFromPassphraseFragment.newInstance())
.commitNow()
replaceFragment(R.id.container, KeysBackupRestoreFromPassphraseFragment::class.java)
} else {
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupRestoreFromKeyFragment.newInstance())
.commitNow()
replaceFragment(R.id.container, KeysBackupRestoreFromKeyFragment::class.java)
}
}
})
@ -80,16 +77,11 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
viewModel.navigateEvent.observeEvent(this) { uxStateEvent ->
when (uxStateEvent) {
KeysBackupRestoreSharedViewModel.NAVIGATE_TO_RECOVER_WITH_KEY -> {
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupRestoreFromKeyFragment.newInstance())
.addToBackStack(null)
.commit()
addFragmentToBackstack(R.id.container, KeysBackupRestoreFromKeyFragment::class.java)
}
KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupRestoreSuccessFragment.newInstance())
.commit()
replaceFragment(R.id.container, KeysBackupRestoreSuccessFragment::class.java)
}
}
}

View File

@ -28,15 +28,15 @@ import butterknife.OnClick
import butterknife.OnTextChanged
import com.google.android.material.textfield.TextInputLayout
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.startImportTextFromFileIntent
import timber.log.Timber
import javax.inject.Inject
class KeysBackupRestoreFromKeyFragment : VectorBaseFragment() {
class KeysBackupRestoreFromKeyFragment @Inject constructor()
: VectorBaseFragment() {
companion object {
fun newInstance() = KeysBackupRestoreFromKeyFragment()
private const val REQUEST_TEXT_FILE_GET = 1
}
@ -51,10 +51,6 @@ class KeysBackupRestoreFromKeyFragment : VectorBaseFragment() {
@BindView(R.id.keys_restore_key_enter_edittext)
lateinit var mKeyTextEdit: EditText
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreFromKeyViewModel::class.java)
@ -72,7 +68,7 @@ class KeysBackupRestoreFromKeyFragment : VectorBaseFragment() {
}
mKeyInputLayout.error = viewModel.recoveryCodeErrorText.value
viewModel.recoveryCodeErrorText.observe(this, Observer { newValue ->
viewModel.recoveryCodeErrorText.observe(viewLifecycleOwner, Observer { newValue ->
mKeyInputLayout.error = newValue
})
}

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.fragments.keysbackup.restore
package im.vector.riotx.features.crypto.keysbackup.restore
import android.content.Context
import android.os.Bundle
@ -33,13 +33,11 @@ import butterknife.OnClick
import butterknife.OnTextChanged
import com.google.android.material.textfield.TextInputLayout
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.showPassword
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreFromPassphraseViewModel
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreSharedViewModel
import javax.inject.Inject
class KeysBackupRestoreFromPassphraseFragment : VectorBaseFragment() {
class KeysBackupRestoreFromPassphraseFragment @Inject constructor(): VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_passphrase
@ -63,14 +61,6 @@ class KeysBackupRestoreFromPassphraseFragment : VectorBaseFragment() {
viewModel.showPasswordMode.value = !(viewModel.showPasswordMode.value ?: false)
}
companion object {
fun newInstance() = KeysBackupRestoreFromPassphraseFragment()
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -79,13 +69,13 @@ class KeysBackupRestoreFromPassphraseFragment : VectorBaseFragment() {
ViewModelProviders.of(this, viewModelFactory).get(KeysBackupRestoreSharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
viewModel.passphraseErrorText.observe(this, Observer { newValue ->
viewModel.passphraseErrorText.observe(viewLifecycleOwner, Observer { newValue ->
mPassphraseInputLayout.error = newValue
})
helperTextWithLink.text = spannableStringForHelperText(context!!)
viewModel.showPasswordMode.observe(this, Observer {
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
val shouldBeVisible = it ?: false
mPassphraseTextEdit.showPassword(shouldBeVisible)
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)

View File

@ -21,11 +21,11 @@ import androidx.lifecycle.ViewModelProviders
import butterknife.BindView
import butterknife.OnClick
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.LiveEvent
import javax.inject.Inject
class KeysBackupRestoreSuccessFragment : VectorBaseFragment() {
class KeysBackupRestoreSuccessFragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_success
@ -36,10 +36,6 @@ class KeysBackupRestoreSuccessFragment : VectorBaseFragment() {
private lateinit var sharedViewModel: KeysBackupRestoreSharedViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
sharedViewModel = activity?.run {
@ -62,8 +58,4 @@ class KeysBackupRestoreSuccessFragment : VectorBaseFragment() {
fun onDone() {
sharedViewModel.importRoomKeysFinishWithResult.value = LiveEvent(sharedViewModel.importKeyResult!!)
}
companion object {
fun newInstance() = KeysBackupRestoreSuccessFragment()
}
}

View File

@ -23,6 +23,7 @@ import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.viewModel
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.SimpleFragmentActivity
import im.vector.riotx.core.platform.WaitingViewData
import javax.inject.Inject
@ -49,10 +50,7 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
override fun initUiAndData() {
super.initUiAndData()
if (supportFragmentManager.fragments.isEmpty()) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupSettingsFragment.newInstance())
.commitNow()
replaceFragment(R.id.container, KeysBackupSettingsFragment::class.java)
viewModel.init()
}

View File

@ -21,29 +21,20 @@ import androidx.appcompat.app.AlertDialog
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import im.vector.riotx.features.crypto.keysbackup.setup.KeysBackupSetupActivity
import kotlinx.android.synthetic.main.fragment_keys_backup_settings.*
import javax.inject.Inject
class KeysBackupSettingsFragment : VectorBaseFragment(),
KeysBackupSettingsRecyclerViewController.Listener {
companion object {
fun newInstance() = KeysBackupSettingsFragment()
}
class KeysBackupSettingsFragment @Inject constructor(private val keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController)
: VectorBaseFragment(),
KeysBackupSettingsRecyclerViewController.Listener {
override fun getLayoutResId() = R.layout.fragment_keys_backup_settings
@Inject lateinit var keysBackupSettingsRecyclerViewController: KeysBackupSettingsRecyclerViewController
private val viewModel: KeysBackupSettingsViewModel by activityViewModel()
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -26,6 +26,7 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.riotx.R
import im.vector.riotx.core.dialogs.ExportKeysDialog
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.SimpleFragmentActivity
import im.vector.riotx.core.utils.*
import im.vector.riotx.features.crypto.keys.KeysExporter
@ -39,9 +40,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
override fun initUiAndData() {
super.initUiAndData()
if (isFirstCreation()) {
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupSetupStep1Fragment.newInstance())
.commitNow()
replaceFragment(R.id.container, KeysBackupSetupStep1Fragment::class.java)
}
viewModel = ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java)
@ -67,15 +66,11 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
when (uxStateEvent) {
KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_2 -> {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupSetupStep2Fragment.newInstance())
.commit()
replaceFragment(R.id.container, KeysBackupSetupStep2Fragment::class.java)
}
KeysBackupSetupSharedViewModel.NAVIGATE_TO_STEP_3 -> {
supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
supportFragmentManager.beginTransaction()
.replace(R.id.container, KeysBackupSetupStep3Fragment.newInstance())
.commit()
replaceFragment(R.id.container, KeysBackupSetupStep3Fragment::class.java)
}
KeysBackupSetupSharedViewModel.NAVIGATE_FINISH -> {
val resultIntent = Intent()

View File

@ -25,15 +25,11 @@ import androidx.lifecycle.ViewModelProviders
import butterknife.BindView
import butterknife.OnClick
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.LiveEvent
import javax.inject.Inject
class KeysBackupSetupStep1Fragment : VectorBaseFragment() {
companion object {
fun newInstance() = KeysBackupSetupStep1Fragment()
}
class KeysBackupSetupStep1Fragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step1
@ -45,10 +41,6 @@ class KeysBackupSetupStep1Fragment : VectorBaseFragment() {
@BindView(R.id.keys_backup_setup_step1_manualExport)
lateinit var manualExportButton: Button
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -56,7 +48,7 @@ class KeysBackupSetupStep1Fragment : VectorBaseFragment() {
ViewModelProviders.of(this, viewModelFactory).get(KeysBackupSetupSharedViewModel::class.java)
} ?: throw Exception("Invalid Activity")
viewModel.showManualExport.observe(this, Observer {
viewModel.showManualExport.observe(viewLifecycleOwner, Observer {
val showOption = it ?: false
// Can't use isVisible because the kotlin compiler will crash with Back-end (JVM) Internal error: wrong code generated
advancedOptionText.visibility = if (showOption) View.VISIBLE else View.GONE

View File

@ -30,13 +30,13 @@ import butterknife.OnTextChanged
import com.google.android.material.textfield.TextInputLayout
import com.nulabinc.zxcvbn.Zxcvbn
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.showPassword
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.ui.views.PasswordStrengthBar
import im.vector.riotx.features.settings.VectorLocale
import javax.inject.Inject
class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
class KeysBackupSetupStep2Fragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step2
@ -76,10 +76,6 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
private lateinit var viewModel: KeysBackupSetupSharedViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -96,7 +92,7 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
* ========================================================================================== */
private fun bindViewToViewModel() {
viewModel.passwordStrength.observe(this, Observer { strength ->
viewModel.passwordStrength.observe(viewLifecycleOwner, Observer { strength ->
if (strength == null) {
mPassphraseProgressLevel.strength = 0
mPassphraseInputLayout.error = null
@ -120,7 +116,7 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
}
})
viewModel.passphrase.observe(this, Observer<String> { newValue ->
viewModel.passphrase.observe(viewLifecycleOwner, Observer<String> { newValue ->
if (newValue.isEmpty()) {
viewModel.passwordStrength.value = null
} else {
@ -135,21 +131,21 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
mPassphraseTextEdit.setText(viewModel.passphrase.value)
viewModel.passphraseError.observe(this, Observer {
viewModel.passphraseError.observe(viewLifecycleOwner, Observer {
TransitionManager.beginDelayedTransition(rootGroup)
mPassphraseInputLayout.error = it
})
mPassphraseConfirmTextEdit.setText(viewModel.confirmPassphrase.value)
viewModel.showPasswordMode.observe(this, Observer {
viewModel.showPasswordMode.observe(viewLifecycleOwner, Observer {
val shouldBeVisible = it ?: false
mPassphraseTextEdit.showPassword(shouldBeVisible)
mPassphraseConfirmTextEdit.showPassword(shouldBeVisible)
mPassphraseReveal.setImageResource(if (shouldBeVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
})
viewModel.confirmPassphraseError.observe(this, Observer {
viewModel.confirmPassphraseError.observe(viewLifecycleOwner, Observer {
TransitionManager.beginDelayedTransition(rootGroup)
mPassphraseConfirmInputLayout.error = it
})
@ -203,8 +199,4 @@ class KeysBackupSetupStep2Fragment : VectorBaseFragment() {
}
}
}
companion object {
fun newInstance() = KeysBackupSetupStep2Fragment()
}
}

View File

@ -30,7 +30,6 @@ import butterknife.BindView
import butterknife.OnClick
import com.google.android.material.bottomsheet.BottomSheetDialog
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.files.addEntryToDownloadManager
import im.vector.riotx.core.files.writeToFile
import im.vector.riotx.core.platform.VectorBaseFragment
@ -40,8 +39,9 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import javax.inject.Inject
class KeysBackupSetupStep3Fragment : VectorBaseFragment() {
class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3
@ -54,16 +54,8 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() {
@BindView(R.id.keys_backup_setup_step3_line2_text)
lateinit var mRecoveryKeyLabel2TextView: TextView
companion object {
fun newInstance() = KeysBackupSetupStep3Fragment()
}
private lateinit var viewModel: KeysBackupSetupSharedViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = activity?.run {
@ -72,7 +64,7 @@ class KeysBackupSetupStep3Fragment : VectorBaseFragment() {
viewModel.shouldPromptOnBack = false
viewModel.passphrase.observe(this, Observer {
viewModel.passphrase.observe(viewLifecycleOwner, Observer {
if (it.isNullOrBlank()) {
// Recovery was generated, so show key and options to save
mRecoveryKeyLabel2TextView.text = getString(R.string.keys_backup_setup_step3_text_line2_no_passphrase)

View File

@ -27,6 +27,7 @@ import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTr
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
import im.vector.matrix.android.api.session.crypto.sas.SasVerificationTxState
import im.vector.riotx.R
import im.vector.riotx.core.extensions.inTransaction
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.SimpleFragmentActivity
import im.vector.riotx.core.platform.WaitingViewData
@ -102,23 +103,23 @@ class SASVerificationActivity : SimpleFragmentActivity() {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT,
IncomingSasVerificationTransaction.UxState.WAIT_FOR_KEY_AGREEMENT -> {
supportActionBar?.setTitle(R.string.sas_incoming_request_title)
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationIncomingFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationIncomingFragment::class.java, null)
}
}
IncomingSasVerificationTransaction.UxState.WAIT_FOR_VERIFICATION,
IncomingSasVerificationTransaction.UxState.SHOW_SAS -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationShortCodeFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
}
}
IncomingSasVerificationTransaction.UxState.VERIFIED -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationVerifiedFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
}
}
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_ME,
IncomingSasVerificationTransaction.UxState.CANCELLED_BY_OTHER -> {
@ -133,23 +134,23 @@ class SASVerificationActivity : SimpleFragmentActivity() {
OutgoingSasVerificationRequest.UxState.UNKNOWN,
OutgoingSasVerificationRequest.UxState.WAIT_FOR_START,
OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationStartFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationStartFragment::class.java, null)
}
}
OutgoingSasVerificationRequest.UxState.SHOW_SAS,
OutgoingSasVerificationRequest.UxState.WAIT_FOR_VERIFICATION -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationShortCodeFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
}
}
OutgoingSasVerificationRequest.UxState.VERIFIED -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationVerifiedFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.no_anim, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
}
}
OutgoingSasVerificationRequest.UxState.CANCELLED_BY_ME,
OutgoingSasVerificationRequest.UxState.CANCELLED_BY_OTHER -> {
@ -172,16 +173,16 @@ class SASVerificationActivity : SimpleFragmentActivity() {
finish()
}
SasVerificationViewModel.NAVIGATE_SAS_DISPLAY -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationShortCodeFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationShortCodeFragment::class.java, null)
}
}
SasVerificationViewModel.NAVIGATE_SUCCESS -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
.replace(R.id.container, SASVerificationVerifiedFragment.newInstance())
.commitNow()
supportFragmentManager.inTransaction {
setCustomAnimations(R.anim.enter_from_right, R.anim.exit_fade_out)
replace(R.id.container, SASVerificationVerifiedFragment::class.java, null)
}
}
SasVerificationViewModel.NAVIGATE_CANCELLED -> {
val isCancelledByMe = viewModel.transaction?.state == SasVerificationTxState.Cancelled

View File

@ -24,16 +24,13 @@ import butterknife.BindView
import butterknife.OnClick
import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTransaction
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject
class SASVerificationIncomingFragment : VectorBaseFragment() {
companion object {
fun newInstance() = SASVerificationIncomingFragment()
}
class SASVerificationIncomingFragment @Inject constructor(
private var avatarRenderer: AvatarRenderer
) : VectorBaseFragment() {
@BindView(R.id.sas_incoming_request_user_display_name)
lateinit var otherUserDisplayNameTextView: TextView
@ -49,13 +46,8 @@ 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) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -74,7 +66,7 @@ class SASVerificationIncomingFragment : VectorBaseFragment() {
avatarRenderer.render(null, viewModel.otherUserId ?: "", viewModel.otherUserId, avatarImageView)
}
viewModel.transactionState.observe(this, Observer {
viewModel.transactionState.observe(viewLifecycleOwner, Observer {
val uxState = (viewModel.transaction as? IncomingSasVerificationTransaction)?.uxState
when (uxState) {
IncomingSasVerificationTransaction.UxState.SHOW_ACCEPT -> {

View File

@ -28,15 +28,12 @@ import im.vector.matrix.android.api.session.crypto.sas.IncomingSasVerificationTr
import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRequest
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseFragment
import javax.inject.Inject
class SASVerificationShortCodeFragment : VectorBaseFragment() {
class SASVerificationShortCodeFragment @Inject constructor(): VectorBaseFragment() {
private lateinit var viewModel: SasVerificationViewModel
companion object {
fun newInstance() = SASVerificationShortCodeFragment()
}
@BindView(R.id.sas_decimal_code)
lateinit var decimalTextView: TextView
@ -120,7 +117,7 @@ class SASVerificationShortCodeFragment : VectorBaseFragment() {
}
}
viewModel.transactionState.observe(this, Observer {
viewModel.transactionState.observe(viewLifecycleOwner, Observer {
if (viewModel.transaction is IncomingSasVerificationTransaction) {
val uxState = (viewModel.transaction as IncomingSasVerificationTransaction).uxState
when (uxState) {

View File

@ -31,12 +31,9 @@ import im.vector.matrix.android.api.session.crypto.sas.OutgoingSasVerificationRe
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import javax.inject.Inject
class SASVerificationStartFragment : VectorBaseFragment() {
companion object {
fun newInstance() = SASVerificationStartFragment()
}
class SASVerificationStartFragment @Inject constructor(): VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_sas_verification_start
@ -57,7 +54,7 @@ class SASVerificationStartFragment : VectorBaseFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
viewModel = ViewModelProviders.of(vectorBaseActivity, viewModelFactory).get(SasVerificationViewModel::class.java)
viewModel.transactionState.observe(this, Observer {
viewModel.transactionState.observe(viewLifecycleOwner, Observer {
val uxState = (viewModel.transaction as? OutgoingSasVerificationRequest)?.uxState
when (uxState) {
OutgoingSasVerificationRequest.UxState.WAIT_FOR_KEY_AGREEMENT -> {

View File

@ -20,15 +20,12 @@ import androidx.lifecycle.ViewModelProviders
import butterknife.OnClick
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseFragment
import javax.inject.Inject
class SASVerificationVerifiedFragment : VectorBaseFragment() {
class SASVerificationVerifiedFragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_sas_verification_verified
companion object {
fun newInstance() = SASVerificationVerifiedFragment()
}
private lateinit var viewModel: SasVerificationViewModel
override fun onActivityCreated(savedInstanceState: Bundle?) {

View File

@ -78,10 +78,8 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
navigationViewModel = ViewModelProviders.of(this).get(HomeNavigationViewModel::class.java)
drawerLayout.addDrawerListener(drawerListener)
if (isFirstCreation()) {
val homeDrawerFragment = HomeDrawerFragment.newInstance()
val loadingDetail = LoadingFragment.newInstance()
replaceFragment(loadingDetail, R.id.homeDetailFragmentContainer)
replaceFragment(homeDrawerFragment, R.id.homeDrawerFragmentContainer)
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
}
navigationViewModel.observe()
@ -90,8 +88,7 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
is Navigation.OpenDrawer -> drawerLayout.openDrawer(GravityCompat.START)
is Navigation.OpenGroup -> {
drawerLayout.closeDrawer(GravityCompat.START)
val homeDetailFragment = HomeDetailFragment.newInstance()
replaceFragment(homeDetailFragment, R.id.homeDetailFragmentContainer)
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
}
}
}

View File

@ -29,7 +29,7 @@ import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.keysbackup.KeysBackupState
import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.addChildFragmentToBackstack
import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.ui.views.KeysBackupBanner
@ -45,25 +45,21 @@ private const val INDEX_CATCHUP = 0
private const val INDEX_PEOPLE = 1
private const val INDEX_ROOMS = 2
class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
class HomeDetailFragment @Inject constructor(
private val session: Session,
val homeDetailViewModelFactory: HomeDetailViewModel.Factory,
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment(), KeysBackupBanner.Delegate {
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
private val viewModel: HomeDetailViewModel by fragmentViewModel()
private lateinit var navigationViewModel: HomeNavigationViewModel
@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
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -99,7 +95,7 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
model.init(session)
model.keysBackupState.observe(this, Observer { keysBackupState ->
model.keysBackupState.observe(viewLifecycleOwner, Observer { keysBackupState ->
when (keysBackupState) {
null ->
homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false)
@ -172,14 +168,13 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
private fun updateSelectedFragment(displayMode: RoomListFragment.DisplayMode) {
val fragmentTag = "FRAGMENT_TAG_${displayMode.name}"
var fragment = childFragmentManager.findFragmentByTag(fragmentTag)
val fragment = childFragmentManager.findFragmentByTag(fragmentTag)
if (fragment == null) {
fragment = RoomListFragment.newInstance(RoomListParams(displayMode))
val params = RoomListParams(displayMode)
addChildFragmentToBackstack(R.id.roomListContainer, RoomListFragment::class.java, params, fragmentTag)
} else {
addChildFragmentToBackstack(R.id.roomListContainer, fragment, fragmentTag)
}
childFragmentManager.beginTransaction()
.replace(R.id.roomListContainer, fragment, fragmentTag)
.addToBackStack(fragmentTag)
.commit()
}
/* ==========================================================================================
@ -201,11 +196,4 @@ class HomeDetailFragment : VectorBaseFragment(), KeysBackupBanner.Delegate {
unreadCounterBadgeViews[INDEX_ROOMS].render(UnreadCounterBadgeView.State(it.notificationCountRooms, it.notificationHighlightRooms))
syncStateView.render(it.syncState)
}
companion object {
fun newInstance(): HomeDetailFragment {
return HomeDetailFragment()
}
}
}

View File

@ -19,7 +19,6 @@ package im.vector.riotx.features.home
import android.os.Bundle
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.observeK
import im.vector.riotx.core.extensions.replaceChildFragment
import im.vector.riotx.core.platform.VectorBaseFragment
@ -27,29 +26,17 @@ import im.vector.riotx.features.home.group.GroupListFragment
import kotlinx.android.synthetic.main.fragment_home_drawer.*
import javax.inject.Inject
class HomeDrawerFragment : VectorBaseFragment() {
companion object {
fun newInstance(): HomeDrawerFragment {
return HomeDrawerFragment()
}
}
@Inject lateinit var session: Session
@Inject lateinit var avatarRenderer: AvatarRenderer
class HomeDrawerFragment @Inject constructor(
private val session: Session,
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_home_drawer
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) {
val groupListFragment = GroupListFragment.newInstance()
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
}
session.liveUser(session.myUserId).observeK(this) { optionalUser ->
val user = optionalUser?.getOrNull()

View File

@ -22,15 +22,9 @@ import android.view.View
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_loading.*
import javax.inject.Inject
class LoadingFragment : VectorBaseFragment() {
companion object {
fun newInstance(): LoadingFragment {
return LoadingFragment()
}
}
class LoadingFragment @Inject constructor(): VectorBaseFragment() {
override fun getLayoutResId() = R.layout.fragment_loading

View File

@ -58,18 +58,17 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
super.onCreate(savedInstanceState)
toolbar.visibility = View.GONE
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(CreateDirectRoomNavigationViewModel::class.java)
navigationViewModel
.observe()
navigationViewModel.observe()
.subscribe { navigation ->
when (navigation) {
is Navigation.UsersDirectory -> addFragmentToBackstack(CreateDirectRoomDirectoryUsersFragment(), R.id.container)
is Navigation.UsersDirectory -> addFragmentToBackstack(R.id.container, CreateDirectRoomDirectoryUsersFragment::class.java)
Navigation.Close -> finish()
Navigation.Previous -> onBackPressed()
}
}
.disposeOnDestroy()
if (isFirstCreation()) {
addFragment(CreateDirectRoomKnownUsersFragment(), R.id.container)
addFragment(R.id.container, CreateDirectRoomKnownUsersFragment::class.java)
}
viewModel.selectSubscribe(this, CreateDirectRoomViewState::createAndInviteState) {
renderCreateAndInviteState(it)

View File

@ -25,26 +25,22 @@ import com.airbnb.mvrx.withState
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.setupAsSearch
import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_create_direct_room_directory_users.*
import javax.inject.Inject
class CreateDirectRoomDirectoryUsersFragment : VectorBaseFragment(), DirectoryUsersController.Callback {
class CreateDirectRoomDirectoryUsersFragment @Inject constructor(
private val directRoomController: DirectoryUsersController
) : VectorBaseFragment(), DirectoryUsersController.Callback {
override fun getLayoutResId() = R.layout.fragment_create_direct_room_directory_users
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
@Inject lateinit var directRoomController: DirectoryUsersController
private lateinit var navigationViewModel: CreateDirectRoomNavigationViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navigationViewModel = ViewModelProviders.of(requireActivity(), viewModelFactory).get(CreateDirectRoomNavigationViewModel::class.java)

View File

@ -31,33 +31,26 @@ import com.google.android.material.chip.ChipGroup
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.hideKeyboard
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.extensions.setupAsSearch
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.DimensionConverter
import im.vector.riotx.features.home.AvatarRenderer
import kotlinx.android.synthetic.main.fragment_create_direct_room.*
import javax.inject.Inject
class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersController.Callback {
class CreateDirectRoomKnownUsersFragment @Inject constructor(
private val knownUsersController: KnownUsersController,
private val dimensionConverter: DimensionConverter
) : VectorBaseFragment(), KnownUsersController.Callback {
override fun getLayoutResId() = R.layout.fragment_create_direct_room
override fun getMenuRes() = R.menu.vector_create_direct_room
private val viewModel: CreateDirectRoomViewModel by activityViewModel()
@Inject lateinit var directRoomController: KnownUsersController
@Inject lateinit var avatarRenderer: AvatarRenderer
@Inject lateinit var dimensionConverter: DimensionConverter
private lateinit var navigationViewModel: CreateDirectRoomNavigationViewModel
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navigationViewModel = ViewModelProviders.of(requireActivity(), viewModelFactory).get(CreateDirectRoomNavigationViewModel::class.java)
@ -104,8 +97,8 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr
recyclerView.setHasFixedSize(true)
// Don't activate animation as we might have way to much item animation when filtering
recyclerView.itemAnimator = null
directRoomController.callback = this
recyclerView.setController(directRoomController)
knownUsersController.callback = this
recyclerView.setController(knownUsersController)
}
private fun setupFilterView() {
@ -134,7 +127,7 @@ class CreateDirectRoomKnownUsersFragment : VectorBaseFragment(), KnownUsersContr
}
override fun invalidate() = withState(viewModel) {
directRoomController.setData(it)
knownUsersController.setData(it)
}
private fun updateChipsView(data: SelectUserAction) {

View File

@ -23,7 +23,6 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.fragmentViewModel
import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.StateView
import im.vector.riotx.core.platform.VectorBaseFragment
@ -32,26 +31,16 @@ import im.vector.riotx.features.home.HomeNavigationViewModel
import kotlinx.android.synthetic.main.fragment_group_list.*
import javax.inject.Inject
class GroupListFragment : VectorBaseFragment(), GroupSummaryController.Callback {
companion object {
fun newInstance(): GroupListFragment {
return GroupListFragment()
}
}
class GroupListFragment @Inject constructor(
val groupListViewModelFactory: GroupListViewModel.Factory,
private val groupController: GroupSummaryController
) : VectorBaseFragment(), GroupSummaryController.Callback {
private lateinit var navigationViewModel: HomeNavigationViewModel
private val viewModel: GroupListViewModel by fragmentViewModel()
@Inject lateinit var groupListViewModelFactory: GroupListViewModel.Factory
@Inject lateinit var groupController: GroupSummaryController
override fun getLayoutResId() = R.layout.fragment_group_list
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navigationViewModel = ViewModelProviders.of(requireActivity()).get(HomeNavigationViewModel::class.java)

View File

@ -50,7 +50,14 @@ sealed class RoomDetailActions {
data class ResendMessage(val eventId: String) : RoomDetailActions()
data class RemoveFailedEcho(val eventId: String) : RoomDetailActions()
data class ReportContent(val eventId: String, val reason: String, val spam: Boolean = false, val inappropriate: Boolean = false) : RoomDetailActions()
data class ReportContent(
val eventId: String,
val senderId: String?,
val reason: String,
val spam: Boolean = false,
val inappropriate: Boolean = false) : RoomDetailActions()
data class IgnoreUser(val userId: String?) : RoomDetailActions()
object ClearSendQueue : RoomDetailActions()
object ResendAll : RoomDetailActions()

View File

@ -38,8 +38,7 @@ class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
if (isFirstCreation()) {
val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
?: return
val roomDetailFragment = RoomDetailFragment.newInstance(roomDetailArgs)
replaceFragment(roomDetailFragment, R.id.roomDetailContainer)
replaceFragment(R.id.roomDetailContainer, RoomDetailFragment::class.java, roomDetailArgs)
}
}

View File

@ -68,7 +68,6 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.dialogs.withColoredButton
import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer
import im.vector.riotx.core.error.ErrorFormatter
@ -134,7 +133,22 @@ data class RoomDetailArgs(
private const val REACTION_SELECT_REQUEST_CODE = 0
class RoomDetailFragment :
class RoomDetailFragment @Inject constructor(
private val session: Session,
private val avatarRenderer: AvatarRenderer,
private val timelineEventController: TimelineEventController,
private val commandAutocompletePolicy: CommandAutocompletePolicy,
private val autocompleteCommandPresenter: AutocompleteCommandPresenter,
private val autocompleteUserPresenter: AutocompleteUserPresenter,
private val permalinkHandler: PermalinkHandler,
private val notificationDrawerManager: NotificationDrawerManager,
val roomDetailViewModelFactory: RoomDetailViewModel.Factory,
val textComposerViewModelFactory: TextComposerViewModel.Factory,
private val errorFormatter: ErrorFormatter,
private val eventHtmlRenderer: EventHtmlRenderer,
private val vectorPreferences: VectorPreferences,
private val readMarkerHelper: ReadMarkerHelper
) :
VectorBaseFragment(),
TimelineEventController.Callback,
AutocompleteUserPresenter.Callback,
@ -145,12 +159,6 @@ class RoomDetailFragment :
companion object {
fun newInstance(args: RoomDetailArgs): RoomDetailFragment {
return RoomDetailFragment().apply {
setArguments(args)
}
}
/**x
* Sanitize the display name.
*
@ -178,21 +186,6 @@ class RoomDetailFragment :
private val debouncer = Debouncer(createUIHandler())
@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
@Inject lateinit var autocompleteUserPresenter: AutocompleteUserPresenter
@Inject lateinit var permalinkHandler: PermalinkHandler
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
@Inject lateinit var roomDetailViewModelFactory: RoomDetailViewModel.Factory
@Inject lateinit var textComposerViewModelFactory: TextComposerViewModel.Factory
@Inject lateinit var errorFormatter: ErrorFormatter
@Inject lateinit var eventHtmlRenderer: EventHtmlRenderer
@Inject lateinit var vectorPreferences: VectorPreferences
@Inject lateinit var readMarkerHelper: ReadMarkerHelper
private lateinit var scrollOnNewMessageCallback: ScrollOnNewMessageCallback
private lateinit var scrollOnHighlightedEventCallback: ScrollOnHighlightedEventCallback
@ -211,10 +204,6 @@ class RoomDetailFragment :
private var lockSendButton = false
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
messageActionsDispatcher = ViewModelProviders.of(requireActivity()).get(MessageActionsDispatcher::class.java)
@ -771,7 +760,7 @@ class RoomDetailFragment :
.setView(layout)
.setPositiveButton(R.string.report_content_custom_submit) { _, _ ->
val reason = input.text.toString()
roomDetailViewModel.process(RoomDetailActions.ReportContent(action.eventId, reason))
roomDetailViewModel.process(RoomDetailActions.ReportContent(action.eventId, action.senderId, reason))
}
.setNegativeButton(R.string.cancel, null)
.show()
@ -795,7 +784,9 @@ class RoomDetailFragment :
.setTitle(R.string.content_reported_as_spam_title)
.setMessage(R.string.content_reported_as_spam_content)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.block_user) { _, _ -> vectorBaseActivity.notImplemented("block user") }
.setNegativeButton(R.string.block_user) { _, _ ->
roomDetailViewModel.process(RoomDetailActions.IgnoreUser(data.senderId))
}
.show()
.withColoredButton(DialogInterface.BUTTON_NEGATIVE)
}
@ -804,7 +795,9 @@ class RoomDetailFragment :
.setTitle(R.string.content_reported_as_inappropriate_title)
.setMessage(R.string.content_reported_as_inappropriate_content)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.block_user) { _, _ -> vectorBaseActivity.notImplemented("block user") }
.setNegativeButton(R.string.block_user) { _, _ ->
roomDetailViewModel.process(RoomDetailActions.IgnoreUser(data.senderId))
}
.show()
.withColoredButton(DialogInterface.BUTTON_NEGATIVE)
}
@ -813,7 +806,9 @@ class RoomDetailFragment :
.setTitle(R.string.content_reported_title)
.setMessage(R.string.content_reported_content)
.setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.block_user) { _, _ -> vectorBaseActivity.notImplemented("block user") }
.setNegativeButton(R.string.block_user) { _, _ ->
roomDetailViewModel.process(RoomDetailActions.IgnoreUser(data.senderId))
}
.show()
.withColoredButton(DialogInterface.BUTTON_NEGATIVE)
}
@ -962,6 +957,7 @@ class RoomDetailFragment :
val roomId = roomDetailArgs.roomId
this.view?.hideKeyboard()
MessageActionsBottomSheet
.newInstance(roomId, informationData)
.show(requireActivity().supportFragmentManager, "MESSAGE_CONTEXTUAL_ACTIONS")
@ -1137,10 +1133,12 @@ class RoomDetailFragment :
roomDetailViewModel.process(RoomDetailActions.RemoveFailedEcho(action.eventId))
}
is SimpleAction.ReportContentSpam -> {
roomDetailViewModel.process(RoomDetailActions.ReportContent(action.eventId, "This message is spam", spam = true))
roomDetailViewModel.process(RoomDetailActions.ReportContent(
action.eventId, action.senderId, "This message is spam", spam = true))
}
is SimpleAction.ReportContentInappropriate -> {
roomDetailViewModel.process(RoomDetailActions.ReportContent(action.eventId, "This message is inappropriate", inappropriate = true))
roomDetailViewModel.process(RoomDetailActions.ReportContent(
action.eventId, action.senderId, "This message is inappropriate", inappropriate = true))
}
is SimpleAction.ReportContentCustom -> {
promptReasonToReportContent(action)

View File

@ -157,6 +157,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
is RoomDetailActions.SetReadMarkerAction -> handleSetReadMarkerAction(action)
is RoomDetailActions.MarkAllAsRead -> handleMarkAllAsRead()
is RoomDetailActions.ReportContent -> handleReportContent(action)
is RoomDetailActions.IgnoreUser -> handleIgnoreUser(action)
}
}
@ -710,6 +711,22 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro
})
}
private fun handleIgnoreUser(action: RoomDetailActions.IgnoreUser) {
if (action.userId.isNullOrEmpty()) {
return
}
session.ignoreUserIds(listOf(action.userId), object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
_requestLiveData.postValue(LiveEvent(Success(action)))
}
override fun onFailure(failure: Throwable) {
_requestLiveData.postValue(LiveEvent(Fail(failure)))
}
})
}
private fun observeSyncState() {
session.rx()
.liveSyncState()

View File

@ -109,9 +109,9 @@ class MessageActionsEpoxyController @Inject constructor(private val stringProvid
if (action is SimpleAction.ReportContent && state.expendedReportContentMenu) {
// Special case for report content menu: add the submenu
listOf(
SimpleAction.ReportContentSpam(action.eventId),
SimpleAction.ReportContentInappropriate(action.eventId),
SimpleAction.ReportContentCustom(action.eventId)
SimpleAction.ReportContentSpam(action.eventId, action.senderId),
SimpleAction.ReportContentInappropriate(action.eventId, action.senderId),
SimpleAction.ReportContentCustom(action.eventId, action.senderId)
).forEachIndexed { indexReport, actionReport ->
bottomSheetItemAction {
id("actionReport_$indexReport")

View File

@ -263,7 +263,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted
if (session.myUserId != event.root.senderId && event.root.getClearType() == EventType.MESSAGE) {
// not sent by me
add(SimpleAction.ReportContent(eventId))
add(SimpleAction.ReportContent(eventId, event.root.senderId))
}
}
}

View File

@ -22,25 +22,63 @@ import im.vector.riotx.R
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
sealed class SimpleAction(@StringRes val titleRes: Int, @DrawableRes val iconResId: Int) {
data class AddReaction(val eventId: String) : SimpleAction(R.string.message_add_reaction, R.drawable.ic_add_reaction)
data class Copy(val content: String) : SimpleAction(R.string.copy, R.drawable.ic_copy)
data class Edit(val eventId: String) : SimpleAction(R.string.edit, R.drawable.ic_edit)
data class Quote(val eventId: String) : SimpleAction(R.string.quote, R.drawable.ic_quote)
data class Reply(val eventId: String) : SimpleAction(R.string.reply, R.drawable.ic_reply)
data class Share(val imageUrl: String) : SimpleAction(R.string.share, R.drawable.ic_share)
data class Resend(val eventId: String) : SimpleAction(R.string.global_retry, R.drawable.ic_refresh_cw)
data class Remove(val eventId: String) : SimpleAction(R.string.remove, R.drawable.ic_trash)
data class Delete(val eventId: String) : SimpleAction(R.string.delete, R.drawable.ic_delete)
data class Cancel(val eventId: String) : SimpleAction(R.string.cancel, R.drawable.ic_close_round)
data class ViewSource(val content: String) : SimpleAction(R.string.view_source, R.drawable.ic_view_source)
data class ViewDecryptedSource(val content: String) : SimpleAction(R.string.view_decrypted_source, R.drawable.ic_view_source)
data class CopyPermalink(val eventId: String) : SimpleAction(R.string.permalink, R.drawable.ic_permalink)
data class ReportContent(val eventId: String) : SimpleAction(R.string.report_content, R.drawable.ic_flag)
data class ReportContentSpam(val eventId: String) : SimpleAction(R.string.report_content_spam, R.drawable.ic_report_spam)
data class ReportContentInappropriate(val eventId: String) : SimpleAction(R.string.report_content_inappropriate, R.drawable.ic_report_inappropriate)
data class ReportContentCustom(val eventId: String) : SimpleAction(R.string.report_content_custom, R.drawable.ic_report_custom)
data class QuickReact(val eventId: String, val clickedOn: String, val add: Boolean) : SimpleAction(0, 0)
data class ViewReactions(val messageInformationData: MessageInformationData) : SimpleAction(R.string.message_view_reaction, R.drawable.ic_view_reactions)
data class AddReaction(val eventId: String) :
SimpleAction(R.string.message_add_reaction, R.drawable.ic_add_reaction)
data class Copy(val content: String) :
SimpleAction(R.string.copy, R.drawable.ic_copy)
data class Edit(val eventId: String) :
SimpleAction(R.string.edit, R.drawable.ic_edit)
data class Quote(val eventId: String) :
SimpleAction(R.string.quote, R.drawable.ic_quote)
data class Reply(val eventId: String) :
SimpleAction(R.string.reply, R.drawable.ic_reply)
data class Share(val imageUrl: String) :
SimpleAction(R.string.share, R.drawable.ic_share)
data class Resend(val eventId: String) :
SimpleAction(R.string.global_retry, R.drawable.ic_refresh_cw)
data class Remove(val eventId: String) :
SimpleAction(R.string.remove, R.drawable.ic_trash)
data class Delete(val eventId: String) :
SimpleAction(R.string.delete, R.drawable.ic_delete)
data class Cancel(val eventId: String) :
SimpleAction(R.string.cancel, R.drawable.ic_close_round)
data class ViewSource(val content: String) :
SimpleAction(R.string.view_source, R.drawable.ic_view_source)
data class ViewDecryptedSource(val content: String) :
SimpleAction(R.string.view_decrypted_source, R.drawable.ic_view_source)
data class CopyPermalink(val eventId: String) :
SimpleAction(R.string.permalink, R.drawable.ic_permalink)
data class ReportContent(val eventId: String, val senderId: String?) :
SimpleAction(R.string.report_content, R.drawable.ic_flag)
data class ReportContentSpam(val eventId: String, val senderId: String?) :
SimpleAction(R.string.report_content_spam, R.drawable.ic_report_spam)
data class ReportContentInappropriate(val eventId: String, val senderId: String?) :
SimpleAction(R.string.report_content_inappropriate, R.drawable.ic_report_inappropriate)
data class ReportContentCustom(val eventId: String, val senderId: String?) :
SimpleAction(R.string.report_content_custom, R.drawable.ic_report_custom)
data class QuickReact(val eventId: String, val clickedOn: String, val add: Boolean) :
SimpleAction(0, 0)
data class ViewReactions(val messageInformationData: MessageInformationData) :
SimpleAction(R.string.message_view_reaction, R.drawable.ic_view_reactions)
data class ViewEditHistory(val messageInformationData: MessageInformationData) :
SimpleAction(R.string.message_view_edit_history, R.drawable.ic_view_edit_history)
}

View File

@ -30,7 +30,10 @@ import kotlinx.android.synthetic.main.activity_filtered_rooms.*
class FilteredRoomsActivity : VectorBaseActivity() {
private lateinit var roomListFragment: RoomListFragment
private val roomListFragment: RoomListFragment?
get() {
return supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as? RoomListFragment
}
override fun getLayoutRes(): Int {
return R.layout.activity_filtered_rooms
@ -44,19 +47,16 @@ class FilteredRoomsActivity : VectorBaseActivity() {
super.onCreate(savedInstanceState)
configureToolbar(filteredRoomsToolbar)
if (isFirstCreation()) {
roomListFragment = RoomListFragment.newInstance(RoomListParams(RoomListFragment.DisplayMode.FILTERED))
replaceFragment(roomListFragment, R.id.filteredRoomsFragmentContainer, FRAGMENT_TAG)
} else {
roomListFragment = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as RoomListFragment
val params = RoomListParams(RoomListFragment.DisplayMode.FILTERED)
replaceFragment(R.id.filteredRoomsFragmentContainer, RoomListFragment::class.java, params, FRAGMENT_TAG)
}
filteredRoomsSearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return true
}
override fun onQueryTextChange(newText: String): Boolean {
roomListFragment.filterRoomsWith(newText)
roomListFragment?.filterRoomsWith(newText)
return true
}
})

View File

@ -34,7 +34,6 @@ import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.matrix.android.api.session.room.notification.RoomNotificationState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.epoxy.LayoutManagerStateRestorer
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.platform.OnBackPressed
@ -57,7 +56,13 @@ data class RoomListParams(
val sharedData: SharedData? = null
) : Parcelable
class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
class RoomListFragment @Inject constructor(
private val roomController: RoomSummaryController,
val roomListViewModelFactory: RoomListViewModel.Factory,
private val errorFormatter: ErrorFormatter,
private val notificationDrawerManager: NotificationDrawerManager
) : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
enum class DisplayMode(@StringRes val titleRes: Int) {
HOME(R.string.bottom_action_home),
@ -67,28 +72,12 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, O
SHARE(/* Not used */ 0)
}
companion object {
fun newInstance(roomListParams: RoomListParams): RoomListFragment {
return RoomListFragment().apply {
setArguments(roomListParams)
}
}
}
private lateinit var quickActionsDispatcher: RoomListQuickActionsStore
private val roomListParams: RoomListParams by args()
@Inject lateinit var roomController: RoomSummaryController
@Inject lateinit var roomListViewModelFactory: RoomListViewModel.Factory
@Inject lateinit var errorFormatter: ErrorFormatter
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
override fun getLayoutResId() = R.layout.fragment_room_list
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
private var hasUnreadRooms = false
override fun getMenuRes() = R.menu.room_list

View File

@ -51,7 +51,7 @@ class LoginActivity : VectorBaseActivity() {
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(LoginFragment(), R.id.simpleFragmentContainer)
addFragment(R.id.simpleFragmentContainer, LoginFragment::class.java)
}
// Get config extra
@ -62,7 +62,7 @@ class LoginActivity : VectorBaseActivity() {
loginViewModel.navigationLiveData.observeEvent(this) {
when (it) {
is Navigation.OpenSsoLoginFallback -> addFragmentToBackstack(LoginSsoFallbackFragment(), R.id.simpleFragmentContainer)
is Navigation.OpenSsoLoginFallback -> addFragmentToBackstack(R.id.simpleFragmentContainer, LoginSsoFallbackFragment::class.java)
is Navigation.GoBack -> supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
}
}

View File

@ -26,8 +26,6 @@ import com.airbnb.mvrx.*
import com.jakewharton.rxbinding3.view.focusChanges
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.setTextWithColoredPart
import im.vector.riotx.core.extensions.showPassword
import im.vector.riotx.core.platform.VectorBaseFragment
@ -43,20 +41,14 @@ import javax.inject.Inject
* What can be improved:
* - When filtering more (when entering new chars), we could filter on result we already have, during the new server request, to avoid empty screen effect
*/
class LoginFragment : VectorBaseFragment() {
class LoginFragment @Inject constructor() : VectorBaseFragment() {
private val viewModel: LoginViewModel by activityViewModel()
private var passwordShown = false
@Inject lateinit var errorFormatter: ErrorFormatter
override fun getLayoutResId() = R.layout.fragment_login
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -35,17 +35,17 @@ import im.vector.matrix.android.api.auth.data.Credentials
import im.vector.matrix.android.api.util.JsonDict
import im.vector.matrix.android.internal.di.MoshiProvider
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.OnBackPressed
import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_login_sso_fallback.*
import timber.log.Timber
import java.net.URLDecoder
import javax.inject.Inject
/**
* Only login is supported for the moment
*/
class LoginSsoFallbackFragment : VectorBaseFragment(), OnBackPressed {
class LoginSsoFallbackFragment @Inject constructor() : VectorBaseFragment(), OnBackPressed {
private val viewModel: LoginViewModel by activityViewModel()
@ -62,10 +62,6 @@ class LoginSsoFallbackFragment : VectorBaseFragment(), OnBackPressed {
override fun getLayoutResId() = R.layout.fragment_login_sso_fallback
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -20,12 +20,9 @@ import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.RecyclerView
import im.vector.riotx.R
import im.vector.riotx.core.platform.VectorBaseFragment
import javax.inject.Inject
class EmojiChooserFragment : VectorBaseFragment() {
companion object {
fun newInstance() = EmojiChooserFragment()
}
class EmojiChooserFragment @Inject constructor() : VectorBaseFragment() {
override fun getLayoutResId() = R.layout.emoji_chooser_fragment

View File

@ -25,7 +25,6 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
@ -131,8 +130,8 @@ class EmojiReactionPickerActivity : VectorBaseActivity(),
}
}
supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isVisible = true
supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isInvisible = true
emojiPickerWholeListFragmentContainer.isVisible = true
emojiPickerFilteredListFragmentContainer.isVisible = false
tabLayout.isVisible = true
}
@ -195,13 +194,13 @@ class EmojiReactionPickerActivity : VectorBaseActivity(),
private fun onQueryText(query: String) {
if (query.isEmpty()) {
supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isVisible = true
supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isInvisible = true
tabLayout.isVisible = true
emojiPickerWholeListFragmentContainer.isVisible = true
emojiPickerFilteredListFragmentContainer.isVisible = false
} else {
tabLayout.isVisible = false
supportFragmentManager.findFragmentById(R.id.fragment)?.view?.isInvisible = true
supportFragmentManager.findFragmentById(R.id.searchFragment)?.view?.isVisible = true
emojiPickerWholeListFragmentContainer.isVisible = false
emojiPickerFilteredListFragmentContainer.isVisible = true
searchResultViewModel.updateQuery(query)
}
}

View File

@ -24,12 +24,13 @@ import com.airbnb.epoxy.EpoxyRecyclerView
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.utils.LiveEvent
import javax.inject.Inject
class EmojiSearchResultFragment : VectorBaseFragment() {
class EmojiSearchResultFragment @Inject constructor(
private val epoxyController: EmojiSearchResultController
) : VectorBaseFragment() {
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
@ -37,12 +38,6 @@ class EmojiSearchResultFragment : VectorBaseFragment() {
var sharedViewModel: EmojiChooserViewModel? = null
@Inject lateinit var epoxyController: EmojiSearchResultController
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)

View File

@ -28,7 +28,6 @@ import com.google.android.material.snackbar.Snackbar
import com.jakewharton.rxbinding3.appcompat.queryTextChanges
import im.vector.matrix.android.api.session.room.model.roomdirectory.PublicRoom
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.VectorBaseFragment
@ -42,22 +41,18 @@ import javax.inject.Inject
* What can be improved:
* - When filtering more (when entering new chars), we could filter on result we already have, during the new server request, to avoid empty screen effect
*/
class PublicRoomsFragment : VectorBaseFragment(), PublicRoomsController.Callback {
class PublicRoomsFragment @Inject constructor(
private val publicRoomsController: PublicRoomsController,
private val errorFormatter: ErrorFormatter
) : VectorBaseFragment(), PublicRoomsController.Callback {
private val viewModel: RoomDirectoryViewModel by activityViewModel()
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
@Inject lateinit var publicRoomsController: PublicRoomsController
@Inject lateinit var errorFormatter: ErrorFormatter
override fun getLayoutResId() = R.layout.fragment_public_rooms
override fun getMenuRes() = R.menu.menu_room_directory
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

View File

@ -65,8 +65,8 @@ class RoomDirectoryActivity : VectorBaseActivity() {
.subscribe { navigation ->
when (navigation) {
is Navigation.Back -> onBackPressed()
is Navigation.CreateRoom -> addFragmentToBackstack(CreateRoomFragment(), R.id.simpleFragmentContainer)
is Navigation.ChangeProtocol -> addFragmentToBackstack(RoomDirectoryPickerFragment(), R.id.simpleFragmentContainer)
is Navigation.CreateRoom -> addFragmentToBackstack(R.id.simpleFragmentContainer, CreateRoomFragment::class.java)
is Navigation.ChangeProtocol -> addFragmentToBackstack(R.id.simpleFragmentContainer, RoomDirectoryPickerFragment::class.java)
is Navigation.Close -> finish()
}
}
@ -80,7 +80,7 @@ class RoomDirectoryActivity : VectorBaseActivity() {
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(PublicRoomsFragment(), R.id.simpleFragmentContainer)
addFragment(R.id.simpleFragmentContainer, PublicRoomsFragment::class.java)
}
}

View File

@ -23,7 +23,6 @@ import androidx.appcompat.widget.Toolbar
import androidx.lifecycle.ViewModelProviders
import com.airbnb.mvrx.viewModel
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.addFragment
import im.vector.riotx.core.platform.ToolbarConfigurable
import im.vector.riotx.core.platform.VectorBaseActivity
@ -49,16 +48,11 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarConfigurable {
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(CreateRoomFragment(), R.id.simpleFragmentContainer)
addFragment(R.id.simpleFragmentContainer, CreateRoomFragment::class.java)
createRoomViewModel.setName(intent?.getStringExtra(INITIAL_NAME) ?: "")
}
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
navigationViewModel = ViewModelProviders.of(this, viewModelFactory).get(RoomDirectoryNavigationViewModel::class.java)

View File

@ -24,7 +24,6 @@ import com.airbnb.mvrx.Success
import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.RoomDirectoryNavigationViewModel
@ -32,20 +31,15 @@ import kotlinx.android.synthetic.main.fragment_create_room.*
import timber.log.Timber
import javax.inject.Inject
class CreateRoomFragment : VectorBaseFragment(), CreateRoomController.Listener {
class CreateRoomFragment @Inject constructor(private val createRoomController: CreateRoomController): VectorBaseFragment(), CreateRoomController.Listener {
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
private val viewModel: CreateRoomViewModel by activityViewModel()
@Inject lateinit var createRoomController: CreateRoomController
override fun getLayoutResId() = R.layout.fragment_create_room
override fun getMenuRes() = R.menu.vector_room_creation
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
vectorBaseActivity.setSupportActionBar(createRoomToolbar)

View File

@ -26,7 +26,6 @@ import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.session.room.model.thirdparty.RoomDirectoryData
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.RoomDirectoryNavigationViewModel
@ -37,15 +36,14 @@ import javax.inject.Inject
// TODO Set title to R.string.select_room_directory
// TODO Menu to add custom room directory (not done in RiotWeb so far...)
class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
class RoomDirectoryPickerFragment @Inject constructor(val roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory,
private val roomDirectoryPickerController: RoomDirectoryPickerController
) : VectorBaseFragment(), RoomDirectoryPickerController.Callback {
private val viewModel: RoomDirectoryViewModel by activityViewModel()
private lateinit var navigationViewModel: RoomDirectoryNavigationViewModel
private val pickerViewModel: RoomDirectoryPickerViewModel by fragmentViewModel()
@Inject lateinit var roomDirectoryPickerViewModelFactory: RoomDirectoryPickerViewModel.Factory
@Inject lateinit var roomDirectoryPickerController: RoomDirectoryPickerController
override fun getLayoutResId() = R.layout.fragment_room_directory_picker
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -71,10 +69,6 @@ class RoomDirectoryPickerFragment : VectorBaseFragment(), RoomDirectoryPickerCon
return super.onOptionsItemSelected(item)
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
navigationViewModel = ViewModelProviders.of(requireActivity()).get(RoomDirectoryNavigationViewModel::class.java)

View File

@ -67,9 +67,9 @@ class RoomPreviewActivity : VectorBaseActivity(), ToolbarConfigurable {
if (args.worldReadable) {
// TODO Room preview: Note: M does not recommend to use /events anymore, so for now we just display the room preview
// TODO the same way if it was not world readable
addFragment(RoomPreviewNoPreviewFragment.newInstance(args), R.id.simpleFragmentContainer)
addFragment(R.id.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args)
} else {
addFragment(RoomPreviewNoPreviewFragment.newInstance(args), R.id.simpleFragmentContainer)
addFragment(R.id.simpleFragmentContainer, RoomPreviewNoPreviewFragment::class.java, args)
}
}
}

View File

@ -19,13 +19,11 @@ package im.vector.riotx.features.roomdirectory.roompreview
import android.os.Bundle
import android.view.View
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.transition.TransitionManager
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.core.platform.ButtonStateView
@ -38,24 +36,15 @@ import javax.inject.Inject
/**
* Note: this Fragment is also used for world readable room for the moment
*/
class RoomPreviewNoPreviewFragment : VectorBaseFragment() {
class RoomPreviewNoPreviewFragment @Inject constructor(
private val errorFormatter: ErrorFormatter,
val roomPreviewViewModelFactory: RoomPreviewViewModel.Factory,
private val avatarRenderer: AvatarRenderer
) : VectorBaseFragment() {
companion object {
fun newInstance(arg: RoomPreviewData): Fragment {
return RoomPreviewNoPreviewFragment().apply { setArguments(arg) }
}
}
@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()
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setupToolbar(roomPreviewNoPreviewToolbar)

View File

@ -55,8 +55,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
const val SETTINGS_CONTACT_PREFERENCE_KEYS = "SETTINGS_CONTACT_PREFERENCE_KEYS"
const val SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGETS_PREFERENCE_KEY"
const val SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY = "SETTINGS_NOTIFICATIONS_TARGET_DIVIDER_PREFERENCE_KEY"
const val SETTINGS_IGNORED_USERS_PREFERENCE_KEY = "SETTINGS_IGNORED_USERS_PREFERENCE_KEY"
const val SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY = "SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY"
const val SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY"
const val SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY = "SETTINGS_BACKGROUND_SYNC_DIVIDER_PREFERENCE_KEY"
const val SETTINGS_LABS_PREFERENCE_KEY = "SETTINGS_LABS_PREFERENCE_KEY"
@ -544,7 +542,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
MEDIA_SAVING_1_WEEK -> System.currentTimeMillis() / 1000 - 7 * 24 * 60 * 60
MEDIA_SAVING_1_MONTH -> System.currentTimeMillis() / 1000 - 30 * 24 * 60 * 60
MEDIA_SAVING_FOREVER -> 0
else -> 0
else -> 0
}
}
@ -559,7 +557,7 @@ class VectorPreferences @Inject constructor(private val context: Context) {
MEDIA_SAVING_1_WEEK -> context.getString(R.string.media_saving_period_1_week)
MEDIA_SAVING_1_MONTH -> context.getString(R.string.media_saving_period_1_month)
MEDIA_SAVING_FOREVER -> context.getString(R.string.media_saving_period_forever)
else -> "?"
else -> "?"
}
}

View File

@ -23,6 +23,7 @@ import androidx.preference.PreferenceFragmentCompat
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.VectorBaseActivity
import kotlinx.android.synthetic.main.activity_vector_settings.*
import timber.log.Timber
@ -52,11 +53,8 @@ class VectorSettingsActivity : VectorBaseActivity(),
configureToolbar(settingsToolbar)
if (isFirstCreation()) {
val vectorSettingsPreferencesFragment = VectorSettingsRootFragment.newInstance()
// display the fragment
supportFragmentManager.beginTransaction()
.replace(R.id.vector_settings_page, vectorSettingsPreferencesFragment, FRAGMENT_TAG)
.commit()
replaceFragment(R.id.vector_settings_page, VectorSettingsRootFragment::class.java, null, FRAGMENT_TAG)
}
supportFragmentManager.addOnBackStackChangedListener(this)
@ -76,9 +74,9 @@ class VectorSettingsActivity : VectorBaseActivity(),
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
val oFragment = when {
VectorPreferences.SETTINGS_NOTIFICATION_TROUBLESHOOT_PREFERENCE_KEY == pref.key ->
VectorSettingsNotificationsTroubleshootFragment.newInstance()
supportFragmentManager.fragmentFactory.instantiate(classLoader, VectorSettingsNotificationsTroubleshootFragment::class.java.name)
VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY == pref.key ->
VectorSettingsAdvancedNotificationPreferenceFragment.newInstance()
supportFragmentManager.fragmentFactory.instantiate(classLoader, VectorSettingsAdvancedNotificationPreferenceFragment::class.java.name)
else ->
try {
pref.fragment?.let {

View File

@ -24,14 +24,15 @@ import androidx.core.content.edit
import androidx.preference.Preference
import androidx.preference.PreferenceManager
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.preference.BingRule
import im.vector.riotx.core.preference.BingRulePreference
import im.vector.riotx.core.preference.VectorPreference
import im.vector.riotx.features.notifications.NotificationUtils
import javax.inject.Inject
class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseFragment() {
class VectorSettingsAdvancedNotificationPreferenceFragment @Inject constructor(
private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
// events listener
/* TODO
@ -46,12 +47,6 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
override val preferenceXmlRes = R.xml.vector_settings_notification_advanced_preferences
@Inject lateinit var vectorPreferences: VectorPreferences
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun bindPref() {
val callNotificationsSystemOptions = findPreference<VectorPreference>(VectorPreferences.SETTINGS_SYSTEM_CALL_NOTIFICATION_PREFERENCE_KEY)!!
if (NotificationUtils.supportNotificationChannels()) {
@ -229,7 +224,5 @@ class VectorSettingsAdvancedNotificationPreferenceFragment : VectorSettingsBaseF
VectorPreferences.SETTINGS_CALL_INVITATIONS_PREFERENCE_KEY to BingRule.RULE_ID_CALL,
VectorPreferences.SETTINGS_MESSAGES_SENT_BY_BOT_PREFERENCE_KEY to BingRule.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS
)
fun newInstance() = VectorSettingsAdvancedNotificationPreferenceFragment()
}
}

View File

@ -23,24 +23,19 @@ import androidx.preference.Preference
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
import im.vector.matrix.android.api.Matrix
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.preference.VectorPreference
import im.vector.riotx.core.utils.copyToClipboard
import im.vector.riotx.core.utils.displayInWebView
import im.vector.riotx.features.version.VersionProvider
import javax.inject.Inject
class VectorSettingsHelpAboutFragment : VectorSettingsBaseFragment() {
class VectorSettingsHelpAboutFragment @Inject constructor(
private val versionProvider: VersionProvider
) : VectorSettingsBaseFragment() {
override var titleRes = R.string.preference_root_help_about
override val preferenceXmlRes = R.xml.vector_settings_help_about
@Inject lateinit var versionProvider: VersionProvider
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun bindPref() {
// preference to start the App info screen, to facilitate App permissions access
findPreference<VectorPreference>(APP_INFO_LINK_PREFERENCE_KEY)!!

View File

@ -1,121 +0,0 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.settings
import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import im.vector.riotx.R
import im.vector.riotx.core.preference.VectorPreference
import java.util.ArrayList
import kotlin.Comparator
class VectorSettingsIgnoredUsersFragment : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_ignored_users
override val preferenceXmlRes = R.xml.vector_settings_ignored_users
// displayed the ignored users list
private val mIgnoredUserSettingsCategoryDivider by lazy {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY)!!
}
private val mIgnoredUserSettingsCategory by lazy {
findPreference<PreferenceCategory>(VectorPreferences.SETTINGS_IGNORED_USERS_PREFERENCE_KEY)!!
}
override fun bindPref() {
// Ignore users
refreshIgnoredUsersList()
}
// ==============================================================================================================
// ignored users list management
// ==============================================================================================================
/**
* Refresh the ignored users list
*/
private fun refreshIgnoredUsersList() {
val ignoredUsersList = mutableListOf<String>() // TODO session.dataHandler.ignoredUserIds
ignoredUsersList.sortWith(Comparator { u1, u2 ->
u1.toLowerCase(VectorLocale.applicationLocale).compareTo(u2.toLowerCase(VectorLocale.applicationLocale))
})
val preferenceScreen = preferenceScreen
preferenceScreen.removePreference(mIgnoredUserSettingsCategory)
preferenceScreen.removePreference(mIgnoredUserSettingsCategoryDivider)
mIgnoredUserSettingsCategory.removeAll()
if (ignoredUsersList.size > 0) {
preferenceScreen.addPreference(mIgnoredUserSettingsCategoryDivider)
preferenceScreen.addPreference(mIgnoredUserSettingsCategory)
for (userId in ignoredUsersList) {
val preference = Preference(activity)
preference.title = userId
preference.key = IGNORED_USER_KEY_BASE + userId
preference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
activity?.let {
AlertDialog.Builder(it)
.setMessage(getString(R.string.settings_unignore_user, userId))
.setPositiveButton(R.string.yes) { _, _ ->
displayLoadingView()
val idsList = ArrayList<String>()
idsList.add(userId)
notImplemented()
/* TODO
session.unIgnoreUsers(idsList, object : MatrixCallback<Unit> {
override fun onSuccess(info: Void?) {
onCommonDone(null)
}
override fun onNetworkError(e: Exception) {
onCommonDone(e.localizedMessage)
}
override fun onMatrixError(e: MatrixError) {
onCommonDone(e.localizedMessage)
}
override fun onUnexpectedError(e: Exception) {
onCommonDone(e.localizedMessage)
}
})
*/
}
.setNegativeButton(R.string.no, null)
.show()
}
false
}
mIgnoredUserSettingsCategory.addPreference(preference)
}
}
}
companion object {
private const val IGNORED_USER_KEY_BASE = "IGNORED_USER_KEY_BASE"
}
}

View File

@ -24,22 +24,21 @@ import im.vector.matrix.android.api.pushrules.RuleIds
import im.vector.matrix.android.api.pushrules.RuleKind
import im.vector.riotx.R
import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.preference.VectorSwitchPreference
import im.vector.riotx.core.pushers.PushersManager
import im.vector.riotx.push.fcm.FcmHelper
import javax.inject.Inject
// Referenced in vector_settings_preferences_root.xml
class VectorSettingsNotificationPreferenceFragment : VectorSettingsBaseFragment() {
class VectorSettingsNotificationPreferenceFragment @Inject constructor(
private val pushManager: PushersManager,
private val activeSessionHolder: ActiveSessionHolder,
private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
override var titleRes: Int = R.string.settings_notifications
override val preferenceXmlRes = R.xml.vector_settings_notifications
@Inject lateinit var pushManager: PushersManager
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
@Inject lateinit var vectorPreferences: VectorPreferences
override fun bindPref() {
findPreference<VectorSwitchPreference>(VectorPreferences.SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY)!!.let { pref ->
val pushRuleService = session
@ -57,10 +56,6 @@ class VectorSettingsNotificationPreferenceFragment : VectorSettingsBaseFragment(
}
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onResume() {
super.onResume()
activeSessionHolder.getSafeActiveSession()?.refreshPushers()

View File

@ -28,9 +28,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import butterknife.BindView
import im.vector.matrix.android.api.session.Session
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.features.rageshake.BugReporter
@ -39,7 +37,10 @@ import im.vector.riotx.features.settings.troubleshoot.TroubleshootTest
import im.vector.riotx.push.fcm.NotificationTroubleshootTestManagerFactory
import javax.inject.Inject
class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() {
class VectorSettingsNotificationsTroubleshootFragment @Inject constructor(
private val bugReporter: BugReporter,
private val testManagerFactory: NotificationTroubleshootTestManagerFactory
) : VectorBaseFragment() {
@BindView(R.id.troubleshoot_test_recycler_view)
lateinit var mRecyclerView: RecyclerView
@ -54,18 +55,11 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() {
private var testManager: NotificationTroubleshootTestManager? = null
// members
@Inject lateinit var session: Session
@Inject lateinit var bugReporter: BugReporter
@Inject lateinit var testManagerFactory: NotificationTroubleshootTestManagerFactory
override fun getLayoutResId() = R.layout.fragment_settings_notifications_troubleshoot
private var interactionListener: VectorSettingsFragmentInteractionListener? = null
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@ -73,7 +67,7 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() {
mRecyclerView.layoutManager = layoutManager
val dividerItemDecoration = DividerItemDecoration(mRecyclerView.context,
layoutManager.orientation)
layoutManager.orientation)
mRecyclerView.addItemDecoration(dividerItemDecoration)
mSummaryButton.setOnClickListener {
@ -88,7 +82,7 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() {
private fun startUI() {
mSummaryDescription.text = getString(R.string.settings_troubleshoot_diagnostic_running_status,
0, 0)
0, 0)
testManager = testManagerFactory.create(this)
testManager?.statusListener = { troubleshootTestManager ->
if (isAdded) {
@ -167,9 +161,4 @@ class VectorSettingsNotificationsTroubleshootFragment : VectorBaseFragment() {
interactionListener = context
}
}
companion object {
// static constructor
fun newInstance() = VectorSettingsNotificationsTroubleshootFragment()
}
}

View File

@ -25,14 +25,16 @@ import androidx.appcompat.app.AlertDialog
import androidx.preference.Preference
import androidx.preference.SwitchPreference
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.preference.VectorListPreference
import im.vector.riotx.core.preference.VectorPreference
import im.vector.riotx.features.configuration.VectorConfiguration
import im.vector.riotx.features.themes.ThemeUtils
import javax.inject.Inject
class VectorSettingsPreferencesFragment : VectorSettingsBaseFragment() {
class VectorSettingsPreferencesFragment @Inject constructor(
private val vectorConfiguration: VectorConfiguration,
private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_preferences
override val preferenceXmlRes = R.xml.vector_settings_preferences
@ -44,13 +46,6 @@ class VectorSettingsPreferencesFragment : VectorSettingsBaseFragment() {
findPreference<VectorPreference>(VectorPreferences.SETTINGS_INTERFACE_TEXT_SIZE_KEY)!!
}
@Inject lateinit var vectorConfiguration: VectorConfiguration
@Inject lateinit var vectorPreferences: VectorPreferences
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun bindPref() {
// user interface preferences
setUserInterfacePreferences()

View File

@ -17,9 +17,9 @@
package im.vector.riotx.features.settings
import im.vector.riotx.R
import im.vector.riotx.core.extensions.withArgs
import javax.inject.Inject
class VectorSettingsRootFragment : VectorSettingsBaseFragment() {
class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() {
override var titleRes: Int = R.string.title_activity_settings
override val preferenceXmlRes = R.xml.vector_settings_root
@ -27,11 +27,4 @@ class VectorSettingsRootFragment : VectorSettingsBaseFragment() {
override fun bindPref() {
// Nothing to do
}
companion object {
fun newInstance() = VectorSettingsRootFragment()
.withArgs {
// putString(ARG_MATRIX_ID, matrixId)
}
}
}

View File

@ -40,7 +40,6 @@ import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.crypto.model.rest.DeviceInfo
import im.vector.matrix.android.internal.crypto.model.rest.DevicesListResponse
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.dialogs.ExportKeysDialog
import im.vector.riotx.core.intent.ExternalIntentData
import im.vector.riotx.core.intent.analyseIntent
@ -60,7 +59,9 @@ import java.util.Date
import java.util.Locale
import javax.inject.Inject
class VectorSettingsSecurityPrivacyFragment : VectorSettingsBaseFragment() {
class VectorSettingsSecurityPrivacyFragment @Inject constructor(
private val vectorPreferences: VectorPreferences
) : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_security_and_privacy
override val preferenceXmlRes = R.xml.vector_settings_security_privacy
@ -128,12 +129,6 @@ class VectorSettingsSecurityPrivacyFragment : VectorSettingsBaseFragment() {
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!!
}
@Inject lateinit var vectorPreferences: VectorPreferences
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun bindPref() {
// Push target
refreshPushersList()

View File

@ -0,0 +1,68 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.settings.ignored
import com.airbnb.epoxy.EpoxyController
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.noResultItem
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject
class IgnoredUsersController @Inject constructor(private val stringProvider: StringProvider,
private val avatarRenderer: AvatarRenderer) : EpoxyController() {
var callback: Callback? = null
private var viewState: IgnoredUsersViewState? = null
init {
requestModelBuild()
}
fun update(viewState: IgnoredUsersViewState) {
this.viewState = viewState
requestModelBuild()
}
override fun buildModels() {
val nonNullViewState = viewState ?: return
buildIgnoredUserModels(nonNullViewState.ignoredUsers)
}
private fun buildIgnoredUserModels(userIds: List<User>) {
if (userIds.isEmpty()) {
noResultItem {
id("empty")
text(stringProvider.getString(R.string.no_ignored_users))
}
} else {
userIds.forEach { userId ->
userItem {
id(userId.userId)
avatarRenderer(avatarRenderer)
user(userId)
itemClickAction { callback?.onUserIdClicked(userId.userId) }
}
}
}
}
interface Callback {
fun onUserIdClicked(userId: String)
}
}

View File

@ -0,0 +1,102 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.settings.ignored
import com.airbnb.mvrx.*
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.user.model.User
import im.vector.matrix.rx.rx
import im.vector.riotx.core.extensions.postLiveEvent
import im.vector.riotx.core.platform.VectorViewModel
data class IgnoredUsersViewState(
val ignoredUsers: List<User> = emptyList(),
val unIgnoreRequest: Async<Unit> = Uninitialized
) : MvRxState
sealed class IgnoredUsersAction {
data class UnIgnore(val userId: String) : IgnoredUsersAction()
}
class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState,
private val session: Session) : VectorViewModel<IgnoredUsersViewState>(initialState) {
@AssistedInject.Factory
interface Factory {
fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel
}
companion object : MvRxViewModelFactory<IgnoredUsersViewModel, IgnoredUsersViewState> {
@JvmStatic
override fun create(viewModelContext: ViewModelContext, state: IgnoredUsersViewState): IgnoredUsersViewModel? {
val ignoredUsersFragment: VectorSettingsIgnoredUsersFragment = (viewModelContext as FragmentViewModelContext).fragment()
return ignoredUsersFragment.ignoredUsersViewModelFactory.create(state)
}
}
init {
observeIgnoredUsers()
}
private fun observeIgnoredUsers() {
session.rx()
.liveIgnoredUsers()
.execute { async ->
copy(
ignoredUsers = async.invoke().orEmpty()
)
}
}
fun handle(action: IgnoredUsersAction) {
when (action) {
is IgnoredUsersAction.UnIgnore -> handleUnIgnore(action)
}
}
private fun handleUnIgnore(action: IgnoredUsersAction.UnIgnore) {
setState {
copy(
unIgnoreRequest = Loading()
)
}
session.unIgnoreUserIds(listOf(action.userId), object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
setState {
copy(
unIgnoreRequest = Fail(failure)
)
}
_requestErrorLiveData.postLiveEvent(failure)
}
override fun onSuccess(data: Unit) {
setState {
copy(
unIgnoreRequest = Success(data)
)
}
}
})
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.settings.ignored
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.matrix.android.api.session.user.model.User
import im.vector.riotx.R
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.features.home.AvatarRenderer
/**
* A list item for User.
*/
@EpoxyModelClass(layout = R.layout.item_user)
abstract class UserItem : VectorEpoxyModel<UserItem.Holder>() {
@EpoxyAttribute
lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute
lateinit var user: User
@EpoxyAttribute
var itemClickAction: (() -> Unit)? = null
override fun bind(holder: Holder) {
holder.root.setOnClickListener { itemClickAction?.invoke() }
avatarRenderer.render(user, holder.avatarImage)
holder.userIdText.setTextOrHide(user.userId)
holder.displayNameText.setTextOrHide(user.displayName)
}
class Holder : VectorEpoxyHolder() {
val root by bind<View>(R.id.itemUserRoot)
val avatarImage by bind<ImageView>(R.id.itemUserAvatar)
val userIdText by bind<TextView>(R.id.itemUserId)
val displayNameText by bind<TextView>(R.id.itemUserName)
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.settings.ignored
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.error.ErrorFormatter
import im.vector.riotx.core.extensions.observeEvent
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
import kotlinx.android.synthetic.main.merge_overlay_waiting_view.*
import javax.inject.Inject
class VectorSettingsIgnoredUsersFragment @Inject constructor(
val ignoredUsersViewModelFactory: IgnoredUsersViewModel.Factory,
private val ignoredUsersController: IgnoredUsersController,
private val errorFormatter: ErrorFormatter
) : VectorBaseFragment(), IgnoredUsersController.Callback {
override fun getLayoutResId() = R.layout.fragment_generic_recycler_epoxy
private val ignoredUsersViewModel: IgnoredUsersViewModel by fragmentViewModel()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
waiting_view_status_text.setText(R.string.please_wait)
waiting_view_status_text.isVisible = true
ignoredUsersController.callback = this
epoxyRecyclerView.setController(ignoredUsersController)
ignoredUsersViewModel.requestErrorLiveData.observeEvent(this) {
displayErrorDialog(it)
}
}
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_ignored_users)
}
override fun onUserIdClicked(userId: String) {
AlertDialog.Builder(requireActivity())
.setMessage(getString(R.string.settings_unignore_user, userId))
.setPositiveButton(R.string.yes) { _, _ ->
ignoredUsersViewModel.handle(IgnoredUsersAction.UnIgnore(userId))
}
.setNegativeButton(R.string.no, null)
.show()
}
private fun displayErrorDialog(throwable: Throwable) {
AlertDialog.Builder(requireActivity())
.setTitle(R.string.dialog_title_error)
.setMessage(errorFormatter.toHumanReadable(throwable))
.setPositiveButton(R.string.ok, null)
.show()
}
// ==============================================================================================================
// ignored users list management
// ==============================================================================================================
override fun invalidate() = withState(ignoredUsersViewModel) { state ->
ignoredUsersController.update(state)
handleUnIgnoreRequestStatus(state.unIgnoreRequest)
}
private fun handleUnIgnoreRequestStatus(unIgnoreRequest: Async<Unit>) {
when (unIgnoreRequest) {
is Loading -> waiting_view.isVisible = true
else -> waiting_view.isVisible = false
}
}
}

View File

@ -24,7 +24,6 @@ import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotx.R
import im.vector.riotx.core.di.ScreenComponent
import im.vector.riotx.core.platform.VectorBaseActivity
import im.vector.riotx.core.platform.VectorBaseFragment
import im.vector.riotx.core.resources.StringProvider
@ -33,11 +32,12 @@ import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
import javax.inject.Inject
// Referenced in vector_settings_notifications.xml
class PushGatewaysFragment : VectorBaseFragment() {
class PushGatewaysFragment @Inject constructor(
val pushGatewaysViewModelFactory: PushGatewaysViewModel.Factory
) : VectorBaseFragment() {
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
@Inject lateinit var pushGatewaysViewModelFactory: PushGatewaysViewModel.Factory
private val viewModel: PushGatewaysViewModel by fragmentViewModel(PushGatewaysViewModel::class)
private val epoxyController by lazy { PushGateWayController(StringProvider(requireContext().resources)) }
@ -46,10 +46,6 @@ class PushGatewaysFragment : VectorBaseFragment() {
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_notifications_targets)
}
override fun injectWith(injector: ScreenComponent) {
injector.inject(this)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val lmgr = LinearLayoutManager(context, RecyclerView.VERTICAL, false)

View File

@ -42,9 +42,12 @@ class IncomingShareActivity :
@Inject lateinit var sessionHolder: ActiveSessionHolder
@Inject lateinit var incomingShareViewModelFactory: IncomingShareViewModel.Factory
private var roomListFragment: RoomListFragment? = null
private lateinit var attachmentsHelper: AttachmentsHelper
private val incomingShareViewModel: IncomingShareViewModel by viewModel()
private val roomListFragment: RoomListFragment?
get() {
return supportFragmentManager.findFragmentById(R.id.shareRoomListFragmentContainer) as? RoomListFragment
}
override fun getLayoutRes(): Int {
return R.layout.activity_incoming_share
@ -64,8 +67,7 @@ class IncomingShareActivity :
}
configureToolbar(incomingShareToolbar)
if (isFirstCreation()) {
val loadingDetail = LoadingFragment.newInstance()
replaceFragment(loadingDetail, R.id.shareRoomListFragmentContainer)
replaceFragment(R.id.shareRoomListFragmentContainer, LoadingFragment::class.java)
}
attachmentsHelper = AttachmentsHelper.create(this, this).register()
if (intent?.action == Intent.ACTION_SEND || intent?.action == Intent.ACTION_SEND_MULTIPLE) {
@ -96,8 +98,7 @@ class IncomingShareActivity :
override fun onContentAttachmentsReady(attachments: List<ContentAttachmentData>) {
val roomListParams = RoomListParams(RoomListFragment.DisplayMode.SHARE, sharedData = SharedData.Attachments(attachments))
roomListFragment = RoomListFragment.newInstance(roomListParams)
.also { replaceFragment(it, R.id.shareRoomListFragmentContainer) }
replaceFragment(R.id.shareRoomListFragmentContainer, RoomListFragment::class.java, roomListParams)
}
override fun onAttachmentsProcessFailed() {
@ -116,8 +117,7 @@ class IncomingShareActivity :
false
} else {
val roomListParams = RoomListParams(RoomListFragment.DisplayMode.SHARE, sharedData = SharedData.Text(sharedText))
roomListFragment = RoomListFragment.newInstance(roomListParams)
.also { replaceFragment(it, R.id.shareRoomListFragmentContainer) }
replaceFragment(R.id.shareRoomListFragmentContainer, RoomListFragment::class.java, roomListParams)
true
}
}

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -13,7 +12,7 @@
android:elevation="4dp"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/container"
android:layout_width="0dp"
android:layout_height="0dp"

View File

@ -6,21 +6,21 @@
android:layout_height="match_parent"
tools:context="im.vector.riotx.features.reactions.EmojiReactionPickerActivity">
<fragment
android:id="@+id/fragment"
<androidx.fragment.app.FragmentContainerView
android:id="@+id/emojiPickerWholeListFragmentContainer"
android:name="im.vector.riotx.features.reactions.EmojiChooserFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:layout="@layout/emoji_chooser_fragment" />
<fragment
android:id="@+id/searchFragment"
<androidx.fragment.app.FragmentContainerView
android:id="@+id/emojiPickerFilteredListFragmentContainer"
android:name="im.vector.riotx.features.reactions.EmojiSearchResultFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:visibility="invisible" />
android:visibility="gone" />
<com.google.android.material.appbar.AppBarLayout
style="@style/VectorAppBarLayoutStyle"

View File

@ -29,7 +29,7 @@
</androidx.appcompat.widget.Toolbar>
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/filteredRoomsFragmentContainer"
android:layout_width="0dp"
android:layout_height="0dp"

View File

@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/homeDetailFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
@ -20,7 +20,7 @@
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<FrameLayout
<androidx.fragment.app.FragmentContainerView
android:id="@+id/homeDrawerFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"

Some files were not shown because too many files have changed in this diff Show More