Code review and cleanup

This commit is contained in:
Benoit Marty 2019-06-25 14:45:13 +02:00
parent ab0141a5c6
commit 71ae99012b
41 changed files with 283 additions and 158 deletions

View File

@ -1,2 +0,0 @@
package im.vector.matrix.android.api.pushrules

View File

@ -15,16 +15,23 @@
*/ */
package im.vector.matrix.android.api.pushrules.rest package im.vector.matrix.android.api.pushrules.rest


import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import com.squareup.moshi.JsonClass
import im.vector.matrix.android.api.pushrules.rest.Ruleset


/** /**
* All push rulesets for a user. * All push rulesets for a user.
*/ */
@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class PushrulesResponse( data class GetPushRulesResponse(
//Global rules, account level applying to all devices /**
* Global rules, account level applying to all devices
*/
@Json(name = "global")
val global: Ruleset, val global: Ruleset,
//Device specific rules, apply only to current device
/**
* Device specific rules, apply only to current device
*/
@Json(name = "device")
val device: Ruleset? = null val device: Ruleset? = null
) )

View File

@ -22,15 +22,26 @@ import timber.log.Timber


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class PushCondition( data class PushCondition(
//Required. The kind of condition to apply. /**
* Required. The kind of condition to apply.
*/
val kind: String, val kind: String,
//Required for event_match conditions. The dot- separated field of the event to match.
/**
* Required for event_match conditions. The dot- separated field of the event to match.
*/

val key: String? = null, val key: String? = null,
//Required for event_match conditions. /**
*Required for event_match conditions.
*/

val pattern: String? = null, val pattern: String? = null,
//Required for room_member_count conditions. /**
// A decimal integer optionally prefixed by one of, ==, <, >, >= or <=. * Required for room_member_count conditions.
// A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==. * A decimal integer optionally prefixed by one of, ==, <, >, >= or <=.
* A prefix of < matches rooms where the member count is strictly less than the given number and so forth. If no prefix is present, this parameter defaults to ==.
*/
@Json(name = "is") val iz: String? = null @Json(name = "is") val iz: String? = null
) { ) {


@ -58,7 +69,7 @@ data class PushCondition(
Condition.Kind.sender_notification_permission -> { Condition.Kind.sender_notification_permission -> {
this.key?.let { SenderNotificationPermissionCondition(it) } this.key?.let { SenderNotificationPermissionCondition(it) }
} }
Condition.Kind.UNRECOGNIZE -> { Condition.Kind.UNRECOGNIZE -> {
Timber.e("Unknwon kind $kind") Timber.e("Unknwon kind $kind")
null null
} }

View File

@ -22,17 +22,29 @@ import com.squareup.moshi.JsonClass


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
data class PushRule( data class PushRule(
//Required. The domainActions to perform when this rule is matched. /**
* Required. The actions to perform when this rule is matched.
*/
val actions: List<Any>, val actions: List<Any>,
//Required. Whether this is a default rule, or has been set explicitly. /**
* Required. Whether this is a default rule, or has been set explicitly.
*/
val default: Boolean? = false, val default: Boolean? = false,
//Required. Whether the push rule is enabled or not. /**
* Required. Whether the push rule is enabled or not.
*/
val enabled: Boolean, val enabled: Boolean,
//Required. The ID of this rule. /**
* Required. The ID of this rule.
*/
@Json(name = "rule_id") val ruleId: String, @Json(name = "rule_id") val ruleId: String,
//The conditions that must hold true for an event in order for a rule to be applied to an event /**
* The conditions that must hold true for an event in order for a rule to be applied to an event
*/
val conditions: List<PushCondition>? = null, val conditions: List<PushCondition>? = null,
//The glob-style pattern to match against. Only applicable to content rules. /**
* The glob-style pattern to match against. Only applicable to content rules.
*/
val pattern: String? = null val pattern: String? = null
) )



View File

@ -32,7 +32,7 @@ data class Pusher(
) )


enum class PusherState { enum class PusherState {
UNREGISTRED, UNREGISTERED,
REGISTERING, REGISTERING,
UNREGISTERING, UNREGISTERING,
REGISTERED, REGISTERED,

View File

@ -19,7 +19,7 @@ import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject


internal open class PushRuleEntity( internal open class PushRuleEntity(
//Required. The domainActions to perform when this rule is matched. //Required. The actions to perform when this rule is matched.
var actionsStr: String? = null, var actionsStr: String? = null,
//Required. Whether this is a default rule, or has been set explicitly. //Required. Whether this is a default rule, or has been set explicitly.
var default: Boolean = false, var default: Boolean = false,

View File

@ -38,7 +38,7 @@ internal open class PusherEntity(
var lang: String? = null, var lang: String? = null,
var data: PusherDataEntity? = null var data: PusherDataEntity? = null
) : RealmObject() { ) : RealmObject() {
private var stateStr: String = PusherState.UNREGISTRED.name private var stateStr: String = PusherState.UNREGISTERED.name


var state: PusherState var state: PusherState
get() { get() {
@ -46,7 +46,7 @@ internal open class PusherEntity(
return PusherState.valueOf(stateStr) return PusherState.valueOf(stateStr)
} catch (e: Exception) { } catch (e: Exception) {
//can this happen? //can this happen?
return PusherState.UNREGISTRED return PusherState.UNREGISTERED
} }


} }

View File

@ -15,15 +15,17 @@
*/ */
package im.vector.matrix.android.internal.database.query package im.vector.matrix.android.internal.database.query


import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.internal.database.model.*
import im.vector.matrix.android.internal.database.model.PushRulesEntity import im.vector.matrix.android.internal.database.model.PushRulesEntity
import im.vector.matrix.android.internal.database.model.PushRulesEntityFields
import im.vector.matrix.android.internal.database.model.PusherEntity import im.vector.matrix.android.internal.database.model.PusherEntity
import im.vector.matrix.android.internal.database.model.PusherEntityFields
import io.realm.Realm import io.realm.Realm
import io.realm.RealmQuery import io.realm.RealmQuery
import io.realm.kotlin.where import io.realm.kotlin.where


internal fun PusherEntity.Companion.where(realm: Realm, userId: String, pushKey: String? = null): RealmQuery<PusherEntity> { internal fun PusherEntity.Companion.where(realm: Realm,
userId: String,
pushKey: String? = null): RealmQuery<PusherEntity> {
return realm.where<PusherEntity>() return realm.where<PusherEntity>()
.equalTo(PusherEntityFields.USER_ID, userId) .equalTo(PusherEntityFields.USER_ID, userId)
.apply { .apply {
@ -33,9 +35,12 @@ internal fun PusherEntity.Companion.where(realm: Realm, userId: String, pushKey:
} }
} }


internal fun PushRulesEntity.Companion.where(realm: Realm, userId: String, scope: String, rulesetKey: String) : RealmQuery<PushRulesEntity> { internal fun PushRulesEntity.Companion.where(realm: Realm,
return realm.where<PushRulesEntity>() userId: String,
.equalTo(PushRulesEntityFields.USER_ID,userId) scope: String,
.equalTo(PushRulesEntityFields.SCOPE,scope) ruleSetKey: String): RealmQuery<PushRulesEntity> {
.equalTo(PushRulesEntityFields.RULESET_KEY,rulesetKey) return realm.where<PushRulesEntity>()
.equalTo(PushRulesEntityFields.USER_ID, userId)
.equalTo(PushRulesEntityFields.SCOPE, scope)
.equalTo(PushRulesEntityFields.RULESET_KEY, ruleSetKey)
} }

View File

@ -172,7 +172,7 @@ internal class SessionModule(private val sessionParams: SessionParams) {


scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {
val retrofit: Retrofit = get() val retrofit: Retrofit = get()
retrofit.create(PushrulesApi::class.java) retrofit.create(PushRulesApi::class.java)
} }


scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {
@ -184,7 +184,7 @@ internal class SessionModule(private val sessionParams: SessionParams) {
} }


scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {
DefaultGetPushrulesTask(get()) as GetPushRulesTask DefaultGetPushRulesTask(get()) as GetPushRulesTask
} }


scope(DefaultSession.SCOPE) { scope(DefaultSession.SCOPE) {

View File

@ -20,8 +20,8 @@ import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.auth.data.SessionParams
import im.vector.matrix.android.api.pushrules.Action import im.vector.matrix.android.api.pushrules.Action
import im.vector.matrix.android.api.pushrules.PushRuleService import im.vector.matrix.android.api.pushrules.PushRuleService
import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.api.pushrules.rest.PushrulesResponse
import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.Event
import im.vector.matrix.android.internal.database.mapper.PushRulesMapper import im.vector.matrix.android.internal.database.mapper.PushRulesMapper
import im.vector.matrix.android.internal.database.model.PushRulesEntity import im.vector.matrix.android.internal.database.model.PushRulesEntity
@ -47,8 +47,8 @@ internal class DefaultPushRuleService(
override fun fetchPushRules(scope: String) { override fun fetchPushRules(scope: String) {
pushRulesTask pushRulesTask
.configureWith(Unit) .configureWith(Unit)
.dispatchTo(object : MatrixCallback<PushrulesResponse> { .dispatchTo(object : MatrixCallback<GetPushRulesResponse> {
override fun onSuccess(data: PushrulesResponse) { override fun onSuccess(data: GetPushRulesResponse) {
monarchy.runTransactionSync { realm -> monarchy.runTransactionSync { realm ->
//clear existings? //clear existings?
//TODO //TODO
@ -56,7 +56,7 @@ internal class DefaultPushRuleService(
.equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId) .equalTo(PusherEntityFields.USER_ID, sessionParams.credentials.userId)
.findAll().deleteAllFromRealm() .findAll().deleteAllFromRealm()


var content = PushRulesEntity(sessionParams.credentials.userId, scope, "content") val content = PushRulesEntity(sessionParams.credentials.userId, scope, "content")
data.global.content?.forEach { rule -> data.global.content?.forEach { rule ->
PushRulesMapper.map(rule).also { PushRulesMapper.map(rule).also {
content.pushRules.add(it) content.pushRules.add(it)
@ -64,7 +64,7 @@ internal class DefaultPushRuleService(
} }
realm.insertOrUpdate(content) realm.insertOrUpdate(content)


var override = PushRulesEntity(sessionParams.credentials.userId, scope, "override") val override = PushRulesEntity(sessionParams.credentials.userId, scope, "override")
data.global.override?.forEach { rule -> data.global.override?.forEach { rule ->
PushRulesMapper.map(rule).also { PushRulesMapper.map(rule).also {
override.pushRules.add(it) override.pushRules.add(it)
@ -72,7 +72,7 @@ internal class DefaultPushRuleService(
} }
realm.insertOrUpdate(override) realm.insertOrUpdate(override)


var rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room") val rooms = PushRulesEntity(sessionParams.credentials.userId, scope, "room")
data.global.room?.forEach { rule -> data.global.room?.forEach { rule ->
PushRulesMapper.map(rule).also { PushRulesMapper.map(rule).also {
rooms.pushRules.add(it) rooms.pushRules.add(it)
@ -80,7 +80,7 @@ internal class DefaultPushRuleService(
} }
realm.insertOrUpdate(rooms) realm.insertOrUpdate(rooms)


var senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender") val senders = PushRulesEntity(sessionParams.credentials.userId, scope, "sender")
data.global.sender?.forEach { rule -> data.global.sender?.forEach { rule ->
PushRulesMapper.map(rule).also { PushRulesMapper.map(rule).also {
senders.pushRules.add(it) senders.pushRules.add(it)
@ -88,7 +88,7 @@ internal class DefaultPushRuleService(
} }
realm.insertOrUpdate(senders) realm.insertOrUpdate(senders)


var underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride") val underrides = PushRulesEntity(sessionParams.credentials.userId, scope, "underride")
data.global.underride?.forEach { rule -> data.global.underride?.forEach { rule ->
PushRulesMapper.map(rule).also { PushRulesMapper.map(rule).also {
underrides.pushRules.add(it) underrides.pushRules.add(it)
@ -106,35 +106,24 @@ internal class DefaultPushRuleService(
override fun getPushrules(scope: String): List<PushRule> { override fun getPushrules(scope: String): List<PushRule> {


var contentRules: List<PushRule> = emptyList() var contentRules: List<PushRule> = emptyList()
var overrideRules: List<PushRule> = emptyList()
var roomRules: List<PushRule> = emptyList()
var senderRules: List<PushRule> = emptyList()
var underrideRules: List<PushRule> = emptyList()

monarchy.doWithRealm { realm -> monarchy.doWithRealm { realm ->
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "content").findFirst()?.let { re -> PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "content").findFirst()?.let { re ->
contentRules = re.pushRules.map { PushRulesMapper.mapContentRule(it) } contentRules = re.pushRules.map { PushRulesMapper.mapContentRule(it) }
} }
}

var overrideRules: List<PushRule> = emptyList()
monarchy.doWithRealm { realm ->
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "override").findFirst()?.let { re -> PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "override").findFirst()?.let { re ->
overrideRules = re.pushRules.map { PushRulesMapper.map(it) } overrideRules = re.pushRules.map { PushRulesMapper.map(it) }
} }
}

var roomRules: List<PushRule> = emptyList()
monarchy.doWithRealm { realm ->
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "room").findFirst()?.let { re -> PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "room").findFirst()?.let { re ->
roomRules = re.pushRules.map { PushRulesMapper.mapRoomRule(it) } roomRules = re.pushRules.map { PushRulesMapper.mapRoomRule(it) }
} }
}

var senderRules: List<PushRule> = emptyList()
monarchy.doWithRealm { realm ->
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "sender").findFirst()?.let { re -> PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "sender").findFirst()?.let { re ->
senderRules = re.pushRules.map { PushRulesMapper.mapSenderRule(it) } senderRules = re.pushRules.map { PushRulesMapper.mapSenderRule(it) }
} }
}

var underrideRules: List<PushRule> = emptyList()
monarchy.doWithRealm { realm ->
PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "underride").findFirst()?.let { re -> PushRulesEntity.where(realm, sessionParams.credentials.userId, scope, "underride").findFirst()?.let { re ->
underrideRules = re.pushRules.map { PushRulesMapper.map(it) } underrideRules = re.pushRules.map { PushRulesMapper.map(it) }
} }
@ -184,6 +173,4 @@ internal class DefaultPushRuleService(


} }
} }


} }

View File

@ -47,8 +47,8 @@ internal class DefaultPusherService(
override fun refreshPushers() { override fun refreshPushers() {
getPusherTask getPusherTask
.configureWith(Unit) .configureWith(Unit)
.dispatchTo(object : MatrixCallback<PushersResponse> { .dispatchTo(object : MatrixCallback<GetPushersResponse> {
override fun onSuccess(data: PushersResponse) { override fun onSuccess(data: GetPushersResponse) {
monarchy.runTransactionSync { realm -> monarchy.runTransactionSync { realm ->
//clear existings? //clear existings?
realm.where(PusherEntity::class.java) realm.where(PusherEntity::class.java)
@ -66,9 +66,6 @@ internal class DefaultPusherService(
.executeBy(taskExecutor) .executeBy(taskExecutor)
} }


/**
*
*/
override fun addHttpPusher(pushkey: String, appId: String, profileTag: String, override fun addHttpPusher(pushkey: String, appId: String, profileTag: String,
lang: String, appDisplayName: String, deviceDisplayName: String, lang: String, appDisplayName: String, deviceDisplayName: String,
url: String, append: Boolean, withEventIdOnly: Boolean) url: String, append: Boolean, withEventIdOnly: Boolean)

View File

@ -20,6 +20,7 @@ import com.squareup.moshi.JsonClass




@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal class PushersResponse( internal class GetPushersResponse(
@Json(name = "pushers") val pushers: List<JsonPusher>? = null @Json(name = "pushers")
val pushers: List<JsonPusher>? = null
) )

View File

@ -19,11 +19,11 @@ import arrow.core.Try
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task


internal interface GetPushersTask : Task<Unit, PushersResponse> internal interface GetPushersTask : Task<Unit, GetPushersResponse>


internal class DefaultGetPusherTask(private val pushersAPI: PushersAPI) : GetPushersTask { internal class DefaultGetPusherTask(private val pushersAPI: PushersAPI) : GetPushersTask {


override suspend fun execute(params: Unit): Try<PushersResponse> { override suspend fun execute(params: Unit): Try<GetPushersResponse> {
return executeRequest { return executeRequest {
apiCall = pushersAPI.getPushers() apiCall = pushersAPI.getPushers()
} }

View File

@ -16,18 +16,18 @@
package im.vector.matrix.android.internal.session.pushers package im.vector.matrix.android.internal.session.pushers


import arrow.core.Try import arrow.core.Try
import im.vector.matrix.android.api.pushrules.rest.PushrulesResponse import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.task.Task




internal interface GetPushRulesTask : Task<Unit, PushrulesResponse> internal interface GetPushRulesTask : Task<Unit, GetPushRulesResponse>


internal class DefaultGetPushrulesTask(private val pushrulesApi: PushrulesApi) : GetPushRulesTask { internal class DefaultGetPushRulesTask(private val pushRulesApi: PushRulesApi) : GetPushRulesTask {


override suspend fun execute(params: Unit): Try<PushrulesResponse> { override suspend fun execute(params: Unit): Try<GetPushRulesResponse> {
return executeRequest { return executeRequest {
apiCall = pushrulesApi.getAllRules() apiCall = pushRulesApi.getAllRules()
} }
} }
} }

View File

@ -20,14 +20,7 @@ import com.squareup.moshi.JsonClass
import im.vector.matrix.android.internal.di.SerializeNulls import im.vector.matrix.android.internal.di.SerializeNulls


/** /**
* pushkey string Required. This is a unique identifier for this pusher. See /set for more detail. Max length, 512 bytes. * Example:
* kind string Required. The kind of pusher. "http" is a pusher that sends HTTP pokes.
* app_id string Required. This is a reverse-DNS style identifier for the application. Max length, 64 chars.
* app_display_name string Required. A string that will allow the user to identify what application owns this pusher.
* device_display_name string Required. A string that will allow the user to identify what device owns this pusher.
* profile_tag string This string determines which set of device specific rules this pusher executes.
* lang string Required. The preferred language for receiving notifications (e.g. 'en' or 'en-US')
* data PusherData Required. A dictionary of information for the pusher implementation itself.
* *
* <code> * <code>
* { * {
@ -50,20 +43,61 @@ import im.vector.matrix.android.internal.di.SerializeNulls


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class JsonPusher( internal data class JsonPusher(
@Json(name = "pushkey") val pushKey: String, /**
@Json(name = "kind") @SerializeNulls val kind: String?, * Required. This is a unique identifier for this pusher. See /set for more detail. Max length, 512 bytes.
@Json(name = "app_id") val appId: String, */
@Json(name = "app_display_name") val appDisplayName: String? = null, @Json(name = "pushkey")
@Json(name = "device_display_name") val deviceDisplayName: String? = null, val pushKey: String,
@Json(name = "profile_tag") val profileTag: String? = null,
@Json(name = "lang") val lang: String? = null, /**
@Json(name = "data") val data: JsonPusherData? = null, * Required. The kind of pusher. "http" is a pusher that sends HTTP pokes.
*/
@SerializeNulls
@Json(name = "kind")
val kind: String?,

/**
* Required. This is a reverse-DNS style identifier for the application. Max length, 64 chars.
*/
@Json(name = "app_id")
val appId: String,

/**
* Required. A string that will allow the user to identify what application owns this pusher.
*/
@Json(name = "app_display_name")
val appDisplayName: String? = null,

/**
* Required. A string that will allow the user to identify what device owns this pusher.
*/
@Json(name = "device_display_name")
val deviceDisplayName: String? = null,

/**
* This string determines which set of device specific rules this pusher executes.
*/
@Json(name = "profile_tag")
val profileTag: String? = null,

/**
* Required. The preferred language for receiving notifications (e.g. 'en' or 'en-US')
*/
@Json(name = "lang")
val lang: String? = null,

/**
* Required. A dictionary of information for the pusher implementation itself.
*/
@Json(name = "data")
val data: JsonPusherData? = null,


// Only used to update add Pusher (body of api request) // Only used to update add Pusher (body of api request)
// Used If true, the homeserver should add another pusher with the given pushkey and App ID in addition // Used If true, the homeserver should add another pusher with the given pushkey and App ID in addition
// to any others with different user IDs. // to any others with different user IDs.
// Otherwise, the homeserver must remove any other pushers with the same App ID and pushkey for different users. // Otherwise, the homeserver must remove any other pushers with the same App ID and pushkey for different users.
// The default is false. // The default is false.
@Json(name = "append") val append: Boolean? = false @Json(name = "append")
val append: Boolean? = false
) )



View File

@ -20,8 +20,15 @@ import com.squareup.moshi.JsonClass


@JsonClass(generateAdapter = true) @JsonClass(generateAdapter = true)
internal data class JsonPusherData( internal data class JsonPusherData(
//Required if kind is http. The URL to use to send notifications to. /**
@Json(name = "url") val url: String? = null, * Required if kind is http. The URL to use to send notifications to.
//The format to use when sending notifications to the Push Gateway. */
@Json(name = "format") val format: String? = null @Json(name = "url")
val url: String? = null,

/**
* The format to use when sending notifications to the Push Gateway.
*/
@Json(name = "format")
val format: String? = null
) )

View File

@ -16,18 +16,18 @@
package im.vector.matrix.android.internal.session.pushers package im.vector.matrix.android.internal.session.pushers


import im.vector.matrix.android.api.pushrules.rest.PushRule import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.api.pushrules.rest.PushrulesResponse import im.vector.matrix.android.api.pushrules.rest.GetPushRulesResponse
import im.vector.matrix.android.internal.network.NetworkConstants import im.vector.matrix.android.internal.network.NetworkConstants
import retrofit2.Call import retrofit2.Call
import retrofit2.http.* import retrofit2.http.*




internal interface PushrulesApi { internal interface PushRulesApi {
/** /**
* Get all push rules * Get all push rules
*/ */
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/")
fun getAllRules(): Call<PushrulesResponse> fun getAllRules(): Call<GetPushRulesResponse>


/** /**
* Update the ruleID enable status * Update the ruleID enable status
@ -37,28 +37,36 @@ internal interface PushrulesApi {
* @param enable the new enable status * @param enable the new enable status
*/ */
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/enabled") @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/enabled")
fun updateEnableRuleStatus(@Path("kind") kind: String, @Path("ruleId") ruleId: String, @Body enable: Boolean?): Call<Unit> fun updateEnableRuleStatus(@Path("kind") kind: String,
@Path("ruleId") ruleId: String,
@Body enable: Boolean?)
: Call<Unit>




/** /**
* Update the ruleID enable status * Update the ruleID action
* *
* @param kind the notification kind (sender, room...) * @param kind the notification kind (sender, room...)
* @param ruleId the ruleId * @param ruleId the ruleId
* @param actions the actions * @param actions the actions
*/ */
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/actions") @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}/actions")
fun updateRuleActions(@Path("kind") kind: String, @Path("ruleId") ruleId: String, @Body actions: Any): Call<Unit> fun updateRuleActions(@Path("kind") kind: String,
@Path("ruleId") ruleId: String,
@Body actions: Any)
: Call<Unit>




/** /**
* Update the ruleID enable status * Delete a rule
* *
* @param kind the notification kind (sender, room...) * @param kind the notification kind (sender, room...)
* @param ruleId the ruleId * @param ruleId the ruleId
*/ */
@DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}") @DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}")
fun deleteRule(@Path("kind") kind: String, @Path("ruleId") ruleId: String): Call<Unit> fun deleteRule(@Path("kind") kind: String,
@Path("ruleId") ruleId: String)
: Call<Unit>


/** /**
* Add the ruleID enable status * Add the ruleID enable status
@ -68,5 +76,8 @@ internal interface PushrulesApi {
* @param rule the rule to add. * @param rule the rule to add.
*/ */
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}") @PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushrules/global/{kind}/{ruleId}")
fun addRule(@Path("kind") kind: String, @Path("ruleId") ruleId: String, @Body rule: PushRule): Call<Unit> fun addRule(@Path("kind") kind: String,
@Path("ruleId") ruleId: String,
@Body rule: PushRule)
: Call<Unit>
} }

View File

@ -27,14 +27,16 @@ internal interface PushersAPI {
/** /**
* Get the pushers for this user. * Get the pushers for this user.
* *
* Ref: https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-client-r0-thirdparty-protocols * Ref: https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-pushers
*/ */
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushers") @GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushers")
fun getPushers(): Call<PushersResponse> fun getPushers(): Call<GetPushersResponse>


/** /**
* This endpoint allows the creation, modification and deletion of pushers for this user ID. * This endpoint allows the creation, modification and deletion of pushers for this user ID.
* The behaviour of this endpoint varies depending on the values in the JSON body. * The behaviour of this endpoint varies depending on the values in the JSON body.
*
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-pushers-set
*/ */
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushers/set") @POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "pushers/set")
fun setPusher(@Body jsonPusher: JsonPusher): Call<Unit> fun setPusher(@Body jsonPusher: JsonPusher): Call<Unit>

View File

@ -12,7 +12,9 @@ import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.tryTransactionSync import im.vector.matrix.android.internal.util.tryTransactionSync


internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> { internal interface RemovePusherTask : Task<RemovePusherTask.Params, Unit> {
data class Params(val userId: String, val pushKey: String, val pushAppId: String) data class Params(val userId: String,
val pushKey: String,
val pushAppId: String)
} }


internal class DefaultRemovePusherTask( internal class DefaultRemovePusherTask(
@ -35,10 +37,11 @@ internal class DefaultRemovePusherTask(
} }
}.flatMap { }.flatMap {
executeRequest<Unit> { executeRequest<Unit> {
val deleteRequest = JsonPusher( val deleteBody = JsonPusher(
pushKey = params.pushKey, pushKey = params.pushKey,
appId = params.pushAppId, appId = params.pushAppId,
kind = null, //null deletes the pusher // kind null deletes the pusher
kind = null,
appDisplayName = it.appDisplayName ?: "", appDisplayName = it.appDisplayName ?: "",
deviceDisplayName = it.deviceDisplayName ?: "", deviceDisplayName = it.deviceDisplayName ?: "",
profileTag = it.profileTag ?: "", profileTag = it.profileTag ?: "",
@ -46,7 +49,7 @@ internal class DefaultRemovePusherTask(
data = JsonPusherData(it.data.url, it.data.format), data = JsonPusherData(it.data.url, it.data.format),
append = false append = false
) )
apiCall = pushersAPI.setPusher(deleteRequest) apiCall = pushersAPI.setPusher(deleteBody)
} }
}.flatMap { }.flatMap {
monarchy.tryTransactionSync { monarchy.tryTransactionSync {

View File

@ -29,7 +29,7 @@ import im.vector.matrix.android.internal.task.Task


internal interface SyncTask : Task<SyncTask.Params, SyncResponse> { internal interface SyncTask : Task<SyncTask.Params, SyncResponse> {


data class Params(val token: String?, var timeout: Long = 30_1000L) data class Params(val token: String?, var timeout: Long = 30_000L)


} }



View File

@ -50,7 +50,7 @@ class PushRuleActionsTest {
val pushRule = MoshiProvider.providesMoshi().adapter<PushRule>(PushRule::class.java).fromJson(rawPushRule) val pushRule = MoshiProvider.providesMoshi().adapter<PushRule>(PushRule::class.java).fromJson(rawPushRule)


Assert.assertNotNull("Should have parsed the rule", pushRule) Assert.assertNotNull("Should have parsed the rule", pushRule)
Assert.assertNotNull("Failed to parse domainActions", Action.mapFrom(pushRule!!)) Assert.assertNotNull("Failed to parse actions", Action.mapFrom(pushRule!!))


val actions = Action.mapFrom(pushRule) val actions = Action.mapFrom(pushRule)
Assert.assertEquals(3, actions!!.size) Assert.assertEquals(3, actions!!.size)

View File

@ -33,8 +33,6 @@ import timber.log.Timber
* It has an alter ego in the fdroid variant. * It has an alter ego in the fdroid variant.
*/ */
object FcmHelper { object FcmHelper {
private val LOG_TAG = FcmHelper::class.java.simpleName

private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN"




@ -51,6 +49,7 @@ object FcmHelper {


/** /**
* Store FCM token to the SharedPrefs * Store FCM token to the SharedPrefs
* TODO Store in realm
* *
* @param context android context * @param context android context
* @param token the token to store * @param token the token to store

View File

@ -54,7 +54,7 @@ import im.vector.riotredesign.features.workers.signout.SignOutViewModel


class HomeActivity : VectorBaseActivity(), ToolbarConfigurable { class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {


// Supported navigation domainActions for this Activity // Supported navigation actions for this Activity
sealed class Navigation { sealed class Navigation {
object OpenDrawer : Navigation() object OpenDrawer : Navigation()
} }

View File

@ -30,7 +30,7 @@ import im.vector.matrix.android.api.session.user.model.User
* QUOTE: User is currently quoting a message * QUOTE: User is currently quoting a message
* EDIT: User is currently editing an existing message * EDIT: User is currently editing an existing message
* *
* Depending on the state the bottom toolbar will change (icons/preview/domainActions...) * Depending on the state the bottom toolbar will change (icons/preview/actions...)
*/ */
enum class SendMode { enum class SendMode {
REGULAR, REGULAR,

View File

@ -20,7 +20,7 @@ import androidx.lifecycle.ViewModel
import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.core.utils.LiveEvent


/** /**
* Activity shared view model to handle message domainActions * Activity shared view model to handle message actions
*/ */
class ActionsHandler : ViewModel() { class ActionsHandler : ViewModel() {



View File

@ -38,8 +38,8 @@ import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInf
import kotlinx.android.synthetic.main.bottom_sheet_message_actions.* import kotlinx.android.synthetic.main.bottom_sheet_message_actions.*


/** /**
* Bottom sheet fragment that shows a message preview with list of contextual domainActions * Bottom sheet fragment that shows a message preview with list of contextual actions
* (Includes fragments for quick reactions and list of domainActions) * (Includes fragments for quick reactions and list of actions)
*/ */
class MessageActionsBottomSheet : BaseMvRxBottomSheetDialog() { class MessageActionsBottomSheet : BaseMvRxBottomSheetDialog() {



View File

@ -37,7 +37,7 @@ data class SimpleAction(val uid: String, val titleRes: Int, val iconResId: Int?,
data class MessageMenuState(val actions: List<SimpleAction> = emptyList()) : MvRxState data class MessageMenuState(val actions: List<SimpleAction> = emptyList()) : MvRxState


/** /**
* Manages list domainActions for a given message (copy / paste / forward...) * Manages list actions for a given message (copy / paste / forward...)
*/ */
class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<MessageMenuState>(initialState) { class MessageMenuViewModel(initialState: MessageMenuState) : VectorViewModel<MessageMenuState>(initialState) {



View File

@ -30,12 +30,6 @@ import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
import timber.log.Timber import timber.log.Timber


// TODO Remove
class RoomState {

}


/** /**
* The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event. * The notifiable event resolver is able to create a NotifiableEvent (view model for notifications) from an sdk Event.
* It is used as a bridge between the Event Thread and the NotificationDrawerManager. * It is used as a bridge between the Event Thread and the NotificationDrawerManager.

View File

@ -27,7 +27,7 @@ import org.koin.standalone.inject
import timber.log.Timber import timber.log.Timber


/** /**
* Receives domainActions broadcast by notification (on click, on dismiss, inline replies, etc.) * Receives actions broadcast by notification (on click, on dismiss, inline replies, etc.)
*/ */
class NotificationBroadcastReceiver : BroadcastReceiver(), KoinComponent { class NotificationBroadcastReceiver : BroadcastReceiver(), KoinComponent {



View File

@ -64,7 +64,7 @@ object NotificationUtils {
const val NOTIFICATION_ID_FOREGROUND_SERVICE = 61 const val NOTIFICATION_ID_FOREGROUND_SERVICE = 61


/* ========================================================================================== /* ==========================================================================================
* IDs for domainActions * IDs for actions
* ========================================================================================== */ * ========================================================================================== */


private const val JOIN_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.JOIN_ACTION" private const val JOIN_ACTION = "${BuildConfig.APPLICATION_ID}.NotificationActions.JOIN_ACTION"
@ -426,7 +426,7 @@ object NotificationUtils {
priority = NotificationCompat.PRIORITY_LOW priority = NotificationCompat.PRIORITY_LOW
} }


//Add domainActions and notification intents //Add actions and notification intents
// Mark room as read // Mark room as read
val markRoomReadIntent = Intent(context, NotificationBroadcastReceiver::class.java) val markRoomReadIntent = Intent(context, NotificationBroadcastReceiver::class.java)
markRoomReadIntent.action = MARK_ROOM_READ_ACTION markRoomReadIntent.action = MARK_ROOM_READ_ACTION

View File

@ -17,7 +17,7 @@ package im.vector.riotredesign.features.notifications


import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix


class OutdatedEventDetector() { class OutdatedEventDetector {


/** /**
* Returns true if the given event is outdated. * Returns true if the given event is outdated.

View File

@ -1,3 +1,19 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.notifications package im.vector.riotredesign.features.notifications


import im.vector.matrix.android.api.pushrules.Action import im.vector.matrix.android.api.pushrules.Action

View File

@ -1,3 +1,19 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.settings package im.vector.riotredesign.features.settings


import android.os.Bundle import android.os.Bundle
@ -5,15 +21,13 @@ import androidx.preference.Preference
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.pushers.PushersService
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.VectorPreferenceFragment import im.vector.riotredesign.core.platform.VectorPreferenceFragment
import im.vector.riotredesign.core.pushers.PushersManager import im.vector.riotredesign.core.pushers.PushersManager
import im.vector.riotredesign.push.fcm.FcmHelper import im.vector.riotredesign.push.fcm.FcmHelper
import org.koin.android.ext.android.get
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject



// Referenced in vector_settings_preferences_root.xml
class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() { class VectorSettingsNotificationPreferenceFragment : VectorPreferenceFragment() {


override var titleRes: Int = R.string.settings_notifications override var titleRes: Int = R.string.settings_notifications

View File

@ -1,3 +1,19 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.settings package im.vector.riotredesign.features.settings


import android.os.Bundle import android.os.Bundle

View File

@ -1,3 +1,19 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package im.vector.riotredesign.features.settings.push package im.vector.riotredesign.features.settings.push


import android.widget.TextView import android.widget.TextView
@ -17,6 +33,7 @@ abstract class PushGatewayItem : EpoxyModelWithHolder<PushGatewayItem.Holder>()


override fun bind(holder: Holder) { override fun bind(holder: Holder) {
holder.kind.text = when (pusher.kind) { holder.kind.text = when (pusher.kind) {
// TODO Create const
"http" -> "Http Pusher" "http" -> "Http Pusher"
"mail" -> "Email Pusher" "mail" -> "Email Pusher"
else -> pusher.kind else -> pusher.kind

View File

@ -30,6 +30,7 @@ import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.core.ui.list.genericFooterItem import im.vector.riotredesign.core.ui.list.genericFooterItem
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.* import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*


// Referenced in vector_settings_notifications.xml
class PushGatewaysFragment : VectorBaseFragment() { class PushGatewaysFragment : VectorBaseFragment() {


override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
@ -50,16 +51,16 @@ class PushGatewaysFragment : VectorBaseFragment() {
val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context, val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context,
lmgr.orientation) lmgr.orientation)
epoxyRecyclerView.addItemDecoration(dividerItemDecoration) epoxyRecyclerView.addItemDecoration(dividerItemDecoration)
epoxyRecyclerView.adapter = epoxyController.adapter epoxyRecyclerView.setController(epoxyController)
} }


override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) { state ->
epoxyController.setData(it) epoxyController.setData(state)
} }


class PushGateWayController(private val stringProvider: StringProvider) : TypedEpoxyController<PushGatewayViewState>() { class PushGateWayController(private val stringProvider: StringProvider) : TypedEpoxyController<PushGatewayViewState>() {
override fun buildModels(data: PushGatewayViewState?) { override fun buildModels(data: PushGatewayViewState?) {
data?.pushgateways?.invoke()?.let { pushers -> data?.pushGateways?.invoke()?.let { pushers ->
if (pushers.isEmpty()) { if (pushers.isEmpty()) {
genericFooterItem { genericFooterItem {
id("footer") id("footer")

View File

@ -25,12 +25,11 @@ import org.koin.android.ext.android.get




data class PushGatewayViewState( data class PushGatewayViewState(
val pushgateways: Async<List<Pusher>> = Uninitialized) val pushGateways: Async<List<Pusher>> = Uninitialized
: MvRxState ) : MvRxState


class PushGatewaysViewModel(initialState: PushGatewayViewState) : VectorViewModel<PushGatewayViewState>(initialState) { class PushGatewaysViewModel(initialState: PushGatewayViewState) : VectorViewModel<PushGatewayViewState>(initialState) {



companion object : MvRxViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> { companion object : MvRxViewModelFactory<PushGatewaysViewModel, PushGatewayViewState> {


override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? { override fun create(viewModelContext: ViewModelContext, state: PushGatewayViewState): PushGatewaysViewModel? {

View File

@ -23,6 +23,7 @@ abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
@EpoxyAttribute @EpoxyAttribute
lateinit var pushRule: PushRule lateinit var pushRule: PushRule


// TODO i18n
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun bind(holder: Holder) { override fun bind(holder: Holder) {
val context = holder.view.context val context = holder.view.context
@ -48,7 +49,7 @@ abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_dont_notify)) holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_dont_notify))
} }


var description = StringBuffer() val description = StringBuffer()
pushRule.conditions?.forEachIndexed { i, condition -> pushRule.conditions?.forEachIndexed { i, condition ->
if (i > 0) description.append("\n") if (i > 0) description.append("\n")
description.append(condition.asExecutableCondition()?.technicalDescription() description.append(condition.asExecutableCondition()?.technicalDescription()

View File

@ -29,14 +29,14 @@ import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.core.ui.list.genericFooterItem import im.vector.riotredesign.core.ui.list.genericFooterItem
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.* import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*



// Referenced in vector_settings_notifications.xml
class PushRulesFragment : VectorBaseFragment() { class PushRulesFragment : VectorBaseFragment() {


override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy


private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class) private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class)


private val epoxyController by lazy { PushRulesFragment.PushRulesController(StringProvider(requireContext().resources)) } private val epoxyController by lazy { PushRulesController(StringProvider(requireContext().resources)) }




override fun onResume() { override fun onResume() {
@ -51,11 +51,11 @@ class PushRulesFragment : VectorBaseFragment() {
val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context, val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context,
lmgr.orientation) lmgr.orientation)
epoxyRecyclerView.addItemDecoration(dividerItemDecoration) epoxyRecyclerView.addItemDecoration(dividerItemDecoration)
epoxyRecyclerView.adapter = epoxyController.adapter epoxyRecyclerView.setController(epoxyController)
} }


override fun invalidate() = withState(viewModel) { override fun invalidate() = withState(viewModel) { state ->
epoxyController.setData(it) epoxyController.setData(state)
} }


class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController<PushRulesViewState>() { class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController<PushRulesViewState>() {

View File

@ -24,8 +24,8 @@ import im.vector.riotredesign.core.platform.VectorViewModel
import org.koin.android.ext.android.get import org.koin.android.ext.android.get


data class PushRulesViewState( data class PushRulesViewState(
val rules: List<PushRule> = emptyList()) val rules: List<PushRule> = emptyList()
: MvRxState ) : MvRxState




class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) { class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) {

View File

@ -1,16 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.airbnb.epoxy.EpoxyRecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/epoxyRecyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> app:itemSpacing="1dp"

tools:listitem="@layout/item_pushgateway" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/epoxyRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:itemSpacing="1dp"
tools:listitem="@layout/item_pushgateway" />

</FrameLayout>