forked from GitHub-Mirror/riotX-android
Merge pull request #382 from vector-im/feature/better_long_tap_menu
Feature/better long tap menu
This commit is contained in:
commit
4d5bdecec6
@ -7,6 +7,8 @@ Features:
|
|||||||
|
|
||||||
Improvements:
|
Improvements:
|
||||||
- Handle click on redacted events: view source and create permalink
|
- Handle click on redacted events: view source and create permalink
|
||||||
|
- Improve long tap menu: reply on top, more compact (#368)
|
||||||
|
- Quick reply in timeline with swipe gesture
|
||||||
- Improve edit of replies
|
- Improve edit of replies
|
||||||
|
|
||||||
Other changes:
|
Other changes:
|
||||||
|
@ -37,9 +37,11 @@ import androidx.annotation.DrawableRes
|
|||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import butterknife.BindView
|
import butterknife.BindView
|
||||||
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||||
import com.airbnb.mvrx.args
|
import com.airbnb.mvrx.args
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
@ -57,6 +59,7 @@ import im.vector.matrix.android.api.session.Session
|
|||||||
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
import im.vector.matrix.android.api.session.room.model.EditAggregatedSummary
|
||||||
import im.vector.matrix.android.api.session.room.model.Membership
|
import im.vector.matrix.android.api.session.room.model.Membership
|
||||||
import im.vector.matrix.android.api.session.room.model.message.*
|
import im.vector.matrix.android.api.session.room.model.message.*
|
||||||
|
import im.vector.matrix.android.api.session.room.send.SendState
|
||||||
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
import im.vector.matrix.android.api.session.room.timeline.TimelineEvent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
import im.vector.matrix.android.api.session.room.timeline.getLastMessageContent
|
||||||
import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent
|
import im.vector.matrix.android.api.session.room.timeline.getTextEditableContent
|
||||||
@ -88,7 +91,7 @@ import im.vector.riotx.features.home.room.detail.composer.TextComposerViewState
|
|||||||
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotx.features.home.room.detail.timeline.TimelineEventController
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.action.*
|
import im.vector.riotx.features.home.room.detail.timeline.action.*
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
import im.vector.riotx.features.home.room.detail.timeline.helper.EndlessRecyclerViewScrollListener
|
||||||
import im.vector.riotx.features.home.room.detail.timeline.item.MessageInformationData
|
import im.vector.riotx.features.home.room.detail.timeline.item.*
|
||||||
import im.vector.riotx.features.html.EventHtmlRenderer
|
import im.vector.riotx.features.html.EventHtmlRenderer
|
||||||
import im.vector.riotx.features.html.PillImageSpan
|
import im.vector.riotx.features.html.PillImageSpan
|
||||||
import im.vector.riotx.features.invite.VectorInviteView
|
import im.vector.riotx.features.invite.VectorInviteView
|
||||||
@ -324,6 +327,32 @@ class RoomDetailFragment :
|
|||||||
})
|
})
|
||||||
recyclerView.setController(timelineEventController)
|
recyclerView.setController(timelineEventController)
|
||||||
timelineEventController.callback = this
|
timelineEventController.callback = this
|
||||||
|
|
||||||
|
if (VectorPreferences.swipeToReplyIsEnabled(requireContext())) {
|
||||||
|
val swipeCallback = RoomMessageTouchHelperCallback(requireContext(),
|
||||||
|
R.drawable.ic_reply,
|
||||||
|
object : RoomMessageTouchHelperCallback.QuickReplayHandler {
|
||||||
|
override fun performQuickReplyOnHolder(model: EpoxyModel<*>) {
|
||||||
|
(model as? AbsMessageItem)?.informationData?.let {
|
||||||
|
val eventId = it.eventId
|
||||||
|
roomDetailViewModel.process(RoomDetailActions.EnterReplyMode(eventId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canSwipeModel(model: EpoxyModel<*>): Boolean {
|
||||||
|
return when (model) {
|
||||||
|
is MessageFileItem,
|
||||||
|
is MessageImageVideoItem,
|
||||||
|
is MessageTextItem -> {
|
||||||
|
return (model as AbsMessageItem).informationData.sendState == SendState.SYNCED
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
val touchHelper = ItemTouchHelper(swipeCallback)
|
||||||
|
touchHelper.attachToRecyclerView(recyclerView)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupComposer() {
|
private fun setupComposer() {
|
||||||
|
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package im.vector.riotx.features.home.room.detail
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.HapticFeedbackConstants
|
||||||
|
import android.view.MotionEvent
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper.ACTION_STATE_SWIPE
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.airbnb.epoxy.EpoxyModel
|
||||||
|
import com.airbnb.epoxy.EpoxyTouchHelperCallback
|
||||||
|
import com.airbnb.epoxy.EpoxyViewHolder
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
|
||||||
|
class RoomMessageTouchHelperCallback(private val context: Context,
|
||||||
|
@DrawableRes actionIcon: Int,
|
||||||
|
private val handler: QuickReplayHandler) : EpoxyTouchHelperCallback() {
|
||||||
|
|
||||||
|
interface QuickReplayHandler {
|
||||||
|
fun performQuickReplyOnHolder(model: EpoxyModel<*>)
|
||||||
|
fun canSwipeModel(model: EpoxyModel<*>): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
private var swipeBack: Boolean = false
|
||||||
|
private var dX = 0f
|
||||||
|
private var startTracking = false
|
||||||
|
private var isVibrate = false
|
||||||
|
|
||||||
|
private var replyButtonProgress: Float = 0F
|
||||||
|
private var lastReplyButtonAnimationTime: Long = 0
|
||||||
|
|
||||||
|
private var imageDrawable: Drawable = ContextCompat.getDrawable(context, actionIcon)!!
|
||||||
|
|
||||||
|
|
||||||
|
private val triggerDistance = convertToPx(100)
|
||||||
|
private val minShowDistance = convertToPx(20)
|
||||||
|
private val triggerDelta = convertToPx(20)
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: EpoxyViewHolder?, direction: Int) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMove(recyclerView: RecyclerView?, viewHolder: EpoxyViewHolder?, target: EpoxyViewHolder?): Boolean {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: EpoxyViewHolder): Int {
|
||||||
|
if (handler.canSwipeModel(viewHolder.model)) {
|
||||||
|
return ItemTouchHelper.Callback.makeMovementFlags(0, ItemTouchHelper.START) //Should we use Left?
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//We never let items completely go out
|
||||||
|
override fun convertToAbsoluteDirection(flags: Int, layoutDirection: Int): Int {
|
||||||
|
if (swipeBack) {
|
||||||
|
swipeBack = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return super.convertToAbsoluteDirection(flags, layoutDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChildDraw(c: Canvas, recyclerView: RecyclerView, viewHolder: EpoxyViewHolder, dX: Float, dY: Float, actionState: Int, isCurrentlyActive: Boolean) {
|
||||||
|
if (actionState == ACTION_STATE_SWIPE) {
|
||||||
|
setTouchListener(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
|
||||||
|
}
|
||||||
|
val size = triggerDistance
|
||||||
|
if (Math.abs(viewHolder.itemView.translationX) < size || dX > this.dX /*going back*/) {
|
||||||
|
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
|
||||||
|
this.dX = dX
|
||||||
|
startTracking = true
|
||||||
|
}
|
||||||
|
drawReplyButton(c, viewHolder.itemView)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
private fun setTouchListener(c: Canvas,
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: EpoxyViewHolder,
|
||||||
|
dX: Float, dY: Float,
|
||||||
|
actionState: Int, isCurrentlyActive: Boolean) {
|
||||||
|
//TODO can this interfer with other interactions? should i remove it
|
||||||
|
recyclerView.setOnTouchListener { v, event ->
|
||||||
|
swipeBack = event.action == MotionEvent.ACTION_CANCEL || event.action == MotionEvent.ACTION_UP
|
||||||
|
if (swipeBack) {
|
||||||
|
if (Math.abs(dX) >= triggerDistance) {
|
||||||
|
try {
|
||||||
|
viewHolder.model?.let { handler.performQuickReplyOnHolder(it) }
|
||||||
|
} catch (e: IllegalStateException) {
|
||||||
|
Timber.e(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun drawReplyButton(canvas: Canvas, itemView: View) {
|
||||||
|
|
||||||
|
Timber.v("drawReplyButton")
|
||||||
|
val translationX = Math.abs(itemView.translationX)
|
||||||
|
val newTime = System.currentTimeMillis()
|
||||||
|
val dt = Math.min(17, newTime - lastReplyButtonAnimationTime)
|
||||||
|
lastReplyButtonAnimationTime = newTime
|
||||||
|
val showing = translationX >= minShowDistance
|
||||||
|
if (showing) {
|
||||||
|
if (replyButtonProgress < 1.0f) {
|
||||||
|
replyButtonProgress += dt / 180.0f
|
||||||
|
if (replyButtonProgress > 1.0f) {
|
||||||
|
replyButtonProgress = 1.0f
|
||||||
|
} else {
|
||||||
|
itemView.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (translationX <= 0.0f) {
|
||||||
|
replyButtonProgress = 0f
|
||||||
|
startTracking = false
|
||||||
|
isVibrate = false
|
||||||
|
} else {
|
||||||
|
if (replyButtonProgress > 0.0f) {
|
||||||
|
replyButtonProgress -= dt / 180.0f
|
||||||
|
if (replyButtonProgress < 0.1f) {
|
||||||
|
replyButtonProgress = 0f
|
||||||
|
} else {
|
||||||
|
itemView.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val alpha: Int
|
||||||
|
val scale: Float
|
||||||
|
if (showing) {
|
||||||
|
scale = if (replyButtonProgress <= 0.8f) {
|
||||||
|
1.2f * (replyButtonProgress / 0.8f)
|
||||||
|
} else {
|
||||||
|
1.2f - 0.2f * ((replyButtonProgress - 0.8f) / 0.2f)
|
||||||
|
}
|
||||||
|
alpha = Math.min(255f, 255 * (replyButtonProgress / 0.8f)).toInt()
|
||||||
|
} else {
|
||||||
|
scale = replyButtonProgress
|
||||||
|
alpha = Math.min(255f, 255 * replyButtonProgress).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
imageDrawable.alpha = alpha
|
||||||
|
if (startTracking) {
|
||||||
|
if (!isVibrate && translationX >= triggerDistance) {
|
||||||
|
itemView.performHapticFeedback(
|
||||||
|
HapticFeedbackConstants.LONG_PRESS
|
||||||
|
// , HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
|
||||||
|
)
|
||||||
|
isVibrate = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val x: Int = itemView.width - if (translationX > triggerDistance + triggerDelta) {
|
||||||
|
(convertToPx(130) / 2).toInt()
|
||||||
|
} else {
|
||||||
|
(translationX / 2).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
val y = (itemView.top + itemView.measuredHeight / 2).toFloat()
|
||||||
|
//magic numbers?
|
||||||
|
imageDrawable.setBounds(
|
||||||
|
(x - convertToPx(12) * scale).toInt(),
|
||||||
|
(y - convertToPx(11) * scale).toInt(),
|
||||||
|
(x + convertToPx(12) * scale).toInt(),
|
||||||
|
(y + convertToPx(10) * scale).toInt()
|
||||||
|
)
|
||||||
|
imageDrawable.draw(canvas)
|
||||||
|
imageDrawable.alpha = 255
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertToPx(dp: Int): Float {
|
||||||
|
return TypedValue.applyDimension(
|
||||||
|
TypedValue.COMPLEX_UNIT_DIP,
|
||||||
|
dp.toFloat(),
|
||||||
|
context.resources.displayMetrics
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -127,13 +127,6 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||||||
//TODO is downloading attachement?
|
//TODO is downloading attachement?
|
||||||
|
|
||||||
if (!event.root.isRedacted()) {
|
if (!event.root.isRedacted()) {
|
||||||
if (event.canReact()) {
|
|
||||||
this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, eventId))
|
|
||||||
}
|
|
||||||
if (canCopy(type)) {
|
|
||||||
//TODO copy images? html? see ClipBoard
|
|
||||||
this.add(SimpleAction(ACTION_COPY, R.string.copy, R.drawable.ic_copy, messageContent!!.body))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canReply(event, messageContent)) {
|
if (canReply(event, messageContent)) {
|
||||||
this.add(SimpleAction(ACTION_REPLY, R.string.reply, R.drawable.ic_reply, eventId))
|
this.add(SimpleAction(ACTION_REPLY, R.string.reply, R.drawable.ic_reply, eventId))
|
||||||
@ -147,6 +140,15 @@ class MessageMenuViewModel @AssistedInject constructor(@Assisted initialState: M
|
|||||||
this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, eventId))
|
this.add(SimpleAction(ACTION_DELETE, R.string.delete, R.drawable.ic_delete, eventId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (canCopy(type)) {
|
||||||
|
//TODO copy images? html? see ClipBoard
|
||||||
|
this.add(SimpleAction(ACTION_COPY, R.string.copy, R.drawable.ic_copy, messageContent!!.body))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.canReact()) {
|
||||||
|
this.add(SimpleAction(ACTION_ADD_REACTION, R.string.message_add_reaction, R.drawable.ic_add_reaction, eventId))
|
||||||
|
}
|
||||||
|
|
||||||
if (canQuote(event, messageContent)) {
|
if (canQuote(event, messageContent)) {
|
||||||
this.add(SimpleAction(ACTION_QUOTE, R.string.quote, R.drawable.ic_quote, eventId))
|
this.add(SimpleAction(ACTION_QUOTE, R.string.quote, R.drawable.ic_quote, eventId))
|
||||||
}
|
}
|
||||||
|
@ -148,6 +148,7 @@ object VectorPreferences {
|
|||||||
private const val SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY = "SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY"
|
private const val SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY = "SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY"
|
||||||
|
|
||||||
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
private const val SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||||
|
private const val SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY = "SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
||||||
|
|
||||||
// analytics
|
// analytics
|
||||||
const val SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY"
|
const val SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY"
|
||||||
@ -249,6 +250,10 @@ object VectorPreferences {
|
|||||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, false)
|
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun swipeToReplyIsEnabled(context: Context): Boolean {
|
||||||
|
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY, true)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if we have already asked the user to disable battery optimisations on android >= M devices.
|
* Tells if we have already asked the user to disable battery optimisations on android >= M devices.
|
||||||
*
|
*
|
||||||
|
@ -7,18 +7,6 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/quickReactionTitle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="8dp"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="@string/quick_reactions"
|
|
||||||
android:textColor="?riotx_text_secondary"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/quickReaction0"
|
android:id="@+id/quickReaction0"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -104,16 +92,14 @@
|
|||||||
android:id="@+id/reactionsFlowHelper"
|
android:id="@+id/reactionsFlowHelper"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
app:constraint_referenced_ids="quickReaction0,quickReaction1,quickReaction2,quickReaction3,quickReaction4,quickReaction5,quickReaction6,quickReaction7"
|
app:constraint_referenced_ids="quickReaction0,quickReaction1,quickReaction2,quickReaction3,quickReaction4,quickReaction5,quickReaction6,quickReaction7"
|
||||||
app:flow_horizontalGap="8dp"
|
app:flow_horizontalGap="0dp"
|
||||||
app:flow_horizontalStyle="spread"
|
app:flow_horizontalStyle="spread"
|
||||||
app:flow_verticalBias="0"
|
app:flow_verticalBias="0"
|
||||||
app:flow_verticalGap="4dp"
|
app:flow_verticalGap="4dp"
|
||||||
app:flow_wrapMode="chain"
|
app:flow_wrapMode="chain"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/quickReactionTitle" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_bias="0"
|
||||||
tools:src="@tools:sample/avatars" />
|
tools:src="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -1534,7 +1534,6 @@ Why choose Riot.im?
|
|||||||
<string name="settings_other_third_party_notices">Other third party notices</string>
|
<string name="settings_other_third_party_notices">Other third party notices</string>
|
||||||
<string name="navigate_to_room_when_already_in_the_room">You are already viewing this room!</string>
|
<string name="navigate_to_room_when_already_in_the_room">You are already viewing this room!</string>
|
||||||
|
|
||||||
<string name="quick_reactions">Quick Reactions</string>
|
|
||||||
|
|
||||||
<!-- Settings -->
|
<!-- Settings -->
|
||||||
<string name="settings_general_title">General</string>
|
<string name="settings_general_title">General</string>
|
||||||
|
@ -35,4 +35,5 @@
|
|||||||
<string name="room_directory_search_hint">Name or ID (#example:matrix.org)</string>
|
<string name="room_directory_search_hint">Name or ID (#example:matrix.org)</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="labs_swipe_to_reply_in_timeline">Enable swipe to reply in timeline</string>
|
||||||
</resources>
|
</resources>
|
@ -1,7 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
|
||||||
|
|
||||||
<!--<im.vector.riotx.core.preference.VectorPreferenceCategory-->
|
<!--<im.vector.riotx.core.preference.VectorPreferenceCategory-->
|
||||||
<!--android:key="SETTINGS_LABS_PREFERENCE_KEY"-->
|
<!--android:key="SETTINGS_LABS_PREFERENCE_KEY"-->
|
||||||
@ -37,10 +35,16 @@
|
|||||||
<!--android:title="@string/settings_labs_enable_send_voice" />-->
|
<!--android:title="@string/settings_labs_enable_send_voice" />-->
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorSwitchPreference
|
<im.vector.riotx.core.preference.VectorSwitchPreference
|
||||||
android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
|
||||||
android:defaultValue="false"
|
android:defaultValue="false"
|
||||||
|
android:key="SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"
|
||||||
android:title="@string/settings_labs_show_hidden_events_in_timeline" />
|
android:title="@string/settings_labs_show_hidden_events_in_timeline" />
|
||||||
|
|
||||||
|
|
||||||
|
<im.vector.riotx.core.preference.VectorSwitchPreference
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="SETTINGS_LABS_ENABLE_SWIPE_TO_REPLY"
|
||||||
|
android:title="@string/labs_swipe_to_reply_in_timeline" />
|
||||||
|
|
||||||
<!--</im.vector.riotx.core.preference.VectorPreferenceCategory>-->
|
<!--</im.vector.riotx.core.preference.VectorPreferenceCategory>-->
|
||||||
|
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user