Moving static sizes to the Shape class

This commit is contained in:
Vitor Pamplona 2023-06-16 19:57:25 -04:00
parent e3eae80d4c
commit da62760fd7
13 changed files with 183 additions and 122 deletions

View File

@ -73,7 +73,6 @@ class TextToSpeechEngine private constructor() {
)
speak(message)
} else {
Log.d("AAA", "initTTS: $it")
onErrorListener?.invoke(getErrorText(it))
}
}

View File

@ -52,6 +52,7 @@ import com.vitorpamplona.amethyst.model.RelaySetupInfo
import com.vitorpamplona.amethyst.service.relays.FeedType
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import java.lang.Math.round
@ -477,7 +478,7 @@ fun EditableServerConfig(relayToAdd: String, onNewRelay: (RelaySetupInfo) -> Uni
imageVector = Icons.Default.Download,
null,
modifier = Modifier
.size(35.dp)
.size(Size35dp)
.padding(horizontal = 5.dp),
tint = if (read) Color.Green else MaterialTheme.colors.placeholderText
)
@ -488,7 +489,7 @@ fun EditableServerConfig(relayToAdd: String, onNewRelay: (RelaySetupInfo) -> Uni
imageVector = Icons.Default.Upload,
null,
modifier = Modifier
.size(35.dp)
.size(Size35dp)
.padding(horizontal = 5.dp),
tint = if (write) Color.Green else MaterialTheme.colors.placeholderText
)

View File

@ -12,7 +12,7 @@ class UserProfileAppRecommendationsFeedFilter(val user: User) : FeedFilter<Note>
}.mapNotNull {
(it.event as? AppRecommendationEvent)?.recommendations()
}.flatten()
.mapNotNull {
.map {
LocalCache.getOrCreateAddressableNote(it)
}.toSet().toList()

View File

@ -22,6 +22,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import kotlinx.collections.immutable.ImmutableSet
@Composable
@ -88,7 +89,7 @@ fun HiddenNote(
baseNote = it,
nav = nav,
accountViewModel = accountViewModel,
size = 35.dp
size = Size35dp
)
}
}

View File

@ -58,6 +58,7 @@ import com.vitorpamplona.amethyst.ui.screen.MultiSetCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.showAmountAxis
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
import com.vitorpamplona.amethyst.ui.theme.overPictureBackground
import kotlinx.collections.immutable.ImmutableList
@ -367,9 +368,7 @@ val textBoxModifier = Modifier.padding(start = 5.dp).fillMaxWidth()
val simpleModifier = Modifier
val size = 35.dp
val sizedModifier = Modifier.size(size)
val sizedModifier = Modifier.size(Size35dp)
val bottomPadding1dp = Modifier.padding(bottom = 1.dp)
@ -398,7 +397,7 @@ private fun AuthorPictureAndComment(
Box(modifier = sizedModifier, contentAlignment = Alignment.BottomCenter) {
FastNoteAuthorPicture(
author = author,
size = size,
size = Size35dp,
accountViewModel = accountViewModel,
pictureModifier = simpleModifier
)

View File

@ -142,6 +142,7 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.Following
import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.mediumImportanceLink
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
import com.vitorpamplona.amethyst.ui.theme.placeholderText
@ -947,7 +948,7 @@ fun RenderAppDefinition(
Row(
modifier = Modifier
.height(35.dp)
.height(Size35dp)
.padding(bottom = 3.dp)
) {
}
@ -1354,7 +1355,7 @@ private fun RenderBadgeAward(
awardees.take(100).forEach { user ->
Row(
modifier = Modifier
.size(size = 35.dp)
.size(size = Size35dp)
.clickable {
nav("User/${user.pubkeyHex}")
},
@ -1363,7 +1364,7 @@ private fun RenderBadgeAward(
UserPicture(
baseUser = user,
accountViewModel = accountViewModel,
size = 35.dp
size = Size35dp
)
}
}

View File

@ -39,6 +39,7 @@ import com.vitorpamplona.amethyst.ui.components.CreateTextWithEmoji
import com.vitorpamplona.amethyst.ui.components.ResizeImage
import com.vitorpamplona.amethyst.ui.components.RobohashAsyncImageProxy
import com.vitorpamplona.amethyst.ui.qrcode.NIP19QrCodeScanner
import com.vitorpamplona.amethyst.ui.theme.Size35dp
@Composable
fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
@ -99,7 +100,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
horizontalArrangement = Arrangement.Center,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 35.dp)
.padding(horizontal = Size35dp)
) {
QrCodeDrawer("nostr:${user.pubkeyNpub()}")
}
@ -112,7 +113,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
) {
Button(
onClick = { presenting = false },
shape = RoundedCornerShape(35.dp),
shape = RoundedCornerShape(Size35dp),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),

View File

@ -80,6 +80,7 @@ import com.vitorpamplona.amethyst.ui.note.ChatroomMessageCompose
import com.vitorpamplona.amethyst.ui.screen.NostrChannelFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -396,11 +397,11 @@ fun ChannelHeader(baseChannel: Channel, accountViewModel: AccountViewModel, nav:
Row(verticalAlignment = Alignment.CenterVertically) {
RobohashAsyncImageProxy(
robot = channel.idHex,
model = ResizeImage(channel.profilePicture(), 35.dp),
model = ResizeImage(channel.profilePicture(), Size35dp),
contentDescription = context.getString(R.string.profile_image),
modifier = Modifier
.width(35.dp)
.height(35.dp)
.width(Size35dp)
.height(Size35dp)
.clip(shape = CircleShape)
)
@ -429,7 +430,7 @@ fun ChannelHeader(baseChannel: Channel, accountViewModel: AccountViewModel, nav:
Row(
modifier = Modifier
.height(35.dp)
.height(Size35dp)
.padding(bottom = 3.dp)
) {
ChannelActionOptions(channel, accountViewModel, nav)

View File

@ -36,6 +36,7 @@ import com.vitorpamplona.amethyst.ui.note.UserPicture
import com.vitorpamplona.amethyst.ui.note.UsernameDisplay
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.RefreshingChatroomFeedView
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -198,7 +199,7 @@ fun ChatroomHeader(baseUser: User, accountViewModel: AccountViewModel, nav: (Str
UserPicture(
baseUser = baseUser,
accountViewModel = accountViewModel,
size = 35.dp
size = Size35dp
)
Column(modifier = Modifier.padding(start = 10.dp)) {

View File

@ -9,6 +9,7 @@ import androidx.compose.foundation.*
import androidx.compose.foundation.gestures.scrollBy
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerState
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.ClickableText
@ -95,10 +96,12 @@ import com.vitorpamplona.amethyst.ui.screen.RefreshingFeedUserFeedView
import com.vitorpamplona.amethyst.ui.screen.RelayFeedView
import com.vitorpamplona.amethyst.ui.screen.RelayFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.UserFeedViewModel
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -108,13 +111,16 @@ import java.math.BigDecimal
fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
if (userId == null) return
var userBase by remember { mutableStateOf<User?>(null) }
var userBase by remember { mutableStateOf<User?>(LocalCache.getUserIfExists(userId)) }
LaunchedEffect(userId) {
withContext(Dispatchers.IO) {
val newUserBase = LocalCache.checkGetOrCreateUser(userId)
if (newUserBase != userBase) {
userBase = newUserBase
if (userBase == null) {
// waits to resolve.
withContext(Dispatchers.IO) {
val newUserBase = LocalCache.checkGetOrCreateUser(userId)
if (newUserBase != userBase) {
userBase = newUserBase
}
}
}
}
@ -257,7 +263,7 @@ fun ProfileScreen(
})
.fillMaxHeight()
) {
Column(modifier = Modifier.padding()) {
Column() {
ProfileHeader(baseUser, appRecommendations, nav, accountViewModel)
ScrollableTabRow(
backgroundColor = MaterialTheme.colors.background,
@ -267,26 +273,7 @@ fun ProfileScreen(
tabsSize = it
}
) {
val tabs = listOf<@Composable() (() -> Unit)?>(
{ Text(text = stringResource(R.string.notes)) },
{ Text(text = stringResource(R.string.replies)) },
{ FollowTabHeader(baseUser) },
{ FollowersTabHeader(baseUser) },
{ ZapTabHeader(baseUser) },
{ BookmarkTabHeader(baseUser) },
{ ReportsTabHeader(baseUser) },
{ RelaysTabHeader(baseUser) }
)
tabs.forEachIndexed { index, function ->
Tab(
selected = pagerState.currentPage == index,
onClick = {
coroutineScope.launch { pagerState.animateScrollToPage(index) }
},
text = function
)
}
CreateAndRenderTabs(baseUser, pagerState)
}
HorizontalPager(
pageCount = 8,
@ -295,16 +282,15 @@ fun ProfileScreen(
Modifier.height((columnSize.height - tabsSize.height).toDp())
}
) { page ->
when (page) {
0 -> TabNotesNewThreads(accountViewModel, nav)
1 -> TabNotesConversations(accountViewModel, nav)
2 -> TabFollows(baseUser, followsFeedViewModel, accountViewModel, nav)
3 -> TabFollowers(baseUser, followersFeedViewModel, accountViewModel, nav)
4 -> TabReceivedZaps(baseUser, zapFeedViewModel, accountViewModel, nav)
5 -> TabBookmarks(baseUser, accountViewModel, nav)
6 -> TabReports(baseUser, accountViewModel, nav)
7 -> TabRelays(baseUser, accountViewModel)
}
CreateAndRenderPages(
page,
baseUser,
followsFeedViewModel,
followersFeedViewModel,
zapFeedViewModel,
accountViewModel,
nav,
)
}
}
}
@ -312,6 +298,58 @@ fun ProfileScreen(
}
}
@Composable
private fun CreateAndRenderPages(
page: Int,
baseUser: User,
followsFeedViewModel: NostrUserProfileFollowsUserFeedViewModel,
followersFeedViewModel: NostrUserProfileFollowersUserFeedViewModel,
zapFeedViewModel: NostrUserProfileZapsFeedViewModel,
accountViewModel: AccountViewModel,
nav: (String) -> Unit
) {
when (page) {
0 -> TabNotesNewThreads(accountViewModel, nav)
1 -> TabNotesConversations(accountViewModel, nav)
2 -> TabFollows(baseUser, followsFeedViewModel, accountViewModel, nav)
3 -> TabFollowers(baseUser, followersFeedViewModel, accountViewModel, nav)
4 -> TabReceivedZaps(baseUser, zapFeedViewModel, accountViewModel, nav)
5 -> TabBookmarks(baseUser, accountViewModel, nav)
6 -> TabReports(baseUser, accountViewModel, nav)
7 -> TabRelays(baseUser, accountViewModel)
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun CreateAndRenderTabs(
baseUser: User,
pagerState: PagerState,
) {
val coroutineScope = rememberCoroutineScope()
val tabs = listOf<@Composable() (() -> Unit)?>(
{ Text(text = stringResource(R.string.notes)) },
{ Text(text = stringResource(R.string.replies)) },
{ FollowTabHeader(baseUser) },
{ FollowersTabHeader(baseUser) },
{ ZapTabHeader(baseUser) },
{ BookmarkTabHeader(baseUser) },
{ ReportsTabHeader(baseUser) },
{ RelaysTabHeader(baseUser) }
)
tabs.forEachIndexed { index, function ->
Tab(
selected = pagerState.currentPage == index,
onClick = {
coroutineScope.launch { pagerState.animateScrollToPage(index) }
},
text = function
)
}
}
@Composable
private fun RelaysTabHeader(baseUser: User) {
val userState by baseUser.live().relays.observeAsState()
@ -500,7 +538,7 @@ private fun ProfileHeader(
Row(
modifier = Modifier
.height(35.dp)
.height(Size35dp)
.padding(bottom = 3.dp)
) {
MessageButton(baseUser, nav)
@ -879,7 +917,7 @@ private fun WatchApp(baseApp: Note, nav: (String) -> Unit) {
Box(
remember {
Modifier
.size(35.dp)
.size(Size35dp)
.clickable {
nav("Note/${baseApp.idHex}")
}
@ -890,7 +928,7 @@ private fun WatchApp(baseApp: Note, nav: (String) -> Unit) {
contentDescription = null,
modifier = remember {
Modifier
.size(35.dp)
.size(Size35dp)
.clip(shape = CircleShape)
}
)
@ -931,27 +969,37 @@ private fun DisplayBadges(
@Composable
private fun LoadAndRenderBadge(badgeAwardEventHex: String, nav: (String) -> Unit) {
var baseNote by remember {
mutableStateOf<Note?>(null)
mutableStateOf<Note?>(LocalCache.getNoteIfExists(badgeAwardEventHex))
}
LaunchedEffect(key1 = badgeAwardEventHex) {
launch(Dispatchers.IO) {
baseNote = LocalCache.getOrCreateNote(badgeAwardEventHex)
if (baseNote == null) {
launch(Dispatchers.IO) {
baseNote = LocalCache.getOrCreateNote(badgeAwardEventHex)
}
}
}
baseNote?.let {
val badgeAwardState by it.live().metadata.observeAsState()
val baseBadgeDefinition by remember(badgeAwardState) {
derivedStateOf {
badgeAwardState?.note?.replyTo?.firstOrNull()
}
}
ObserveAndRenderBadge(it, nav)
}
}
baseBadgeDefinition?.let {
BadgeThumb(it, nav, 35.dp)
@Composable
private fun ObserveAndRenderBadge(
it: Note,
nav: (String) -> Unit
) {
val badgeAwardState by it.live().metadata.observeAsState()
val baseBadgeDefinition by remember(badgeAwardState) {
derivedStateOf {
badgeAwardState?.note?.replyTo?.firstOrNull()
}
}
baseBadgeDefinition?.let {
BadgeThumb(it, nav, Size35dp)
}
}
@Composable
@ -980,41 +1028,54 @@ fun BadgeThumb(
.height(size)
}
) {
val noteState by baseNote.live().metadata.observeAsState()
val event = remember(noteState) { noteState?.note?.event as? BadgeDefinitionEvent } ?: return
val image = remember(noteState) { event.thumb()?.ifBlank { null } ?: event.image()?.ifBlank { null } }
WatchAndRenderBadgeImage(baseNote, size, pictureModifier, onClick)
}
}
if (image == null) {
RobohashAsyncImage(
robot = "authornotfound",
robotSize = size,
contentDescription = stringResource(R.string.unknown_author),
modifier = pictureModifier
.width(size)
.height(size)
.background(MaterialTheme.colors.background)
)
} else {
RobohashFallbackAsyncImage(
robot = event.id,
robotSize = size,
model = image,
contentDescription = stringResource(id = R.string.profile_image),
modifier = pictureModifier
.width(size)
.height(size)
.clip(shape = CircleShape)
.background(MaterialTheme.colors.background)
.run {
if (onClick != null) {
this.clickable(onClick = { onClick(event.id) })
} else {
this
}
@Composable
private fun WatchAndRenderBadgeImage(
baseNote: Note,
size: Dp,
pictureModifier: Modifier,
onClick: ((String) -> Unit)?
) {
val noteState by baseNote.live().metadata.observeAsState()
val eventId = remember(noteState) { noteState?.note?.idHex } ?: return
val image = remember(noteState) {
val event = noteState?.note?.event as? BadgeDefinitionEvent
event?.thumb()?.ifBlank { null } ?: event?.image()?.ifBlank { null }
}
if (image == null) {
RobohashAsyncImage(
robot = "authornotfound",
robotSize = size,
contentDescription = stringResource(R.string.unknown_author),
modifier = pictureModifier
.width(size)
.height(size)
.background(MaterialTheme.colors.background)
)
} else {
RobohashFallbackAsyncImage(
robot = eventId,
robotSize = size,
model = image,
contentDescription = stringResource(id = R.string.profile_image),
modifier = pictureModifier
.width(size)
.height(size)
.clip(shape = CircleShape)
.background(MaterialTheme.colors.background)
.run {
if (onClick != null) {
this.clickable(onClick = { onClick(eventId) })
} else {
this
}
}
)
}
)
}
}
@ -1114,9 +1175,7 @@ fun TabFollows(baseUser: User, feedViewModel: UserFeedViewModel, accountViewMode
WatchFollowChanges(baseUser, feedViewModel)
Column(Modifier.fillMaxHeight()) {
Column(
modifier = Modifier.padding(vertical = 0.dp)
) {
Column() {
RefreshingFeedUserFeedView(feedViewModel, accountViewModel, nav, enablePullRefresh = false)
}
}
@ -1127,9 +1186,7 @@ fun TabFollowers(baseUser: User, feedViewModel: UserFeedViewModel, accountViewMo
WatchFollowerChanges(baseUser, feedViewModel)
Column(Modifier.fillMaxHeight()) {
Column(
modifier = Modifier.padding(vertical = 0.dp)
) {
Column() {
RefreshingFeedUserFeedView(feedViewModel, accountViewModel, nav, enablePullRefresh = false)
}
}
@ -1164,9 +1221,7 @@ fun TabReceivedZaps(baseUser: User, zapFeedViewModel: NostrUserProfileZapsFeedVi
WatchZapsAndUpdateFeed(baseUser, zapFeedViewModel)
Column(Modifier.fillMaxHeight()) {
Column(
modifier = Modifier.padding(vertical = 0.dp)
) {
Column() {
LnZapFeedView(zapFeedViewModel, accountViewModel, nav)
}
}
@ -1191,9 +1246,7 @@ fun TabReports(baseUser: User, accountViewModel: AccountViewModel, nav: (String)
WatchReportsAndUpdateFeed(baseUser, feedViewModel)
Column(Modifier.fillMaxHeight()) {
Column(
modifier = Modifier.padding(vertical = 0.dp)
) {
Column() {
RefresheableFeedView(feedViewModel, null, accountViewModel, nav, enablePullRefresh = false)
}
}
@ -1346,16 +1399,16 @@ fun ShowUserButton(onClick: () -> Unit) {
@Composable
fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () -> Unit, accountViewModel: AccountViewModel) {
val clipboardManager = LocalClipboardManager.current
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account ?: return
val scope = rememberCoroutineScope()
DropdownMenu(
expanded = popupExpanded,
onDismissRequest = onDismiss
) {
val clipboardManager = LocalClipboardManager.current
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account!!
val scope = rememberCoroutineScope()
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(user.pubkeyNpub())); onDismiss() }) {
Text(stringResource(R.string.copy_user_id))
}

View File

@ -87,6 +87,7 @@ import com.vitorpamplona.amethyst.ui.screen.LoadingFeed
import com.vitorpamplona.amethyst.ui.screen.NostrVideoFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys
import com.vitorpamplona.amethyst.ui.screen.rememberForeverPagerState
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import kotlinx.collections.immutable.ImmutableList
import kotlinx.coroutines.Dispatchers
@ -397,8 +398,8 @@ fun ReactionsColumn(baseNote: Note, accountViewModel: AccountViewModel, nav: (St
BoostReaction(baseNote, accountViewModel, iconSize = 40.dp) {
wantsToQuote = baseNote
}*/
LikeReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, heartSize = 35.dp, 28.sp)
ZapReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, animationSize = 35.dp)
LikeReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, heartSize = Size35dp, 28.sp)
ZapReaction(baseNote, grayTint = MaterialTheme.colors.onBackground, accountViewModel, iconSize = 40.dp, animationSize = Size35dp)
ViewCountReaction(baseNote.idHex, grayTint = MaterialTheme.colors.onBackground, iconSize = 40.dp, barChartSize = 39.dp)
}
}

View File

@ -40,6 +40,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ConnectOrbotDialog
import com.vitorpamplona.amethyst.ui.theme.Size35dp
import com.vitorpamplona.amethyst.ui.theme.placeholderText
import java.util.*
@ -275,7 +276,7 @@ fun LoginPage(
}
}
},
shape = RoundedCornerShape(35.dp),
shape = RoundedCornerShape(Size35dp),
modifier = Modifier
.fillMaxWidth()
.height(50.dp),

View File

@ -22,3 +22,5 @@ val ChatBubbleShapeThem = RoundedCornerShape(3.dp, 15.dp, 15.dp, 15.dp)
val StdButtonSizeModifier = Modifier.size(20.dp)
val StdHorzSpacer = Modifier.width(5.dp)
val DoubleHorzSpacer = Modifier.width(10.dp)
val Size35dp = 35.dp