Skip to content

Commit

Permalink
Merge pull request #8644 from wmontwe/add-account-avatar
Browse files Browse the repository at this point in the history
Add account avatar
  • Loading branch information
wmontwe authored Dec 5, 2024
2 parents 1f3a3d0 + b51d94c commit 2e202a3
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 59 deletions.
15 changes: 15 additions & 0 deletions feature/account/avatar/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
id(ThunderbirdPlugins.Library.androidCompose)
}

android {
namespace = "app.k9mail.feature.account.avatar"
resourcePrefix = "account_avatar_"
}

dependencies {
implementation(projects.core.ui.compose.designsystem)
implementation(projects.core.common)

testImplementation(projects.core.ui.compose.testing)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package app.k9mail.feature.account.avatar.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import app.k9mail.core.ui.compose.designsystem.PreviewWithThemes

@Composable
@Preview(showBackground = true)
internal fun AvatarPreview() {
PreviewWithThemes {
Avatar(
color = Color(0xFFe57373),
name = "example",
selected = false,
)
}
}

@Composable
@Preview(showBackground = true)
internal fun AvatarSelectedPreview() {
PreviewWithThemes {
Avatar(
color = Color(0xFFe57373),
name = "example",
selected = true,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package app.k9mail.feature.account.avatar.ui

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium
import app.k9mail.core.ui.compose.theme2.MainTheme

val selectedAvatarSize = 40.dp

@Composable
fun Avatar(
color: Color,
name: String,
selected: Boolean,
modifier: Modifier = Modifier,
onClick: (() -> Unit)? = null,
) {
val avatarSize by animateDpAsState(
targetValue = if (selected) selectedAvatarSize else MainTheme.sizes.iconAvatar,
label = "Avatar size",
)

Box(
modifier = modifier
.clip(CircleShape)
.clickable(enabled = onClick != null && !selected, onClick = { onClick?.invoke() }),
contentAlignment = Alignment.Center,
) {
AvatarOutline(
color = color,
modifier = Modifier.size(avatarSize),
) {
AvatarPlaceholder(
displayName = name,
)
// TODO: Add image loading
}
}
}

@Composable
private fun AvatarOutline(
color: Color,
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Surface(
modifier = modifier
.clip(CircleShape)
.border(2.dp, color, CircleShape)
.padding(2.dp),
color = color.copy(alpha = 0.3f),
) {
Box(
modifier = Modifier
.fillMaxSize()
.border(2.dp, MainTheme.colors.surfaceContainerLowest, CircleShape),
contentAlignment = Alignment.Center,
) {
content()
}
}
}

@Composable
private fun AvatarPlaceholder(
displayName: String,
modifier: Modifier = Modifier,
) {
TextTitleMedium(
text = extractNameInitials(displayName).uppercase(),
modifier = modifier,
)
}

private fun extractNameInitials(displayName: String): String {
return displayName.take(2)
}
2 changes: 2 additions & 0 deletions feature/navigation/drawer/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ dependencies {
implementation(projects.core.ui.theme.api)
implementation(projects.core.ui.compose.designsystem)

implementation(projects.feature.account.avatar)

implementation(projects.legacy.account)
implementation(projects.legacy.mailstore)
implementation(projects.legacy.message)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,21 @@
package app.k9mail.feature.navigation.drawer.ui.account

import androidx.compose.animation.core.animateDpAsState
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import app.k9mail.core.ui.compose.designsystem.atom.Surface
import app.k9mail.core.ui.compose.designsystem.atom.text.TextLabelSmall
import app.k9mail.core.ui.compose.designsystem.atom.text.TextTitleMedium
import app.k9mail.core.ui.compose.theme2.ColorRoles
import app.k9mail.core.ui.compose.theme2.MainTheme
import app.k9mail.core.ui.compose.theme2.toColorRoles
import app.k9mail.feature.account.avatar.ui.Avatar
import app.k9mail.feature.navigation.drawer.domain.entity.DisplayAccount
import app.k9mail.feature.navigation.drawer.ui.common.labelForCount

val selectedAvatarSize = 40.dp

@Composable
internal fun AccountAvatar(
account: DisplayAccount,
Expand All @@ -36,62 +27,23 @@ internal fun AccountAvatar(
val accountColor = calculateAccountColor(account.color)
val accountColorRoles = accountColor.toColorRoles(context)

val avatarSize by animateDpAsState(
targetValue = if (selected) selectedAvatarSize else MainTheme.sizes.iconAvatar,
label = "Avatar size",
)

Box(
modifier = modifier,
contentAlignment = Alignment.BottomEnd,
) {
val clickableModifier = if (onClick != null && !selected) Modifier.clickable { onClick(account) } else Modifier

Box(
modifier = Modifier
.size(MainTheme.sizes.iconAvatar),
contentAlignment = Alignment.Center,
) {
Surface(
modifier = Modifier
.size(avatarSize)
.clip(CircleShape)
.border(2.dp, accountColor, CircleShape)
.padding(2.dp)
.then(clickableModifier),
color = accountColor.copy(alpha = 0.3f),
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.border(2.dp, MainTheme.colors.surfaceContainerLowest, CircleShape),
) {
Placeholder(
displayName = account.name,
)
// TODO: Add image loading
}
}
}

Avatar(
color = accountColor,
name = account.name,
onClick = onClick?.let { { onClick(account) } },
selected = selected,
)
UnreadBadge(
unreadCount = account.unreadMessageCount,
accountColorRoles = accountColorRoles,
)
}
}

@Composable
private fun Placeholder(
displayName: String,
modifier: Modifier = Modifier,
) {
TextTitleMedium(
text = extractNameInitials(displayName).uppercase(),
modifier = modifier,
)
}

@Composable
private fun UnreadBadge(
unreadCount: Int,
Expand Down Expand Up @@ -120,7 +72,3 @@ private fun UnreadBadge(
}
}
}

private fun extractNameInitials(displayName: String): String {
return displayName.take(2)
}
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ include(
)

include(
":feature:account:avatar",
":feature:account:common",
":feature:account:edit",
":feature:account:oauth",
Expand Down

0 comments on commit 2e202a3

Please sign in to comment.