First Commit

This commit is contained in:
2025-12-18 16:28:50 +07:00
commit 8c3e4f491f
9974 changed files with 396488 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.
*/
plugins {
id("io.element.android-compose-library")
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.libraries.mediaviewer.api"
}
dependencies {
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 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.libraries.mediaviewer.api
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
import io.element.android.libraries.matrix.api.core.EventId
interface MediaGalleryEntryPoint : FeatureEntryPoint {
fun createNode(
parentNode: Node,
buildContext: BuildContext,
callback: Callback,
): Node
interface Callback : Plugin {
fun onBackClick()
fun viewInTimeline(eventId: EventId)
fun forward(eventId: EventId, fromPinnedEvents: Boolean)
}
}

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 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.libraries.mediaviewer.api
import android.os.Parcelable
import io.element.android.libraries.core.mimetype.MimeTypes
import io.element.android.libraries.matrix.api.core.UserId
import kotlinx.parcelize.Parcelize
@Parcelize
data class MediaInfo(
val filename: String,
val caption: String?,
val mimeType: String,
val fileSize: Long?,
val formattedFileSize: String,
val fileExtension: String,
val senderId: UserId?,
val senderName: String?,
val senderAvatar: String?,
val dateSent: String?,
val dateSentFull: String?,
val waveform: List<Float>?,
val duration: String?,
) : Parcelable
fun anImageMediaInfo(
senderId: UserId? = UserId("@alice:server.org"),
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
): MediaInfo = MediaInfo(
filename = "an image file.jpg",
fileSize = 4 * 1024 * 1024,
caption = caption,
mimeType = MimeTypes.Jpeg,
formattedFileSize = "4MB",
fileExtension = "jpg",
senderId = senderId,
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = null,
duration = null,
)
fun aVideoMediaInfo(
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
duration: String? = null,
): MediaInfo = MediaInfo(
filename = "a video file.mp4",
fileSize = 14 * 1024 * 1024,
caption = caption,
mimeType = MimeTypes.Mp4,
formattedFileSize = "14MB",
fileExtension = "mp4",
senderId = UserId("@alice:server.org"),
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = null,
duration = duration,
)
fun aPdfMediaInfo(
filename: String = "a pdf file.pdf",
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
): MediaInfo = MediaInfo(
filename = filename,
fileSize = 23 * 1024 * 1024,
caption = caption,
mimeType = MimeTypes.Pdf,
formattedFileSize = "23MB",
fileExtension = "pdf",
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,
dateSent: String? = null,
dateSentFull: String? = null,
): MediaInfo = MediaInfo(
filename = "an apk file.apk",
fileSize = 50 * 1024 * 1024,
caption = null,
mimeType = MimeTypes.Apk,
formattedFileSize = "50MB",
fileExtension = "apk",
senderId = senderId,
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = null,
duration = null,
)
fun anAudioMediaInfo(
filename: String = "an audio file.mp3",
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
waveForm: List<Float>? = null,
duration: String? = null,
): MediaInfo = MediaInfo(
filename = filename,
fileSize = 7 * 1024 * 1024,
caption = caption,
mimeType = MimeTypes.Mp3,
formattedFileSize = "7MB",
fileExtension = "mp3",
senderId = UserId("@alice:server.org"),
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = waveForm,
duration = duration,
)
fun aVoiceMediaInfo(
filename: String = "a voice file.ogg",
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
waveForm: List<Float>? = null,
duration: String? = null,
): MediaInfo = MediaInfo(
filename = filename,
fileSize = 3 * 1024 * 1024,
caption = caption,
mimeType = MimeTypes.Ogg,
formattedFileSize = "3MB",
fileExtension = "ogg",
senderId = UserId("@alice:server.org"),
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = waveForm,
duration = duration,
)
fun aTxtMediaInfo(
filename: String = "a text file.txt",
caption: String? = null,
senderName: String? = null,
dateSent: String? = null,
dateSentFull: String? = null,
): MediaInfo = MediaInfo(
filename = filename,
fileSize = 2 * 1024,
caption = caption,
mimeType = MimeTypes.PlainText,
formattedFileSize = "2kB",
fileExtension = "txt",
senderId = UserId("@alice:server.org"),
senderName = senderName,
senderAvatar = null,
dateSent = dateSent,
dateSentFull = dateSentFull,
waveform = null,
duration = null,
)

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 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.libraries.mediaviewer.api
import android.os.Parcelable
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.timeline.Timeline
import kotlinx.parcelize.Parcelize
interface MediaViewerEntryPoint : FeatureEntryPoint {
fun createNode(
parentNode: Node,
buildContext: BuildContext,
params: Params,
callback: Callback,
): Node
fun createParamsForAvatar(filename: String, avatarUrl: String): Params
interface Callback : Plugin {
fun onDone()
fun viewInTimeline(eventId: EventId)
fun forwardEvent(eventId: EventId, fromPinnedEvents: Boolean)
}
data class Params(
val mode: MediaViewerMode,
val eventId: EventId?,
val mediaInfo: MediaInfo,
val mediaSource: MediaSource,
val thumbnailSource: MediaSource?,
val canShowInfo: Boolean,
) : NodeInputs
sealed interface MediaViewerMode : Parcelable {
@Parcelize
data object SingleMedia : MediaViewerMode
@Parcelize
data class TimelineImagesAndVideos(val timelineMode: Timeline.Mode) : MediaViewerMode
@Parcelize
data class TimelineFilesAndAudios(val timelineMode: Timeline.Mode) : MediaViewerMode
}
}

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.libraries.mediaviewer.api.helper
fun formatFileExtensionAndSize(extension: String, size: String?): String {
return buildString {
append(extension.uppercase())
if (size != null) {
append(' ')
append("($size)")
}
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.libraries.mediaviewer.api.local
import android.net.Uri
import android.os.Parcelable
import androidx.compose.runtime.Immutable
import io.element.android.libraries.mediaviewer.api.MediaInfo
import kotlinx.parcelize.Parcelize
@Parcelize
@Immutable
data class LocalMedia(
val uri: Uri,
val info: MediaInfo,
) : Parcelable

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.libraries.mediaviewer.api.local
import android.net.Uri
import io.element.android.libraries.matrix.api.media.MediaFile
import io.element.android.libraries.mediaviewer.api.MediaInfo
interface LocalMediaFactory {
/**
* This method will create a [LocalMedia] with the given [MediaFile] and [MediaInfo].
*/
fun createFromMediaFile(
mediaFile: MediaFile,
mediaInfo: MediaInfo,
): LocalMedia
/**
* This method will create a [LocalMedia] with the given mimeType, name and formattedFileSize
* If any of those params are null, it'll try to read them from the content.
*/
fun createFromUri(
uri: Uri,
mimeType: String?,
name: String?,
formattedFileSize: String?
): LocalMedia
}

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2024, 2025 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.libraries.mediaviewer.api.local
import androidx.compose.runtime.Composable
interface LocalMediaRenderer {
@Composable
fun Render(localMedia: LocalMedia)
}

View File

@@ -0,0 +1,13 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 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.libraries.mediaviewer.api.util
interface FileExtensionExtractor {
fun extractFromName(name: String): String
}