Merge pull request #221 from Radiokot/fix/looong_buttons

Fix looong buttons due to localization
This commit is contained in:
Vitor Pamplona
2023-03-08 13:58:40 -05:00
committed by GitHub
8 changed files with 147 additions and 75 deletions

View File

@@ -38,7 +38,6 @@ import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.TextNoteEvent import com.vitorpamplona.amethyst.service.model.TextNoteEvent
import com.vitorpamplona.amethyst.ui.components.* import com.vitorpamplona.amethyst.ui.components.*
import com.vitorpamplona.amethyst.ui.navigation.UploadFromGallery
import com.vitorpamplona.amethyst.ui.note.ReplyInformation import com.vitorpamplona.amethyst.ui.note.ReplyInformation
import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine import com.vitorpamplona.amethyst.ui.screen.loggedIn.UserLine
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -74,9 +73,22 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
decorFitsSystemWindows = false decorFitsSystemWindows = false
) )
) { ) {
Surface(modifier = Modifier.fillMaxWidth().fillMaxHeight()) { Surface(
Column(modifier = Modifier.fillMaxWidth().fillMaxHeight()) { modifier = Modifier
Column(modifier = Modifier.padding(10.dp).imePadding().weight(1f)) { .fillMaxWidth()
.fillMaxHeight()
) {
Column(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
) {
Column(
modifier = Modifier
.padding(start = 10.dp, end = 10.dp, top = 10.dp)
.imePadding()
.weight(1f)
) {
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
@@ -87,12 +99,6 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
onClose() onClose()
}) })
UploadFromGallery(
isUploading = postViewModel.isUploadingImage
) {
postViewModel.upload(it, context)
}
PostButton( PostButton(
onPost = { onPost = {
postViewModel.sendPost() postViewModel.sendPost()
@@ -104,9 +110,15 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
} }
Row( Row(
modifier = Modifier.fillMaxWidth().weight(1f) modifier = Modifier
.fillMaxWidth()
.weight(1f)
) {
Column(
modifier = Modifier
.fillMaxWidth()
.verticalScroll(scroolState)
) { ) {
Column(modifier = Modifier.fillMaxWidth().verticalScroll(scroolState)) {
if (postViewModel.replyTos != null && baseReplyTo?.event is TextNoteEvent) { if (postViewModel.replyTos != null && baseReplyTo?.event is TextNoteEvent) {
ReplyInformation(postViewModel.replyTos, postViewModel.mentions, account, "") { ReplyInformation(postViewModel.replyTos, postViewModel.mentions, account, "") {
postViewModel.removeFromReplyList(it) postViewModel.removeFromReplyList(it)
@@ -203,6 +215,14 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
} }
} }
} }
Row(modifier = Modifier.fillMaxWidth()) {
UploadFromGallery(
isUploading = postViewModel.isUploadingImage
) {
postViewModel.upload(it, context)
}
}
} }
} }
} }
@@ -221,7 +241,12 @@ fun CloseButton(onCancel: () -> Unit) {
backgroundColor = Color.Gray backgroundColor = Color.Gray
) )
) { ) {
Text(text = stringResource(R.string.cancel), color = Color.White) Icon(
painter = painterResource(id = R.drawable.ic_close),
contentDescription = stringResource(id = R.string.cancel),
modifier = Modifier.size(20.dp),
tint = Color.White
)
} }
} }

View File

@@ -1,17 +1,15 @@
package com.vitorpamplona.amethyst.ui.navigation package com.vitorpamplona.amethyst.ui.actions
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Column import androidx.compose.material.*
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.ExperimentalPermissionsApi
@@ -47,15 +45,23 @@ fun UploadFromGallery(
) )
} else { } else {
Box() { Box() {
Button( TextButton(
modifier = Modifier modifier = Modifier
.align(Alignment.TopCenter) .align(Alignment.TopCenter),
.padding(4.dp),
enabled = !isUploading, enabled = !isUploading,
onClick = { onClick = {
showGallerySelect = true showGallerySelect = true
} }
) { ) {
Icon(
painter = painterResource(id = R.drawable.ic_add_photo),
contentDescription = stringResource(id = R.string.upload_image),
modifier = Modifier
.height(20.dp)
.padding(end = 8.dp),
tint = MaterialTheme.colors.primary
)
if (!isUploading) { if (!isUploading) {
Text(stringResource(R.string.upload_image)) Text(stringResource(R.string.upload_image))
} else { } else {

View File

@@ -31,10 +31,13 @@ import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
@@ -49,7 +52,11 @@ import com.vitorpamplona.amethyst.ui.components.ResizeImage
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@Composable @Composable
fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navController: NavController) { fun ChatroomCompose(
baseNote: Note,
accountViewModel: AccountViewModel,
navController: NavController
) {
val noteState by baseNote.live().metadata.observeAsState() val noteState by baseNote.live().metadata.observeAsState()
val note = noteState?.note val note = noteState?.note
@@ -84,24 +91,43 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
LaunchedEffect(key1 = notificationCache, key2 = note) { LaunchedEffect(key1 = notificationCache, key2 = note) {
note.createdAt()?.let { note.createdAt()?.let {
hasNewMessages = it > notificationCache.cache.load("Channel/${channel.idHex}", context) hasNewMessages =
it > notificationCache.cache.load("Channel/${channel.idHex}", context)
} }
} }
ChannelName( ChannelName(
channelPicture = channel.profilePicture(), channelPicture = channel.profilePicture(),
channelPicturePlaceholder = BitmapPainter(RoboHashCache.get(context, channel.idHex)), channelPicturePlaceholder = BitmapPainter(
RoboHashCache.get(
context,
channel.idHex
)
),
channelTitle = { channelTitle = {
Text( Text(
"${channel.info.name}", text = buildAnnotatedString {
withStyle(
SpanStyle(
fontWeight = FontWeight.Bold
)
) {
append(channel.info.name)
}
withStyle(
SpanStyle(
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
fontWeight = FontWeight.Normal
)
) {
append(" ${stringResource(id = R.string.public_chat)}")
}
},
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = it, modifier = it,
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content) style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
) )
Text(
" ${stringResource(R.string.public_chat)}",
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
}, },
channelLastTime = note.createdAt(), channelLastTime = note.createdAt(),
channelLastContent = "${author?.toBestDisplayName()}: " + description, channelLastContent = "${author?.toBestDisplayName()}: " + description,
@@ -127,12 +153,21 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
LaunchedEffect(key1 = notificationCache, key2 = note) { LaunchedEffect(key1 = notificationCache, key2 = note) {
noteEvent?.let { noteEvent?.let {
hasNewMessages = it.createdAt() > notificationCache.cache.load("Room/${userToComposeOn.pubkeyHex}", context) hasNewMessages = it.createdAt() > notificationCache.cache.load(
"Room/${userToComposeOn.pubkeyHex}",
context
)
} }
} }
ChannelName( ChannelName(
channelPicture = { UserPicture(userToComposeOn, account.userProfile(), size = 55.dp) }, channelPicture = {
UserPicture(
userToComposeOn,
account.userProfile(),
size = 55.dp
)
},
channelTitle = { UsernameDisplay(userToComposeOn, it) }, channelTitle = { UsernameDisplay(userToComposeOn, it) },
channelLastTime = note.createdAt(), channelLastTime = note.createdAt(),
channelLastContent = accountViewModel.decrypt(note), channelLastContent = accountViewModel.decrypt(note),
@@ -209,7 +244,10 @@ fun ChannelName(
} }
} }
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
if (channelLastContent != null) { if (channelLastContent != null) {
Text( Text(
channelLastContent, channelLastContent,

View File

@@ -1,39 +1,18 @@
package com.vitorpamplona.amethyst.ui.screen package com.vitorpamplona.amethyst.ui.screen
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.ClickableText
import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Button import androidx.compose.material.*
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Checkbox
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedTextField
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
@@ -50,18 +29,14 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.*
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.*
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import java.util.*
@OptIn(ExperimentalComposeUiApi::class) @OptIn(ExperimentalComposeUiApi::class)
@Composable @Composable
@@ -178,13 +153,29 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
onCheckedChange = { acceptedTerms.value = it } onCheckedChange = { acceptedTerms.value = it }
) )
Text(text = stringResource(R.string.i_accept_the)) val clickableTextStyle =
SpanStyle(color = MaterialTheme.colors.primary)
val annotatedTermsString = buildAnnotatedString {
append(stringResource(R.string.i_accept_the))
withStyle(clickableTextStyle) {
pushStringAnnotation("openTerms", "")
append(stringResource(R.string.terms_of_use))
}
}
ClickableText( ClickableText(
text = AnnotatedString(stringResource(R.string.terms_of_use)), text = annotatedTermsString
onClick = { runCatching { uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") } }, ) { spanOffset ->
style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary) annotatedTermsString.getStringAnnotations(spanOffset, spanOffset)
) .firstOrNull()
?.also { span ->
if (span.tag == "openTerms") {
runCatching { uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") }
}
}
}
} }
if (termsAcceptanceIsRequired.isNotBlank()) { if (termsAcceptanceIsRequired.isNotBlank()) {
@@ -201,7 +192,8 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
Button( Button(
onClick = { onClick = {
if (!acceptedTerms.value) { if (!acceptedTerms.value) {
termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) termsAcceptanceIsRequired =
context.getString(R.string.acceptance_of_terms_is_required)
} }
if (key.value.text.isBlank()) { if (key.value.text.isBlank()) {
@@ -240,7 +232,8 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
if (acceptedTerms.value) { if (acceptedTerms.value) {
accountViewModel.newKey() accountViewModel.newKey()
} else { } else {
termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) termsAcceptanceIsRequired =
context.getString(R.string.acceptance_of_terms_is_required)
} }
}, },
style = TextStyle( style = TextStyle(

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,7v2.99s-1.99,0.01 -2,0L17,7h-3s0.01,-1.99 0,-2h3L17,2h2v3h3v2h-3zM16,11L16,8h-3L13,5L5,5c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2v-8h-3zM5,19l3,-4 2,3 3,-4 4,5L5,19z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>

View File

@@ -67,7 +67,7 @@
<string name="description">Описание</string> <string name="description">Описание</string>
<string name="about_us">"О нас.. "</string> <string name="about_us">"О нас.. "</string>
<string name="what_s_on_your_mind">Что нового?</string> <string name="what_s_on_your_mind">Что нового?</string>
<string name="post">Опубликовать</string> <string name="post">Отправить</string>
<string name="save">Сохранить</string> <string name="save">Сохранить</string>
<string name="create">Создать</string> <string name="create">Создать</string>
<string name="cancel">Отменить</string> <string name="cancel">Отменить</string>
@@ -92,7 +92,7 @@
<string name="ln_url_outdated">LN URL (устаревш.)</string> <string name="ln_url_outdated">LN URL (устаревш.)</string>
<string name="image_saved_to_the_gallery">Фото сохранено в галерею</string> <string name="image_saved_to_the_gallery">Фото сохранено в галерею</string>
<string name="failed_to_save_the_image">Не удалось сохранить фото</string> <string name="failed_to_save_the_image">Не удалось сохранить фото</string>
<string name="upload_image">Загрузить\nфото</string> <string name="upload_image">Загрузить фото</string>
<string name="uploading">Загрузка…</string> <string name="uploading">Загрузка…</string>
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Пользователь не установил Lightning адрес для получения чаевых</string> <string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Пользователь не установил Lightning адрес для получения чаевых</string>
<string name="reply_here">"ответить.. "</string> <string name="reply_here">"ответить.. "</string>

View File

@@ -67,7 +67,7 @@
<string name="description">Опис</string> <string name="description">Опис</string>
<string name="about_us">"Про нас.. "</string> <string name="about_us">"Про нас.. "</string>
<string name="what_s_on_your_mind">Що нового?</string> <string name="what_s_on_your_mind">Що нового?</string>
<string name="post">Опублікувати</string> <string name="post">Надіслати</string>
<string name="save">Зберегти</string> <string name="save">Зберегти</string>
<string name="create">Створити</string> <string name="create">Створити</string>
<string name="cancel">Скасувати</string> <string name="cancel">Скасувати</string>
@@ -92,7 +92,7 @@
<string name="ln_url_outdated">LN URL (застарівш.)</string> <string name="ln_url_outdated">LN URL (застарівш.)</string>
<string name="image_saved_to_the_gallery">Фото збережено до галереї</string> <string name="image_saved_to_the_gallery">Фото збережено до галереї</string>
<string name="failed_to_save_the_image">Не вдалося зберегти фото</string> <string name="failed_to_save_the_image">Не вдалося зберегти фото</string>
<string name="upload_image">Завантажити\nфото</string> <string name="upload_image">Завантажити фото</string>
<string name="uploading">Завантаження…</string> <string name="uploading">Завантаження…</string>
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Користувач не встановив Lightning адресу для отримання чайових</string> <string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">Користувач не встановив Lightning адресу для отримання чайових</string>
<string name="reply_here">"відповісти.. "</string> <string name="reply_here">"відповісти.. "</string>