Skip to content

Commit

Permalink
Update timestamp and add pronouns
Browse files Browse the repository at this point in the history
  • Loading branch information
wingio committed Dec 17, 2023
1 parent ab0790a commit 4380af5
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 33 deletions.
33 changes: 32 additions & 1 deletion app/src/main/java/xyz/wingio/dimett/rest/dto/user/User.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import xyz.wingio.dimett.rest.dto.CustomEmoji
import xyz.wingio.dimett.utils.plain

/**
* Regex to match the typical pronoun format (he/him, she/her, they/them, etc.)
*/
private val pronounsRegex = (
"(?:" +
"[\\w:]+" + // Word characters and `:` for emotes
"(?:" +
"\\/[\\w:]+" + // Word characters and `:` for emotes with a preceding `/`
")+" + // Allow for more than 2
"|" +
"any(?: pronouns)?" + // Special use case for people without a preference
")"
).toRegex(RegexOption.IGNORE_CASE)

// https://docs.joinmastodon.org/entities/Account
@Stable
Expand Down Expand Up @@ -36,4 +51,20 @@ data class User(
@SerialName("followers_count") val followers: Int,
@SerialName("following_count") val following: Int,
@SerialName("mute_expires_at") val muteExpiration: Instant? = null
)
) {

/**
* Finds a pronouns field that matches [pronounsRegex]
*
* NOT FROM THE API
*/
val pronouns = fields
.firstOrNull {
it.name.lowercase() == "pronouns"
}
?.let {
pronounsRegex.find(it.value.plain)
}
?.value?.lowercase()

}
67 changes: 39 additions & 28 deletions app/src/main/java/xyz/wingio/dimett/ui/widgets/posts/Post.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package xyz.wingio.dimett.ui.widgets.posts

import android.text.format.DateUtils
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.material.icons.Icons
Expand All @@ -11,11 +11,10 @@ import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import xyz.wingio.dimett.R
import xyz.wingio.dimett.ast.DefaultSyntakts
Expand Down Expand Up @@ -47,6 +46,8 @@ import xyz.wingio.dimett.utils.toMentionMap
@Suppress("LocalVariableName")
fun Post(
post: Post,
showPronouns: Boolean = true, // TODO: Make a setting
showVisibility: Boolean = true, // TODO: Make a setting
onAvatarClick: (String) -> Unit = {},
onMentionClick: (String) -> Unit = {},
onHashtagClick: (String) -> Unit = {},
Expand All @@ -57,29 +58,12 @@ fun Post(
) {
val ctx = LocalContext.current
val _post = post.boosted ?: post // The actually displayed post, not the same if its a boost
val timeString = remember(post.createdAt) {
DateUtils.getRelativeTimeSpanString(
/* time = */ post.createdAt.toEpochMilliseconds(),
/* now = */ System.currentTimeMillis(),
/* minResolution = */ 0L,
/* flags = */ DateUtils.FORMAT_ABBREV_ALL
).toString()
}

Surface(
modifier = Modifier.fillMaxWidth(),
tonalElevation = 1.dp,
shadowElevation = 3.dp
) {
Text(
text = timeString,
style = MaterialTheme.typography.labelSmall,
color = LocalContentColor.current.copy(alpha = 0.5f),
textAlign = TextAlign.End,
modifier = Modifier
.fillMaxWidth()
.padding(18.dp)
)
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier
Expand All @@ -97,14 +81,41 @@ fun Post(
)
}

PostAuthor(
avatarUrl = _post.author.avatar,
displayName = _post.author.displayName,
acct = _post.author.acct,
emojis = _post.author.emojis.toEmojiMap(),
bot = _post.author.bot,
onAvatarClick = { onAvatarClick(_post.author.id) }
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier.fillMaxWidth()
) {
PostAuthor(
avatarUrl = _post.author.avatar,
displayName = _post.author.displayName,
acct = _post.author.acct,
emojis = _post.author.emojis.toEmojiMap(),
bot = _post.author.bot,
onAvatarClick = { onAvatarClick(_post.author.id) },
modifier = Modifier.weight(0.75f)
)

Column(
horizontalAlignment = Alignment.End,
verticalArrangement = Arrangement.spacedBy(3.5.dp),
modifier = Modifier
.weight(0.25f)
) {
PostTimestamp(
createdAt = _post.createdAt,
visibility = _post.visibility,
showVisibility = showVisibility
)

if (showPronouns) {
PostPronouns(
pronouns = _post.author.pronouns,
emoji = _post.author.emojis
)
}
}
}

_post.userRepliedTo?.let { repliedTo ->
_post.mentions.firstOrNull {
Expand Down
15 changes: 11 additions & 4 deletions app/src/main/java/xyz/wingio/dimett/ui/widgets/posts/PostAuthor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import xyz.wingio.dimett.R
Expand All @@ -41,11 +42,13 @@ fun PostAuthor(
acct: String,
emojis: Map<String, String>,
bot: Boolean,
modifier: Modifier = Modifier,
onAvatarClick: () -> Unit = {}
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp)
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = modifier
) {
BadgedItem(badge = {
if (bot) {
Expand All @@ -68,13 +71,17 @@ fun PostAuthor(

Column {
Text(
text = EmojiSyntakts.render(displayName, emojis, emptyMap()),
style = MaterialTheme.typography.labelLarge
text = EmojiSyntakts.render(displayName, emojis),
style = MaterialTheme.typography.labelLarge,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
Text(
text = "@$acct",
style = MaterialTheme.typography.labelMedium,
color = LocalContentColor.current.copy(alpha = 0.5f)
color = LocalContentColor.current.copy(alpha = 0.5f),
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package xyz.wingio.dimett.ui.widgets.posts

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Person
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import xyz.wingio.dimett.R
import xyz.wingio.dimett.ast.EmojiSyntakts
import xyz.wingio.dimett.ast.render
import xyz.wingio.dimett.rest.dto.CustomEmoji
import xyz.wingio.dimett.ui.components.Text
import xyz.wingio.dimett.utils.toEmojiMap

/**
* Displays the users pronouns
*
* @param pronouns The users pronouns
* @param emoji Emoji used in the users profile, possibly used for their pronouns
* @param modifier The [Modifier] used for this component
* @param color Content color for the icon and text
*/
@Composable
fun PostPronouns(
pronouns: String?,
emoji: List<CustomEmoji>,
modifier: Modifier = Modifier,
color: Color = LocalContentColor.current.copy(alpha = 0.5f)
) {
pronouns?.let {
Row(
horizontalArrangement = Arrangement.spacedBy(5.5.dp, Alignment.End),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
) {
Text(
text = EmojiSyntakts.render(pronouns, emojiMap = emoji.toEmojiMap()),
style = MaterialTheme.typography.labelSmall,
color = color,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.End,
modifier = Modifier.weight(1f)
)

Icon(
imageVector = Icons.Filled.Person,
contentDescription = stringResource(R.string.cd_pronouns),
tint = color,
modifier = Modifier.size(13.dp)
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package xyz.wingio.dimett.ui.widgets.posts

import android.text.format.DateUtils
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material.icons.outlined.Mail
import androidx.compose.material.icons.outlined.Public
import androidx.compose.material.icons.outlined.VpnLock
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import kotlinx.datetime.Instant
import xyz.wingio.dimett.R
import xyz.wingio.dimett.rest.dto.post.Post

/**
* Displays a relative timestamp along with the posts visibility
*
* @param createdAt Timestamp for the posts creation
* @param visibility The visibility level of the post
* @param modifier The [Modifier] for this component
* @param color Content color for the icon and text
* @param showVisibility Whether or not to show an icon for the posts [visibility]
*/
@Composable
fun PostTimestamp(
createdAt: Instant,
visibility: Post.Visibility,
modifier: Modifier = Modifier,
color: Color = LocalContentColor.current.copy(alpha = 0.5f),
showVisibility: Boolean = true,
) {
Row(
horizontalArrangement = Arrangement.spacedBy(5.5.dp),
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
) {
val (privacyIcon, privacyIconLabelRes) = remember(visibility) {
when (visibility) {
Post.Visibility.PUBLIC,
Post.Visibility.LOCAL -> Icons.Outlined.Public to R.string.cd_privacy_public
Post.Visibility.PRIVATE -> Icons.Outlined.Lock to R.string.cd_privacy_private
Post.Visibility.DIRECT -> Icons.Outlined.Mail to R.string.cd_privacy_direct
Post.Visibility.UNLISTED -> Icons.Outlined.VpnLock to R.string.cd_privacy_unlisted
}
}

val timeString = remember(createdAt) {
DateUtils.getRelativeTimeSpanString(
/* time = */ createdAt.toEpochMilliseconds(),
/* now = */ System.currentTimeMillis(),
/* minResolution = */ 0L,
/* flags = */ DateUtils.FORMAT_ABBREV_ALL
).toString()
}

Text(
text = timeString,
style = MaterialTheme.typography.labelSmall,
color = color
)

if (showVisibility) {
Icon(
imageVector = privacyIcon,
contentDescription = stringResource(privacyIconLabelRes),
tint = color,
modifier = Modifier.size(13.dp)
)
}
}
}
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@
<string name="cd_play">Play</string>
<string name="cd_pause">Pause</string>
<string name="cd_thinking_emoji">Thinking Emoji</string>
<string name="cd_pronouns">Pronouns</string>

<string name="cd_privacy_public">Public</string>
<string name="cd_privacy_unlisted">Unlisted</string>
<string name="cd_privacy_private">Private</string>
<string name="cd_privacy_direct">Direct</string>

<string name="post_user_boosted">%1$s boosted</string>
<string name="post_replying_to">Replying to **[@%1$s]{onUserClick}**</string>
Expand Down

0 comments on commit 4380af5

Please sign in to comment.