+24
@@ -103,6 +103,30 @@ fun aPdfMediaInfo(
|
||||
duration = null,
|
||||
)
|
||||
|
||||
fun aZipMediaInfo(
|
||||
filename: String = "a zip file.zip",
|
||||
caption: String? = null,
|
||||
formattedCaption: CharSequence? = null,
|
||||
senderName: String? = null,
|
||||
dateSent: String? = null,
|
||||
dateSentFull: String? = null,
|
||||
): MediaInfo = MediaInfo(
|
||||
filename = filename,
|
||||
fileSize = 12 * 1024 * 1024,
|
||||
caption = caption,
|
||||
formattedCaption = formattedCaption,
|
||||
mimeType = MimeTypes.Pdf,
|
||||
formattedFileSize = "45MB",
|
||||
fileExtension = "zip",
|
||||
senderId = UserId("@alice:server.org"),
|
||||
senderName = senderName,
|
||||
senderAvatar = null,
|
||||
dateSent = dateSent,
|
||||
dateSentFull = dateSentFull,
|
||||
waveform = null,
|
||||
duration = null,
|
||||
)
|
||||
|
||||
fun anApkMediaInfo(
|
||||
senderId: UserId? = UserId("@alice:server.org"),
|
||||
senderName: String? = null,
|
||||
|
||||
+1
@@ -41,6 +41,7 @@ class DefaultLocalMediaRenderer(
|
||||
textFileViewer = textFileViewer,
|
||||
audioFocus = audioFocus,
|
||||
onClick = {},
|
||||
onOpenWith = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -31,6 +31,7 @@ fun LocalMediaView(
|
||||
bottomPaddingInPixels: Int,
|
||||
audioFocus: AudioFocus?,
|
||||
onClick: () -> Unit,
|
||||
onOpenWith: (() -> Unit)?,
|
||||
textFileViewer: TextFileViewer,
|
||||
modifier: Modifier = Modifier,
|
||||
isDisplayed: Boolean = true,
|
||||
@@ -80,7 +81,7 @@ fun LocalMediaView(
|
||||
uri = localMedia?.uri,
|
||||
info = mediaInfo,
|
||||
modifier = modifier,
|
||||
onClick = onClick,
|
||||
onOpenWith = onOpenWith,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+40
-34
@@ -9,23 +9,16 @@
|
||||
package io.element.android.libraries.mediaviewer.impl.local.file
|
||||
|
||||
import android.net.Uri
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
@@ -33,55 +26,54 @@ import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes
|
||||
import io.element.android.libraries.core.mimetype.MimeTypes.isMimeTypeAudio
|
||||
import io.element.android.libraries.designsystem.components.BigIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.ButtonSize
|
||||
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.helper.formatFileExtensionAndSize
|
||||
import io.element.android.libraries.mediaviewer.impl.R
|
||||
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaViewState
|
||||
import io.element.android.libraries.mediaviewer.impl.local.rememberLocalMediaViewState
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=3361-16623
|
||||
*/
|
||||
@Composable
|
||||
fun MediaFileView(
|
||||
localMediaViewState: LocalMediaViewState,
|
||||
uri: Uri?,
|
||||
info: MediaInfo?,
|
||||
onClick: () -> Unit,
|
||||
onOpenWith: (() -> Unit)?,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val isAudio = info?.mimeType.isMimeTypeAudio().orFalse()
|
||||
localMediaViewState.isReady = uri != null
|
||||
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
Box(
|
||||
modifier = modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
.clickable(
|
||||
onClick = onClick,
|
||||
interactionSource = interactionSource,
|
||||
indication = null
|
||||
),
|
||||
.padding(horizontal = 8.dp),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(72.dp)
|
||||
.clip(CircleShape)
|
||||
.background(ElementTheme.colors.iconPrimary),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (isAudio) CompoundIcons.Audio() else CompoundIcons.Attachment(),
|
||||
contentDescription = null,
|
||||
tint = ElementTheme.colors.iconOnSolidPrimary,
|
||||
modifier = Modifier
|
||||
.size(32.dp)
|
||||
.rotate(if (isAudio) 0f else -45f),
|
||||
)
|
||||
val isApk = info?.mimeType == MimeTypes.Apk
|
||||
val icon = when {
|
||||
isAudio -> CompoundIcons.Audio()
|
||||
isApk -> CompoundIcons.Bug()
|
||||
else -> CompoundIcons.Files()
|
||||
}
|
||||
BigIcon(
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
style = BigIcon.Style.Default(
|
||||
vectorIcon = icon,
|
||||
usePrimaryTint = true,
|
||||
),
|
||||
)
|
||||
if (info != null) {
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(
|
||||
@@ -100,6 +92,20 @@ fun MediaFileView(
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
color = ElementTheme.colors.textPrimary
|
||||
)
|
||||
if (onOpenWith != null) {
|
||||
val (icon, textResId) = if (isApk) {
|
||||
IconSource.Resource(R.drawable.ic_apk_install) to CommonStrings.common_install_apk_android
|
||||
} else {
|
||||
IconSource.Vector(CompoundIcons.PopOut()) to CommonStrings.action_open_with
|
||||
}
|
||||
OutlinedButton(
|
||||
modifier = Modifier.padding(top = 24.dp),
|
||||
size = ButtonSize.Small,
|
||||
leadingIcon = icon,
|
||||
onClick = onOpenWith,
|
||||
text = stringResource(id = textResId),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +121,6 @@ internal fun MediaFileViewPreview(
|
||||
localMediaViewState = rememberLocalMediaViewState(),
|
||||
uri = null,
|
||||
info = info,
|
||||
onClick = {},
|
||||
onOpenWith = {},
|
||||
)
|
||||
}
|
||||
|
||||
+6
-2
@@ -10,11 +10,15 @@ package io.element.android.libraries.mediaviewer.impl.local.file
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.aPdfMediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.aZipMediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
||||
import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo
|
||||
|
||||
open class MediaInfoFileProvider : PreviewParameterProvider<MediaInfo> {
|
||||
override val values: Sequence<MediaInfo>
|
||||
get() = sequenceOf(
|
||||
aPdfMediaInfo(),
|
||||
aZipMediaInfo(),
|
||||
anAudioMediaInfo(),
|
||||
anApkMediaInfo(),
|
||||
)
|
||||
}
|
||||
|
||||
+5
@@ -239,6 +239,9 @@ fun MediaViewerView(
|
||||
onRetry = {
|
||||
state.eventSink(MediaViewerEvent.LoadMedia(dataForPage))
|
||||
},
|
||||
onOpenWith = {
|
||||
state.eventSink(MediaViewerEvent.OpenWith(dataForPage))
|
||||
},
|
||||
onDismissError = {
|
||||
state.eventSink(MediaViewerEvent.ClearLoadingError(dataForPage))
|
||||
},
|
||||
@@ -333,6 +336,7 @@ private fun MediaViewerPage(
|
||||
isUserSelected: Boolean,
|
||||
onDismiss: () -> Unit,
|
||||
onRetry: () -> Unit,
|
||||
onOpenWith: () -> Unit,
|
||||
onDismissError: () -> Unit,
|
||||
onShowOverlayChange: (Boolean) -> Unit,
|
||||
audioFocus: AudioFocus?,
|
||||
@@ -387,6 +391,7 @@ private fun MediaViewerPage(
|
||||
currentOnShowOverlayChange(!currentShowOverlay)
|
||||
}
|
||||
},
|
||||
onOpenWith = onOpenWith,
|
||||
isUserSelected = isUserSelected,
|
||||
audioFocus = audioFocus,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user