Skip to content

Commit

Permalink
Merge branch 'develop' into feature/ons/delabs_voice_message
Browse files Browse the repository at this point in the history
  • Loading branch information
onurays authored Aug 11, 2021
2 parents 9b011f9 + ec093e7 commit f6477d5
Show file tree
Hide file tree
Showing 23 changed files with 478 additions and 91 deletions.
1 change: 1 addition & 0 deletions changelog.d/3646.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Reorganise Advanced Notifications in to Default Notifications, Keywords and Mentions, Other (This feature is hidden in the release ui until a future release date.)
1 change: 1 addition & 0 deletions changelog.d/3798.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Voice Message - UI Improvements
4 changes: 4 additions & 0 deletions vector/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ android {
resValue "bool", "useLoginV1", "true"
resValue "bool", "useLoginV2", "false"

// NotificationSettingsV2 is disabled. To be released in conjunction with iOS/Web
resValue "bool", "useNotificationSettingsV1", "true"
resValue "bool", "useNotificationSettingsV2", "false"

buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"

buildConfigField "Long", "VOICE_MESSAGE_DURATION_LIMIT_MS", "120_000L"
Expand Down
15 changes: 3 additions & 12 deletions vector/src/main/java/im/vector/app/core/preference/PushRulePreference.kt
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,10 @@ import android.view.View
import android.widget.RadioGroup
import androidx.preference.PreferenceViewHolder
import im.vector.app.R
import im.vector.app.features.settings.notifications.NotificationIndex

class PushRulePreference : VectorPreference {

enum class NotificationIndex(val index: Int) {
OFF(0),
SILENT(1),
NOISY(2);

companion object {
fun fromInt(index: Int) = values().first { it.index == index }
}
}

/**
* @return the selected push rule index
*/
Expand Down Expand Up @@ -66,7 +57,7 @@ class PushRulePreference : VectorPreference {
*/
private fun refreshSummary() {
summary = context.getString(when (index) {
NotificationIndex.OFF -> R.string.notification_off
NotificationIndex.OFF -> R.string.notification_off
NotificationIndex.SILENT -> R.string.notification_silent
NotificationIndex.NOISY, null -> R.string.notification_noisy
})
Expand All @@ -83,7 +74,7 @@ class PushRulePreference : VectorPreference {
radioGroup?.setOnCheckedChangeListener(null)

when (index) {
NotificationIndex.OFF -> {
NotificationIndex.OFF -> {
radioGroup?.check(R.id.bingPreferenceRadioBingRuleOff)
}
NotificationIndex.SILENT -> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2021 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.app.core.preference

import android.content.Context
import android.util.AttributeSet
import android.widget.TextView
import androidx.preference.CheckBoxPreference
import androidx.preference.PreferenceViewHolder

class VectorCheckboxPreference : CheckBoxPreference {
// Note: @JvmOverload does not work here...
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)

constructor(context: Context, attrs: AttributeSet) : super(context, attrs)

constructor(context: Context) : super(context)

init {
// Set to false to remove the space when there is no icon
isIconSpaceReserved = true
}

override fun onBindViewHolder(holder: PreferenceViewHolder) {
// display the title in multi-line to avoid ellipsis.
(holder.findViewById(android.R.id.title) as? TextView)?.isSingleLine = false
super.onBindViewHolder(holder)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,9 @@ class RoomDetailFragment @Inject constructor(
notificationDrawerManager.setCurrentRoom(roomDetailArgs.roomId)
roomDetailPendingActionStore.data?.let { handlePendingAction(it) }
roomDetailPendingActionStore.data = null

// Removed listeners should be set again
setupVoiceMessageView()
}

private fun handlePendingAction(roomDetailPendingAction: RoomDetailPendingAction) {
Expand Down Expand Up @@ -1318,7 +1321,6 @@ class RoomDetailFragment @Inject constructor(
if (text.isNotBlank()) {
// We collapse ASAP, if not there will be a slight annoying delay
views.composerLayout.collapse(true)
views.voiceMessageRecorderView.isVisible = true
lockSendButton = true
roomDetailViewModel.handle(RoomDetailAction.SendMessage(text, vectorPreferences.isMarkdownEnabled()))
emojiPopup.dismiss()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import android.content.Context
import android.text.format.DateUtils
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
Expand Down Expand Up @@ -87,6 +88,15 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
initListeners()
}

override fun onVisibilityChanged(changedView: View, visibility: Int) {
super.onVisibilityChanged(changedView, visibility)
if (changedView == this && visibility == VISIBLE) {
views.voiceMessageMicButton.contentDescription = context.getString(R.string.a11y_start_voice_message)
} else {
views.voiceMessageMicButton.contentDescription = ""
}
}

fun initVoiceRecordingViews() {
recordingState = RecordingState.NONE

Expand Down Expand Up @@ -209,6 +219,7 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
}
RecordingState.CANCELLED -> {
hideRecordingViews(isCancelled = true)
vibrate(context)
}
RecordingState.LOCKED -> {
if (isRecordingStateChanged) { // Do not update views if it was already in locked state.
Expand All @@ -220,6 +231,9 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
}
RecordingState.STARTED -> {
showRecordingViews()
val translationAmount = distanceX.coerceAtMost(distanceToCancel)
views.voiceMessageMicButton.translationX = -translationAmount * rtlXMultiplier
views.voiceMessageSlideToCancel.translationX = -translationAmount / 2 * rtlXMultiplier
}
RecordingState.NONE -> Timber.d("VoiceMessageRecorderView shouldn't be in NONE state while moving.")
RecordingState.PLAYBACK -> Timber.d("VoiceMessageRecorderView shouldn't be in PLAYBACK state while moving.")
Expand All @@ -235,9 +249,9 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
if (recordingState == RecordingState.STARTED) {
// Determine if cancelling or locking for the first move action.
if (((currentX < firstX && rtlXMultiplier == 1) || (currentX > firstX && rtlXMultiplier == -1))
&& distanceX > distanceY) {
&& distanceX > distanceY && distanceX > lastDistanceX) {
recordingState = RecordingState.CANCELLING
} else if (currentY < firstY && distanceY > distanceX) {
} else if (currentY < firstY && distanceY > distanceX && distanceY > lastDistanceY) {
recordingState = RecordingState.LOCKING
}
} else if (recordingState == RecordingState.CANCELLING) {
Expand Down Expand Up @@ -507,12 +521,14 @@ class VoiceMessageRecorderView @JvmOverloads constructor(
}
is VoiceMessagePlaybackTracker.Listener.State.Playing -> {
views.voicePlaybackControlButton.setImageResource(R.drawable.ic_play_pause_pause)
views.voicePlaybackControlButton.contentDescription = context.getString(R.string.a11y_pause_voice_message)
val formattedTimerText = DateUtils.formatElapsedTime((state.playbackTime / 1000).toLong())
views.voicePlaybackTime.text = formattedTimerText
}
is VoiceMessagePlaybackTracker.Listener.State.Paused,
is VoiceMessagePlaybackTracker.Listener.State.Idle -> {
views.voicePlaybackControlButton.setImageResource(R.drawable.ic_play_pause_play)
views.voicePlaybackControlButton.contentDescription = context.getString(R.string.a11y_play_voice_message)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ abstract class MessageVoiceItem : AbsMessageItem<MessageVoiceItem.Holder>() {
contentUploadStateTrackerBinder.bind(attributes.informationData.eventId, izLocalFile, holder.progressLayout)
} else {
holder.voicePlaybackControlButton.setImageResource(R.drawable.ic_cross)
holder.voicePlaybackControlButton.contentDescription = holder.view.context.getString(R.string.error_voice_message_unable_to_play)
holder.progressLayout.isVisible = false
}

Expand Down Expand Up @@ -98,16 +99,19 @@ abstract class MessageVoiceItem : AbsMessageItem<MessageVoiceItem.Holder>() {

private fun renderIdleState(holder: Holder) {
holder.voicePlaybackControlButton.setImageResource(R.drawable.ic_play_pause_play)
holder.voicePlaybackControlButton.contentDescription = holder.view.context.getString(R.string.a11y_play_voice_message)
holder.voicePlaybackTime.text = formatPlaybackTime(duration)
}

private fun renderPlayingState(holder: Holder, state: VoiceMessagePlaybackTracker.Listener.State.Playing) {
holder.voicePlaybackControlButton.setImageResource(R.drawable.ic_play_pause_pause)
holder.voicePlaybackControlButton.contentDescription = holder.view.context.getString(R.string.a11y_pause_voice_message)
holder.voicePlaybackTime.text = formatPlaybackTime(state.playbackTime)
}

private fun renderPausedState(holder: Holder, state: VoiceMessagePlaybackTracker.Listener.State.Paused) {
holder.voicePlaybackControlButton.setImageResource(R.drawable.ic_play_pause_play)
holder.voicePlaybackControlButton.contentDescription = holder.view.context.getString(R.string.a11y_play_voice_message)
holder.voicePlaybackTime.text = formatPlaybackTime(state.playbackTime)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2021 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.app.features.settings.notifications

import org.matrix.android.sdk.api.pushrules.rest.PushRule
import org.matrix.android.sdk.api.pushrules.toJson

enum class NotificationIndex {
OFF,
SILENT,
NOISY;
}

/**
* Given a push rule determine the NotificationIndex by comparing it to the static push rule definitions.
* Used when determining the selected state of the PushRulePreference.
*/
val PushRule.notificationIndex: NotificationIndex? get() =
NotificationIndex.values().firstOrNull {
// Get the actions for the index
val standardAction = getStandardAction(this.ruleId, it) ?: return@firstOrNull false
val indexActions = standardAction.actions ?: listOf()
// Check if the input rule matches a rule generated from the static rule definitions
val targetRule = this.copy(enabled = standardAction != StandardActions.Disabled, actions = indexActions.toJson())
ruleMatches(this, targetRule)
}

/**
* A check to determine if two push rules should be considered a match.
*/
private fun ruleMatches(rule: PushRule, targetRule: PushRule): Boolean {
// Rules match if both are disabled, or if both are enabled and their highlight/sound/notify actions match up.
return (!rule.enabled && !targetRule.enabled)
|| (rule.enabled
&& targetRule.enabled
&& rule.getHighlight() == targetRule.getHighlight()
&& rule.getNotificationSound() == targetRule.getNotificationSound()
&& rule.shouldNotify() == targetRule.shouldNotify()
&& rule.shouldNotNotify() == targetRule.shouldNotNotify())
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,76 +16,75 @@

package im.vector.app.features.settings.notifications

import im.vector.app.core.preference.PushRulePreference
import org.matrix.android.sdk.api.pushrules.RuleIds

fun getStandardAction(ruleId: String, index: PushRulePreference.NotificationIndex): StandardActions? {
fun getStandardAction(ruleId: String, index: NotificationIndex): StandardActions? {
return when (ruleId) {
RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.HighlightDefaultSound
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.HighlightDefaultSound
}
RuleIds.RULE_ID_CONTAIN_USER_NAME ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.HighlightDefaultSound
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.HighlightDefaultSound
}
RuleIds.RULE_ID_ROOM_NOTIF ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.Highlight
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.Highlight
}
RuleIds.RULE_ID_ONE_TO_ONE_ROOM ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.DontNotify
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.DontNotify
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_ONE_TO_ONE_ENCRYPTED_ROOM ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.DontNotify
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.DontNotify
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_ALL_OTHER_MESSAGES_ROOMS ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.DontNotify
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.DontNotify
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_ENCRYPTED ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.DontNotify
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.DontNotify
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_INVITE_ME ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_CALL ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyRingSound
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.NotifyRingSound
}
RuleIds.RULE_ID_SUPPRESS_BOTS_NOTIFICATIONS ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.DontNotify
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Disabled
PushRulePreference.NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
NotificationIndex.OFF -> StandardActions.DontNotify
NotificationIndex.SILENT -> StandardActions.Disabled
NotificationIndex.NOISY -> StandardActions.NotifyDefaultSound
}
RuleIds.RULE_ID_TOMBSTONE ->
when (index) {
PushRulePreference.NotificationIndex.OFF -> StandardActions.Disabled
PushRulePreference.NotificationIndex.SILENT -> StandardActions.Notify
PushRulePreference.NotificationIndex.NOISY -> StandardActions.Highlight
NotificationIndex.OFF -> StandardActions.Disabled
NotificationIndex.SILENT -> StandardActions.Notify
NotificationIndex.NOISY -> StandardActions.Highlight
}
else -> null
}
Expand Down
Loading

0 comments on commit f6477d5

Please sign in to comment.