Merge pull request #1466 from vector-im/feature/toggle_favorite

Add capability to add and remove a room from the favorites (#1217)
This commit is contained in:
Benoit Marty 2020-06-15 14:29:48 +02:00 committed by GitHub
commit 2c1487d303
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 395 additions and 20 deletions

View file

@ -13,6 +13,7 @@ Improvements 🙌:
- Correctly handle SSO login redirection
- SSO login is now performed in the default browser, or in Chrome Custom tab if available (#1400)
- Improve checking of homeserver version support (#1442)
- Add capability to add and remove a room from the favorites (#1217)
Bugfix 🐛:
- Switch theme is not fully taken into account without restarting the app

View file

@ -27,6 +27,7 @@ import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.send.DraftService
import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.state.StateService
import im.vector.matrix.android.api.session.room.tags.TagsService
import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.session.room.typing.TypingService
import im.vector.matrix.android.api.session.room.uploads.UploadsService
@ -41,6 +42,7 @@ interface Room :
DraftService,
ReadService,
TypingService,
TagsService,
MembershipService,
StateService,
UploadsService,

View file

@ -59,6 +59,9 @@ data class RoomSummary constructor(
val hasNewMessages: Boolean
get() = notificationCount != 0
val isFavorite: Boolean
get() = tags.any { it.name == RoomTag.ROOM_TAG_FAVOURITE }
companion object {
const val NOT_IN_BREADCRUMBS = -1
}

View file

@ -22,9 +22,8 @@ data class RoomTag(
) {
companion object {
val ROOM_TAG_FAVOURITE = "m.favourite"
val ROOM_TAG_LOW_PRIORITY = "m.lowpriority"
val ROOM_TAG_NO_TAG = "m.recent"
val ROOM_TAG_SERVER_NOTICE = "m.server_notice"
const val ROOM_TAG_FAVOURITE = "m.favourite"
const val ROOM_TAG_LOW_PRIORITY = "m.lowpriority"
const val ROOM_TAG_SERVER_NOTICE = "m.server_notice"
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.api.session.room.tags
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.util.Cancelable
/**
* This interface defines methods to handle tags of a room. It's implemented at the room level.
*/
interface TagsService {
/**
* Add a tag to a room
*/
fun addTag(tag: String, order: Double?, callback: MatrixCallback<Unit>): Cancelable
/**
* Remove tag form a room
*/
fun deleteTag(tag: String, callback: MatrixCallback<Unit>): Cancelable
}

View file

@ -32,6 +32,7 @@ import im.vector.matrix.android.api.session.room.reporting.ReportingService
import im.vector.matrix.android.api.session.room.send.DraftService
import im.vector.matrix.android.api.session.room.send.SendService
import im.vector.matrix.android.api.session.room.state.StateService
import im.vector.matrix.android.api.session.room.tags.TagsService
import im.vector.matrix.android.api.session.room.timeline.TimelineService
import im.vector.matrix.android.api.session.room.typing.TypingService
import im.vector.matrix.android.api.session.room.uploads.UploadsService
@ -59,6 +60,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
private val reportingService: ReportingService,
private val readService: ReadService,
private val typingService: TypingService,
private val tagsService: TagsService,
private val cryptoService: CryptoService,
private val relationService: RelationService,
private val roomMembersService: MembershipService,
@ -74,6 +76,7 @@ internal class DefaultRoom @Inject constructor(override val roomId: String,
ReportingService by reportingService,
ReadService by readService,
TypingService by typingService,
TagsService by tagsService,
RelationService by relationService,
MembershipService by roomMembersService,
RoomPushRuleService by roomPushRuleService {

View file

@ -33,11 +33,13 @@ import im.vector.matrix.android.internal.session.room.membership.joining.InviteB
import im.vector.matrix.android.internal.session.room.relation.RelationsResponse
import im.vector.matrix.android.internal.session.room.reporting.ReportContentBody
import im.vector.matrix.android.internal.session.room.send.SendResponse
import im.vector.matrix.android.internal.session.room.tags.TagBody
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
import im.vector.matrix.android.internal.session.room.timeline.PaginationResponse
import im.vector.matrix.android.internal.session.room.typing.TypingBody
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Headers
import retrofit2.http.POST
@ -316,4 +318,25 @@ internal interface RoomAPI {
fun sendTypingState(@Path("roomId") roomId: String,
@Path("userId") userId: String,
@Body body: TypingBody): Call<Unit>
/**
* Room tagging
*/
/**
* Add a tag to a room.
*/
@PUT(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}")
fun putTag(@Path("userId") userId: String,
@Path("roomId") roomId: String,
@Path("tag") tag: String,
@Body body: TagBody): Call<Unit>
/**
* Delete a tag from a room.
*/
@DELETE(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/rooms/{roomId}/tags/{tag}")
fun deleteTag(@Path("userId") userId: String,
@Path("roomId") roomId: String,
@Path("tag") tag: String): Call<Unit>
}

View file

@ -30,6 +30,7 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReporting
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
import im.vector.matrix.android.internal.session.room.state.DefaultStateService
import im.vector.matrix.android.internal.session.room.state.SendStateTask
import im.vector.matrix.android.internal.session.room.tags.DefaultTagsService
import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService
import im.vector.matrix.android.internal.session.room.typing.DefaultTypingService
import im.vector.matrix.android.internal.session.room.uploads.DefaultUploadsService
@ -52,6 +53,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
private val reportingServiceFactory: DefaultReportingService.Factory,
private val readServiceFactory: DefaultReadService.Factory,
private val typingServiceFactory: DefaultTypingService.Factory,
private val tagsServiceFactory: DefaultTagsService.Factory,
private val relationServiceFactory: DefaultRelationService.Factory,
private val membershipServiceFactory: DefaultMembershipService.Factory,
private val roomPushRuleServiceFactory: DefaultRoomPushRuleService.Factory,
@ -72,6 +74,7 @@ internal class DefaultRoomFactory @Inject constructor(private val monarchy: Mona
reportingService = reportingServiceFactory.create(roomId),
readService = readServiceFactory.create(roomId),
typingService = typingServiceFactory.create(roomId),
tagsService = tagsServiceFactory.create(roomId),
cryptoService = cryptoService,
relationService = relationServiceFactory.create(roomId),
roomMembersService = membershipServiceFactory.create(roomId),

View file

@ -58,6 +58,10 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReportCon
import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
import im.vector.matrix.android.internal.session.room.state.SendStateTask
import im.vector.matrix.android.internal.session.room.tags.AddTagToRoomTask
import im.vector.matrix.android.internal.session.room.tags.DefaultAddTagToRoomTask
import im.vector.matrix.android.internal.session.room.tags.DefaultDeleteTagFromRoomTask
import im.vector.matrix.android.internal.session.room.tags.DeleteTagFromRoomTask
import im.vector.matrix.android.internal.session.room.timeline.DefaultFetchNextTokenAndPaginateTask
import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask
import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask
@ -191,4 +195,10 @@ internal abstract class RoomModule {
@Binds
abstract fun bindGetUploadsTask(task: DefaultGetUploadsTask): GetUploadsTask
@Binds
abstract fun bindAddTagToRoomTask(task: DefaultAddTagToRoomTask): AddTagToRoomTask
@Binds
abstract fun bindDeleteTagFromRoomTask(task: DefaultDeleteTagFromRoomTask): DeleteTagFromRoomTask
}

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.room.tags
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject
internal interface AddTagToRoomTask : Task<AddTagToRoomTask.Params, Unit> {
data class Params(
val roomId: String,
val tag: String,
val order: Double?
)
}
internal class DefaultAddTagToRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
@UserId private val userId: String,
private val eventBus: EventBus
) : AddTagToRoomTask {
override suspend fun execute(params: AddTagToRoomTask.Params) {
executeRequest<Unit>(eventBus) {
apiCall = roomAPI.putTag(
userId = userId,
roomId = params.roomId,
tag = params.tag,
body = TagBody(
order = params.order
)
)
}
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.room.tags
import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.room.tags.TagsService
import im.vector.matrix.android.api.util.Cancelable
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
internal class DefaultTagsService @AssistedInject constructor(
@Assisted private val roomId: String,
private val taskExecutor: TaskExecutor,
private val addTagToRoomTask: AddTagToRoomTask,
private val deleteTagFromRoomTask: DeleteTagFromRoomTask
) : TagsService {
@AssistedInject.Factory
interface Factory {
fun create(roomId: String): TagsService
}
override fun addTag(tag: String, order: Double?, callback: MatrixCallback<Unit>): Cancelable {
val params = AddTagToRoomTask.Params(roomId, tag, order)
return addTagToRoomTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
}
override fun deleteTag(tag: String, callback: MatrixCallback<Unit>): Cancelable {
val params = DeleteTagFromRoomTask.Params(roomId, tag)
return deleteTagFromRoomTask
.configureWith(params) {
this.callback = callback
}
.executeBy(taskExecutor)
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.room.tags
import im.vector.matrix.android.internal.di.UserId
import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.session.room.RoomAPI
import im.vector.matrix.android.internal.task.Task
import org.greenrobot.eventbus.EventBus
import javax.inject.Inject
internal interface DeleteTagFromRoomTask : Task<DeleteTagFromRoomTask.Params, Unit> {
data class Params(
val roomId: String,
val tag: String
)
}
internal class DefaultDeleteTagFromRoomTask @Inject constructor(
private val roomAPI: RoomAPI,
@UserId private val userId: String,
private val eventBus: EventBus
) : DeleteTagFromRoomTask {
override suspend fun execute(params: DeleteTagFromRoomTask.Params) {
executeRequest<Unit>(eventBus) {
apiCall = roomAPI.deleteTag(
userId = userId,
roomId = params.roomId,
tag = params.tag
)
}
}
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.matrix.android.internal.session.room.tags
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
internal data class TagBody(
/**
* A number in a range [0,1] describing a relative position of the room under the given tag.
*/
@Json(name = "order")
val order: Double?
)

View file

@ -16,9 +16,12 @@
*/
package im.vector.riotx.core.epoxy.bottomsheet
import android.content.res.ColorStateList
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.widget.ImageViewCompat
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.matrix.android.api.util.MatrixItem
@ -28,7 +31,9 @@ import im.vector.riotx.core.epoxy.VectorEpoxyHolder
import im.vector.riotx.core.epoxy.VectorEpoxyModel
import im.vector.riotx.core.epoxy.onClick
import im.vector.riotx.core.extensions.setTextOrHide
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer
import im.vector.riotx.features.themes.ThemeUtils
/**
* A room preview for bottom sheet.
@ -36,22 +41,46 @@ import im.vector.riotx.features.home.AvatarRenderer
@EpoxyModelClass(layout = R.layout.item_bottom_sheet_room_preview)
abstract class BottomSheetRoomPreviewItem : VectorEpoxyModel<BottomSheetRoomPreviewItem.Holder>() {
@EpoxyAttribute
lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute
lateinit var matrixItem: MatrixItem
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
@EpoxyAttribute lateinit var matrixItem: MatrixItem
@EpoxyAttribute lateinit var stringProvider: StringProvider
@EpoxyAttribute var izFavorite: Boolean = false
@EpoxyAttribute var settingsClickListener: ClickListener? = null
@EpoxyAttribute var favoriteClickListener: ClickListener? = null
override fun bind(holder: Holder) {
avatarRenderer.render(matrixItem, holder.avatar)
holder.avatar.onClick(settingsClickListener)
holder.roomName.setTextOrHide(matrixItem.displayName)
setFavoriteState(holder, izFavorite)
holder.roomFavorite.setOnClickListener {
// Immediate echo
setFavoriteState(holder, !izFavorite)
// And do the action
favoriteClickListener?.invoke()
}
holder.roomSettings.onClick(settingsClickListener)
}
private fun setFavoriteState(holder: Holder, isFavorite: Boolean) {
val tintColor: Int
if (isFavorite) {
holder.roomFavorite.contentDescription = stringProvider.getString(R.string.room_list_quick_actions_favorite_remove)
holder.roomFavorite.setImageResource(R.drawable.ic_star_green_24dp)
tintColor = ContextCompat.getColor(holder.view.context, R.color.riotx_accent)
} else {
holder.roomFavorite.contentDescription = stringProvider.getString(R.string.room_list_quick_actions_favorite_add)
holder.roomFavorite.setImageResource(R.drawable.ic_star_24dp)
tintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
}
ImageViewCompat.setImageTintList(holder.roomFavorite, ColorStateList.valueOf(tintColor))
}
class Holder : VectorEpoxyHolder() {
val avatar by bind<ImageView>(R.id.bottomSheetRoomPreviewAvatar)
val roomName by bind<TextView>(R.id.bottomSheetRoomPreviewName)
val roomFavorite by bind<ImageView>(R.id.bottomSheetRoomPreviewFavorite)
val roomSettings by bind<View>(R.id.bottomSheetRoomPreviewSettings)
}
}

View file

@ -58,7 +58,7 @@ class ShortcutsHandler @Inject constructor(
.observeOn(Schedulers.computation())
.subscribe { rooms ->
val shortcuts = rooms
.filter { room -> room.tags.any { it.name == RoomTag.ROOM_TAG_FAVOURITE } }
.filter { room -> room.isFavorite }
.take(n = 4) // Android only allows us to create 4 shortcuts
.map { room ->
val intent = RoomDetailActivity.shortcutIntent(context, room.roomId)

View file

@ -27,6 +27,7 @@ sealed class RoomListAction : VectorViewModelAction {
data class RejectInvitation(val roomSummary: RoomSummary) : RoomListAction()
data class FilterWith(val filter: String) : RoomListAction()
data class ChangeRoomNotificationState(val roomId: String, val notificationState: RoomNotificationState) : RoomListAction()
data class ToggleFavorite(val roomId: String) : RoomListAction()
data class LeaveRoom(val roomId: String) : RoomListAction()
object MarkAllRoomsRead : RoomListAction()
}

View file

@ -230,6 +230,9 @@ class RoomListFragment @Inject constructor(
is RoomListQuickActionsSharedAction.Settings -> {
navigator.openRoomProfile(requireActivity(), quickAction.roomId)
}
is RoomListQuickActionsSharedAction.Favorite -> {
roomListViewModel.handle(RoomListAction.ToggleFavorite(quickAction.roomId))
}
is RoomListQuickActionsSharedAction.Leave -> {
AlertDialog.Builder(requireContext())
.setTitle(R.string.room_participants_leave_prompt_title)
@ -239,8 +242,9 @@ class RoomListFragment @Inject constructor(
}
.setNegativeButton(R.string.cancel, null)
.show()
Unit
}
}
}.exhaustive
}
override fun invalidate() = withState(roomListViewModel) { state ->

View file

@ -21,6 +21,7 @@ import com.airbnb.mvrx.MvRxViewModelFactory
import com.airbnb.mvrx.ViewModelContext
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.NoOpMatrixCallback
import im.vector.matrix.android.api.extensions.orFalse
import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary
@ -67,6 +68,7 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
is RoomListAction.MarkAllRoomsRead -> handleMarkAllRoomsRead()
is RoomListAction.LeaveRoom -> handleLeaveRoom(action)
is RoomListAction.ChangeRoomNotificationState -> handleChangeNotificationMode(action)
is RoomListAction.ToggleFavorite -> handleToggleFavorite(action)
}.exhaustive
}
@ -205,6 +207,22 @@ class RoomListViewModel @Inject constructor(initialState: RoomListViewState,
})
}
private fun handleToggleFavorite(action: RoomListAction.ToggleFavorite) {
session.getRoom(action.roomId)?.let {
val callback = object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
_viewEvents.post(RoomListViewEvents.Failure(failure))
}
}
if (it.roomSummary()?.isFavorite == false) {
// Set favorite tag. We do not handle the order for the moment
it.addTag(RoomTag.ROOM_TAG_FAVOURITE, 0.5, callback)
} else {
it.deleteTag(RoomTag.ROOM_TAG_FAVOURITE, callback)
}
}
}
private fun handleLeaveRoom(action: RoomListAction.LeaveRoom) {
_viewEvents.post(RoomListViewEvents.Loading(null))
session.getRoom(action.roomId)?.leave(null, object : MatrixCallback<Unit> {

View file

@ -86,7 +86,11 @@ class RoomListQuickActionsBottomSheet : VectorBaseBottomSheetDialogFragment(), R
override fun didSelectMenuAction(quickAction: RoomListQuickActionsSharedAction) {
sharedActionViewModel.post(quickAction)
dismiss()
// Do not dismiss for all the actions
when (quickAction) {
is RoomListQuickActionsSharedAction.Favorite -> Unit
else -> dismiss()
}
}
companion object {

View file

@ -22,14 +22,17 @@ import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetActionItem
import im.vector.riotx.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem
import im.vector.riotx.core.epoxy.dividerItem
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.features.home.AvatarRenderer
import javax.inject.Inject
/**
* Epoxy controller for room list actions
*/
class RoomListQuickActionsEpoxyController @Inject constructor(private val avatarRenderer: AvatarRenderer)
: TypedEpoxyController<RoomListQuickActionsState>() {
class RoomListQuickActionsEpoxyController @Inject constructor(
private val avatarRenderer: AvatarRenderer,
private val stringProvider: StringProvider
) : TypedEpoxyController<RoomListQuickActionsState>() {
var listener: Listener? = null
@ -38,12 +41,15 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val avatar
val showAll = state.mode == RoomListActionsArgs.Mode.FULL
if (showAll) {
// Preview
// Preview, favorite, settings
bottomSheetRoomPreviewItem {
id("room_preview")
avatarRenderer(avatarRenderer)
matrixItem(roomSummary.toMatrixItem())
stringProvider(stringProvider)
izFavorite(roomSummary.isFavorite)
settingsClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) }
favoriteClickListener { listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Favorite(roomSummary.roomId)) }
}
// Notifications
@ -73,8 +79,7 @@ class RoomListQuickActionsEpoxyController @Inject constructor(private val avatar
is RoomListQuickActionsSharedAction.NotificationsAll -> roomNotificationState == RoomNotificationState.ALL_MESSAGES
is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> roomNotificationState == RoomNotificationState.MENTIONS_ONLY
is RoomListQuickActionsSharedAction.NotificationsMute -> roomNotificationState == RoomNotificationState.MUTE
is RoomListQuickActionsSharedAction.Settings,
is RoomListQuickActionsSharedAction.Leave -> false
else -> false
}
return bottomSheetActionItem {
id("action_$index")

View file

@ -52,6 +52,10 @@ sealed class RoomListQuickActionsSharedAction(
R.drawable.ic_room_actions_settings
)
data class Favorite(val roomId: String) : RoomListQuickActionsSharedAction(
R.string.room_list_quick_actions_favorite_add,
R.drawable.ic_star_24dp)
data class Leave(val roomId: String) : RoomListQuickActionsSharedAction(
R.string.room_list_quick_actions_leave,
R.drawable.ic_room_actions_leave,

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2L15.09,8.26L22,9.27L17,14.14L18.18,21.02L12,17.77L5.82,21.02L7,14.14L2,9.27L8.91,8.26L12,2Z"
android:strokeLineJoin="round"
android:strokeWidth="2"
android:fillColor="#00000000"
android:fillType="evenOdd"
android:strokeColor="#2E2F32"
android:strokeLineCap="round"/>
</vector>

View file

@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#03B381"
android:fillType="evenOdd"
android:pathData="M12,2L15.09,8.26L22,9.27L17,14.14L18.18,21.02L12,17.77L5.82,21.02L7,14.14L2,9.27L8.91,8.26L12,2Z"
android:strokeWidth="2"
android:strokeColor="#03B381"
android:strokeLineCap="round"
android:strokeLineJoin="round" />
</vector>

View file

@ -11,13 +11,13 @@
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="@dimen/layout_horizontal_margin"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:layout_marginTop="8dp"
android:layout_marginEnd="@dimen/layout_horizontal_margin"
android:layout_marginBottom="8dp"
android:adjustViewBounds="true"
android:background="@drawable/circle"
android:importantForAccessibility="no"
android:contentDescription="@string/avatar"
android:importantForAccessibility="no"
android:scaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
@ -39,19 +39,33 @@
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
app:layout_constraintEnd_toStartOf="@+id/bottomSheetRoomPreviewSettings"
app:layout_constraintEnd_toStartOf="@+id/bottomSheetRoomPreviewFavorite"
app:layout_constraintStart_toEndOf="@id/bottomSheetRoomPreviewAvatar"
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar"
tools:text="@tools:sample/full_names" />
<ImageView
android:id="@+id/bottomSheetRoomPreviewFavorite"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
app:layout_constraintEnd_toStartOf="@+id/bottomSheetRoomPreviewSettings"
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar"
tools:contentDescription="@string/room_list_quick_actions_favorite_add"
tools:src="@drawable/ic_star_24dp"
tools:tint="?riotx_text_secondary" />
<ImageView
android:id="@+id/bottomSheetRoomPreviewSettings"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/room_list_quick_actions_settings"
android:scaleType="centerInside"
android:src="@drawable/ic_room_actions_settings"
android:contentDescription="@string/room_list_quick_actions_settings"
android:tint="?riotx_text_secondary"
app:layout_constraintBottom_toBottomOf="@+id/bottomSheetRoomPreviewAvatar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/bottomSheetRoomPreviewAvatar" />

View file

@ -1838,6 +1838,8 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
<string name="room_list_quick_actions_notifications_mentions">"Mentions only"</string>
<string name="room_list_quick_actions_notifications_mute">"Mute"</string>
<string name="room_list_quick_actions_settings">"Settings"</string>
<string name="room_list_quick_actions_favorite_add">"Add to favorites"</string>
<string name="room_list_quick_actions_favorite_remove">"Remove from favorites"</string>
<string name="room_list_quick_actions_leave">"Leave the room"</string>
<string name="notice_member_no_changes">"%1$s made no changes"</string>
<string name="notice_member_no_changes_by_you">"You made no changes"</string>