Merge remote-tracking branch 'origin/develop' into bma/brandColorFix
This commit is contained in:
commit
24fc74caf4
44 changed files with 159 additions and 267 deletions
|
|
@ -56,6 +56,7 @@ import io.element.android.features.ftue.api.state.FtueState
|
|||
import io.element.android.features.home.api.HomeEntryPoint
|
||||
import io.element.android.features.networkmonitor.api.NetworkMonitor
|
||||
import io.element.android.features.networkmonitor.api.NetworkStatus
|
||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
||||
import io.element.android.features.preferences.api.PreferencesEntryPoint
|
||||
import io.element.android.features.roomdirectory.api.RoomDescription
|
||||
import io.element.android.features.roomdirectory.api.RoomDirectoryEntryPoint
|
||||
|
|
@ -82,6 +83,7 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
|||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.core.toRoomIdOrAlias
|
||||
import io.element.android.libraries.matrix.api.permalink.PermalinkData
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationServiceListener
|
||||
import io.element.android.libraries.matrix.api.verification.VerificationRequest
|
||||
import io.element.android.libraries.preferences.api.store.AppPreferencesStore
|
||||
|
|
@ -128,6 +130,7 @@ class LoggedInFlowNode(
|
|||
private val sessionEnterpriseService: SessionEnterpriseService,
|
||||
private val networkMonitor: NetworkMonitor,
|
||||
private val notificationConversationService: NotificationConversationService,
|
||||
private val syncService: SyncService,
|
||||
private val enterpriseService: EnterpriseService,
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val buildMeta: BuildMeta,
|
||||
|
|
@ -556,11 +559,17 @@ class LoggedInFlowNode(
|
|||
compoundDark = colors.dark,
|
||||
buildMeta = buildMeta,
|
||||
) {
|
||||
Box(modifier = modifier) {
|
||||
val ftueState by ftueService.state.collectAsState()
|
||||
BackstackView()
|
||||
if (ftueState is FtueState.Complete) {
|
||||
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)
|
||||
val isOnline by syncService.isOnline.collectAsState()
|
||||
ConnectivityIndicatorContainer(
|
||||
isOnline = isOnline,
|
||||
modifier = modifier,
|
||||
) { contentModifier ->
|
||||
Box(modifier = contentModifier) {
|
||||
val ftueState by ftueService.state.collectAsState()
|
||||
BackstackView()
|
||||
if (ftueState is FtueState.Complete) {
|
||||
PermanentChild(permanentNavModel = permanentNavModel, navTarget = NavTarget.LoggedInPermanent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ package io.element.android.appnav.room
|
|||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
|
@ -48,7 +47,6 @@ import io.element.android.libraries.matrix.api.core.RoomIdOrAlias
|
|||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.alias.ResolvedRoomAlias
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.ui.room.LoadingRoomState
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.combine
|
||||
|
|
@ -71,7 +69,6 @@ class RoomFlowNode(
|
|||
private val client: MatrixClient,
|
||||
private val joinRoomEntryPoint: JoinRoomEntryPoint,
|
||||
private val roomAliasResolverEntryPoint: RoomAliasResolverEntryPoint,
|
||||
private val syncService: SyncService,
|
||||
private val membershipObserver: RoomMembershipObserver,
|
||||
private val spaceEntryPoint: SpaceEntryPoint,
|
||||
) : BaseFlowNode<RoomFlowNode.NavTarget>(
|
||||
|
|
@ -222,10 +219,8 @@ class RoomFlowNode(
|
|||
}
|
||||
|
||||
private fun loadingNode(buildContext: BuildContext) = node(buildContext) { modifier ->
|
||||
val isOnline by syncService.isOnline.collectAsState()
|
||||
LoadingRoomNodeView(
|
||||
state = LoadingRoomState.Loading,
|
||||
hasNetworkConnection = isOnline,
|
||||
onBackClick = { navigateUp() },
|
||||
modifier = modifier,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import io.element.android.libraries.architecture.createNode
|
|||
import io.element.android.libraries.architecture.inputs
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.ui.room.LoadingRoomState
|
||||
import io.element.android.libraries.matrix.ui.room.LoadingRoomStateFlowFactory
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
|
@ -50,7 +49,6 @@ class JoinedRoomFlowNode(
|
|||
@Assisted val buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
loadingRoomStateFlowFactory: LoadingRoomStateFlowFactory,
|
||||
private val syncService: SyncService,
|
||||
) :
|
||||
BaseFlowNode<JoinedRoomFlowNode.NavTarget>(
|
||||
backstack = BackStack(
|
||||
|
|
@ -116,12 +114,10 @@ class JoinedRoomFlowNode(
|
|||
|
||||
private fun loadingNode(buildContext: BuildContext, onBackClick: () -> Unit) = node(buildContext) { modifier ->
|
||||
val loadingRoomState by loadingRoomStateStateFlow.collectAsState()
|
||||
val isOnline by syncService.isOnline.collectAsState()
|
||||
LoadingRoomNodeView(
|
||||
state = loadingRoomState,
|
||||
hasNetworkConnection = isOnline,
|
||||
modifier = modifier,
|
||||
onBackClick = onBackClick
|
||||
onBackClick = onBackClick,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
package io.element.android.appnav.room.joined
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
|
|
@ -21,7 +19,6 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.IconTitlePlaceholdersRowMolecule
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||
|
|
@ -38,17 +35,13 @@ import io.element.android.libraries.ui.strings.CommonStrings
|
|||
@Composable
|
||||
fun LoadingRoomNodeView(
|
||||
state: LoadingRoomState,
|
||||
hasNetworkConnection: Boolean,
|
||||
onBackClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
Column {
|
||||
ConnectivityIndicatorView(isOnline = hasNetworkConnection)
|
||||
LoadingRoomTopBar(onBackClick)
|
||||
}
|
||||
LoadingRoomTopBar(onBackClick)
|
||||
},
|
||||
content = { padding ->
|
||||
Box(
|
||||
|
|
@ -85,7 +78,6 @@ private fun LoadingRoomTopBar(
|
|||
title = {
|
||||
IconTitlePlaceholdersRowMolecule(iconSize = AvatarSize.TimelineRoom.dp)
|
||||
},
|
||||
windowInsets = WindowInsets(0.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +86,6 @@ private fun LoadingRoomTopBar(
|
|||
internal fun LoadingRoomNodeViewPreview(@PreviewParameter(LoadingRoomStateProvider::class) state: LoadingRoomState) = ElementPreview {
|
||||
LoadingRoomNodeView(
|
||||
state = state,
|
||||
onBackClick = {},
|
||||
hasNetworkConnection = false
|
||||
onBackClick = {}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import androidx.compose.foundation.layout.calculateStartPadding
|
|||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
|
|
@ -50,7 +49,6 @@ import io.element.android.features.home.impl.roomlist.RoomListEvents
|
|||
import io.element.android.features.home.impl.roomlist.RoomListState
|
||||
import io.element.android.features.home.impl.search.RoomListSearchView
|
||||
import io.element.android.features.home.impl.spaces.HomeSpacesView
|
||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorContainer
|
||||
import io.element.android.libraries.androidutils.throttler.FirstThrottler
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
|
@ -84,56 +82,47 @@ fun HomeView(
|
|||
val state: RoomListState = homeState.roomListState
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val firstThrottler = remember { FirstThrottler(300, coroutineScope) }
|
||||
|
||||
ConnectivityIndicatorContainer(
|
||||
modifier = modifier,
|
||||
isOnline = homeState.hasNetworkConnection,
|
||||
) { topPadding ->
|
||||
Box {
|
||||
if (state.contextMenu is RoomListState.ContextMenu.Shown) {
|
||||
RoomListContextMenu(
|
||||
contextMenu = state.contextMenu,
|
||||
canReportRoom = state.canReportRoom,
|
||||
eventSink = state.eventSink,
|
||||
onRoomSettingsClick = onRoomSettingsClick,
|
||||
onReportRoomClick = onReportRoomClick,
|
||||
)
|
||||
}
|
||||
if (state.declineInviteMenu is RoomListState.DeclineInviteMenu.Shown) {
|
||||
RoomListDeclineInviteMenu(
|
||||
menu = state.declineInviteMenu,
|
||||
canReportRoom = state.canReportRoom,
|
||||
eventSink = state.eventSink,
|
||||
onDeclineAndBlockClick = onDeclineInviteAndBlockUser,
|
||||
)
|
||||
}
|
||||
|
||||
leaveRoomView()
|
||||
|
||||
HomeScaffold(
|
||||
state = homeState,
|
||||
onSetUpRecoveryClick = onSetUpRecoveryClick,
|
||||
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
|
||||
onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) },
|
||||
onOpenSettings = { if (firstThrottler.canHandle()) onSettingsClick() },
|
||||
onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() },
|
||||
onMenuActionClick = onMenuActionClick,
|
||||
modifier = Modifier.padding(top = topPadding),
|
||||
)
|
||||
// This overlaid view will only be visible when state.displaySearchResults is true
|
||||
RoomListSearchView(
|
||||
state = state.searchState,
|
||||
Box(modifier) {
|
||||
if (state.contextMenu is RoomListState.ContextMenu.Shown) {
|
||||
RoomListContextMenu(
|
||||
contextMenu = state.contextMenu,
|
||||
canReportRoom = state.canReportRoom,
|
||||
eventSink = state.eventSink,
|
||||
hideInvitesAvatars = state.hideInvitesAvatars,
|
||||
onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) },
|
||||
modifier = Modifier
|
||||
.statusBarsPadding()
|
||||
.padding(top = topPadding)
|
||||
.fillMaxSize()
|
||||
.background(ElementTheme.colors.bgCanvasDefault)
|
||||
onRoomSettingsClick = onRoomSettingsClick,
|
||||
onReportRoomClick = onReportRoomClick,
|
||||
)
|
||||
acceptDeclineInviteView()
|
||||
}
|
||||
if (state.declineInviteMenu is RoomListState.DeclineInviteMenu.Shown) {
|
||||
RoomListDeclineInviteMenu(
|
||||
menu = state.declineInviteMenu,
|
||||
canReportRoom = state.canReportRoom,
|
||||
eventSink = state.eventSink,
|
||||
onDeclineAndBlockClick = onDeclineInviteAndBlockUser,
|
||||
)
|
||||
}
|
||||
|
||||
leaveRoomView()
|
||||
|
||||
HomeScaffold(
|
||||
state = homeState,
|
||||
onSetUpRecoveryClick = onSetUpRecoveryClick,
|
||||
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
|
||||
onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) },
|
||||
onOpenSettings = { if (firstThrottler.canHandle()) onSettingsClick() },
|
||||
onStartChatClick = { if (firstThrottler.canHandle()) onStartChatClick() },
|
||||
onMenuActionClick = onMenuActionClick,
|
||||
)
|
||||
// This overlaid view will only be visible when state.displaySearchResults is true
|
||||
RoomListSearchView(
|
||||
state = state.searchState,
|
||||
eventSink = state.eventSink,
|
||||
hideInvitesAvatars = state.hideInvitesAvatars,
|
||||
onRoomClick = { if (firstThrottler.canHandle()) onRoomClick(it) },
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(ElementTheme.colors.bgCanvasDefault)
|
||||
)
|
||||
acceptDeclineInviteView()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import androidx.compose.foundation.lazy.items
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
|
|
@ -51,7 +50,6 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
|||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.designsystem.utils.copy
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
|
|
@ -157,7 +155,6 @@ private fun RoomListSearchContent(
|
|||
focusRequester.saveFocusedChild()
|
||||
}
|
||||
},
|
||||
windowInsets = TopAppBarDefaults.windowInsets.copy(top = 0)
|
||||
)
|
||||
}
|
||||
) { padding ->
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ import io.element.android.libraries.matrix.api.room.powerlevels.canPinUnpin
|
|||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOther
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canRedactOwn
|
||||
import io.element.android.libraries.matrix.api.room.powerlevels.canSendMessage
|
||||
import io.element.android.libraries.matrix.api.sync.SyncService
|
||||
import io.element.android.libraries.matrix.api.timeline.item.event.EventOrTransactionId
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.map
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
|
|
@ -112,7 +111,6 @@ class MessagesPresenter(
|
|||
private val pinnedMessagesBannerPresenter: Presenter<PinnedMessagesBannerState>,
|
||||
private val roomCallStatePresenter: Presenter<RoomCallState>,
|
||||
private val roomMemberModerationPresenter: Presenter<RoomMemberModerationState>,
|
||||
private val syncService: SyncService,
|
||||
private val snackbarDispatcher: SnackbarDispatcher,
|
||||
private val dispatchers: CoroutineDispatchers,
|
||||
private val clipboardHelper: ClipboardHelper,
|
||||
|
|
@ -193,7 +191,6 @@ class MessagesPresenter(
|
|||
showReinvitePrompt = !hasDismissedInviteDialog && composerHasFocus && roomInfo.isDm && roomInfo.activeMembersCount == 1L
|
||||
}
|
||||
}
|
||||
val isOnline by syncService.isOnline.collectAsState()
|
||||
|
||||
val snackbarMessage by snackbarDispatcher.collectSnackbarMessageAsState()
|
||||
|
||||
|
|
@ -250,8 +247,8 @@ class MessagesPresenter(
|
|||
roomName = roomInfo.name,
|
||||
roomAvatar = roomAvatar,
|
||||
heroes = heroes,
|
||||
composerState = composerState,
|
||||
userEventPermissions = userEventPermissions,
|
||||
composerState = composerState,
|
||||
voiceMessageComposerState = voiceMessageComposerState,
|
||||
timelineState = timelineState,
|
||||
timelineProtectionState = timelineProtectionState,
|
||||
|
|
@ -261,19 +258,17 @@ class MessagesPresenter(
|
|||
customReactionState = customReactionState,
|
||||
reactionSummaryState = reactionSummaryState,
|
||||
readReceiptBottomSheetState = readReceiptBottomSheetState,
|
||||
hasNetworkConnection = isOnline,
|
||||
snackbarMessage = snackbarMessage,
|
||||
showReinvitePrompt = showReinvitePrompt,
|
||||
inviteProgress = inviteProgress.value,
|
||||
showReinvitePrompt = showReinvitePrompt,
|
||||
enableTextFormatting = MessageComposerConfig.ENABLE_RICH_TEXT_EDITING,
|
||||
appName = buildMeta.applicationName,
|
||||
roomCallState = roomCallState,
|
||||
appName = buildMeta.applicationName,
|
||||
pinnedMessagesBannerState = pinnedMessagesBannerState,
|
||||
dmUserVerificationState = dmUserVerificationState,
|
||||
roomMemberModerationState = roomMemberModerationState,
|
||||
successorRoom = roomInfo.successorRoom,
|
||||
eventSink = { handleEvents(it) }
|
||||
)
|
||||
successorRoom = roomInfo.successorRoom
|
||||
) { handleEvents(it) }
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ data class MessagesState(
|
|||
val customReactionState: CustomReactionState,
|
||||
val reactionSummaryState: ReactionSummaryState,
|
||||
val readReceiptBottomSheetState: ReadReceiptBottomSheetState,
|
||||
val hasNetworkConnection: Boolean,
|
||||
val snackbarMessage: SnackbarMessage?,
|
||||
val inviteProgress: AsyncData<Unit>,
|
||||
val showReinvitePrompt: Boolean,
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ open class MessagesStateProvider : PreviewParameterProvider<MessagesState> {
|
|||
override val values: Sequence<MessagesState>
|
||||
get() = sequenceOf(
|
||||
aMessagesState(),
|
||||
aMessagesState(hasNetworkConnection = false),
|
||||
aMessagesState(composerState = aMessageComposerState(showAttachmentSourcePicker = true)),
|
||||
aMessagesState(userEventPermissions = aUserEventPermissions(canSendMessage = false)),
|
||||
aMessagesState(showReinvitePrompt = true),
|
||||
|
|
@ -108,7 +107,6 @@ fun aMessagesState(
|
|||
actionListState: ActionListState = anActionListState(),
|
||||
customReactionState: CustomReactionState = aCustomReactionState(),
|
||||
reactionSummaryState: ReactionSummaryState = aReactionSummaryState(),
|
||||
hasNetworkConnection: Boolean = true,
|
||||
showReinvitePrompt: Boolean = false,
|
||||
roomCallState: RoomCallState = aStandByCallState(),
|
||||
pinnedMessagesBannerState: PinnedMessagesBannerState = aLoadedPinnedMessagesBannerState(),
|
||||
|
|
@ -132,7 +130,6 @@ fun aMessagesState(
|
|||
actionListState = actionListState,
|
||||
customReactionState = customReactionState,
|
||||
reactionSummaryState = reactionSummaryState,
|
||||
hasNetworkConnection = hasNetworkConnection,
|
||||
snackbarMessage = null,
|
||||
inviteProgress = AsyncData.Uninitialized,
|
||||
showReinvitePrompt = showReinvitePrompt,
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ import io.element.android.features.messages.impl.topbars.MessagesViewTopBar
|
|||
import io.element.android.features.messages.impl.topbars.ThreadTopBar
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessagePermissionRationaleDialog
|
||||
import io.element.android.features.messages.impl.voicemessages.composer.VoiceMessageSendingFailedDialog
|
||||
import io.element.android.features.networkmonitor.api.ui.ConnectivityIndicatorView
|
||||
import io.element.android.libraries.androidutils.ui.hideKeyboard
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.ComposerAlertMolecule
|
||||
import io.element.android.libraries.designsystem.components.ExpandableBottomSheetLayout
|
||||
|
|
@ -84,6 +83,7 @@ import io.element.android.libraries.designsystem.text.toAnnotatedString
|
|||
import io.element.android.libraries.designsystem.theme.components.BottomSheetDragHandle
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.HideKeyboardWhenDisposed
|
||||
import io.element.android.libraries.designsystem.utils.KeepScreenOn
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
||||
|
|
@ -123,6 +123,8 @@ fun MessagesView(
|
|||
|
||||
KeepScreenOn(state.voiceMessageComposerState.keepScreenOn)
|
||||
|
||||
HideKeyboardWhenDisposed()
|
||||
|
||||
val snackbarHostState = rememberSnackbarHostState(snackbarMessage = state.snackbarMessage)
|
||||
|
||||
// This is needed because the composer is inside an AndroidView that can't be affected by the FocusManager in Compose
|
||||
|
|
@ -180,8 +182,6 @@ fun MessagesView(
|
|||
Scaffold(
|
||||
contentWindowInsets = WindowInsets.statusBars,
|
||||
topBar = {
|
||||
Column {
|
||||
ConnectivityIndicatorView(isOnline = state.hasNetworkConnection)
|
||||
if (state.timelineState.timelineMode is Timeline.Mode.Thread) {
|
||||
ThreadTopBar(
|
||||
roomName = state.roomName,
|
||||
|
|
@ -203,7 +203,6 @@ fun MessagesView(
|
|||
onJoinCallClick = onJoinCallClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
content = { padding ->
|
||||
Box(
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ import io.element.android.libraries.matrix.test.room.FakeBaseRoom
|
|||
import io.element.android.libraries.matrix.test.room.FakeJoinedRoom
|
||||
import io.element.android.libraries.matrix.test.room.aRoomInfo
|
||||
import io.element.android.libraries.matrix.test.room.aRoomMember
|
||||
import io.element.android.libraries.matrix.test.sync.FakeSyncService
|
||||
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
|
||||
import io.element.android.libraries.matrix.test.timeline.aTimelineItemDebugInfo
|
||||
import io.element.android.libraries.matrix.ui.messages.reply.InReplyToDetails
|
||||
|
|
@ -130,7 +129,6 @@ class MessagesPresenterTest {
|
|||
.isEqualTo(AvatarData(id = A_ROOM_ID.value, name = "", url = AN_AVATAR_URL, size = AvatarSize.TimelineRoom))
|
||||
assertThat(initialState.userEventPermissions.canSendMessage).isTrue()
|
||||
assertThat(initialState.userEventPermissions.canRedactOwn).isTrue()
|
||||
assertThat(initialState.hasNetworkConnection).isTrue()
|
||||
assertThat(initialState.snackbarMessage).isNull()
|
||||
assertThat(initialState.inviteProgress).isEqualTo(AsyncData.Uninitialized)
|
||||
assertThat(initialState.showReinvitePrompt).isFalse()
|
||||
|
|
@ -1274,31 +1272,30 @@ class MessagesPresenterTest {
|
|||
addRecentEmoji: AddRecentEmoji = AddRecentEmoji(FakeMatrixClient(), testCoroutineDispatchers()),
|
||||
): MessagesPresenter {
|
||||
return MessagesPresenter(
|
||||
navigator = navigator,
|
||||
room = joinedRoom,
|
||||
composerPresenter = messageComposerPresenter,
|
||||
voiceMessageComposerPresenterFactory = FakeDefaultVoiceMessageComposerPresenterFactory(backgroundScope),
|
||||
timelinePresenter = { aTimelineState(eventSink = timelineEventSink) },
|
||||
timelineProtectionPresenter = { aTimelineProtectionState() },
|
||||
identityChangeStatePresenter = { anIdentityChangeState() },
|
||||
linkPresenter = { aLinkState() },
|
||||
actionListPresenter = { anActionListState(eventSink = actionListEventSink) },
|
||||
customReactionPresenter = { aCustomReactionState() },
|
||||
reactionSummaryPresenter = { aReactionSummaryState() },
|
||||
readReceiptBottomSheetPresenter = { aReadReceiptBottomSheetState() },
|
||||
identityChangeStatePresenter = { anIdentityChangeState() },
|
||||
linkPresenter = { aLinkState() },
|
||||
pinnedMessagesBannerPresenter = { aLoadedPinnedMessagesBannerState() },
|
||||
roomCallStatePresenter = { aStandByCallState() },
|
||||
roomMemberModerationPresenter = roomMemberModerationPresenter,
|
||||
syncService = FakeSyncService(),
|
||||
snackbarDispatcher = SnackbarDispatcher(),
|
||||
navigator = navigator,
|
||||
clipboardHelper = clipboardHelper,
|
||||
buildMeta = aBuildMeta(),
|
||||
dispatchers = coroutineDispatchers,
|
||||
clipboardHelper = clipboardHelper,
|
||||
htmlConverterProvider = FakeHtmlConverterProvider(),
|
||||
buildMeta = aBuildMeta(),
|
||||
timelineController = TimelineController(joinedRoom, timeline),
|
||||
permalinkParser = permalinkParser,
|
||||
encryptionService = encryptionService,
|
||||
analyticsService = analyticsService,
|
||||
encryptionService = encryptionService,
|
||||
featureFlagService = featureFlagService,
|
||||
addRecentEmoji = addRecentEmoji,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
|
|
@ -32,7 +33,8 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
|||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@Composable
|
||||
internal fun Indicator(
|
||||
internal fun ConnectivityIndicator(
|
||||
verticalPadding: Dp,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
|
|
@ -40,7 +42,7 @@ internal fun Indicator(
|
|||
.fillMaxWidth()
|
||||
.background(ElementTheme.colors.bgSubtlePrimary)
|
||||
.statusBarsPadding()
|
||||
.padding(vertical = 6.dp),
|
||||
.padding(vertical = verticalPadding),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
|
|
@ -61,6 +63,6 @@ internal fun Indicator(
|
|||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun IndicatorPreview() = ElementPreview {
|
||||
Indicator()
|
||||
internal fun ConnectivityIndicatorPreview() = ElementPreview {
|
||||
ConnectivityIndicator(verticalPadding = 6.dp)
|
||||
}
|
||||
|
|
@ -16,55 +16,58 @@ import androidx.compose.animation.expandVertically
|
|||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
private val INDICATOR_VERTICAL_PADDING = 6.dp
|
||||
|
||||
/**
|
||||
* A view that displays a connectivity indicator when the device is offline, passing the padding
|
||||
* needed to make sure the status bar is not overlapped to its content views.
|
||||
* A view that displays a connectivity indicator when the device is offline.
|
||||
*/
|
||||
@Composable
|
||||
fun ConnectivityIndicatorContainer(
|
||||
isOnline: Boolean,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable (topPadding: Dp) -> Unit = {},
|
||||
content: @Composable (Modifier) -> Unit = {},
|
||||
) {
|
||||
val isIndicatorVisible = remember { MutableTransitionState(!isOnline) }.apply { targetState = !isOnline }
|
||||
|
||||
val statusBarTopPadding = if (LocalInspectionMode.current) {
|
||||
// Needed to get valid UI previews
|
||||
24.dp
|
||||
} else {
|
||||
WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + 6.dp
|
||||
}
|
||||
val target = remember(isIndicatorVisible.targetState, statusBarTopPadding) {
|
||||
if (!isIndicatorVisible.targetState) 0.dp else statusBarTopPadding
|
||||
}
|
||||
val animationStateOffset by animateDpAsState(
|
||||
targetValue = target,
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessMediumLow,
|
||||
visibilityThreshold = 1.dp,
|
||||
),
|
||||
label = "insets-animation",
|
||||
)
|
||||
|
||||
content(animationStateOffset)
|
||||
|
||||
// Display the network indicator with an animation
|
||||
AnimatedVisibility(
|
||||
visibleState = isIndicatorVisible,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
Indicator(modifier)
|
||||
Column(modifier = modifier) {
|
||||
val statusBarTopPadding = if (LocalInspectionMode.current) {
|
||||
// Needed to get valid UI previews
|
||||
24.dp
|
||||
} else {
|
||||
WindowInsets.statusBars.asPaddingValues().calculateTopPadding() + INDICATOR_VERTICAL_PADDING
|
||||
}
|
||||
val target = if (isIndicatorVisible.targetState) statusBarTopPadding else 0.dp
|
||||
val topWindowInset by animateDpAsState(
|
||||
targetValue = target,
|
||||
animationSpec = spring(
|
||||
stiffness = Spring.StiffnessMediumLow,
|
||||
visibilityThreshold = 1.dp,
|
||||
),
|
||||
label = "insets-animation",
|
||||
)
|
||||
// Display the network indicator with an animation
|
||||
AnimatedVisibility(
|
||||
visibleState = isIndicatorVisible,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
ConnectivityIndicator(verticalPadding = INDICATOR_VERTICAL_PADDING)
|
||||
}
|
||||
// Consume the window insets to avoid double padding.
|
||||
content(
|
||||
Modifier.consumeWindowInsets(PaddingValues(top = topWindowInset))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright 2023, 2024 New Vector Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.features.networkmonitor.api.ui
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.MutableTransitionState
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
||||
/**
|
||||
* A view that displays a connectivity indicator when the device is offline, adding a default
|
||||
* padding to make sure the status bar is not overlapped.
|
||||
*/
|
||||
@Composable
|
||||
fun ConnectivityIndicatorView(
|
||||
isOnline: Boolean,
|
||||
) {
|
||||
val isIndicatorVisible = remember { MutableTransitionState(!isOnline) }.apply { targetState = !isOnline }
|
||||
val isStatusBarPaddingVisible = remember { MutableTransitionState(isOnline) }.apply { targetState = isOnline }
|
||||
|
||||
// Display the network indicator with an animation
|
||||
AnimatedVisibility(
|
||||
visibleState = isIndicatorVisible,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
Indicator()
|
||||
}
|
||||
|
||||
// Show missing status bar padding when the indicator is not visible
|
||||
AnimatedVisibility(
|
||||
visibleState = isStatusBarPaddingVisible,
|
||||
enter = fadeIn() + expandVertically(),
|
||||
exit = fadeOut() + shrinkVertically(),
|
||||
) {
|
||||
StatusBarPaddingSpacer()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatusBarPaddingSpacer(modifier: Modifier = Modifier) {
|
||||
Spacer(modifier = modifier.statusBarsPadding())
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun ConnectivityIndicatorViewPreview() {
|
||||
ElementPreview {
|
||||
ConnectivityIndicatorView(isOnline = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:513b6de9643106b0c021a60a2791e6227ce81ff1089338a5d3de8ba525e353ab
|
||||
size 8389
|
||||
oid sha256:c9583a29e680bee98819258e5b7356dd8677144957d5869da72c47685d986e87
|
||||
size 6494
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7aebe39a70a79e025d392ffb6c97793c828cc29acf7700461399e6cbea0d27a3
|
||||
size 10512
|
||||
oid sha256:f5c19a8b26c9187c9bfd630242b15370ec8f0b874f9d3913ce53c743c0e0bdcd
|
||||
size 8574
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:89bd61aa2d74f720a2b1d73fa5379e712fc61e423cbcbfab83cb291bdbd75766
|
||||
size 8013
|
||||
oid sha256:74ad11143fc70164f67a8326cb87ce90a2c8730317540810ea138e39fc9093fa
|
||||
size 6306
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:831058152c5c6e691afecab498ae07f4b35f7b75438a4efa1841cc04922bb7be
|
||||
size 10037
|
||||
oid sha256:bde612ade7298aeef44bbc480ee9d742ccb8c94108e21dcae9e804c744032a08
|
||||
size 8308
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bc9668d1caef19e9a4fe76ff4ed0eab8107aa493c3adcaef7ebbbb878925ac62
|
||||
size 66408
|
||||
oid sha256:6a249702f230f3dc0c9ee097fc11496df64c11436680e3f790d1fbf9051c4119
|
||||
size 65098
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5bfc8aff1305c39b400c95831a6b07f00c376c328b3ad2281cf4b6b74970f67c
|
||||
size 61538
|
||||
oid sha256:ea48147772f8fa99aca0345a5a98f8d2ea6fd26793edab55f7d920a7e3f56414
|
||||
size 60213
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:67981be91a4736680a69b9d2dfe11cab3a69e0d375cf2589e38bed3630b9fc12
|
||||
size 53199
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4dd9bacf4f467ac0f2b1050fcf5a4246e520674009471c05d2e32eb5d1d1f7bf
|
||||
size 57599
|
||||
oid sha256:3917d9d2d5c67e840e613cc8dfc39212e11853ac8710e87af554e20dea31d34d
|
||||
size 39439
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3917d9d2d5c67e840e613cc8dfc39212e11853ac8710e87af554e20dea31d34d
|
||||
size 39439
|
||||
oid sha256:432fae13ece80f287afc16411ca162c2ea0b19d66b148adcb13c7710ac442b5d
|
||||
size 60866
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:432fae13ece80f287afc16411ca162c2ea0b19d66b148adcb13c7710ac442b5d
|
||||
size 60866
|
||||
oid sha256:cc380e2b1c75c5b38ac410a271ddb9c02d41ebf9ff037fc59f20d23d87241590
|
||||
size 56864
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:cc380e2b1c75c5b38ac410a271ddb9c02d41ebf9ff037fc59f20d23d87241590
|
||||
size 56864
|
||||
oid sha256:0cb2168ef240a788416f0f7d5cf949b282b9c4cf76338c4d547562b15ff3dba1
|
||||
size 55322
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0cb2168ef240a788416f0f7d5cf949b282b9c4cf76338c4d547562b15ff3dba1
|
||||
size 55322
|
||||
oid sha256:17ec77b5053bff9057d6b122140f53c5384abac7998bbc8d770db95a04bc0062
|
||||
size 59963
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:17ec77b5053bff9057d6b122140f53c5384abac7998bbc8d770db95a04bc0062
|
||||
size 59963
|
||||
oid sha256:ac595ce33affb3eec6c465fd68ab1fa57eb942f58944cc16e5e01892a21ba4a7
|
||||
size 50323
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ac595ce33affb3eec6c465fd68ab1fa57eb942f58944cc16e5e01892a21ba4a7
|
||||
size 50323
|
||||
oid sha256:2831b5841aac7cdec50829002aa46fabf530163e0600185f32da0793c3637fb5
|
||||
size 61695
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2831b5841aac7cdec50829002aa46fabf530163e0600185f32da0793c3637fb5
|
||||
size 61695
|
||||
oid sha256:ac8dd9bc435999370adc7b3d4a0eb96c7eeedcb500818b44e05aafe759b720ba
|
||||
size 63860
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ac8dd9bc435999370adc7b3d4a0eb96c7eeedcb500818b44e05aafe759b720ba
|
||||
size 63860
|
||||
oid sha256:67981be91a4736680a69b9d2dfe11cab3a69e0d375cf2589e38bed3630b9fc12
|
||||
size 53199
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7fb56dba32bfc9db1ddf201d118c580b21143f1f74575bda95ff43fa0914b2a3
|
||||
size 52344
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3e64f40aac075bd075f92cf98ffa864ced12b3a43a874d72cd5f293202859623
|
||||
size 55090
|
||||
oid sha256:beb8fc32a4b048ba5c5053ad5d62da55aac8072234af59a2a1af6dd3b03be74c
|
||||
size 37401
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:beb8fc32a4b048ba5c5053ad5d62da55aac8072234af59a2a1af6dd3b03be74c
|
||||
size 37401
|
||||
oid sha256:d654cda7c0f4df547ccf00fc3a8121d0c5bd2b337be17b71f7b95e5987833032
|
||||
size 58473
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d654cda7c0f4df547ccf00fc3a8121d0c5bd2b337be17b71f7b95e5987833032
|
||||
size 58473
|
||||
oid sha256:794ef2d62ae364d456930dc7879741848c8f65696a5b7676b032da70e3ef7330
|
||||
size 51156
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:794ef2d62ae364d456930dc7879741848c8f65696a5b7676b032da70e3ef7330
|
||||
size 51156
|
||||
oid sha256:96bdb7695db3a0476480e4e675dfc5d088d210b519a3f6b9592bbe6ec18f4ec6
|
||||
size 52985
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96bdb7695db3a0476480e4e675dfc5d088d210b519a3f6b9592bbe6ec18f4ec6
|
||||
size 52985
|
||||
oid sha256:e12bc7c029daee03dc31bc889c37ebbd597ac61bf18bf13867a867983a79bb2b
|
||||
size 54085
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e12bc7c029daee03dc31bc889c37ebbd597ac61bf18bf13867a867983a79bb2b
|
||||
size 54085
|
||||
oid sha256:72023d9b9eaade788d33ef6c123a89edc079c4cc543421c256676b75fba6adc1
|
||||
size 44505
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:72023d9b9eaade788d33ef6c123a89edc079c4cc543421c256676b75fba6adc1
|
||||
size 44505
|
||||
oid sha256:1ad3ae1b79bf30293e306ebac5806d328569f03b1370adb39c6dec143d8789c1
|
||||
size 59027
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1ad3ae1b79bf30293e306ebac5806d328569f03b1370adb39c6dec143d8789c1
|
||||
size 59027
|
||||
oid sha256:83a7cce4a92980220d2afd24d895154d1a463e685c9f81ee91707ae78c12809d
|
||||
size 64594
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:83a7cce4a92980220d2afd24d895154d1a463e685c9f81ee91707ae78c12809d
|
||||
size 64594
|
||||
oid sha256:7fb56dba32bfc9db1ddf201d118c580b21143f1f74575bda95ff43fa0914b2a3
|
||||
size 52344
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7d7cbce14d66654ba69cd6a154eefecebacf1556f29c5ccefb1d6f1975270814
|
||||
size 5427
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:14927029a06e7f4f5346573d5020fa7582ff716dd552db969bb84304a879d4f0
|
||||
size 5384
|
||||
Loading…
Add table
Add a link
Reference in a new issue