Show poll creator view in timeline (#1429)

- Shows edit/end poll buttons when the user is the creator of the poll.
- Only the end poll button is wired right now as there is no "edit poll" screen yet.
This commit is contained in:
Marco Romano 2023-09-26 11:19:24 +02:00 committed by GitHub
parent 54fb1e79c5
commit 295e10e612
109 changed files with 234 additions and 17 deletions

View file

@ -30,7 +30,6 @@ import androidx.compose.runtime.setValue
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.features.analytics.plan.PollEnd
import io.element.android.features.messages.impl.actionlist.ActionListEvents import io.element.android.features.messages.impl.actionlist.ActionListEvents
import io.element.android.features.messages.impl.actionlist.ActionListPresenter import io.element.android.features.messages.impl.actionlist.ActionListPresenter
import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction import io.element.android.features.messages.impl.actionlist.model.TimelineItemAction
@ -39,6 +38,7 @@ import io.element.android.features.messages.impl.messagecomposer.MessageComposer
import io.element.android.features.messages.impl.messagecomposer.MessageComposerState import io.element.android.features.messages.impl.messagecomposer.MessageComposerState
import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.TimelinePresenter import io.element.android.features.messages.impl.timeline.TimelinePresenter
import io.element.android.features.messages.impl.timeline.TimelineState
import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionPresenter import io.element.android.features.messages.impl.timeline.components.customreaction.CustomReactionPresenter
import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryPresenter import io.element.android.features.messages.impl.timeline.components.reactionsummary.ReactionSummaryPresenter
import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuPresenter import io.element.android.features.messages.impl.timeline.components.retrysendmenu.RetrySendMenuPresenter
@ -76,7 +76,6 @@ import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailType
import io.element.android.libraries.matrix.ui.room.canRedactAsState import io.element.android.libraries.matrix.ui.room.canRedactAsState
import io.element.android.libraries.matrix.ui.room.canSendMessageAsState import io.element.android.libraries.matrix.ui.room.canSendMessageAsState
import io.element.android.libraries.textcomposer.MessageComposerMode import io.element.android.libraries.textcomposer.MessageComposerMode
import io.element.android.services.analytics.api.AnalyticsService
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -95,7 +94,6 @@ class MessagesPresenter @AssistedInject constructor(
private val messageSummaryFormatter: MessageSummaryFormatter, private val messageSummaryFormatter: MessageSummaryFormatter,
private val dispatchers: CoroutineDispatchers, private val dispatchers: CoroutineDispatchers,
private val clipboardHelper: ClipboardHelper, private val clipboardHelper: ClipboardHelper,
private val analyticsService: AnalyticsService,
private val preferencesStore: PreferencesStore, private val preferencesStore: PreferencesStore,
@Assisted private val navigator: MessagesNavigator, @Assisted private val navigator: MessagesNavigator,
) : Presenter<MessagesState> { ) : Presenter<MessagesState> {
@ -155,6 +153,7 @@ class MessagesPresenter @AssistedInject constructor(
targetEvent = event.event, targetEvent = event.event,
composerState = composerState, composerState = composerState,
enableTextFormatting = enableTextFormatting, enableTextFormatting = enableTextFormatting,
timelineState = timelineState,
) )
} }
is MessagesEvents.ToggleReaction -> { is MessagesEvents.ToggleReaction -> {
@ -206,6 +205,7 @@ class MessagesPresenter @AssistedInject constructor(
targetEvent: TimelineItem.Event, targetEvent: TimelineItem.Event,
composerState: MessageComposerState, composerState: MessageComposerState,
enableTextFormatting: Boolean, enableTextFormatting: Boolean,
timelineState: TimelineState,
) = launch { ) = launch {
when (action) { when (action) {
TimelineItemAction.Copy -> handleCopyContents(targetEvent) TimelineItemAction.Copy -> handleCopyContents(targetEvent)
@ -216,7 +216,7 @@ class MessagesPresenter @AssistedInject constructor(
TimelineItemAction.ViewSource -> handleShowDebugInfoAction(targetEvent) TimelineItemAction.ViewSource -> handleShowDebugInfoAction(targetEvent)
TimelineItemAction.Forward -> handleForwardAction(targetEvent) TimelineItemAction.Forward -> handleForwardAction(targetEvent)
TimelineItemAction.ReportContent -> handleReportAction(targetEvent) TimelineItemAction.ReportContent -> handleReportAction(targetEvent)
TimelineItemAction.EndPoll -> handleEndPollAction(targetEvent) TimelineItemAction.EndPoll -> handleEndPollAction(targetEvent, timelineState)
} }
} }
@ -266,7 +266,7 @@ class MessagesPresenter @AssistedInject constructor(
targetEvent: TimelineItem.Event, targetEvent: TimelineItem.Event,
composerState: MessageComposerState, composerState: MessageComposerState,
enableTextFormatting: Boolean, enableTextFormatting: Boolean,
) { ) {
val composerMode = MessageComposerMode.Edit( val composerMode = MessageComposerMode.Edit(
targetEvent.eventId, targetEvent.eventId,
(targetEvent.content as? TimelineItemTextBasedContent)?.let { (targetEvent.content as? TimelineItemTextBasedContent)?.let {
@ -344,11 +344,11 @@ class MessagesPresenter @AssistedInject constructor(
navigator.onReportContentClicked(event.eventId, event.senderId) navigator.onReportContentClicked(event.eventId, event.senderId)
} }
private suspend fun handleEndPollAction(event: TimelineItem.Event) { private fun handleEndPollAction(
event.eventId?.let { event: TimelineItem.Event,
room.endPoll(it, "The poll with event id: $it has ended.") timelineState: TimelineState,
analyticsService.capture(PollEnd()) ) {
} event.eventId?.let { timelineState.eventSink(TimelineEvents.PollEndClicked(it)) }
} }
private suspend fun handleCopyContents(event: TimelineItem.Event) { private suspend fun handleCopyContents(event: TimelineItem.Event) {

View file

@ -108,7 +108,7 @@ class ActionListPresenter @Inject constructor(
buildList { buildList {
val isMineOrCanRedact = timelineItem.isMine || userCanRedact val isMineOrCanRedact = timelineItem.isMine || userCanRedact
// TODO Poll: Reply to poll. Ensure to update `fun TimelineItemEventContent.canBeReplied()` // TODO Polls: Reply to poll. Ensure to update `fun TimelineItemEventContent.canBeReplied()`
// when touching this // when touching this
// if (timelineItem.isRemote) { // if (timelineItem.isRemote) {
// // Can only reply or forward messages already uploaded to the server // // Can only reply or forward messages already uploaded to the server

View file

@ -26,4 +26,8 @@ sealed interface TimelineEvents {
val pollStartId: EventId, val pollStartId: EventId,
val answerId: String val answerId: String
) : TimelineEvents ) : TimelineEvents
data class PollEndClicked(
val pollStartId: EventId,
) : TimelineEvents
} }

View file

@ -26,6 +26,7 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import im.vector.app.features.analytics.plan.PollEnd
import im.vector.app.features.analytics.plan.PollVote import im.vector.app.features.analytics.plan.PollVote
import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory import io.element.android.features.messages.impl.timeline.factories.TimelineItemsFactory
import io.element.android.features.messages.impl.timeline.model.TimelineItem import io.element.android.features.messages.impl.timeline.model.TimelineItem
@ -98,11 +99,18 @@ class TimelinePresenter @Inject constructor(
) )
analyticsService.capture(PollVote()) analyticsService.capture(PollVote())
} }
is TimelineEvents.PollEndClicked -> appScope.launch {
room.endPoll(
pollStartId = event.pollStartId,
text = "The poll with event id: ${event.pollStartId} has ended."
)
analyticsService.capture(PollEnd())
}
} }
} }
LaunchedEffect(timelineItems.size) { LaunchedEffect(timelineItems.size) {
computeHasNewItems(timelineItems, prevMostRecentItemId, hasNewItems) computeHasNewItems(timelineItems, prevMostRecentItemId, hasNewItems)
} }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {

View file

@ -386,6 +386,7 @@ private fun MessageEventBubbleContent(
) { ) {
TimelineItemEventContentView( TimelineItemEventContentView(
content = event.content, content = event.content,
isMine = event.isMine,
interactionSource = interactionSource, interactionSource = interactionSource,
onClick = onMessageClick, onClick = onMessageClick,
onLongClick = onMessageLongClick, onLongClick = onMessageLongClick,

View file

@ -67,6 +67,7 @@ fun TimelineItemStateEventRow(
) { ) {
TimelineItemEventContentView( TimelineItemEventContentView(
content = event.content, content = event.content,
isMine = event.isMine,
interactionSource = interactionSource, interactionSource = interactionSource,
onClick = onClick, onClick = onClick,
onLongClick = onLongClick, onLongClick = onLongClick,

View file

@ -36,6 +36,7 @@ import io.element.android.features.messages.impl.timeline.model.event.TimelineIt
@Composable @Composable
fun TimelineItemEventContentView( fun TimelineItemEventContentView(
content: TimelineItemEventContent, content: TimelineItemEventContent,
isMine: Boolean,
interactionSource: MutableInteractionSource, interactionSource: MutableInteractionSource,
extraPadding: ExtraPadding, extraPadding: ExtraPadding,
onClick: () -> Unit, onClick: () -> Unit,
@ -95,6 +96,7 @@ fun TimelineItemEventContentView(
) )
is TimelineItemPollContent -> TimelineItemPollView( is TimelineItemPollContent -> TimelineItemPollView(
content = content, content = content,
isMine = isMine,
eventSink = eventSink, eventSink = eventSink,
modifier = modifier, modifier = modifier,
) )

View file

@ -31,6 +31,7 @@ import kotlinx.collections.immutable.toImmutableList
@Composable @Composable
fun TimelineItemPollView( fun TimelineItemPollView(
content: TimelineItemPollContent, content: TimelineItemPollContent,
isMine: Boolean,
eventSink: (TimelineEvents) -> Unit, eventSink: (TimelineEvents) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -38,13 +39,20 @@ fun TimelineItemPollView(
eventSink(TimelineEvents.PollAnswerSelected(pollStartId, answerId)) eventSink(TimelineEvents.PollAnswerSelected(pollStartId, answerId))
} }
fun onPollEnd(pollStartId: EventId) {
eventSink(TimelineEvents.PollEndClicked(pollStartId))
}
PollContentView( PollContentView(
eventId = content.eventId, eventId = content.eventId,
question = content.question, question = content.question,
answerItems = content.answerItems.toImmutableList(), answerItems = content.answerItems.toImmutableList(),
pollKind = content.pollKind, pollKind = content.pollKind,
isPollEnded = content.isEnded, isPollEnded = content.isEnded,
isMine = isMine,
onAnswerSelected = ::onAnswerSelected, onAnswerSelected = ::onAnswerSelected,
onPollEdit = {}, // TODO Polls: Wire up this callback once poll edit screen is done.
onPollEnd = ::onPollEnd,
modifier = modifier, modifier = modifier,
) )
} }
@ -55,6 +63,18 @@ internal fun TimelineItemPollViewPreview(@PreviewParameter(TimelineItemPollConte
ElementPreview { ElementPreview {
TimelineItemPollView( TimelineItemPollView(
content = content, content = content,
isMine = false,
eventSink = {},
)
}
@PreviewsDayNight
@Composable
internal fun TimelineItemPollCreatorViewPreview(@PreviewParameter(TimelineItemPollContentProvider::class) content: TimelineItemPollContent) =
ElementPreview {
TimelineItemPollView(
content = content,
isMine = true,
eventSink = {}, eventSink = {},
) )
} }

View file

@ -644,7 +644,6 @@ class MessagesPresenterTest {
messageSummaryFormatter = FakeMessageSummaryFormatter(), messageSummaryFormatter = FakeMessageSummaryFormatter(),
navigator = navigator, navigator = navigator,
clipboardHelper = clipboardHelper, clipboardHelper = clipboardHelper,
analyticsService = analyticsService,
preferencesStore = preferencesStore, preferencesStore = preferencesStore,
dispatchers = coroutineDispatchers, dispatchers = coroutineDispatchers,
) )

View file

@ -20,7 +20,9 @@ import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow import app.cash.molecule.moleculeFlow
import app.cash.turbine.test import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.PollEnd
import im.vector.app.features.analytics.plan.PollVote import im.vector.app.features.analytics.plan.PollVote
import io.element.android.features.messages.fixtures.aMessageEvent
import io.element.android.features.messages.fixtures.aTimelineItemsFactory import io.element.android.features.messages.fixtures.aTimelineItemsFactory
import io.element.android.features.messages.impl.timeline.TimelineEvents import io.element.android.features.messages.impl.timeline.TimelineEvents
import io.element.android.features.messages.impl.timeline.TimelinePresenter import io.element.android.features.messages.impl.timeline.TimelinePresenter
@ -42,6 +44,7 @@ import io.element.android.services.analytics.test.FakeAnalyticsService
import io.element.android.tests.testutils.WarmUpRule import io.element.android.tests.testutils.WarmUpRule
import io.element.android.tests.testutils.awaitWithLatch import io.element.android.tests.testutils.awaitWithLatch
import io.element.android.tests.testutils.testCoroutineDispatchers import io.element.android.tests.testutils.testCoroutineDispatchers
import io.element.android.tests.testutils.waitForPredicate
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -280,6 +283,29 @@ class TimelinePresenterTest {
assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollVote()) assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollVote())
} }
@Test
fun `present - PollEndClicked event calls into rust room api and analytics`() = runTest {
val room = FakeMatrixRoom()
val analyticsService = FakeAnalyticsService()
val presenter = createTimelinePresenter(
room = room,
analyticsService = analyticsService,
)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(TimelineEvents.PollEndClicked(aMessageEvent().eventId!!))
waitForPredicate { room.endPollInvocations.size == 1 }
cancelAndIgnoreRemainingEvents()
assertThat(room.endPollInvocations.size).isEqualTo(1)
assertThat(room.endPollInvocations.first().pollStartId).isEqualTo(AN_EVENT_ID)
assertThat(room.endPollInvocations.first().text).isEqualTo("The poll with event id: \$anEventId has ended.")
assertThat(analyticsService.capturedEvents.size).isEqualTo(1)
assertThat(analyticsService.capturedEvents.last()).isEqualTo(PollEnd())
}
}
private fun TestScope.createTimelinePresenter( private fun TestScope.createTimelinePresenter(
timeline: MatrixTimeline = FakeMatrixTimeline(), timeline: MatrixTimeline = FakeMatrixTimeline(),
timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory() timelineItemsFactory: TimelineItemsFactory = aTimelineItemsFactory()

View file

@ -19,13 +19,17 @@ package io.element.android.features.poll.api
import io.element.android.libraries.matrix.api.poll.PollAnswer import io.element.android.libraries.matrix.api.poll.PollAnswer
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
fun aPollAnswerItemList(isEnded: Boolean = false, isDisclosed: Boolean = true) = persistentListOf( fun aPollAnswerItemList(
hasVotes: Boolean = true,
isEnded: Boolean = false,
isDisclosed: Boolean = true,
) = persistentListOf(
aPollAnswerItem( aPollAnswerItem(
answer = PollAnswer("option_1", "Italian \uD83C\uDDEE\uD83C\uDDF9"), answer = PollAnswer("option_1", "Italian \uD83C\uDDEE\uD83C\uDDF9"),
isDisclosed = isDisclosed, isDisclosed = isDisclosed,
isEnabled = !isEnded, isEnabled = !isEnded,
isWinner = isEnded, isWinner = isEnded,
votesCount = 5, votesCount = if (hasVotes) 5 else 0,
percentage = 0.5f percentage = 0.5f
), ),
aPollAnswerItem( aPollAnswerItem(
@ -42,7 +46,7 @@ fun aPollAnswerItemList(isEnded: Boolean = false, isDisclosed: Boolean = true) =
isEnabled = !isEnded, isEnabled = !isEnded,
isWinner = false, isWinner = false,
isSelected = true, isSelected = true,
votesCount = 1, votesCount = if (hasVotes) 1 else 0,
percentage = 0.1f percentage = 0.1f
), ),
aPollAnswerItem(isDisclosed = isDisclosed, isEnabled = !isEnded), aPollAnswerItem(isDisclosed = isDisclosed, isEnabled = !isEnded),

View file

@ -26,14 +26,19 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectable
import androidx.compose.foundation.selection.selectableGroup import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.designsystem.utils.CommonDrawables
@ -51,13 +56,37 @@ fun PollContentView(
answerItems: ImmutableList<PollAnswerItem>, answerItems: ImmutableList<PollAnswerItem>,
pollKind: PollKind, pollKind: PollKind,
isPollEnded: Boolean, isPollEnded: Boolean,
isMine: Boolean,
onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit, onAnswerSelected: (pollStartId: EventId, answerId: String) -> Unit,
onPollEdit: (pollStartId: EventId) -> Unit,
onPollEnd: (pollStartId: EventId) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val votesCount = remember(answerItems) { answerItems.sumOf { it.votesCount } }
fun onAnswerSelected(pollAnswer: PollAnswer) { fun onAnswerSelected(pollAnswer: PollAnswer) {
eventId?.let { onAnswerSelected(it, pollAnswer.id) } eventId?.let { onAnswerSelected(it, pollAnswer.id) }
} }
fun onPollEdit() {
eventId?.let { onPollEdit(it) }
}
fun onPollEnd() {
eventId?.let { onPollEnd(it) }
}
var showConfirmation: Boolean by remember { mutableStateOf(false) }
if (showConfirmation) ConfirmationDialog(
content = stringResource(id = CommonStrings.common_poll_end_confirmation),
onSubmitClicked = {
onPollEnd()
showConfirmation = false
},
onDismiss = { showConfirmation = false },
)
Column( Column(
modifier = modifier.fillMaxWidth(), modifier = modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
@ -67,11 +96,20 @@ fun PollContentView(
PollAnswers(answerItems = answerItems, onAnswerSelected = ::onAnswerSelected) PollAnswers(answerItems = answerItems, onAnswerSelected = ::onAnswerSelected)
if (isPollEnded || pollKind == PollKind.Disclosed) { if (isPollEnded || pollKind == PollKind.Disclosed) {
val votesCount = remember(answerItems) { answerItems.sumOf { it.votesCount } }
DisclosedPollBottomNotice(votesCount = votesCount) DisclosedPollBottomNotice(votesCount = votesCount)
} else { } else {
UndisclosedPollBottomNotice() UndisclosedPollBottomNotice()
} }
if (isMine) {
CreatorView(
votesCount = 1, // TODO Polls: set to `votesCount` when edit poll screen is implemented.
isPollEnded = isPollEnded,
onPollEdit = ::onPollEdit,
onPollEnd = { showConfirmation = true },
modifier = Modifier.fillMaxWidth(),
)
}
} }
} }
@ -157,6 +195,31 @@ private fun ColumnScope.UndisclosedPollBottomNotice(
) )
} }
@Composable
private fun CreatorView(
@Suppress("SameParameterValue") votesCount: Int, // TODO Polls: remove @Suppress when edit poll screen is implemented.
isPollEnded: Boolean,
onPollEdit: () -> Unit,
onPollEnd: () -> Unit,
modifier: Modifier = Modifier
) {
if (!isPollEnded) {
if (votesCount == 0) {
Button(
text = stringResource(id = CommonStrings.action_edit_poll),
onClick = onPollEdit,
modifier = modifier,
)
} else {
Button(
text = stringResource(id = CommonStrings.action_end_poll),
onClick = onPollEnd,
modifier = modifier,
)
}
}
}
@PreviewsDayNight @PreviewsDayNight
@Composable @Composable
internal fun PollContentUndisclosedPreview() = ElementPreview { internal fun PollContentUndisclosedPreview() = ElementPreview {
@ -166,7 +229,10 @@ internal fun PollContentUndisclosedPreview() = ElementPreview {
answerItems = aPollAnswerItemList(isDisclosed = false), answerItems = aPollAnswerItemList(isDisclosed = false),
pollKind = PollKind.Undisclosed, pollKind = PollKind.Undisclosed,
isPollEnded = false, isPollEnded = false,
isMine = false,
onAnswerSelected = { _, _ -> }, onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
) )
} }
@ -179,7 +245,10 @@ internal fun PollContentDisclosedPreview() = ElementPreview {
answerItems = aPollAnswerItemList(), answerItems = aPollAnswerItemList(),
pollKind = PollKind.Disclosed, pollKind = PollKind.Disclosed,
isPollEnded = false, isPollEnded = false,
isMine = false,
onAnswerSelected = { _, _ -> }, onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
) )
} }
@ -192,6 +261,57 @@ internal fun PollContentEndedPreview() = ElementPreview {
answerItems = aPollAnswerItemList(isEnded = true), answerItems = aPollAnswerItemList(isEnded = true),
pollKind = PollKind.Disclosed, pollKind = PollKind.Disclosed,
isPollEnded = true, isPollEnded = true,
isMine = false,
onAnswerSelected = { _, _ -> }, onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
)
}
@PreviewsDayNight
@Composable
internal fun PollContentCreatorNoVotesPreview() = ElementPreview {
PollContentView(
eventId = EventId("\$anEventId"),
question = "What type of food should we have at the party?",
answerItems = aPollAnswerItemList(hasVotes = false, isEnded = false),
pollKind = PollKind.Disclosed,
isPollEnded = false,
isMine = true,
onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
)
}
@PreviewsDayNight
@Composable
internal fun PollContentCreatorPreview() = ElementPreview {
PollContentView(
eventId = EventId("\$anEventId"),
question = "What type of food should we have at the party?",
answerItems = aPollAnswerItemList(isEnded = false),
pollKind = PollKind.Disclosed,
isPollEnded = false,
isMine = true,
onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
)
}
@PreviewsDayNight
@Composable
internal fun PollContentCreatorEndedPreview() = ElementPreview {
PollContentView(
eventId = EventId("\$anEventId"),
question = "What type of food should we have at the party?",
answerItems = aPollAnswerItemList(isEnded = true),
pollKind = PollKind.Disclosed,
isPollEnded = true,
isMine = true,
onAnswerSelected = { _, _ -> },
onPollEdit = {},
onPollEnd = {},
) )
} }

View file

@ -71,6 +71,7 @@
<string name="action_take_photo">"Take photo"</string> <string name="action_take_photo">"Take photo"</string>
<string name="action_view_source">"View Source"</string> <string name="action_view_source">"View Source"</string>
<string name="action_yes">"Yes"</string> <string name="action_yes">"Yes"</string>
<string name="action_edit_poll">"Edit poll"</string>
<string name="common_about">"About"</string> <string name="common_about">"About"</string>
<string name="common_acceptable_use_policy">"Acceptable use policy"</string> <string name="common_acceptable_use_policy">"Acceptable use policy"</string>
<string name="common_advanced_settings">"Advanced settings"</string> <string name="common_advanced_settings">"Advanced settings"</string>
@ -149,6 +150,7 @@
<string name="common_verification_complete">"Verification complete"</string> <string name="common_verification_complete">"Verification complete"</string>
<string name="common_video">"Video"</string> <string name="common_video">"Video"</string>
<string name="common_waiting">"Waiting…"</string> <string name="common_waiting">"Waiting…"</string>
<string name="common_poll_end_confirmation">"Are you sure you want to end this poll?"</string>
<string name="common_poll_summary">"Poll: %1$s"</string> <string name="common_poll_summary">"Poll: %1$s"</string>
<string name="dialog_title_confirmation">"Confirmation"</string> <string name="dialog_title_confirmation">"Confirmation"</string>
<string name="dialog_title_warning">"Warning"</string> <string name="dialog_title_warning">"Warning"</string>

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:09440b685e219b4a5f5dc78d2694707d7eeb1905d6fdea6395e3dcc941482ac5
size 51846

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:ae8d6b561d358c7ebccae2da4281f3ea1b4d433f52de3c3b2008c1208c0c8bd7
size 54037

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a0cd0936ace9bac190f21680bf339cc23839e5f5d241522cb8f328b2db0887f6
size 48293

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cc96f4b704396e0931a08a968139ee9d586cd1e14358b546361d11bc91e7bab5
size 50373

Some files were not shown because too many files have changed in this diff Show more