mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-28 14:08:44 +03:00
Adding go to timeline event button
This commit is contained in:
parent
eaa9cc740e
commit
384e7f674d
9 changed files with 203 additions and 10 deletions
|
@ -3207,6 +3207,7 @@
|
||||||
<string name="room_polls_wait_for_display">Displaying polls</string>
|
<string name="room_polls_wait_for_display">Displaying polls</string>
|
||||||
<string name="room_polls_load_more">Load more polls</string>
|
<string name="room_polls_load_more">Load more polls</string>
|
||||||
<string name="room_polls_loading_error">Error fetching polls.</string>
|
<string name="room_polls_loading_error">Error fetching polls.</string>
|
||||||
|
<string name="room_poll_details_go_to_timeline">View poll in timeline</string>
|
||||||
|
|
||||||
<!-- Location -->
|
<!-- Location -->
|
||||||
<string name="location_activity_title_static_sharing">Share location</string>
|
<string name="location_activity_title_static_sharing">Share location</string>
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.roomprofile.polls.detail.domain
|
||||||
|
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.RelationType
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.isPollEnd
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
// TODO add unit tests
|
||||||
|
class GetEndedPollEventIdUseCase @Inject constructor(
|
||||||
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun execute(roomId: String, startPollEventId: String): String? {
|
||||||
|
return activeSessionHolder.getActiveSession()
|
||||||
|
.roomService()
|
||||||
|
.getRoom(roomId)
|
||||||
|
?.timelineService()
|
||||||
|
?.getTimelineEventsRelatedTo(RelationType.REFERENCE, startPollEventId)
|
||||||
|
?.find { it.root.isPollEnd() }
|
||||||
|
?.eventId
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,5 +20,6 @@ import im.vector.app.features.poll.PollItemViewState
|
||||||
|
|
||||||
data class RoomPollDetail(
|
data class RoomPollDetail(
|
||||||
val isEnded: Boolean,
|
val isEnded: Boolean,
|
||||||
|
val endedPollEventId: String?,
|
||||||
val pollItemViewState: PollItemViewState,
|
val pollItemViewState: PollItemViewState,
|
||||||
)
|
)
|
||||||
|
|
|
@ -17,12 +17,14 @@
|
||||||
package im.vector.app.features.roomprofile.polls.detail.ui
|
package im.vector.app.features.roomprofile.polls.detail.ui
|
||||||
|
|
||||||
import com.airbnb.epoxy.TypedEpoxyController
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class RoomPollDetailController @Inject constructor() : TypedEpoxyController<RoomPollDetailViewState>() {
|
class RoomPollDetailController @Inject constructor() : TypedEpoxyController<RoomPollDetailViewState>() {
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun vote(pollEventId: String, optionId: String)
|
fun vote(pollEventId: String, optionId: String)
|
||||||
|
fun goToTimelineEvent(eventId: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
@ -41,5 +43,17 @@ class RoomPollDetailController @Inject constructor() : TypedEpoxyController<Room
|
||||||
optionViewStates(pollItemViewState.optionViewStates.orEmpty())
|
optionViewStates(pollItemViewState.optionViewStates.orEmpty())
|
||||||
callback(host.callback)
|
callback(host.callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildGoToTimelineItem(targetEventId = pollDetail.endedPollEventId ?: viewState.pollId)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildGoToTimelineItem(targetEventId: String) {
|
||||||
|
val host = this
|
||||||
|
roomPollGoToTimelineItem {
|
||||||
|
id(UUID.randomUUID().toString())
|
||||||
|
clickListener {
|
||||||
|
host.callback?.goToTimelineEvent(targetEventId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.databinding.FragmentRoomPollDetailBinding
|
import im.vector.app.databinding.FragmentRoomPollDetailBinding
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
@ -45,6 +46,7 @@ class RoomPollDetailFragment :
|
||||||
VectorBaseFragment<FragmentRoomPollDetailBinding>(),
|
VectorBaseFragment<FragmentRoomPollDetailBinding>(),
|
||||||
RoomPollDetailController.Callback {
|
RoomPollDetailController.Callback {
|
||||||
|
|
||||||
|
@Inject lateinit var viewNavigator: RoomPollDetailNavigator
|
||||||
@Inject lateinit var roomPollDetailController: RoomPollDetailController
|
@Inject lateinit var roomPollDetailController: RoomPollDetailController
|
||||||
|
|
||||||
private val viewModel: RoomPollDetailViewModel by fragmentViewModel()
|
private val viewModel: RoomPollDetailViewModel by fragmentViewModel()
|
||||||
|
@ -58,7 +60,6 @@ class RoomPollDetailFragment :
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
setupToolbar(isEnded = roomPollDetailArgs.isEnded)
|
setupToolbar(isEnded = roomPollDetailArgs.isEnded)
|
||||||
setupDetailView()
|
setupDetailView()
|
||||||
// TODO add link to go to timeline message + create a ViewNavigator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroyView() {
|
override fun onDestroyView() {
|
||||||
|
@ -93,4 +94,12 @@ class RoomPollDetailFragment :
|
||||||
override fun vote(pollEventId: String, optionId: String) {
|
override fun vote(pollEventId: String, optionId: String) {
|
||||||
viewModel.handle(RoomPollDetailAction.Vote(pollEventId = pollEventId, optionId = optionId))
|
viewModel.handle(RoomPollDetailAction.Vote(pollEventId = pollEventId, optionId = optionId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun goToTimelineEvent(eventId: String) = withState(viewModel) { state ->
|
||||||
|
viewNavigator.goToTimelineEvent(
|
||||||
|
context = requireContext(),
|
||||||
|
roomId = state.roomId,
|
||||||
|
eventId = eventId,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ package im.vector.app.features.roomprofile.polls.detail.ui
|
||||||
import im.vector.app.core.extensions.getVectorLastMessageContent
|
import im.vector.app.core.extensions.getVectorLastMessageContent
|
||||||
import im.vector.app.features.home.room.detail.timeline.factory.PollItemViewStateFactory
|
import im.vector.app.features.home.room.detail.timeline.factory.PollItemViewStateFactory
|
||||||
import im.vector.app.features.home.room.detail.timeline.helper.PollResponseDataFactory
|
import im.vector.app.features.home.room.detail.timeline.helper.PollResponseDataFactory
|
||||||
|
import im.vector.app.features.home.room.detail.timeline.item.PollResponseData
|
||||||
|
import im.vector.app.features.roomprofile.polls.detail.domain.GetEndedPollEventIdUseCase
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
|
||||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
@ -28,6 +31,7 @@ import javax.inject.Inject
|
||||||
class RoomPollDetailMapper @Inject constructor(
|
class RoomPollDetailMapper @Inject constructor(
|
||||||
private val pollResponseDataFactory: PollResponseDataFactory,
|
private val pollResponseDataFactory: PollResponseDataFactory,
|
||||||
private val pollItemViewStateFactory: PollItemViewStateFactory,
|
private val pollItemViewStateFactory: PollItemViewStateFactory,
|
||||||
|
private val getEndedPollEventIdUseCase: GetEndedPollEventIdUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun map(timelineEvent: TimelineEvent): RoomPollDetail? {
|
fun map(timelineEvent: TimelineEvent): RoomPollDetail? {
|
||||||
|
@ -36,16 +40,13 @@ class RoomPollDetailMapper @Inject constructor(
|
||||||
val content = timelineEvent.getVectorLastMessageContent()
|
val content = timelineEvent.getVectorLastMessageContent()
|
||||||
val pollResponseData = pollResponseDataFactory.create(timelineEvent)
|
val pollResponseData = pollResponseDataFactory.create(timelineEvent)
|
||||||
return if (eventId.isNotEmpty() && content is MessagePollContent) {
|
return if (eventId.isNotEmpty() && content is MessagePollContent) {
|
||||||
// we assume poll message has been sent here
|
val isPollEnded = pollResponseData?.isClosed.orFalse()
|
||||||
val pollItemViewState = pollItemViewStateFactory.create(
|
val endedPollEventId = getEndedPollEventId(
|
||||||
pollContent = content,
|
isPollEnded,
|
||||||
pollResponseData = pollResponseData,
|
startPollEventId = eventId,
|
||||||
isSent = true,
|
roomId = timelineEvent.roomId,
|
||||||
)
|
|
||||||
RoomPollDetail(
|
|
||||||
isEnded = pollResponseData?.isClosed == true,
|
|
||||||
pollItemViewState = pollItemViewState,
|
|
||||||
)
|
)
|
||||||
|
convertToRoomPollDetail(content, pollResponseData, isPollEnded, endedPollEventId)
|
||||||
} else {
|
} else {
|
||||||
Timber.w("missing mandatory info about poll event with id=$eventId")
|
Timber.w("missing mandatory info about poll event with id=$eventId")
|
||||||
null
|
null
|
||||||
|
@ -57,4 +58,35 @@ class RoomPollDetailMapper @Inject constructor(
|
||||||
}
|
}
|
||||||
return result.getOrNull()
|
return result.getOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun convertToRoomPollDetail(
|
||||||
|
content: MessagePollContent,
|
||||||
|
pollResponseData: PollResponseData?,
|
||||||
|
isPollEnded: Boolean,
|
||||||
|
endedPollEventId: String?,
|
||||||
|
): RoomPollDetail {
|
||||||
|
// we assume the poll has been sent
|
||||||
|
val pollItemViewState = pollItemViewStateFactory.create(
|
||||||
|
pollContent = content,
|
||||||
|
pollResponseData = pollResponseData,
|
||||||
|
isSent = true,
|
||||||
|
)
|
||||||
|
return RoomPollDetail(
|
||||||
|
isEnded = isPollEnded,
|
||||||
|
pollItemViewState = pollItemViewState,
|
||||||
|
endedPollEventId = endedPollEventId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEndedPollEventId(
|
||||||
|
isPollEnded: Boolean,
|
||||||
|
startPollEventId: String,
|
||||||
|
roomId: String,
|
||||||
|
): String? {
|
||||||
|
return if (isPollEnded) {
|
||||||
|
getEndedPollEventIdUseCase.execute(startPollEventId = startPollEventId, roomId = roomId)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.roomprofile.polls.detail.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import im.vector.app.features.navigation.Navigator
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
// TODO add unit tests
|
||||||
|
class RoomPollDetailNavigator @Inject constructor(
|
||||||
|
private val navigator: Navigator,
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun goToTimelineEvent(context: Context, roomId: String, eventId: String) {
|
||||||
|
navigator.openRoom(
|
||||||
|
context = context,
|
||||||
|
roomId = roomId,
|
||||||
|
eventId = eventId,
|
||||||
|
buildTask = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 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.roomprofile.polls.detail.ui
|
||||||
|
|
||||||
|
import android.widget.Button
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.ClickListener
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.epoxy.onClick
|
||||||
|
|
||||||
|
@EpoxyModelClass
|
||||||
|
abstract class RoomPollGoToTimelineItem : VectorEpoxyModel<RoomPollGoToTimelineItem.Holder>(R.layout.item_poll_go_to_timeline) {
|
||||||
|
|
||||||
|
@EpoxyAttribute(EpoxyAttribute.Option.DoNotHash)
|
||||||
|
var clickListener: ClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.goToTimelineButton.onClick(clickListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val goToTimelineButton by bind<Button>(R.id.roomPollGoToTimeline)
|
||||||
|
}
|
||||||
|
}
|
20
vector/src/main/res/layout/item_poll_go_to_timeline.xml
Normal file
20
vector/src/main/res/layout/item_poll_go_to_timeline.xml
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/roomPollGoToTimeline"
|
||||||
|
style="@style/Widget.Vector.Button.Text"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="33dp"
|
||||||
|
android:layout_marginBottom="46dp"
|
||||||
|
android:padding="0dp"
|
||||||
|
android:text="@string/room_poll_details_go_to_timeline"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in a new issue