Get real push rules from server and evaluate them

This commit is contained in:
Valere
2019-06-21 18:26:35 +02:00
committed by Benoit Marty
parent 2e417a9143
commit 0584fc3666
49 changed files with 1535 additions and 274 deletions

View File

@ -137,8 +137,10 @@ class VectorApplication : Application() {
} else {
//TODO check if notifications are enabled for this device
//We need to use alarm in this mode
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext,4_000L)
Timber.i("Alarm scheduled to restart service")
if (Matrix.getInstance().currentSession != null) {
AlarmSyncBroadcastReceiver.scheduleAlarm(applicationContext, 4_000L)
Timber.i("Alarm scheduled to restart service")
}
}
}
@ -150,6 +152,7 @@ class VectorApplication : Application() {
it.refreshPushers()
//bind to the sync service
get<PushRuleTriggerListener>().startWithSession(it)
it.fetchPushRules()
}
}

View File

@ -25,7 +25,7 @@ import android.widget.TextView
import androidx.preference.PreferenceViewHolder
import im.vector.riotredesign.R
// TODO Replace by real Bingrule class
// TODO Replace by real Bingrule class, then delete
class BingRule(rule: BingRule) {
fun shouldNotNotify() = false
fun shouldNotify() = false

View File

@ -0,0 +1,62 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotredesign.core.ui.list
import android.widget.TextView
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
import im.vector.riotredesign.core.extensions.setTextOrHide
/**
* A generic list item.
* Displays an item with a title, and optional description.
* Can display an accessory on the right, that can be an image or an indeterminate progress.
* If provided with an action, will display a button at the bottom of the list item.
*/
@EpoxyModelClass(layout = R.layout.item_generic_footer)
abstract class GenericFooterItem : VectorEpoxyModel<GenericFooterItem.Holder>() {
@EpoxyAttribute
var text: String? = null
@EpoxyAttribute
var style: GenericItem.STYLE = GenericItem.STYLE.NORMAL_TEXT
@EpoxyAttribute
var itemClickAction: GenericItem.Action? = null
override fun bind(holder: Holder) {
holder.text.setTextOrHide(text)
when (style) {
GenericItem.STYLE.BIG_TEXT -> holder.text.textSize = 18f
GenericItem.STYLE.NORMAL_TEXT -> holder.text.textSize = 14f
}
holder.view.setOnClickListener {
itemClickAction?.perform?.run()
}
}
class Holder : VectorEpoxyHolder() {
val text by bind<TextView>(R.id.itemGenericFooterText)
}
}

View File

@ -78,6 +78,7 @@ class LoginActivity : VectorBaseActivity() {
data.setFilter(FilterService.FilterPreset.RiotFilter)
data.startSync()
get<PushRuleTriggerListener>().startWithSession(data)
data.fetchPushRules()
goToHome()
}

View File

@ -43,7 +43,7 @@ class NotifiableEventResolver(val context: Context) {
//private val eventDisplay = RiotEventDisplay(context)
fun resolveEvent(event: Event/*, roomState: RoomState?*/, bingRule: PushRule?, session: Session): NotifiableEvent? {
fun resolveEvent(event: Event/*, roomState: RoomState?, bingRule: PushRule?*/, session: Session): NotifiableEvent? {
// val store = session.dataHandler.store
@ -55,7 +55,7 @@ class NotifiableEventResolver(val context: Context) {
when (event.getClearType()) {
EventType.MESSAGE -> {
return resolveMessageEvent(event, bingRule, session)
return resolveMessageEvent(event, session)
}
// EventType.ENCRYPTED -> {
// val messageEvent = resolveMessageEvent(event, bingRule, session, store)
@ -88,12 +88,10 @@ class NotifiableEventResolver(val context: Context) {
}
private fun resolveMessageEvent(event: Event, pushRule: PushRule?, session: Session): NotifiableEvent? {
private fun resolveMessageEvent(event: Event, session: Session): NotifiableEvent? {
//If we are here, that means that the event should be notified to the user, we check now how it should be presented (sound)
// val soundName = pushRule?.notificationSound
val noisy = true//pushRule?.notificationSound != null
//The event only contains an eventId, and roomId (type is m.room.*) , we need to get the displayable content (names, avatar, text, etc...)
val room = session.getRoom(event.roomId!! /*roomID cannot be null (see Matrix SDK code)*/)
@ -109,7 +107,7 @@ class NotifiableEventResolver(val context: Context) {
val notifiableEvent = NotifiableMessageEvent(
eventId = event.eventId ?: "",
timestamp = event.originServerTs ?: 0,
noisy = noisy,
noisy = false,//will be updated
senderName = senderDisplayName,
senderId = event.senderId,
body = body,
@ -130,7 +128,7 @@ class NotifiableEventResolver(val context: Context) {
val notifiableEvent = NotifiableMessageEvent(
eventId = event.eventId!!,
timestamp = event.originServerTs ?: 0,
noisy = noisy,
noisy = false,//will be updated
senderName = senderDisplayName,
senderId = event.senderId,
body = body,

View File

@ -0,0 +1,41 @@
/*
* 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
import im.vector.matrix.android.api.pushrules.Action
data class NotificationAction(
val shouldNotify: Boolean,
val highlight: Boolean = false,
val soundName: String? = null
) {
companion object {
fun extractFrom(ruleActions: List<Action>): NotificationAction {
var shouldNotify = false
var highlight = false
var sound: String? = null
ruleActions.forEach {
if (it.type == Action.Type.NOTIFY) shouldNotify = true
if (it.type == Action.Type.DONT_NOTIFY) shouldNotify = false
if (it.type == Action.Type.SET_TWEAK) {
if (it.tweak_action == "highlight") highlight = it.boolValue ?: false
if (it.tweak_action == "sound") sound = it.stringValue
}
}
return NotificationAction(shouldNotify, highlight, sound)
}
}
}

View File

@ -57,28 +57,6 @@ class NotificationDrawerManager(val context: Context, private val outdatedDetect
}
})
/**
* No multi session support for now
*/
private fun initWithSession(session: Session?) {
session?.let {
/*
myUserDisplayName = it.myUser?.displayname ?: it.myUserId
// User Avatar
it.myUser?.avatarUrl?.let { avatarUrl ->
val userAvatarUrlPath = it.mediaCache?.thumbnailCacheFile(avatarUrl, avatarSize)
if (userAvatarUrlPath != null) {
myUserAvatarUrl = userAvatarUrlPath.path
} else {
// prepare for the next time
session.mediaCache?.loadAvatarThumbnail(session.homeServerConfig, ImageView(context), avatarUrl, avatarSize)
}
}
*/
}
}
/**
Should be called as soon as a new event is ready to be displayed.
The notification corresponding to this event will not be displayed until

View File

@ -16,12 +16,24 @@ class PushRuleTriggerListener(
var session: Session? = null
override fun onMatchRule(event: Event, actions: List<Action>) {
Timber.v("Push rule match for event ${event.eventId}")
if (session == null) {
Timber.e("Called without active session")
return
}
resolver.resolveEvent(event,null,session!!)?.let {
drawerManager.onNotifiableEventReceived(it)
val notificationAction = NotificationAction.extractFrom(actions)
if (notificationAction.shouldNotify) {
val resolveEvent = resolver.resolveEvent(event, session!!)
if (resolveEvent == null) {
Timber.v("## Failed to resolve event")
//TODO
} else {
resolveEvent.noisy = !notificationAction.soundName.isNullOrBlank()
Timber.v("New event to notify $resolveEvent tweaks:$notificationAction")
drawerManager.onNotifiableEventReceived(resolveEvent)
}
} else {
Timber.v("Matched push rule is set to not notify")
}
}
@ -43,4 +55,5 @@ class PushRuleTriggerListener(
drawerManager.clearAllEvents()
drawerManager.refreshNotificationDrawer()
}
}

View File

@ -1671,15 +1671,15 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
var index = 0
for (pusher in mDisplayedPushers) {
if (null != pusher.lang) {
val isThisDeviceTarget = TextUtils.equals(pushManager.currentRegistrationToken, pusher.pushkey)
for (pushRule in mDisplayedPushers) {
if (null != pushRule.lang) {
val isThisDeviceTarget = TextUtils.equals(pushManager.currentRegistrationToken, pushRule.pushkey)
val preference = VectorPreference(activity).apply {
mTypeface = if (isThisDeviceTarget) Typeface.BOLD else Typeface.NORMAL
}
preference.title = pusher.deviceDisplayName
preference.summary = pusher.appDisplayName
preference.title = pushRule.deviceDisplayName
preference.summary = pushRule.appDisplayName
preference.key = PUSHER_PREFERENCE_KEY_BASE + index
index++
mPushersSettingsCategory.addPreference(preference)
@ -1694,7 +1694,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
.setPositiveButton(R.string.remove)
{ _, _ ->
displayLoadingView()
pushManager.unregister(session, pusher, object : MatrixCallback<Unit> {
pushManager.unregister(session, pushRule, object : MatrixCallback<Unit> {
override fun onSuccess(info: Void?) {
refreshPushersList()
onCommonDone(null)

View File

@ -17,7 +17,6 @@
package im.vector.riotredesign.features.settings.push
import android.os.Bundle
import android.widget.LinearLayout
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
@ -27,19 +26,21 @@ import com.airbnb.mvrx.withState
import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.VectorBaseActivity
import im.vector.riotredesign.core.platform.VectorBaseFragment
import kotlinx.android.synthetic.main.fragment_settings_pushgateways.*
import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.core.ui.list.genericFooterItem
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
class PushGatewaysFragment : VectorBaseFragment() {
override fun getLayoutResId(): Int = R.layout.fragment_settings_pushgateways
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
private val viewModel: PushGatewaysViewModel by fragmentViewModel(PushGatewaysViewModel::class)
private val epoxyController by lazy { PushGateWayController() }
private val epoxyController by lazy { PushGateWayController(StringProvider(requireContext().resources)) }
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_gateways)
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_notifications_targets)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -56,13 +57,26 @@ class PushGatewaysFragment : VectorBaseFragment() {
epoxyController.setData(it)
}
class PushGateWayController : TypedEpoxyController<PushGatewayViewState>() {
class PushGateWayController(private val stringProvider: StringProvider) : TypedEpoxyController<PushGatewayViewState>() {
override fun buildModels(data: PushGatewayViewState?) {
val pushers = data?.pushgateways?.invoke() ?: return
pushers.forEach {
pushGatewayItem {
id("${it.pushKey}_${it.appId}")
pusher(it)
data?.pushgateways?.invoke()?.let { pushers ->
if (pushers.isEmpty()) {
genericFooterItem {
id("footer")
text(stringProvider.getString(R.string.settings_push_gateway_no_pushers))
}
} else {
pushers.forEach {
pushGatewayItem {
id("${it.pushKey}_${it.appId}")
pusher(it)
}
}
}
} ?: run {
genericFooterItem {
id("footer")
text(stringProvider.getString(R.string.loading))
}
}
}

View File

@ -0,0 +1,71 @@
package im.vector.riotredesign.features.settings.push
import android.annotation.SuppressLint
import android.graphics.Color
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import com.airbnb.epoxy.EpoxyModelWithHolder
import im.vector.matrix.android.api.pushrules.Action
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.riotredesign.R
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
import im.vector.riotredesign.features.notifications.NotificationAction
@EpoxyModelClass(layout = R.layout.item_pushrule_raw)
abstract class PushRuleItem : EpoxyModelWithHolder<PushRuleItem.Holder>() {
@EpoxyAttribute
lateinit var pushRule: PushRule
@SuppressLint("SetTextI18n")
override fun bind(holder: Holder) {
val context = holder.view.context
if (pushRule.enabled) {
holder.view.setBackgroundColor(Color.TRANSPARENT)
holder.ruleId.text = pushRule.ruleId
} else {
holder.view.setBackgroundColor(ContextCompat.getColor(context, R.color.vector_silver_color))
holder.ruleId.text = "[Disabled] ${pushRule.ruleId}"
}
val actions = Action.mapFrom(pushRule)
if (actions.isNullOrEmpty()) {
holder.actionIcon.isInvisible = true
} else {
holder.actionIcon.isVisible = true
val notifAction = NotificationAction.extractFrom(actions)
if (notifAction.shouldNotify && !notifAction.soundName.isNullOrBlank()) {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_noisy))
} else if (notifAction.shouldNotify) {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_notify_silent))
} else {
holder.actionIcon.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_action_dont_notify))
}
var description = StringBuffer()
pushRule.conditions?.forEachIndexed { i, condition ->
if (i > 0) description.append("\n")
description.append(condition.asExecutableCondition()?.technicalDescription()
?: "UNSUPPORTED")
}
if (description.isBlank()) {
holder.description.text = "No Conditions"
} else {
holder.description.text = description
}
}
}
class Holder : VectorEpoxyHolder() {
val ruleId by bind<TextView>(R.id.pushRuleId)
val description by bind<TextView>(R.id.pushRuleDescription)
val actionIcon by bind<ImageView>(R.id.pushRuleActionIcon)
}
}

View File

@ -0,0 +1,80 @@
/*
* 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
import android.os.Bundle
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.VectorBaseActivity
import im.vector.riotredesign.core.platform.VectorBaseFragment
import im.vector.riotredesign.core.resources.StringProvider
import im.vector.riotredesign.core.ui.list.genericFooterItem
import kotlinx.android.synthetic.main.fragment_generic_recycler_epoxy.*
class PushRulesFragment : VectorBaseFragment() {
override fun getLayoutResId(): Int = R.layout.fragment_generic_recycler_epoxy
private val viewModel: PushRulesViewModel by fragmentViewModel(PushRulesViewModel::class)
private val epoxyController by lazy { PushRulesFragment.PushRulesController(StringProvider(requireContext().resources)) }
override fun onResume() {
super.onResume()
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_push_rules)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val lmgr = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
epoxyRecyclerView.layoutManager = lmgr
val dividerItemDecoration = DividerItemDecoration(epoxyRecyclerView.context,
lmgr.orientation)
epoxyRecyclerView.addItemDecoration(dividerItemDecoration)
epoxyRecyclerView.adapter = epoxyController.adapter
}
override fun invalidate() = withState(viewModel) {
epoxyController.setData(it)
}
class PushRulesController(private val stringProvider: StringProvider) : TypedEpoxyController<PushRulesViewState>() {
override fun buildModels(data: PushRulesViewState?) {
data?.let {
it.rules.forEach {
pushRuleItem {
id(it.ruleId)
pushRule(it)
}
}
} ?: run {
genericFooterItem {
id("footer")
text(stringProvider.getString(R.string.settings_push_rules_no_rules))
}
}
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotredesign.features.settings.push
import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import im.vector.matrix.android.api.pushrules.rest.PushRule
import im.vector.matrix.android.api.session.Session
import im.vector.riotredesign.core.platform.VectorViewModel
import org.koin.android.ext.android.get
data class PushRulesViewState(
val rules: List<PushRule> = emptyList())
: MvRxState
class PushRulesViewModel(initialState: PushRulesViewState) : VectorViewModel<PushRulesViewState>(initialState) {
companion object : MvRxViewModelFactory<PushRulesViewModel, PushRulesViewState> {
override fun initialState(viewModelContext: ViewModelContext): PushRulesViewState? {
val session = viewModelContext.activity.get<Session>()
val rules = session.getPushrules()
return PushRulesViewState(rules)
}
}
}

View File

@ -0,0 +1,25 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="34dp"
android:height="34dp"
android:viewportWidth="34"
android:viewportHeight="34">
<path
android:pathData="M9.7169,15L9.7169,20.2316L7.5734,23.7393C7.5254,23.8178 7.5,23.908 7.5,24C7.5,24.2761 7.7239,24.5 8,24.5L26.4339,24.5C26.5259,24.5 26.6161,24.4746 26.6946,24.4266C26.9302,24.2826 27.0045,23.9749 26.8605,23.7393L24.7169,20.2316L24.7169,15C24.7169,11.558 22.3785,8.582 19.0923,7.7363L18.7169,7.6396L18.7169,6C18.7169,5.1716 18.0454,4.5 17.2169,4.5C16.3885,4.5 15.7169,5.1716 15.7169,6L15.7169,7.6396L15.3416,7.7363C12.0554,8.582 9.7169,11.558 9.7169,15ZM14.797,26.5C15.0741,27.3506 16.0402,28 17.2169,28C18.3937,28 19.3598,27.3506 19.6369,26.5L14.797,26.5Z"
android:strokeWidth="1"
android:fillColor="#00000000"
android:strokeColor="#224955"
android:fillType="evenOdd"/>
<path
android:pathData="M17,17m-16,0a16,16 0,1 1,32 0a16,16 0,1 1,-32 0"
android:strokeWidth="1"
android:fillColor="#00000000"
android:strokeColor="#224955"
android:fillType="evenOdd"/>
<path
android:pathData="M4.5,27.25L28.2169,6"
android:strokeWidth="1"
android:fillColor="#00000000"
android:strokeColor="#224955"
android:fillType="evenOdd"
android:strokeLineCap="square"/>
</vector>

View File

@ -0,0 +1,18 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21dp"
android:height="25dp"
android:viewportWidth="21"
android:viewportHeight="25">
<path
android:pathData="M2.7169,11L2.7169,16.2316L0.5734,19.7393C0.5254,19.8178 0.5,19.908 0.5,20C0.5,20.2761 0.7239,20.5 1,20.5L19.4339,20.5C19.5259,20.5 19.6161,20.4746 19.6946,20.4266C19.9302,20.2826 20.0045,19.9749 19.8605,19.7393L17.7169,16.2316L17.7169,11C17.7169,7.558 15.3785,4.582 12.0923,3.7363L11.7169,3.6396L11.7169,2C11.7169,1.1716 11.0454,0.5 10.2169,0.5C9.3885,0.5 8.7169,1.1716 8.7169,2L8.7169,3.6396L8.3416,3.7363C5.0554,4.582 2.7169,7.558 2.7169,11ZM7.797,22.5C8.0741,23.3506 9.0402,24 10.2169,24C11.3937,24 12.3598,23.3506 12.6369,22.5L7.797,22.5Z"
android:strokeWidth="1"
android:fillColor="#00000000"
android:strokeColor="#224955"
android:fillType="evenOdd"/>
<path
android:pathData="M16,7m-4,0a4,4 0,1 1,8 0a4,4 0,1 1,-8 0"
android:strokeWidth="1"
android:fillColor="#E8707B"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -0,0 +1,24 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="23dp"
android:height="26dp"
android:viewportWidth="23"
android:viewportHeight="26">
<path
android:pathData="M2.7169,12L2.7169,17.2316L0.5734,20.7393C0.5254,20.8178 0.5,20.908 0.5,21C0.5,21.2761 0.7239,21.5 1,21.5L19.4339,21.5C19.5259,21.5 19.6161,21.4746 19.6946,21.4266C19.9302,21.2826 20.0045,20.9749 19.8605,20.7393L17.7169,17.2316L17.7169,12C17.7169,8.558 15.3785,5.582 12.0923,4.7363L11.7169,4.6396L11.7169,3C11.7169,2.1716 11.0454,1.5 10.2169,1.5C9.3885,1.5 8.7169,2.1716 8.7169,3L8.7169,4.6396L8.3416,4.7363C5.0554,5.582 2.7169,8.558 2.7169,12ZM7.797,23.5C8.0741,24.3506 9.0402,25 10.2169,25C11.3937,25 12.3598,24.3506 12.6369,23.5L7.797,23.5Z"
android:strokeWidth="1"
android:fillColor="#00000000"
android:strokeColor="#224955"
android:fillType="evenOdd"/>
<path
android:pathData="M17.5522,4.7158l1.1133,0l0,0.2842l-1.5366,0l0,-0.2227l1.0708,-1.6245l-1.062,0l0,-0.2856l1.4912,0l0,0.2139z"
android:strokeWidth="1"
android:fillColor="#4A4A4A"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
<path
android:pathData="M20.1045,4.4316l2.2266,0l0,0.5684l-3.0732,0l0,-0.4453l2.1416,-3.249l-2.124,0l0,-0.5713l2.9824,0l0,0.4277z"
android:strokeWidth="1"
android:fillColor="#4A4A4A"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/itemGenericFooterText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
tools:text="Empty list, nothing here" />
</LinearLayout>

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/pushRuleId"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
tools:text=".m.rule.contains_user_name"
android:textStyle="bold" />
<TextView
android:id="@+id/pushRuleDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textStyle=""
tools:text="content matches valere" />
</LinearLayout>
<ImageView
android:id="@+id/pushRuleActionIcon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
tools:src="@drawable/ic_action_dont_notify" />
</LinearLayout>

View File

@ -17,6 +17,8 @@
<string name="settings_preferences">Preferences</string>
<string name="settings_security_and_privacy">Security &amp; Privacy</string>
<string name="settings_expert">Expert</string>
<string name="settings_push_gateways">Push Gateways</string>
<string name="settings_push_rules">Push Rules</string>
<string name="settings_push_rules_no_rules">No push rules defined</string>
<string name="settings_push_gateway_no_pushers">No registered push gateways</string>
</resources>

View File

@ -2,14 +2,15 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<SwitchPreference
android:key="SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY"
android:title="@string/settings_enable_all_notif" />
<!--<SwitchPreference-->
<!--android:key="SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY"-->
<!--android:title="@string/settings_enable_all_notif" />-->
<SwitchPreference
android:dependency="SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY"
android:key="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY"
android:title="@string/settings_enable_this_device" />
<!--android:dependency="SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY"-->
<!--<im.vector.riotredesign.core.preference.VectorSwitchPreference-->
<!--android:dependency="SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY"-->
@ -27,6 +28,7 @@
android:persistent="false"
android:summary="@string/settings_notification_advanced_summary"
android:title="@string/settings_notification_advanced"
android:enabled="false"
app:fragment="im.vector.fragments.VectorSettingsNotificationsAdvancedFragment" />
<Preference
@ -38,8 +40,15 @@
<Preference
android:layout_width="match_parent"
android:title="@string/settings_push_gateways"
android:title="@string/settings_notifications_targets"
android:persistent="false"
app:fragment="im.vector.riotredesign.features.settings.push.PushGatewaysFragment" />
<Preference
android:layout_width="match_parent"
android:title="@string/settings_push_rules"
android:persistent="false"
app:fragment="im.vector.riotredesign.features.settings.push.PushRulesFragment" />
</PreferenceCategory>
</PreferenceScreen>