Benoit Marty
10 months ago
committed by
Benoit Marty
16 changed files with 290 additions and 17 deletions
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
/* |
||||
* 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 io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet |
||||
|
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
|
||||
sealed interface ReadReceiptBottomSheetEvents { |
||||
data class EventSelected(val event: TimelineItem.Event) : ReadReceiptBottomSheetEvents |
||||
data object Dismiss : ReadReceiptBottomSheetEvents |
||||
} |
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
/* |
||||
* 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 io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet |
||||
|
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.getValue |
||||
import androidx.compose.runtime.mutableStateOf |
||||
import androidx.compose.runtime.remember |
||||
import androidx.compose.runtime.setValue |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
import io.element.android.libraries.architecture.Presenter |
||||
import javax.inject.Inject |
||||
|
||||
class ReadReceiptBottomSheetPresenter @Inject constructor( |
||||
) : Presenter<ReadReceiptBottomSheetState> { |
||||
|
||||
@Composable |
||||
override fun present(): ReadReceiptBottomSheetState { |
||||
var selectedEvent: TimelineItem.Event? by remember { mutableStateOf(null) } |
||||
|
||||
fun handleEvent(event: ReadReceiptBottomSheetEvents) { |
||||
@Suppress("LiftReturnOrAssignment") |
||||
when (event) { |
||||
is ReadReceiptBottomSheetEvents.EventSelected -> { |
||||
selectedEvent = event.event |
||||
} |
||||
ReadReceiptBottomSheetEvents.Dismiss -> { |
||||
selectedEvent = null |
||||
} |
||||
} |
||||
} |
||||
|
||||
return ReadReceiptBottomSheetState( |
||||
selectedEvent = selectedEvent, |
||||
eventSink = { handleEvent(it) }, |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
/* |
||||
* 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 io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet |
||||
|
||||
import androidx.compose.runtime.Immutable |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItem |
||||
|
||||
@Immutable |
||||
data class ReadReceiptBottomSheetState( |
||||
val selectedEvent: TimelineItem.Event?, |
||||
val eventSink: (ReadReceiptBottomSheetEvents) -> Unit, |
||||
) |
@ -0,0 +1,44 @@
@@ -0,0 +1,44 @@
|
||||
/* |
||||
* 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 io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet |
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider |
||||
import io.element.android.features.messages.impl.timeline.aTimelineItemEvent |
||||
import io.element.android.features.messages.impl.timeline.components.receipt.ReadReceiptViewStateProvider |
||||
import io.element.android.features.messages.impl.timeline.model.TimelineItemReadReceipts |
||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState |
||||
import kotlinx.collections.immutable.toImmutableList |
||||
|
||||
class ReadReceiptBottomSheetStateProvider : PreviewParameterProvider<ReadReceiptBottomSheetState> { |
||||
// Reuse the provider ReadReceiptViewStateProvider |
||||
private val readReceiptViewStateProvider = ReadReceiptViewStateProvider() |
||||
override val values: Sequence<ReadReceiptBottomSheetState> = readReceiptViewStateProvider.values |
||||
.filter { it.sendState is LocalEventSendState.Sent } |
||||
.map { readReceiptViewState -> |
||||
ReadReceiptBottomSheetState( |
||||
selectedEvent = aTimelineItemEvent( |
||||
readReceiptState = TimelineItemReadReceipts.ReadReceipts( |
||||
receipts = readReceiptViewState.receipts.map { readReceiptData -> |
||||
readReceiptData |
||||
.copy(avatarData = readReceiptData.avatarData.copy(id = "@${readReceiptData.avatarData.id}:localhost")) |
||||
}.toImmutableList() |
||||
) |
||||
), |
||||
eventSink = {}, |
||||
) |
||||
} |
||||
} |
@ -0,0 +1,107 @@
@@ -0,0 +1,107 @@
|
||||
/* |
||||
* 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 io.element.android.features.messages.impl.timeline.components.receipt.bottomsheet |
||||
|
||||
import androidx.compose.foundation.layout.Column |
||||
import androidx.compose.foundation.layout.ColumnScope |
||||
import androidx.compose.foundation.layout.Spacer |
||||
import androidx.compose.foundation.layout.height |
||||
import androidx.compose.material3.ExperimentalMaterial3Api |
||||
import androidx.compose.material3.rememberModalBottomSheetState |
||||
import androidx.compose.runtime.Composable |
||||
import androidx.compose.runtime.rememberCoroutineScope |
||||
import androidx.compose.ui.Modifier |
||||
import androidx.compose.ui.tooling.preview.PreviewParameter |
||||
import androidx.compose.ui.unit.dp |
||||
import io.element.android.features.messages.impl.timeline.model.receipts |
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize |
||||
import io.element.android.libraries.designsystem.preview.ElementPreview |
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight |
||||
import io.element.android.libraries.designsystem.theme.components.ModalBottomSheet |
||||
import io.element.android.libraries.designsystem.theme.components.Text |
||||
import io.element.android.libraries.matrix.api.core.UserId |
||||
import io.element.android.libraries.matrix.api.user.MatrixUser |
||||
import io.element.android.libraries.matrix.ui.components.MatrixUserRow |
||||
import io.element.android.libraries.theme.ElementTheme |
||||
import kotlinx.coroutines.launch |
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class) |
||||
@Composable |
||||
internal fun ReadReceiptBottomSheetView( |
||||
state: ReadReceiptBottomSheetState, |
||||
modifier: Modifier = Modifier, |
||||
) { |
||||
val isVisible = state.selectedEvent != null |
||||
|
||||
val sheetState = rememberModalBottomSheetState() |
||||
val coroutineScope = rememberCoroutineScope() |
||||
if (isVisible) { |
||||
ModalBottomSheet( |
||||
modifier = modifier, |
||||
// modifier = modifier.navigationBarsPadding() - FIXME after https://issuetracker.google.com/issues/275849044 |
||||
// .imePadding() |
||||
sheetState = sheetState, |
||||
onDismissRequest = { |
||||
coroutineScope.launch { |
||||
sheetState.hide() |
||||
state.eventSink(ReadReceiptBottomSheetEvents.Dismiss) |
||||
} |
||||
} |
||||
) { |
||||
ReadReceiptBottomSheetContents( |
||||
state = state, |
||||
) |
||||
// FIXME remove after https://issuetracker.google.com/issues/275849044 |
||||
Spacer(modifier = Modifier.height(32.dp)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Composable |
||||
private fun ColumnScope.ReadReceiptBottomSheetContents( |
||||
state: ReadReceiptBottomSheetState, |
||||
) { |
||||
val receipts = state.selectedEvent?.readReceiptState?.receipts().orEmpty() |
||||
receipts.forEach { |
||||
MatrixUserRow( |
||||
matrixUser = MatrixUser( |
||||
UserId(it.avatarData.id), |
||||
it.avatarData.name, |
||||
it.avatarData.url, |
||||
), |
||||
avatarSize = AvatarSize.ReadReceiptList, |
||||
trailingContent = { |
||||
Text( |
||||
text = it.formattedDate, |
||||
style = ElementTheme.typography.fontBodySmRegular, |
||||
color = ElementTheme.colors.textSecondary, |
||||
) |
||||
} |
||||
) |
||||
} |
||||
} |
||||
|
||||
@PreviewsDayNight |
||||
@Composable |
||||
internal fun ReadReceiptBottomSheetViewPreview(@PreviewParameter(ReadReceiptBottomSheetStateProvider::class) state: ReadReceiptBottomSheetState) = ElementPreview { |
||||
// TODO restore RetrySendMessageMenuBottomSheet once the issue with bottom sheet not being previewable is fixed |
||||
Column { |
||||
ReadReceiptBottomSheetContents( |
||||
state = state |
||||
) |
||||
} |
||||
} |
Loading…
Reference in new issue