mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Add capability to add and remove a room from the favorites (#1217)
This commit is contained in:
parent
0a7f77ea16
commit
d8317f7439
25 changed files with 395 additions and 20 deletions
|
@ -12,6 +12,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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -32,11 +32,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
|
||||
|
@ -288,4 +290,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>
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -56,6 +56,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
|
||||
|
@ -186,4 +190,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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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?
|
||||
)
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 ->
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
14
vector/src/main/res/drawable/ic_star_24dp.xml
Normal file
14
vector/src/main/res/drawable/ic_star_24dp.xml
Normal 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>
|
14
vector/src/main/res/drawable/ic_star_green_24dp.xml
Normal file
14
vector/src/main/res/drawable/ic_star_green_24dp.xml
Normal 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>
|
|
@ -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" />
|
||||
|
|
|
@ -1821,6 +1821,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>
|
||||
|
|
Loading…
Reference in a new issue