diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt index 842e2b685..40d517fd1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NewPostView.kt @@ -38,7 +38,6 @@ import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.model.TextNoteEvent 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.screen.loggedIn.UserLine import kotlinx.coroutines.delay @@ -74,9 +73,22 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n decorFitsSystemWindows = false ) ) { - Surface(modifier = Modifier.fillMaxWidth().fillMaxHeight()) { - Column(modifier = Modifier.fillMaxWidth().fillMaxHeight()) { - Column(modifier = Modifier.padding(10.dp).imePadding().weight(1f)) { + Surface( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .fillMaxHeight() + ) { + Column( + modifier = Modifier + .padding(start = 10.dp, end = 10.dp, top = 10.dp) + .imePadding() + .weight(1f) + ) { Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween, @@ -87,12 +99,6 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n onClose() }) - UploadFromGallery( - isUploading = postViewModel.isUploadingImage - ) { - postViewModel.upload(it, context) - } - PostButton( onPost = { postViewModel.sendPost() @@ -104,9 +110,15 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n } 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) { ReplyInformation(postViewModel.replyTos, postViewModel.mentions, account, "✖ ") { 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 ) ) { - 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 + ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt index ce0800e98..a266e116a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/UploadFromGallery.kt @@ -1,17 +1,15 @@ -package com.vitorpamplona.amethyst.ui.navigation +package com.vitorpamplona.amethyst.ui.actions import android.net.Uri import android.os.Build import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.material.Button -import androidx.compose.material.Text +import androidx.compose.foundation.layout.* +import androidx.compose.material.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.google.accompanist.permissions.ExperimentalPermissionsApi @@ -47,15 +45,23 @@ fun UploadFromGallery( ) } else { Box() { - Button( + TextButton( modifier = Modifier - .align(Alignment.TopCenter) - .padding(4.dp), + .align(Alignment.TopCenter), enabled = !isUploading, onClick = { 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) { Text(stringResource(R.string.upload_image)) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt index 4bc794766..785491414 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt @@ -31,10 +31,13 @@ import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.platform.LocalContext 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.style.TextAlign import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.text.withStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController @@ -49,7 +52,11 @@ import com.vitorpamplona.amethyst.ui.components.ResizeImage import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @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 note = noteState?.note @@ -84,24 +91,43 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr LaunchedEffect(key1 = notificationCache, key2 = note) { note.createdAt()?.let { - hasNewMessages = it > notificationCache.cache.load("Channel/${channel.idHex}", context) + hasNewMessages = + it > notificationCache.cache.load("Channel/${channel.idHex}", context) } } ChannelName( channelPicture = channel.profilePicture(), - channelPicturePlaceholder = BitmapPainter(RoboHashCache.get(context, channel.idHex)), + channelPicturePlaceholder = BitmapPainter( + RoboHashCache.get( + context, + channel.idHex + ) + ), channelTitle = { 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, modifier = it, style = LocalTextStyle.current.copy(textDirection = TextDirection.Content) ) - Text( - " ${stringResource(R.string.public_chat)}", - color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f) - ) }, channelLastTime = note.createdAt(), channelLastContent = "${author?.toBestDisplayName()}: " + description, @@ -127,12 +153,21 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr LaunchedEffect(key1 = notificationCache, key2 = note) { noteEvent?.let { - hasNewMessages = it.createdAt() > notificationCache.cache.load("Room/${userToComposeOn.pubkeyHex}", context) + hasNewMessages = it.createdAt() > notificationCache.cache.load( + "Room/${userToComposeOn.pubkeyHex}", + context + ) } } ChannelName( - channelPicture = { UserPicture(userToComposeOn, account.userProfile(), size = 55.dp) }, + channelPicture = { + UserPicture( + userToComposeOn, + account.userProfile(), + size = 55.dp + ) + }, channelTitle = { UsernameDisplay(userToComposeOn, it) }, channelLastTime = note.createdAt(), 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) { Text( channelLastContent, diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt index 8f8a5914a..c505c5738 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedOff/LoginScreen.kt @@ -1,39 +1,18 @@ package com.vitorpamplona.amethyst.ui.screen import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Arrangement -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.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.ClickableText import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Button -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.* import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.outlined.VisibilityOff -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi 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.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.TextStyle -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.* +import androidx.compose.ui.text.input.* import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.R +import java.util.* @OptIn(ExperimentalComposeUiApi::class) @Composable @@ -178,13 +153,29 @@ fun LoginPage(accountViewModel: AccountStateViewModel) { 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( - text = AnnotatedString(stringResource(R.string.terms_of_use)), - onClick = { runCatching { uri.openUri("https://github.com/vitorpamplona/amethyst/blob/main/PRIVACY.md") } }, - style = LocalTextStyle.current.copy(color = MaterialTheme.colors.primary) - ) + text = annotatedTermsString + ) { spanOffset -> + 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()) { @@ -201,7 +192,8 @@ fun LoginPage(accountViewModel: AccountStateViewModel) { Button( onClick = { 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()) { @@ -240,7 +232,8 @@ fun LoginPage(accountViewModel: AccountStateViewModel) { if (acceptedTerms.value) { accountViewModel.newKey() } else { - termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required) + termsAcceptanceIsRequired = + context.getString(R.string.acceptance_of_terms_is_required) } }, style = TextStyle( diff --git a/app/src/main/res/drawable-anydpi/ic_add_photo.xml b/app/src/main/res/drawable-anydpi/ic_add_photo.xml new file mode 100644 index 000000000..4ebcf7e03 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_add_photo.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_close.xml b/app/src/main/res/drawable-anydpi/ic_close.xml new file mode 100644 index 000000000..844b6b62e --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_close.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3c485cbaa..6501cff66 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -67,7 +67,7 @@ Описание "О нас.. " Что нового? - Опубликовать + Отправить Сохранить Создать Отменить @@ -92,7 +92,7 @@ LN URL (устаревш.) Фото сохранено в галерею Не удалось сохранить фото - Загрузить\nфото + Загрузить фото Загрузка… Пользователь не установил Lightning адрес для получения чаевых "ответить.. " diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index a8a541768..07f348f19 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -67,7 +67,7 @@ Опис "Про нас.. " Що нового? - Опублікувати + Надіслати Зберегти Створити Скасувати @@ -92,7 +92,7 @@ LN URL (застарівш.) Фото збережено до галереї Не вдалося зберегти фото - Завантажити\nфото + Завантажити фото Завантаження… Користувач не встановив Lightning адресу для отримання чайових "відповісти.. "