diff --git a/CHANGES.md b/CHANGES.md index 46097b72ae..3a9872a2c1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -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 diff --git a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt index f19777b6f5..1572851d3a 100644 --- a/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt +++ b/matrix-sdk-android-rx/src/main/java/im/vector/matrix/rx/RxSession.kt @@ -54,6 +54,10 @@ class RxSession(private val session: Session) { return session.liveUsers().asObservable() } + fun liveIgnoredUsers(): Observable> { + return session.liveIgnoredUsers().asObservable() + } + fun livePagedUsers(filter: String? = null): Observable> { return session.livePagedUsers(filter).asObservable() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt index f1e4ca6c7b..a84e5af48c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/cache/CacheService.kt @@ -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 { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt index d3de777e34..2a93a876f6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt @@ -64,4 +64,19 @@ interface UserService { * @return a Livedata of users */ fun livePagedUsers(filter: String? = null): LiveData> + + /** + * Get list of ignored users + */ + fun liveIgnoredUsers(): LiveData> + + /** + * Ignore users + */ + fun ignoreUserIds(userIds: List, callback: MatrixCallback): Cancelable + + /** + * Un-ignore some users + */ + fun unIgnoreUserIds(userIds: List, callback: MatrixCallback): Cancelable } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt index bfb9a59956..f83166512e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/util/Types.kt @@ -21,4 +21,6 @@ import java.lang.reflect.ParameterizedType typealias JsonDict = Map +val emptyJsonDict = emptyMap() + internal val JSON_DICT_PARAMETERIZED_TYPE: ParameterizedType = Types.newParameterizedType(Map::class.java, String::class.java, Any::class.java) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt index 5ef2b9b1a2..81988fe209 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/Helper.kt @@ -41,8 +41,7 @@ fun doWithRealm(realmConfiguration: RealmConfiguration, action: (Realm) -> T */ fun 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 doRealmQueryAndCopy(realmConfiguration: RealmConfiguration */ fun doRealmQueryAndCopyList(realmConfiguration: RealmConfiguration, action: (Realm) -> Iterable): Iterable { return Realm.getInstance(realmConfiguration).use { realm -> - val result = action.invoke(realm) - realm.copyFromRealm(result) + action.invoke(realm).let { realm.copyFromRealm(it) } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index d88a84de9e..8a3b66dfe5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -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().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 } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt new file mode 100644 index 0000000000..bd31046f82 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/IgnoredUserEntity.kt @@ -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 +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt index 21b2fdce5a..76b355b064 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/SessionRealmModule.kt @@ -35,6 +35,7 @@ import io.realm.annotations.RealmModule RoomTagEntity::class, SyncEntity::class, UserEntity::class, + IgnoredUserEntity::class, EventAnnotationsSummaryEntity::class, ReactionAggregatedSummaryEntity::class, EditAggregatedSummaryEntity::class, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt index d8db462f7c..96cdf29226 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MoshiProvider.kt @@ -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) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt index 56b96b428d..56bc005805 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/UserAccountDataSyncHandler.kt @@ -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?) { @@ -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 + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt index d084dcdadd..9e5cc2cfa4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/SyncResponse.kt @@ -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) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt new file mode 100644 index 0000000000..ea591d79b0 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/IgnoredUsersContent.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.matrix.android.internal.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 +) { + + companion object { + fun createWithUserIds(userIds: List): IgnoredUsersContent { + return IgnoredUsersContent( + ignoredUsers = userIds.associateWith { emptyJsonDict } + ) + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt similarity index 81% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt index 2173d2f4df..55dbad6099 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountData.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountData.kt @@ -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" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt similarity index 82% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt index 825a16cb1e..e5c6135bd1 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataDirectMessages.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataDirectMessages.kt @@ -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> -) : UserAccountData +) : UserAccountData() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt similarity index 84% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt index 70d28c084f..a8b8235d37 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataFallback.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataFallback.kt @@ -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 -) : UserAccountData +) : UserAccountData() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt new file mode 100644 index 0000000000..63a7604305 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataIgnoredUsers.kt @@ -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() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataPushRules.kt similarity index 83% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataPushRules.kt index 7f357c876b..0d549d1667 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataPushRules.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataPushRules.kt @@ -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() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt similarity index 91% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt index 4b9e9d652d..c7f8bfa4c2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/UserAccountDataSync.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/model/accountdata/UserAccountDataSync.kt @@ -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 diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt index be330bfc36..d314c8d108 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt @@ -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 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> { + 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, callback: MatrixCallback): Cancelable { + val params = UpdateIgnoredUserIdsTask.Params(userIdsToIgnore = userIds.toList()) + return updateIgnoredUserIdsTask + .configureWith(params) { + this.callback = callback + } + .executeBy(taskExecutor) + } + + override fun unIgnoreUserIds(userIds: List, callback: MatrixCallback): Cancelable { + val params = UpdateIgnoredUserIdsTask.Params(userIdsToUnIgnore = userIds.toList()) + return updateIgnoredUserIdsTask + .configureWith(params) { + this.callback = callback + } + .executeBy(taskExecutor) + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt index a997c616f3..51c296ba6e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt @@ -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 } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt new file mode 100644 index 0000000000..c9a3eef440 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/SaveIgnoredUsersTask.kt @@ -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 { + data class Params( + val userIds: List + ) +} + +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 } } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt new file mode 100644 index 0000000000..075eeb23d1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateIgnoredUserIdsTask.kt @@ -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 { + + data class Params( + val userIdsToIgnore: List = emptyList(), + val userIdsToUnIgnore: List = 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 { + 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)) + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt index 5c0dac1125..9fa71005ff 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/accountdata/UpdateUserAccountDataTask.kt @@ -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> ) : Params { diff --git a/vector/build.gradle b/vector/build.gradle index d639b4c3e8..d0a757d4e0 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -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' diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentKey.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentKey.kt new file mode 100644 index 0000000000..57b5c902e5 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentKey.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt new file mode 100644 index 0000000000..6ae4619033 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/di/FragmentModule.kt @@ -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 +} diff --git a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt index 35e646b316..17622020d0 100644 --- a/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt +++ b/vector/src/main/java/im/vector/riotx/core/di/ScreenComponent.kt @@ -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, diff --git a/vector/src/main/java/im/vector/riotx/core/di/VectorFragmentFactory.kt b/vector/src/main/java/im/vector/riotx/core/di/VectorFragmentFactory.kt new file mode 100644 index 0000000000..6b33b9e2a7 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/core/di/VectorFragmentFactory.kt @@ -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, Provider> +) : FragmentFactory() { + + override fun instantiate(classLoader: ClassLoader, className: String): Fragment { + val fragmentClass = loadFragmentClass(classLoader, className) + val creator: Provider? = creators[fragmentClass] + return if (creator == null) { + Timber.v("Unknown model class: $className, fallback to default instance") + super.instantiate(classLoader, className) + } else { + creator.get() + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/Activity.kt b/vector/src/main/java/im/vector/riotx/core/extensions/Activity.kt index b4afb569c4..6e4ecf4775 100644 --- a/vector/src/main/java/im/vector/riotx/core/extensions/Activity.kt +++ b/vector/src/main/java/im/vector/riotx/core/extensions/Activity.kt @@ -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 VectorBaseActivity.addFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseActivity.replaceFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseActivity.addFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { + supportFragmentManager.inTransaction { + replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) + } +} + +fun VectorBaseActivity.hideKeyboard() { currentFocus?.hideKeyboard() } diff --git a/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt index 65f8fb2aaa..e6e83bfd67 100644 --- a/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/riotx/core/extensions/Fragment.kt @@ -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 VectorBaseFragment.addFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseFragment.replaceFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseFragment.addFragmentToBackstack(frameId: Int, fragmentClass: Class, 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 VectorBaseFragment.addChildFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseFragment.replaceChildFragment(frameId: Int, fragmentClass: Class, 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 VectorBaseFragment.addChildFragmentToBackstack(frameId: Int, fragmentClass: Class, params: Parcelable? = null, tag: String? = null) { + childFragmentManager.inTransaction { + replace(frameId, fragmentClass, params.toMvRxBundle(), tag).addToBackStack(tag) + } +} diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt index 9a4f89d13a..ede99e4f28 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseActivity.kt @@ -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) // ============================================================================================== diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseFragment.kt index cc0d8940bc..206a1bab06 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorBaseFragment.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorPreferenceFragment.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorPreferenceFragment.kt deleted file mode 100644 index d534cd2297..0000000000 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorPreferenceFragment.kt +++ /dev/null @@ -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) - } -} diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt index 9679c20efb..ae601bb0f3 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt @@ -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(initialState: S) : BaseMvRxViewModel(initialState, false) { + // Generic handling of any request error + protected val _requestErrorLiveData = MutableLiveData>() + val requestErrorLiveData: LiveData> + 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 diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt index d74a9e9f4f..cd5dc38c3d 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt @@ -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) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt index 3c9ebc3a50..c30393dd5f 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromKeyFragment.kt @@ -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 }) } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt index c70796e09d..d4468081b8 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreFromPassphraseFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt index cb55d664ec..813bb9ca72 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/restore/KeysBackupRestoreSuccessFragment.kt @@ -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() - } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt index 2dabaa792a..a58c99992d 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupManageActivity.kt @@ -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() } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt index 2194ca9871..288d862413 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/settings/KeysBackupSettingsFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt index 6868fb84bb..8491435d3a 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupActivity.kt @@ -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() diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt index 8ece6af714..d018cc1ce9 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep1Fragment.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index f4717fa7b3..21e4747a4e 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -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 { newValue -> + viewModel.passphrase.observe(viewLifecycleOwner, Observer { 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() - } } diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index a5cc0510da..008e1b8aef 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt index a7fb4c67f3..3890479d91 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationActivity.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt index d8d36e0a1d..9bb3661bd7 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationIncomingFragment.kt @@ -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 -> { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt index 1c5488c0cd..da19d48bfe 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationShortCodeFragment.kt @@ -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) { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt index c101b8f9b4..97a29d9b7b 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationStartFragment.kt @@ -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 -> { diff --git a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt index b9d0546f3a..59825c8282 100644 --- a/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/crypto/verification/SASVerificationVerifiedFragment.kt @@ -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?) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt index 01f869c82a..c77e4f9373 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/HomeActivity.kt @@ -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) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeDetailFragment.kt index 5bb427188e..3c2eb1fe39 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/HomeDetailFragment.kt @@ -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() 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() - } - } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt index e5f0c5b2d3..5b052f5ff5 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/HomeDrawerFragment.kt @@ -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() diff --git a/vector/src/main/java/im/vector/riotx/features/home/LoadingFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/LoadingFragment.kt index 379ac69154..e376514955 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/LoadingFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/LoadingFragment.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomActivity.kt index c4e7855c14..ab7ee0d160 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomActivity.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomDirectoryUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomDirectoryUsersFragment.kt index ca4b26ced8..10c932342d 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomDirectoryUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomDirectoryUsersFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt index 124ca018d1..02ca8ba55c 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/createdirect/CreateDirectRoomKnownUsersFragment.kt @@ -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) { diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt index 77f34d7854..a1e13e4acd 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt index a219d25c09..9169183da1 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActions.kt @@ -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() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt index 91addb5744..eb8118a0c9 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailActivity.kt @@ -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) } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index f2f65e5cf0..465e085e3b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 2436b7a8b4..4965de4438 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -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 { + 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() diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt index 7fdb286c26..b7bf69b7a1 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsEpoxyController.kt @@ -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") diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 63a4919763..63429e5def 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -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)) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/SimpleAction.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/SimpleAction.kt index 5da589d862..ab2fb8e41e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/SimpleAction.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/timeline/action/SimpleAction.kt @@ -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) } diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomsActivity.kt b/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomsActivity.kt index 82fd203b87..a3302d40c3 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomsActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/filtered/FilteredRoomsActivity.kt @@ -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 } }) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt index 0ee34f0679..13c6444400 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/list/RoomListFragment.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt index 2cb28be998..86156bc4d4 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginActivity.kt @@ -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) } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index 3da21aa1df..7da8a79ac8 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginSsoFallbackFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginSsoFallbackFragment.kt index cac981db84..9e0cd611d1 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginSsoFallbackFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginSsoFallbackFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt index 77cad5643f..589fa5dbff 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiChooserFragment.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt index a442f5f77e..cd5d5e3e74 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiReactionPickerActivity.kt @@ -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) } } diff --git a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt index a4f443de1e..04fc99bbaa 100644 --- a/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/reactions/EmojiSearchResultFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt index 3545b1cb71..303e931b5c 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/PublicRoomsFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt index 43894aa244..e98c180bc9 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/RoomDirectoryActivity.kt @@ -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) } } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt index 20843f86cb..6377f05d20 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt index 8abf52328f..88178eaad8 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/createroom/CreateRoomFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index 2367bc8d21..e345322613 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewActivity.kt index e4fb122f7a..1bd138552e 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewActivity.kt @@ -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) } } } diff --git a/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt b/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt index e919b0096c..aff89e3b09 100644 --- a/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/roomdirectory/roompreview/RoomPreviewNoPreviewFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt index a593bb6e96..78f57dd548 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorPreferences.kt @@ -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 -> "?" } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt index cd74dd7016..16484224af 100755 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsActivity.kt @@ -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 { diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt index 380e043ecf..a8328fae52 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsAdvancedNotificationPreferenceFragment.kt @@ -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(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() } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsHelpAboutFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsHelpAboutFragment.kt index a05ccb305d..6ce928c05d 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsHelpAboutFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsHelpAboutFragment.kt @@ -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(APP_INFO_LINK_PREFERENCE_KEY)!! diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt deleted file mode 100644 index 32a6fe8f41..0000000000 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsIgnoredUsersFragment.kt +++ /dev/null @@ -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(VectorPreferences.SETTINGS_IGNORE_USERS_DIVIDER_PREFERENCE_KEY)!! - } - private val mIgnoredUserSettingsCategory by lazy { - findPreference(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() // 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() - idsList.add(userId) - - notImplemented() - /* TODO - session.unIgnoreUsers(idsList, object : MatrixCallback { - 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" - } -} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt index cfb4c88259..b397cd1cf6 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationPreferenceFragment.kt @@ -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(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() diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt index 5737425a3b..6f43114eb4 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsNotificationsTroubleshootFragment.kt @@ -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() - } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsPreferencesFragment.kt index ab81e6937e..9c240ad093 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsPreferencesFragment.kt @@ -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(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() diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsRootFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsRootFragment.kt index a70164485f..a50e0e9ad0 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsRootFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsRootFragment.kt @@ -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) - } - } } diff --git a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt index a78529f06c..b7ec443ea0 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -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(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() diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt new file mode 100644 index 0000000000..120781874d --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersController.kt @@ -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) { + 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) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt new file mode 100644 index 0000000000..a9f142058d --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/IgnoredUsersViewModel.kt @@ -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 = emptyList(), + val unIgnoreRequest: Async = Uninitialized +) : MvRxState + +sealed class IgnoredUsersAction { + data class UnIgnore(val userId: String) : IgnoredUsersAction() +} + +class IgnoredUsersViewModel @AssistedInject constructor(@Assisted initialState: IgnoredUsersViewState, + private val session: Session) : VectorViewModel(initialState) { + + @AssistedInject.Factory + interface Factory { + fun create(initialState: IgnoredUsersViewState): IgnoredUsersViewModel + } + + companion object : MvRxViewModelFactory { + + @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 { + override fun onFailure(failure: Throwable) { + setState { + copy( + unIgnoreRequest = Fail(failure) + ) + } + + _requestErrorLiveData.postLiveEvent(failure) + } + + override fun onSuccess(data: Unit) { + setState { + copy( + unIgnoreRequest = Success(data) + ) + } + } + }) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/UserItem.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/UserItem.kt new file mode 100644 index 0000000000..a9c1b98915 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/UserItem.kt @@ -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() { + + @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(R.id.itemUserRoot) + val avatarImage by bind(R.id.itemUserAvatar) + val userIdText by bind(R.id.itemUserId) + val displayNameText by bind(R.id.itemUserName) + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt new file mode 100644 index 0000000000..11e473ae24 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/settings/ignored/VectorSettingsIgnoredUsersFragment.kt @@ -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) { + when (unIgnoreRequest) { + is Loading -> waiting_view.isVisible = true + else -> waiting_view.isVisible = false + } + } +} diff --git a/vector/src/main/java/im/vector/riotx/features/settings/push/PushGatewaysFragment.kt b/vector/src/main/java/im/vector/riotx/features/settings/push/PushGatewaysFragment.kt index c20ba2e248..ea23ba2583 100644 --- a/vector/src/main/java/im/vector/riotx/features/settings/push/PushGatewaysFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/settings/push/PushGatewaysFragment.kt @@ -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) diff --git a/vector/src/main/java/im/vector/riotx/features/share/IncomingShareActivity.kt b/vector/src/main/java/im/vector/riotx/features/share/IncomingShareActivity.kt index 5e471cf78b..1ec020e1a0 100644 --- a/vector/src/main/java/im/vector/riotx/features/share/IncomingShareActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/share/IncomingShareActivity.kt @@ -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) { 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 } } diff --git a/vector/src/main/res/layout/activity.xml b/vector/src/main/res/layout/activity.xml index df0cd3fbea..b5203cd589 100644 --- a/vector/src/main/res/layout/activity.xml +++ b/vector/src/main/res/layout/activity.xml @@ -1,7 +1,6 @@ @@ -13,7 +12,7 @@ android:elevation="4dp" app:layout_constraintTop_toTopOf="parent" /> - - - + android:visibility="gone" /> - - @@ -20,7 +20,7 @@ - - - diff --git a/vector/src/main/res/layout/activity_simple.xml b/vector/src/main/res/layout/activity_simple.xml index 3ffb112b60..8dc41487fe 100644 --- a/vector/src/main/res/layout/activity_simple.xml +++ b/vector/src/main/res/layout/activity_simple.xml @@ -1,5 +1,5 @@ - diff --git a/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml b/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml index c794e8a5fa..3f02081b16 100644 --- a/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml +++ b/vector/src/main/res/layout/fragment_generic_recycler_epoxy.xml @@ -1,9 +1,17 @@ - + android:layout_height="match_parent"> + + + + + + diff --git a/vector/src/main/res/layout/fragment_home_detail.xml b/vector/src/main/res/layout/fragment_home_detail.xml index bda23973ee..7c0886efc5 100644 --- a/vector/src/main/res/layout/fragment_home_detail.xml +++ b/vector/src/main/res/layout/fragment_home_detail.xml @@ -63,7 +63,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/syncStateView" /> - - + + + + + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/merge_overlay_waiting_view.xml b/vector/src/main/res/layout/merge_overlay_waiting_view.xml index 8f09ed0988..b7e7bf41c7 100644 --- a/vector/src/main/res/layout/merge_overlay_waiting_view.xml +++ b/vector/src/main/res/layout/merge_overlay_waiting_view.xml @@ -3,8 +3,7 @@ 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" - android:orientation="vertical"> + android:layout_height="match_parent"> "Leave the room" "%1$s made no changes" + You are not ignoring any users + diff --git a/vector/src/main/res/xml/vector_settings_ignored_users.xml b/vector/src/main/res/xml/vector_settings_ignored_users.xml deleted file mode 100644 index 4ad8aed5b6..0000000000 --- a/vector/src/main/res/xml/vector_settings_ignored_users.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/vector/src/main/res/xml/vector_settings_root.xml b/vector/src/main/res/xml/vector_settings_root.xml index e0cb4f778b..894784767a 100644 --- a/vector/src/main/res/xml/vector_settings_root.xml +++ b/vector/src/main/res/xml/vector_settings_root.xml @@ -37,10 +37,9 @@ + app:fragment="im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment" />