Merge branch 'develop' into feature/fga/better_media_handling

This commit is contained in:
ganfra 2023-07-18 15:13:59 +02:00
commit 84500d41eb
221 changed files with 4574 additions and 845 deletions

View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.atomic.atoms
import android.graphics.BlurMaskFilter
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.RoundRect
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.R
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.theme.ElementTheme
@Composable
fun ElementLogoAtom(
size: ElementLogoAtomSize,
modifier: Modifier = Modifier,
) {
val outerSize = when (size) {
ElementLogoAtomSize.Large -> 158.dp
ElementLogoAtomSize.Medium -> 120.dp
}
val logoSize = when (size) {
ElementLogoAtomSize.Large -> 110.dp
ElementLogoAtomSize.Medium -> 83.5.dp
}
val cornerRadius = when (size) {
ElementLogoAtomSize.Large -> 44.dp
ElementLogoAtomSize.Medium -> 33.dp
}
val borderWidth = when (size) {
ElementLogoAtomSize.Large -> 1.dp
ElementLogoAtomSize.Medium -> 0.38.dp
}
val blur = if (isSystemInDarkTheme()) {
160.dp
} else {
24.dp
}
//box-shadow: 0px 6.075949668884277px 24.30379867553711px 0px #1B1D2280;
val shadowColor = if (isSystemInDarkTheme()) {
Color.Black.copy(alpha = 0.4f)
} else {
Color(0x401B1D22)
}
val backgroundColor = if (isSystemInDarkTheme()) Color.White.copy(alpha = 0.2f) else Color.White.copy(alpha = 0.4f)
val borderColor = if (isSystemInDarkTheme()) Color.White.copy(alpha = 0.8f) else Color.White.copy(alpha = 0.4f)
Box(
modifier = modifier
.size(outerSize)
.border(borderWidth, borderColor, RoundedCornerShape(cornerRadius)),
contentAlignment = Alignment.Center,
) {
Box(
Modifier
.size(outerSize)
.shapeShadow(
color = shadowColor,
cornerRadius = cornerRadius,
blurRadius = 32.dp,
offsetY = 8.dp,
)
)
Box(
Modifier
.clip(RoundedCornerShape(cornerRadius))
.size(outerSize)
.background(backgroundColor)
.blur(blur)
)
Image(
modifier = Modifier.size(logoSize),
painter = painterResource(id = R.drawable.element_logo),
contentDescription = null
)
}
}
enum class ElementLogoAtomSize {
Medium,
Large
}
@Composable
@DayNightPreviews
internal fun ElementLogoAtomPreview() {
ElementPreview {
Box(
Modifier
.size(180.dp)
.background(ElementTheme.colors.bgSubtlePrimary),
contentAlignment = Alignment.Center
) {
ElementLogoAtom(ElementLogoAtomSize.Large)
}
}
}
fun Modifier.shapeShadow(
color: Color = Color.Black,
cornerRadius: Dp = 0.dp,
offsetX: Dp = 0.dp,
offsetY: Dp = 0.dp,
blurRadius: Dp = 0.dp,
) = then(
drawBehind {
drawIntoCanvas { canvas ->
val path = Path().apply {
addRoundRect(RoundRect(Rect(Offset.Zero, size), CornerRadius(cornerRadius.toPx())))
}
clipPath(path, ClipOp.Difference) {
val paint = Paint()
val frameworkPaint = paint.asFrameworkPaint()
if (blurRadius != 0.dp) {
frameworkPaint.maskFilter = (BlurMaskFilter(blurRadius.toPx(), BlurMaskFilter.Blur.NORMAL))
}
frameworkPaint.color = color.toArgb()
val leftPixel = offsetX.toPx()
val topPixel = offsetY.toPx()
val rightPixel = size.width + topPixel
val bottomPixel = size.height + leftPixel
canvas.drawRect(
left = leftPixel,
top = topPixel,
right = rightPixel,
bottom = bottomPixel,
paint = paint,
)
}
}
}
)

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.atomic.atoms
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Info
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
@Composable
fun InfoListItemMolecule(
message: @Composable () -> Unit,
position: InfoListItemPosition,
backgroundColor: Color,
modifier: Modifier = Modifier,
icon: @Composable () -> Unit = {},
) {
val radius = 14.dp
val backgroundShape = remember(position) {
when (position) {
InfoListItemPosition.Single -> RoundedCornerShape(radius)
InfoListItemPosition.Top -> RoundedCornerShape(topStart = radius, topEnd = radius)
InfoListItemPosition.Middle -> RoundedCornerShape(0.dp)
InfoListItemPosition.Bottom -> RoundedCornerShape(bottomStart = radius, bottomEnd = radius)
}
}
Row(
modifier = modifier
.fillMaxWidth()
.background(
color = backgroundColor,
shape = backgroundShape,
)
.padding(vertical = 12.dp, horizontal = 20.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
) {
icon()
message()
}
}
@DayNightPreviews
@Composable
fun InfoListItemMoleculePreview() {
ElementPreview {
val color = if (isSystemInDarkTheme()) Color.DarkGray else Color.LightGray
Column(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
InfoListItemMolecule(
message = { Text("A single item") },
icon = { Icon(imageVector = Icons.Default.Info, contentDescription = null) },
position = InfoListItemPosition.Single,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A top item") },
icon = { Icon(imageVector = Icons.Default.Info, contentDescription = null) },
position = InfoListItemPosition.Top,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A middle item") },
icon = { Icon(imageVector = Icons.Default.Info, contentDescription = null) },
position = InfoListItemPosition.Middle,
backgroundColor = color,
)
InfoListItemMolecule(
message = { Text("A bottom item") },
icon = { Icon(imageVector = Icons.Default.Info, contentDescription = null) },
position = InfoListItemPosition.Bottom,
backgroundColor = color,
)
}
}
}
enum class InfoListItemPosition {
Top,
Middle,
Bottom,
Single,
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.atomic.molecules
import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.atomic.atoms.InfoListItemMolecule
import io.element.android.libraries.designsystem.atomic.atoms.InfoListItemPosition
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.ElementTheme
import kotlinx.collections.immutable.ImmutableList
@Composable
fun InfoListOrganism(
items: ImmutableList<InfoListItem>,
backgroundColor: Color,
modifier: Modifier = Modifier,
iconTint: Color = LocalContentColor.current,
textStyle: TextStyle = LocalTextStyle.current,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(4.dp),
) {
Column(
modifier = modifier,
verticalArrangement = verticalArrangement,
) {
for ((index, item) in items.withIndex()) {
val position = when {
items.size == 1 -> InfoListItemPosition.Single
index == 0 -> InfoListItemPosition.Top
index == items.size - 1 -> InfoListItemPosition.Bottom
else -> InfoListItemPosition.Middle
}
InfoListItemMolecule(
message = {
Text(
text = item.message,
style = textStyle,
color = ElementTheme.colors.textPrimary,
)
},
icon = {
if (item.iconId != null) {
Icon(resourceId = item.iconId, contentDescription = null, tint = iconTint)
} else if (item.iconVector != null) {
Icon(imageVector = item.iconVector, contentDescription = null, tint = iconTint)
} else {
item.iconComposable()
}
},
position = position,
backgroundColor = backgroundColor,
)
}
}
}
data class InfoListItem(
val message: String,
@DrawableRes val iconId: Int? = null,
val iconVector: ImageVector? = null,
val iconComposable: @Composable () -> Unit = {},
)

View file

@ -41,12 +41,14 @@ import io.element.android.libraries.theme.ElementTheme
*
* Ref: https://www.figma.com/file/o9p34zmiuEpZRyvZXJZAYL/FTUE?type=design&node-id=133-5427&t=5SHVppfYzjvkEywR-0
* @param modifier Classical modifier.
* @param contentAlignment horizontal alignment of the contents.
* @param footer optional footer.
* @param content main content.
*/
@Composable
fun OnBoardingPage(
modifier: Modifier = Modifier,
contentAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
footer: @Composable () -> Unit = {},
content: @Composable () -> Unit = {},
) {
@ -78,6 +80,7 @@ fun OnBoardingPage(
.weight(1f)
.padding(horizontal = 24.dp)
.fillMaxWidth(),
horizontalAlignment = contentAlignment,
) {
content()
}

View file

@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="110dp"
android:height="110dp"
android:viewportWidth="110"
android:viewportHeight="110">
<path
android:pathData="M55,110C85.38,110 110,85.38 110,55C110,24.62 85.38,0 55,0C24.62,0 0,24.62 0,55C0,85.38 24.62,110 55,110Z"
android:fillColor="#0DBD8B"
android:fillType="evenOdd"/>
<path
android:pathData="M44.94,25.63C44.94,23.41 46.75,21.61 48.97,21.61C64.05,21.61 76.27,33.81 76.27,48.85C76.27,51.07 74.47,52.87 72.25,52.87C70.02,52.87 68.22,51.07 68.22,48.85C68.22,38.25 59.6,29.65 48.97,29.65C46.75,29.65 44.94,27.85 44.94,25.63Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M84.36,44.83C86.59,44.83 88.39,46.63 88.39,48.85C88.39,63.9 76.17,76.1 61.09,76.1C58.87,76.1 57.06,74.3 57.06,72.08C57.06,69.86 58.87,68.06 61.09,68.06C71.72,68.06 80.34,59.46 80.34,48.85C80.34,46.63 82.14,44.83 84.36,44.83Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M65.12,84.37C65.12,86.59 63.32,88.39 61.09,88.39C46.01,88.39 33.79,76.19 33.79,61.15C33.79,58.93 35.59,57.13 37.82,57.13C40.04,57.13 41.85,58.93 41.85,61.15C41.85,71.75 50.46,80.35 61.09,80.35C63.32,80.35 65.12,82.15 65.12,84.37Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M25.63,65.17C23.41,65.17 21.61,63.37 21.61,61.15C21.61,46.1 33.83,33.9 48.91,33.9C51.13,33.9 52.94,35.7 52.94,37.92C52.94,40.14 51.13,41.94 48.91,41.94C38.28,41.94 29.66,50.54 29.66,61.15C29.66,63.37 27.86,65.17 25.63,65.17Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
</vector>