diff --git a/FileTypes/.gitignore b/FileTypes/.gitignore
new file mode 100644
index 000000000..42afabfd2
--- /dev/null
+++ b/FileTypes/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/FileTypes/build.gradle.kts b/FileTypes/build.gradle.kts
new file mode 100644
index 000000000..826a2df5d
--- /dev/null
+++ b/FileTypes/build.gradle.kts
@@ -0,0 +1,48 @@
+plugins {
+ alias(libs.plugins.android.library)
+ alias(libs.plugins.kotlin.android)
+ alias(libs.plugins.compose.compiler)
+}
+
+android {
+ namespace = "com.infomaniak.library.filetypes"
+ compileSdk = 34
+
+ defaultConfig {
+ minSdk = 24
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ consumerProguardFiles("consumer-rules.pro")
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ buildFeatures {
+ compose = true
+ }
+ composeOptions {
+ kotlinCompilerExtensionVersion = "1.5.14"
+ }
+}
+
+dependencies {
+
+ implementation(libs.androidx.core.ktx)
+ implementation(filetype.androidx.ui.android)
+ implementation(filetype.androidx.foundation.android)
+ implementation(filetype.androidx.ui.tooling.preview.android)
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.androidx.junit)
+ debugImplementation(filetype.androidx.ui.tooling)
+}
diff --git a/FileTypes/consumer-rules.pro b/FileTypes/consumer-rules.pro
new file mode 100644
index 000000000..e69de29bb
diff --git a/FileTypes/gradle/filetype.versions.toml b/FileTypes/gradle/filetype.versions.toml
new file mode 100644
index 000000000..6374ce328
--- /dev/null
+++ b/FileTypes/gradle/filetype.versions.toml
@@ -0,0 +1,11 @@
+[versions]
+uiAndroid = "1.7.3"
+foundationAndroid = "1.7.3"
+uiToolingPreviewAndroid = "1.7.3"
+uiTooling = "1.7.3"
+
+[libraries]
+androidx-ui-android = { group = "androidx.compose.ui", name = "ui-android", version.ref = "uiAndroid" }
+androidx-foundation-android = { group = "androidx.compose.foundation", name = "foundation-android", version.ref = "foundationAndroid" }
+androidx-ui-tooling-preview-android = { group = "androidx.compose.ui", name = "ui-tooling-preview-android", version.ref = "uiToolingPreviewAndroid" }
+androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" }
diff --git a/FileTypes/proguard-rules.pro b/FileTypes/proguard-rules.pro
new file mode 100644
index 000000000..481bb4348
--- /dev/null
+++ b/FileTypes/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileType.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileType.kt
new file mode 100644
index 000000000..489340d3b
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileType.kt
@@ -0,0 +1,67 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.library.filetypes
+
+import android.webkit.MimeTypeMap
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
+import com.infomaniak.library.filetypes.icons.*
+
+private val MEDIA_COLOR_LIGHT = Color(0xFF00BCD4)
+private val MEDIA_COLOR_DARK = Color(0xFF86DEEA)
+
+enum class FileType(val icon: ImageVector, private val colorLight: Color, private val colorDark: Color) {
+ ARCHIVE(icon = FileTypeIcons.Archive, colorLight = Color(0xFF607D8B), colorDark = Color(0xFFA5B7C0)),
+ AUDIO(icon = FileTypeIcons.Audio, colorLight = MEDIA_COLOR_LIGHT, colorDark = MEDIA_COLOR_DARK),
+ CALENDAR(icon = FileTypeIcons.Calendar, colorLight = Color(0xFF36D0EB), colorDark = Color(0xFFA2E9F6)),
+ CODE(icon = FileTypeIcons.Code, colorLight = Color(0xFF673AB7), colorDark = Color(0xFF956DDD)),
+ FONT(icon = FileTypeIcons.Font, colorLight = Color(0xFF9C26B0), colorDark = Color(0xFFCD68DE)),
+ IMAGE(icon = FileTypeIcons.Image, colorLight = MEDIA_COLOR_LIGHT, colorDark = MEDIA_COLOR_DARK),
+ PDF(icon = FileTypeIcons.Pdf, colorLight = Color(0xFFEF5803), colorDark = Color(0xFFFD9459)),
+ POINTS(icon = FileTypeIcons.Points, colorLight = Color(0xFFFF9802), colorDark = Color(0xFFFFC166)),
+ SPREADSHEET(icon = FileTypeIcons.Sheet, colorLight = Color(0xFF3EBF4D), colorDark = Color(0xFF78D383)),
+ TEXT(icon = FileTypeIcons.Text, colorLight = Color(0xFF2196F3), colorDark = Color(0xFF81C4F8)),
+ VCARD(icon = FileTypeIcons.Vcard, colorLight = Color(0xFF9D66E1), colorDark = Color(0xFFC8AAEE)),
+ VIDEO(icon = FileTypeIcons.Video, colorLight = MEDIA_COLOR_LIGHT, colorDark = MEDIA_COLOR_DARK),
+
+ UNKNOWN(icon = FileTypeIcons.Unknown, colorLight = Color(0xFF85A2B6), colorDark = Color(0xFFAFC2CF));
+
+ fun color(isDark: Boolean): Color {
+ return if (isDark) colorDark else colorLight
+ }
+
+ companion object {
+ fun guessFromFileName(fileName: String): FileType {
+ val extension = fileName.extractExtension() ?: return UNKNOWN
+ val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: return UNKNOWN
+ return guessFromMimeType(mimeType)
+ }
+
+ fun guessFromMimeType(mimeType: String): FileType {
+ return FileTypeGuesser.getFileTypeFromMimeType(mimeType)
+ }
+
+ private fun String.extractExtension(): String? {
+ val fileName = lastIndexOf('/').takeIf { it != -1 }?.let { fileNameStart ->
+ substring(fileNameStart + 1)
+ } ?: this
+
+ return fileName.substringAfterLast(".").takeIf { it.isNotEmpty() }
+ }
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeGuesser.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeGuesser.kt
new file mode 100644
index 000000000..1b3416f84
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeGuesser.kt
@@ -0,0 +1,139 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.library.filetypes
+
+internal object FileTypeGuesser {
+ private val pdfMatches = mimeTypeSetOf(
+ "application/pdf",
+ "application/acrobat",
+ "application/nappdf",
+ "application/x-pdf",
+ )
+
+ private val calendarMatches = mimeTypeSetOf(
+ "application/ics",
+ "text/calendar",
+ )
+
+ private val vcardMatches = mimeTypeSetOf(
+ "text/vcard",
+ "text/directory",
+ "text/x-vcard",
+ )
+
+ private val imageMatches = mimeTypeSetOf(
+ "image/",
+ "application/postscript",
+ "application/x-font-type1",
+ )
+
+ private val audioMatches = mimeTypeSetOf("audio/")
+
+ private val videoMatches = mimeTypeSetOf(
+ "video/",
+ "model/vnd.mts",
+ "application/mxf",
+ "application/vnd.rn-realmedia",
+ "application/x-shockwave-flash",
+ )
+
+ private val sheetMatches = mimeTypeSetOf(
+ "text/csv",
+ "application/vnd.ms-excel",
+ "application/msexcel",
+ "application/x-msexcel",
+ "application/vnd.openxmlformats-officedocument.spreadsheetml",
+ "application/vnd.oasis.opendocument.spreadsheet",
+ )
+
+ private val pointMatches = mimeTypeSetOf(
+ "application/powerpoint",
+ "application/mspowerpoint",
+ "application/vnd.ms-powerpoint",
+ "application/x-mspowerpoint",
+ "application/vnd.openxmlformats-officedocument.presentationml",
+ "application/vnd.oasis.opendocument.presentation",
+ )
+
+ private val textMatches = mimeTypeSetOf(
+ "text/markdown",
+ "text/plain",
+ "application/msword",
+ "application/vnd.ms-word",
+ "application/vnd.oasis.opendocument.text",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml",
+ )
+
+ private val archiveMatches = mimeTypeSetOf(
+ "application/x-7z-compressed",
+ "application/x-ace-compressed",
+ "application/x-cfs-compressed",
+ "application/x-compressed-tar",
+ "application/x-cpio-compressed",
+ "application/x-dgc-compressed",
+ "application/x-gca-compressed",
+ "application/x-lrzip-compressed-tar",
+ "application/x-lz4-compressed-tar",
+ "application/x-compress",
+ "application/gzip",
+ "application/x-zip-compressed",
+ "application/x-zip",
+ "application/zip",
+ "application/x-bzip",
+ "application/x-bzip2",
+ "application/java-archive",
+ "application/x-rar-compressed",
+ "application/application/x-tar",
+ )
+
+ private val codeMatches = mimeTypeSetOf(
+ "text/", // Beware of the order, this must come after every other "text/"
+ "application/json",
+ "application/xml",
+ )
+
+ private val fontMatches = mimeTypeSetOf(
+ "font/",
+ "application/vnd.afpc.foca-codedfont",
+ "application/vnd.font-fontforge-sfd",
+ "application/vnd.ms-fontobject",
+ "application/font-tdpfr",
+ )
+
+ fun getFileTypeFromMimeType(mimeType: String): FileType = when (mimeType) {
+ in pdfMatches -> FileType.PDF
+ in calendarMatches -> FileType.CALENDAR
+ in vcardMatches -> FileType.VCARD
+ in imageMatches -> FileType.IMAGE
+ in audioMatches -> FileType.AUDIO
+ in videoMatches -> FileType.VIDEO
+ in sheetMatches -> FileType.SPREADSHEET
+ in pointMatches -> FileType.POINTS
+ in textMatches -> FileType.TEXT
+ in archiveMatches -> FileType.ARCHIVE
+ in codeMatches -> FileType.CODE // Beware of the order, this must come after every other "text/"
+ in fontMatches -> FileType.FONT
+ else -> FileType.UNKNOWN
+ }
+
+ private fun mimeTypeSetOf(vararg mimeTypes: String) = MimeTypeSet(mimeTypes.toSet())
+
+ private class MimeTypeSet(private val mimeTypes: Set) : Set by mimeTypes {
+ override fun contains(element: String): Boolean = mimeTypes.any { mimeType -> element.startsWith(mimeType) }
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeIcons.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeIcons.kt
new file mode 100644
index 000000000..ebf7f20fe
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/FileTypeIcons.kt
@@ -0,0 +1,24 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.library.filetypes
+
+import androidx.compose.ui.unit.dp
+
+internal object FileTypeIcons {
+ val previewSize = 250.dp
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Archive.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Archive.kt
new file mode 100644
index 000000000..2f87455d6
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Archive.kt
@@ -0,0 +1,131 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Archive: ImageVector
+ get() {
+ if (_archive != null) {
+ return _archive!!
+ }
+ _archive = Builder(
+ name = "Archive",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = null,
+ strokeLineWidth = 0.0f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(9.75f, 15.25f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, -0.75f)
+ moveToRelative(0.0f, 0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, false, 0.0f, -0.75f)
+ moveToRelative(0.0f, 5.25f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, -0.75f)
+ moveToRelative(0.0f, 0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, false, 0.0f, -0.75f)
+ moveToRelative(0.0f, -8.25f)
+ arcToRelative(0.375f, 0.375f, 0.0f, true, true, 0.0f, -0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, 0.75f)
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(9.75f, 15.25f)
+ arcToRelative(0.375f, 0.375f, 0.0f, true, true, 0.0f, -0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, 0.75f)
+ close()
+ moveToRelative(0.0f, 4.5f)
+ arcToRelative(0.375f, 0.375f, 0.0f, true, true, 0.0f, -0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, 0.75f)
+ close()
+ moveToRelative(0.0f, -9.0f)
+ arcToRelative(0.375f, 0.375f, 0.0f, true, true, 0.0f, -0.75f)
+ arcToRelative(0.375f, 0.375f, 0.0f, false, true, 0.0f, 0.75f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(20.885f, 23.257f)
+ horizontalLineTo(3.115f)
+ arcToRelative(1.68f, 1.68f, 0.0f, false, true, -1.142f, -0.44f)
+ arcToRelative(1.45f, 1.45f, 0.0f, false, true, -0.473f, -1.06f)
+ verticalLineToRelative(-19.5f)
+ curveToRelative(0.0f, -0.398f, 0.17f, -0.78f, 0.473f, -1.061f)
+ arcToRelative(1.68f, 1.68f, 0.0f, false, true, 1.142f, -0.44f)
+ horizontalLineToRelative(14.678f)
+ curveToRelative(0.428f, 0.0f, 0.838f, 0.159f, 1.141f, 0.44f)
+ lineToRelative(3.093f, 2.872f)
+ curveTo(22.33f, 4.348f, 22.5f, 4.73f, 22.5f, 5.128f)
+ verticalLineToRelative(16.629f)
+ curveToRelative(0.0f, 0.397f, -0.17f, 0.779f, -0.473f, 1.06f)
+ arcToRelative(1.68f, 1.68f, 0.0f, false, true, -1.142f, 0.44f)
+ }
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = null,
+ strokeLineWidth = 0.0f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(11.726f, 4.807f)
+ arcToRelative(1.95f, 1.95f, 0.0f, false, true, -0.474f, 1.533f)
+ arcToRelative(2.04f, 2.04f, 0.0f, false, true, -3.0f, 0.0f)
+ arcToRelative(1.95f, 1.95f, 0.0f, false, true, -0.474f, -1.533f)
+ lineTo(8.25f, 1.0f)
+ horizontalLineToRelative(3.0f)
+ close()
+ }
+ }.build()
+ return _archive!!
+ }
+
+private var _archive: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Archive, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Audio.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Audio.kt
new file mode 100644
index 000000000..cbbcdbf59
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Audio.kt
@@ -0,0 +1,116 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Audio: ImageVector
+ get() {
+ if (_audio != null) {
+ return _audio!!
+ }
+ _audio = Builder(
+ name = "Audio",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineToRelative(15.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.047f, 0.426f)
+ lineToRelative(3.0f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(5.0f, 16.708f)
+ curveToRelative(0.0f, 0.61f, 0.246f, 1.194f, 0.683f, 1.625f)
+ arcToRelative(2.35f, 2.35f, 0.0f, false, false, 1.65f, 0.674f)
+ curveToRelative(0.62f, 0.0f, 1.213f, -0.243f, 1.65f, -0.674f)
+ arcToRelative(2.28f, 2.28f, 0.0f, false, false, 0.684f, -1.625f)
+ curveToRelative(0.0f, -0.61f, -0.246f, -1.195f, -0.684f, -1.626f)
+ arcToRelative(2.35f, 2.35f, 0.0f, false, false, -1.65f, -0.673f)
+ curveToRelative(-0.619f, 0.0f, -1.212f, 0.242f, -1.65f, 0.673f)
+ arcTo(2.28f, 2.28f, 0.0f, false, false, 5.0f, 16.708f)
+ moveToRelative(9.333f, -2.758f)
+ curveToRelative(0.0f, 0.609f, 0.246f, 1.194f, 0.684f, 1.625f)
+ arcToRelative(2.35f, 2.35f, 0.0f, false, false, 1.65f, 0.673f)
+ curveToRelative(0.618f, 0.0f, 1.212f, -0.242f, 1.65f, -0.673f)
+ arcTo(2.28f, 2.28f, 0.0f, false, false, 19.0f, 13.949f)
+ curveToRelative(0.0f, -0.61f, -0.246f, -1.194f, -0.683f, -1.625f)
+ arcToRelative(2.35f, 2.35f, 0.0f, false, false, -1.65f, -0.674f)
+ curveToRelative(-0.62f, 0.0f, -1.213f, 0.242f, -1.65f, 0.674f)
+ arcToRelative(2.28f, 2.28f, 0.0f, false, false, -0.684f, 1.625f)
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(9.667f, 16.708f)
+ verticalLineToRelative(-8.33f)
+ curveToRelative(0.0f, -0.386f, 0.123f, -0.762f, 0.352f, -1.075f)
+ curveToRelative(0.23f, -0.313f, 0.553f, -0.548f, 0.925f, -0.67f)
+ lineToRelative(5.6f, -1.532f)
+ arcToRelative(1.9f, 1.9f, 0.0f, false, true, 1.68f, 0.253f)
+ curveToRelative(0.24f, 0.17f, 0.436f, 0.394f, 0.57f, 0.654f)
+ curveTo(18.93f, 6.267f, 19.0f, 6.554f, 19.0f, 6.845f)
+ verticalLineToRelative(7.104f)
+ }
+ }
+ }.build()
+ return _audio!!
+ }
+
+private var _audio: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Audio, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Calendar.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Calendar.kt
new file mode 100644
index 000000000..844b58a83
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Calendar.kt
@@ -0,0 +1,73 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Calendar: ImageVector
+ get() {
+ if (_calendar != null) {
+ return _calendar!!
+ }
+ _calendar = Builder(
+ name = "Calendar",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.044f, 2.913f)
+ horizontalLineTo(1.957f)
+ arcTo(0.957f, 0.957f, 0.0f, false, false, 1.0f, 3.87f)
+ verticalLineToRelative(18.174f)
+ curveTo(1.0f, 22.572f, 1.428f, 23.0f, 1.957f, 23.0f)
+ horizontalLineToRelative(20.087f)
+ arcTo(0.957f, 0.957f, 0.0f, false, false, 23.0f, 22.044f)
+ verticalLineTo(3.87f)
+ arcToRelative(0.956f, 0.956f, 0.0f, false, false, -0.956f, -0.957f)
+ moveTo(5.783f, 1.0f)
+ verticalLineToRelative(4.783f)
+ moveTo(18.217f, 1.0f)
+ verticalLineToRelative(4.783f)
+ moveTo(1.0f, 7.696f)
+ horizontalLineToRelative(22.0f)
+ }
+ }
+ }.build()
+ return _calendar!!
+ }
+
+private var _calendar: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Calendar, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Code.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Code.kt
new file mode 100644
index 000000000..89eccb4a4
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Code.kt
@@ -0,0 +1,85 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Code: ImageVector
+ get() {
+ if (_code != null) {
+ return _code!!
+ }
+ _code = Builder(
+ name = "Code",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.76f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineTo(2.26f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 3.0f, 0.76f)
+ horizontalLineToRelative(15.045f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.048f, 0.427f)
+ lineToRelative(2.955f, 2.882f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.143f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(14.25f, 8.257f)
+ lineToRelative(3.75f, 3.75f)
+ lineToRelative(-3.75f, 3.75f)
+ moveToRelative(-4.5f, -7.5f)
+ lineTo(6.0f, 12.007f)
+ lineToRelative(3.75f, 3.75f)
+ }
+ }
+ }.build()
+ return _code!!
+ }
+
+private var _code: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Code, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Font.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Font.kt
new file mode 100644
index 000000000..0f64d92d1
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Font.kt
@@ -0,0 +1,87 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Font: ImageVector
+ get() {
+ if (_font != null) {
+ return _font!!
+ }
+ _font = Builder(
+ name = "Font",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineToRelative(15.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.047f, 0.426f)
+ lineToRelative(3.0f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(8.0f, 9.007f)
+ verticalLineToRelative(-2.0f)
+ horizontalLineToRelative(8.0f)
+ verticalLineToRelative(2.0f)
+ moveToRelative(-4.0f, -2.0f)
+ verticalLineToRelative(10.0f)
+ moveToRelative(-2.0f, 0.0f)
+ horizontalLineToRelative(4.0f)
+ }
+ }
+ }.build()
+ return _font!!
+ }
+
+private var _font: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Font, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Image.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Image.kt
new file mode 100644
index 000000000..0b9a41cd7
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Image.kt
@@ -0,0 +1,83 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Image: ImageVector
+ get() {
+ if (_image != null) {
+ return _image!!
+ }
+ _image = Builder(
+ name = "Image",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.503f, 1.5f)
+ horizontalLineTo(3.003f)
+ arcToRelative(1.505f, 1.505f, 0.0f, false, true, -1.503f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.503f, -1.5f)
+ horizontalLineToRelative(15.033f)
+ curveToRelative(0.392f, 0.0f, 0.769f, 0.152f, 1.05f, 0.426f)
+ lineToRelative(2.961f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(18.77f, 18.482f)
+ lineToRelative(-3.925f, -5.888f)
+ arcToRelative(1.01f, 1.01f, 0.0f, false, false, -1.671f, -0.02f)
+ lineToRelative(-2.691f, 3.846f)
+ lineToRelative(-1.668f, -1.338f)
+ arcToRelative(1.01f, 1.01f, 0.0f, false, false, -1.474f, 0.229f)
+ lineTo(5.23f, 18.48f)
+ }
+ }.build()
+ return _image!!
+ }
+
+private var _image: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Image, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Pdf.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Pdf.kt
new file mode 100644
index 000000000..a034d0b1d
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Pdf.kt
@@ -0,0 +1,103 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Pdf: ImageVector
+ get() {
+ if (_pdf != null) {
+ return _pdf!!
+ }
+ _pdf = Builder(
+ name = "Pdf",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineToRelative(15.0f)
+ arcToRelative(1.48f, 1.48f, 0.0f, false, true, 1.05f, 0.43f)
+ lineToRelative(3.0f, 2.88f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 0.45f, 1.07f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(5.62f, 4.259f)
+ curveToRelative(-2.339f, 1.487f, 0.756f, 5.313f, 4.878f, 7.908f)
+ curveToRelative(1.3f, 0.83f, 7.637f, 4.933f, 8.56f, 2.113f)
+ curveToRelative(0.776f, -2.38f, -2.004f, -2.934f, -7.647f, -1.21f)
+ curveToRelative(-7.06f, 2.153f, -7.343f, 6.43f, -5.245f, 6.892f)
+ curveToRelative(2.79f, 0.625f, 3.325f, -5.498f, 3.472f, -6.687f)
+ curveTo(10.1f, 8.946f, 8.169f, 2.669f, 5.62f, 4.259f)
+ }
+ }
+ }.build()
+ return _pdf!!
+ }
+
+private var _pdf: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Pdf, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Points.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Points.kt
new file mode 100644
index 000000000..9678be13b
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Points.kt
@@ -0,0 +1,96 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Points: ImageVector
+ get() {
+ if (_points != null) {
+ return _points!!
+ }
+ _points = Builder(
+ name = "Points",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.503f, 1.5f)
+ horizontalLineTo(3.003f)
+ arcToRelative(1.505f, 1.505f, 0.0f, false, true, -1.503f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.503f, -1.5f)
+ horizontalLineToRelative(15.033f)
+ curveToRelative(0.392f, 0.0f, 0.769f, 0.152f, 1.05f, 0.426f)
+ lineToRelative(2.961f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = null,
+ strokeLineWidth = 0.0f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(13.0f, 5.007f)
+ verticalLineToRelative(6.0f)
+ horizontalLineToRelative(6.0f)
+ arcToRelative(6.0f, 6.0f, 0.0f, false, false, -6.0f, -6.0f)
+ }
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = null,
+ strokeLineWidth = 0.0f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(11.0f, 7.007f)
+ arcToRelative(6.0f, 6.0f, 0.0f, true, false, 6.0f, 6.0f)
+ horizontalLineToRelative(-6.0f)
+ close()
+ }
+ }.build()
+ return _points!!
+ }
+
+private var _points: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Points, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Sheet.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Sheet.kt
new file mode 100644
index 000000000..1dd5d72da
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Sheet.kt
@@ -0,0 +1,94 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Sheet: ImageVector
+ get() {
+ if (_sheet != null) {
+ return _sheet!!
+ }
+ _sheet = Builder(
+ name = "Sheet",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 22.007f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.503f, 1.5f)
+ horizontalLineTo(3.003f)
+ arcToRelative(1.505f, 1.505f, 0.0f, false, true, -1.503f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.503f, -1.5f)
+ horizontalLineToRelative(15.033f)
+ curveToRelative(0.392f, 0.0f, 0.769f, 0.153f, 1.05f, 0.426f)
+ lineToRelative(2.961f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.39f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(9.667f, 9.725f)
+ verticalLineToRelative(8.62f)
+ moveTo(5.0f, 14.034f)
+ horizontalLineToRelative(14.0f)
+ moveTo(5.0f, 9.725f)
+ horizontalLineToRelative(14.0f)
+ moveTo(5.519f, 5.67f)
+ horizontalLineToRelative(12.963f)
+ reflectiveCurveTo(19.0f, 5.67f, 19.0f, 6.177f)
+ verticalLineToRelative(11.661f)
+ reflectiveCurveToRelative(0.0f, 0.507f, -0.518f, 0.507f)
+ horizontalLineTo(5.519f)
+ reflectiveCurveTo(5.0f, 18.345f, 5.0f, 17.838f)
+ verticalLineTo(6.177f)
+ reflectiveCurveToRelative(0.0f, -0.508f, 0.519f, -0.508f)
+ }
+ }
+ }.build()
+ return _sheet!!
+ }
+
+private var _sheet: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Sheet, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Text.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Text.kt
new file mode 100644
index 000000000..0978b5b26
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Text.kt
@@ -0,0 +1,75 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Text: ImageVector
+ get() {
+ if (_text != null) {
+ return _text!!
+ }
+ _text = Builder(
+ name = "Text",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineToRelative(15.045f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.048f, 0.426f)
+ lineToRelative(2.954f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ moveTo(6.0f, 7.507f)
+ horizontalLineToRelative(12.0f)
+ moveToRelative(-12.0f, 4.5f)
+ horizontalLineToRelative(12.0f)
+ moveToRelative(-12.0f, 4.5f)
+ horizontalLineToRelative(6.0f)
+ }
+ }
+ }.build()
+ return _text!!
+ }
+
+private var _text: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Text, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Unknown.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Unknown.kt
new file mode 100644
index 000000000..3b426ed4d
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Unknown.kt
@@ -0,0 +1,69 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Unknown: ImageVector
+ get() {
+ if (_unknown != null) {
+ return _unknown!!
+ }
+ _unknown = Builder(
+ name = "Unknown",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.503f, 1.5f)
+ horizontalLineTo(3.003f)
+ arcToRelative(1.505f, 1.505f, 0.0f, false, true, -1.503f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.503f, -1.5f)
+ horizontalLineToRelative(15.033f)
+ curveToRelative(0.392f, 0.0f, 0.769f, 0.152f, 1.05f, 0.426f)
+ lineToRelative(2.961f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ }
+ }.build()
+ return _unknown!!
+ }
+
+private var _unknown: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Unknown, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Vcard.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Vcard.kt
new file mode 100644
index 000000000..a0550c2ba
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Vcard.kt
@@ -0,0 +1,83 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Vcard: ImageVector
+ get() {
+ if (_vcard != null) {
+ return _vcard!!
+ }
+ _vcard = Builder(
+ name = "Vcard",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.0f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(20.0f, 0.5f)
+ horizontalLineTo(4.5f)
+ arcTo(1.5f, 1.5f, 0.0f, false, false, 3.0f, 2.0f)
+ moveToRelative(0.0f, 0.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, false, 1.5f, 1.5f)
+ horizontalLineToRelative(16.0f)
+ arcTo(0.5f, 0.5f, 0.0f, false, true, 21.0f, 4.0f)
+ verticalLineToRelative(19.0f)
+ arcToRelative(0.5f, 0.5f, 0.0f, false, true, -0.5f, 0.5f)
+ horizontalLineTo(5.0f)
+ arcToRelative(2.0f, 2.0f, 0.0f, false, true, -2.0f, -2.0f)
+ close()
+ }
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.0f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(17.5f, 19.5f)
+ arcToRelative(5.0f, 5.0f, 0.0f, true, false, -10.0f, 0.0f)
+ close()
+ moveToRelative(-5.0f, -6.5f)
+ arcToRelative(3.0f, 3.0f, 0.0f, true, false, 0.0f, -6.0f)
+ arcToRelative(3.0f, 3.0f, 0.0f, false, false, 0.0f, 6.0f)
+ }
+ }.build()
+ return _vcard!!
+ }
+
+private var _vcard: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Vcard, contentDescription = null)
+ }
+}
diff --git a/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Video.kt b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Video.kt
new file mode 100644
index 000000000..ba5a8ef5e
--- /dev/null
+++ b/FileTypes/src/main/java/com/infomaniak/library/filetypes/icons/Video.kt
@@ -0,0 +1,85 @@
+package com.infomaniak.library.filetypes.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.StrokeCap.Companion.Butt
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.library.filetypes.FileTypeIcons
+import com.infomaniak.library.filetypes.FileTypeIcons.previewSize
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+internal val FileTypeIcons.Video: ImageVector
+ get() {
+ if (_video != null) {
+ return _video!!
+ }
+ _video = Builder(
+ name = "Video",
+ defaultWidth = 24.0.dp,
+ defaultHeight = 24.0.dp,
+ viewportWidth = 24.0f,
+ viewportHeight = 24.0f
+ ).apply {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(22.5f, 21.757f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(3.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-19.5f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineToRelative(15.0f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.047f, 0.426f)
+ lineToRelative(3.0f, 2.883f)
+ arcTo(1.5f, 1.5f, 0.0f, false, true, 22.5f, 5.14f)
+ close()
+ }
+ path(
+ fill = SolidColor(Color(0xFF9F9F9F)),
+ stroke = null,
+ strokeLineWidth = 0.0f,
+ strokeLineCap = Butt,
+ strokeLineJoin = Miter,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(9.488f, 15.667f)
+ arcTo(0.856f, 0.856f, 0.0f, false, true, 8.25f, 14.9f)
+ verticalLineTo(9.113f)
+ arcToRelative(0.856f, 0.856f, 0.0f, false, true, 1.238f, -0.766f)
+ lineToRelative(5.789f, 2.895f)
+ arcToRelative(0.855f, 0.855f, 0.0f, false, true, 0.0f, 1.53f)
+ close()
+ }
+ }.build()
+ return _video!!
+ }
+
+private var _video: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box(modifier = Modifier.padding(previewSize)) {
+ Image(imageVector = FileTypeIcons.Video, contentDescription = null)
+ }
+}
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 19b93c19e..bb697e9e7 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -64,6 +64,7 @@ kapt {
}
dependencies {
+ implementation(project(":FileTypes"))
implementation(kotlin("reflect"))
implementation(libs.androidx.core.ktx)
@@ -86,6 +87,8 @@ dependencies {
implementation(libs.swisstransfer.core)
+ implementation(libs.coil.compose)
+
// Compose preview tools
implementation(libs.compose.ui.tooling.preview)
debugImplementation(libs.compose.ui.tooling)
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index dc91f9387..9173a6796 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,6 +19,8 @@
+
+
.
+ */
+package com.infomaniak.swisstransfer.ui.components
+
+import android.net.Uri
+import android.text.format.Formatter
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.core.net.toUri
+import coil.compose.AsyncImage
+import coil.request.ImageRequest
+import com.infomaniak.library.filetypes.FileType
+import com.infomaniak.swisstransfer.R
+import com.infomaniak.swisstransfer.ui.images.AppImages
+import com.infomaniak.swisstransfer.ui.images.icons.CrossThick
+import com.infomaniak.swisstransfer.ui.theme.LocalIsDarkMode
+import com.infomaniak.swisstransfer.ui.theme.Margin
+import com.infomaniak.swisstransfer.ui.theme.Shapes
+import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
+import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow
+import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow
+import com.infomaniak.swisstransfer.ui.utils.fileType
+import com.infomaniak.swisstransfer.ui.utils.hasPreview
+
+// TODO: Get the interface from the shared kmp code
+interface FileUiItem {
+ val uid: String
+ val fileName: String
+ val fileSizeInBytes: Long
+ val mimeType: String?
+ val uri: String
+}
+
+@Composable
+fun FileItem(
+ file: FileUiItem,
+ isRemoveButtonVisible: Boolean,
+ isCheckboxVisible: Boolean,
+ isChecked: () -> Boolean = { false },
+ onClick: () -> Unit,
+ onRemove: (() -> Unit)? = null,
+) {
+ FileItemContent(
+ content = {
+ var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) }
+
+ if (displayPreview) {
+ FileThumbnail(file.uri.toUri(), onError = { displayPreview = false })
+ } else {
+ FileIcon(file.fileType)
+ }
+ },
+ onClick = onClick,
+ isCheckboxVisible = isCheckboxVisible,
+ isChecked = isChecked,
+ isRemoveButtonVisible = isRemoveButtonVisible,
+ onRemove = onRemove,
+ title = file.fileName,
+ description = Formatter.formatShortFileSize(LocalContext.current, file.fileSizeInBytes),
+ )
+}
+
+@Composable
+private fun FileItemContent(
+ content: @Composable () -> Unit,
+ onClick: () -> Unit,
+ isCheckboxVisible: Boolean,
+ isChecked: () -> Boolean,
+ isRemoveButtonVisible: Boolean,
+ onRemove: (() -> Unit)?,
+ title: String,
+ description: String
+) {
+ Card(
+ onClick = onClick,
+ modifier = Modifier.aspectRatio(164 / 152f),
+ colors = CardDefaults.cardColors(containerColor = SwissTransferTheme.materialColors.background),
+ shape = Shapes.small,
+ border = BorderStroke(width = 1.dp, SwissTransferTheme.materialColors.outlineVariant)
+ ) {
+ Box(
+ modifier = Modifier
+ .weight(1f)
+ .fillMaxWidth()
+ .background(SwissTransferTheme.materialColors.surfaceContainerHighest)
+ ) {
+ content()
+
+ if (isCheckboxVisible) {
+ Checkbox(
+ checked = isChecked(),
+ onCheckedChange = null,
+ Modifier
+ .align(Alignment.TopStart)
+ .padding(12.dp),
+ )
+ }
+
+ if (isRemoveButtonVisible) {
+ Button(
+ modifier = Modifier
+ .size(Margin.XXLarge)
+ .padding(12.dp)
+ .align(Alignment.TopEnd),
+ contentPadding = PaddingValues(0.dp),
+ shape = CircleShape,
+ colors = ButtonDefaults.buttonColors(containerColor = SwissTransferTheme.colors.fileTileRemoveButtonBackground),
+ onClick = onRemove ?: {},
+ ) {
+ Icon(
+ modifier = Modifier.size(Margin.Small),
+ imageVector = AppImages.AppIcons.CrossThick,
+ contentDescription = stringResource(R.string.contentDescriptionButtonRemove),
+ tint = Color.White
+ )
+ }
+ }
+ }
+
+ Column(Modifier.padding(Margin.Small)) {
+ Text(
+ text = title,
+ style = SwissTransferTheme.typography.bodySmallRegular,
+ color = SwissTransferTheme.colors.primaryTextColor,
+ maxLines = 1,
+ overflow = TextOverflow.MiddleEllipsis,
+ )
+ Text(
+ text = description,
+ style = SwissTransferTheme.typography.bodySmallRegular,
+ color = SwissTransferTheme.colors.secondaryTextColor,
+ maxLines = 1,
+ overflow = TextOverflow.MiddleEllipsis,
+ )
+ }
+ }
+}
+
+@Composable
+private fun FileThumbnail(uri: Uri, onError: () -> Unit) {
+ AsyncImage(
+ model = ImageRequest.Builder(LocalContext.current)
+ .data(uri)
+ .crossfade(true)
+ .build(),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ onError = { onError() },
+ modifier = Modifier.fillMaxSize(),
+ )
+}
+
+@Composable
+private fun FileIcon(fileType: FileType) {
+ Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) {
+ val surfaceColor = SwissTransferTheme.materialColors.surface
+ Canvas(modifier = Modifier.size(64.dp)) {
+ drawCircle(color = surfaceColor)
+ }
+
+ Icon(
+ modifier = Modifier.size(32.dp),
+ imageVector = fileType.icon,
+ contentDescription = null,
+ tint = fileType.color(LocalIsDarkMode.current)
+ )
+ }
+}
+
+@PreviewSmallWindow
+@PreviewLargeWindow
+@Composable
+private fun FileItemPreview() {
+ SwissTransferTheme {
+ Surface {
+ Column(
+ modifier = Modifier
+ .padding(24.dp)
+ .width(164.dp)
+ )
+ {
+ var isChecked by remember { mutableStateOf(true) }
+
+
+ val iconFile = object : FileUiItem {
+ override val fileName: String = "How to not get fired.pdf"
+ override val uid: String = fileName
+ override val fileSizeInBytes: Long = 10302130
+ override val mimeType: String? = null
+ override val uri: String = ""
+ }
+ FileItem(
+ iconFile,
+ isRemoveButtonVisible = true,
+ isCheckboxVisible = true,
+ isChecked = { isChecked },
+ onClick = { isChecked = !isChecked },
+ onRemove = {},
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ val imageFile = object : FileUiItem {
+ override val fileName: String = "Time-Clock-Circle--Streamline-Ultimate.svg (1).png"
+ override val uid: String = fileName
+ override val fileSizeInBytes: Long = 456782
+ override val mimeType: String? = null
+ override val uri: String = "https://picsum.photos/200/300"
+ }
+ FileItem(
+ file = imageFile,
+ isRemoveButtonVisible = true,
+ isCheckboxVisible = true,
+ isChecked = { isChecked },
+ onClick = { isChecked = !isChecked },
+ onRemove = {},
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt
new file mode 100644
index 000000000..845f8c729
--- /dev/null
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt
@@ -0,0 +1,65 @@
+package com.infomaniak.swisstransfer.ui.images.icons
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
+import androidx.compose.ui.graphics.SolidColor
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.graphics.vector.ImageVector.Builder
+import androidx.compose.ui.graphics.vector.group
+import androidx.compose.ui.graphics.vector.path
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.infomaniak.swisstransfer.ui.images.AppImages
+import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound
+import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound
+
+val AppImages.AppIcons.CrossThick: ImageVector
+ get() {
+ if (_crossThick != null) {
+ return _crossThick!!
+ }
+ _crossThick = Builder(
+ name = "CrossThick",
+ defaultWidth = 16.0.dp,
+ defaultHeight = 16.0.dp,
+ viewportWidth = 16.0f,
+ viewportHeight = 16.0f
+ ).apply {
+ group {
+ path(
+ fill = null,
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 2.0f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero
+ ) {
+ moveTo(1.0f, 15.0f)
+ lineTo(15.0f, 1.0f)
+ moveToRelative(0.0f, 14.0f)
+ lineTo(1.0f, 1.0f)
+ }
+ }
+ }.build()
+ return _crossThick!!
+ }
+
+private var _crossThick: ImageVector? = null
+
+@Preview
+@Composable
+private fun Preview() {
+ Box {
+ Image(
+ imageVector = AppImages.AppIcons.CrossThick,
+ contentDescription = null,
+ modifier = Modifier.size(AppImages.previewSize)
+ )
+ }
+}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentListScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentListScreen.kt
index 36a0977e8..4fca7eb5f 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentListScreen.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentListScreen.kt
@@ -17,24 +17,49 @@
*/
package com.infomaniak.swisstransfer.ui.screen.main.sent
-import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.foundation.lazy.items
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.grid.GridCells
+import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.infomaniak.swisstransfer.ui.components.FileUiItem
+import com.infomaniak.swisstransfer.ui.components.FileItem
+import com.infomaniak.swisstransfer.ui.theme.Margin
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow
import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow
-import java.util.UUID
@Composable
fun SentListScreen(transfers: List) {
- LazyColumn {
- items(items = transfers, key = { UUID.randomUUID() }) {
- Text(text = "Sent screen")
+ LazyVerticalGrid(
+ modifier = Modifier.padding(Margin.Medium),
+ columns = GridCells.Adaptive(150.dp),
+ verticalArrangement = Arrangement.spacedBy(Margin.Medium),
+ horizontalArrangement = Arrangement.spacedBy(Margin.Medium),
+ ) {
+ val imageFile = object : FileUiItem {
+ override val fileName: String = "Time-Clock-Circle--Streamline-Ultimate.svg (1).png"
+ override val uid: String = fileName
+ override val fileSizeInBytes: Long = 456782
+ override val mimeType: String? = null
+ override val uri: String = "https://picsum.photos/200/300"
+ }
+
+ items(3) {
+ FileItem(
+ file = imageFile,
+ isRemoveButtonVisible = true,
+ isCheckboxVisible = true,
+ isChecked = { true },
+ onClick = {},
+ onRemove = {})
}
}
}
+
@PreviewSmallWindow
@PreviewLargeWindow
@Composable
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt
index b622fc490..10f39925e 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/main/sent/SentViewModel.kt
@@ -27,5 +27,5 @@ import javax.inject.Inject
@HiltViewModel
class SentViewModel @Inject constructor() : ViewModel() {
- val transfers = flow> { emit(emptyList()) }.stateIn(viewModelScope, SharingStarted.Eagerly, null)
+ val transfers = flow> { emit(listOf(1)) }.stateIn(viewModelScope, SharingStarted.Eagerly, null)
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorDark.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorDark.kt
index 63f1d4fee..67a87f4c9 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorDark.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorDark.kt
@@ -40,6 +40,7 @@ private const val specific5 = 0xFF49DEFD
// Extra palette
private const val elephant = 0xFF666666
private const val white = 0xFFFFFFFF
+private const val black_translucent = 0x80000000
private const val error = 0xFFFC8878
@@ -74,6 +75,7 @@ val CustomDarkColorScheme = CustomColorScheme(
navigationItemBackground = Color(dark2),
tertiaryButtonBackground = Color(dark2),
selectedSettingItem = Color(dark2),
+ fileTileRemoveButtonBackground = Color(black_translucent),
transferTypeLinkContainer = Color(specific1),
transferTypeLinkOnContainer = Color(green_main),
transferTypeEmailContainer = Color(green_dark),
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorLight.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorLight.kt
index 0a092c132..1a888a5a3 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorLight.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/ColorLight.kt
@@ -41,6 +41,7 @@ private const val specific4 = 0xFFCF9E1B
// Extra palette
private const val on_primary = 0xFFF7FCFA
private const val white = 0xFFFFFFFF
+private const val black_translucent = 0x80000000
private const val error = 0xFFF44336
@@ -75,6 +76,7 @@ val CustomLightColorScheme = CustomColorScheme(
navigationItemBackground = LightColorScheme.background,
tertiaryButtonBackground = Color(rabbit),
selectedSettingItem = Color(rabbit),
+ fileTileRemoveButtonBackground = Color(black_translucent),
transferTypeLinkContainer = Color(specific1),
transferTypeLinkOnContainer = Color(green_main),
transferTypeEmailContainer = Color(specific2),
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt
index 4e4a316e1..27fce6db1 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Theme.kt
@@ -75,6 +75,7 @@ data class CustomColorScheme(
val navigationItemBackground: Color = Color.Unspecified,
val tertiaryButtonBackground: Color = Color.Unspecified,
val selectedSettingItem: Color = Color.Unspecified,
+ val fileTileRemoveButtonBackground: Color = Color.Unspecified,
val transferTypeLinkContainer: Color = Color.Unspecified,
val transferTypeLinkOnContainer: Color = Color.Unspecified,
val transferTypeEmailContainer: Color = Color.Unspecified,
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/FileUiItemExt.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/FileUiItemExt.kt
new file mode 100644
index 000000000..e78f6ccb3
--- /dev/null
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/FileUiItemExt.kt
@@ -0,0 +1,25 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.swisstransfer.ui.utils
+
+import com.infomaniak.library.filetypes.FileType
+import com.infomaniak.swisstransfer.ui.components.FileUiItem
+
+val FileUiItem.fileType: FileType get() = mimeType?.let { FileType.guessFromMimeType(it) } ?: FileType.guessFromFileName(fileName)
+
+val FileUiItem.hasPreview: Boolean get() = fileType == FileType.IMAGE
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 6bf2c9cb3..2aa1eb992 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -20,6 +20,7 @@
Weiter zu
Zurück
Schliessen
+ Datei entfernen
Neuer Transfer
Mache deine erste Überweisung!
Zu übertragende Dateien
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 65a1e4c87..5cf57976d 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -20,6 +20,7 @@
Siguiente
Volver
Cerrar
+ Eliminar archivo
Nueva transferencia
Realice su primera transferencia
Archivos para transferir
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index f4777f365..6d2cc0d60 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -20,6 +20,7 @@
Suivant
Retour
Fermer
+ Supprimer le fichier
Nouveau transfert
Fais ton premier transfert !
Fichiers à transférer
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 70eb953fe..9bc9fdc39 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -20,6 +20,7 @@
Avanti
Indietro
Chiudi
+ Rimuovi il file
Nuovo trasferimento
Effettua il tuo primo trasferimento!
File da trasferire
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 0e93fab58..c2be9758a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -23,6 +23,7 @@
Next
Back
Close
+ Remove file
New transfer
Make your first transfer!
Files to transfer
diff --git a/build.gradle.kts b/build.gradle.kts
index 88ab05926..dcad8f2e1 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -12,4 +12,5 @@ plugins {
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.kapt) apply false
alias(libs.plugins.hilt) apply false
+ alias(libs.plugins.android.library) apply false
}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 5c95d1969..9be8b5e2e 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,6 +2,7 @@
activityCompose = "1.9.2"
adaptiveLayout = "1.0.0"
agp = "8.6.1"
+coilCompose = "2.7.0"
composeAlpha = "1.8.0-alpha02"
composeBom = "2024.09.02"
constraintlayoutCompose = "1.0.1"
@@ -22,6 +23,7 @@ androidx-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", v
androidx-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "adaptiveLayout" }
androidx-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "adaptiveLayout" }
androidx-constraintlayout-compose = { module = "androidx.constraintlayout:constraintlayout-compose", version.ref = "constraintlayoutCompose" }
+coil-compose = { module = "io.coil-kt:coil-compose", version.ref = "coilCompose" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
@@ -48,3 +50,6 @@ compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+
+# FileType module
+android-library = { id = "com.android.library", version.ref = "agp" }
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1a80ad33d..674765690 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -21,7 +21,13 @@ dependencyResolutionManagement {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
+ versionCatalogs {
+ create("filetype") {
+ from(files("FileTypes/gradle/filetype.versions.toml"))
+ }
+ }
}
rootProject.name = "android-SwissTransfer"
include(":app")
+include(":FileTypes")