extract most strings to strings.xml and add arabic language to strings.xml file

This commit is contained in:
Rashed
2023-03-01 07:50:01 +03:00
parent 3780ed001a
commit e6afa7fb9a
47 changed files with 714 additions and 241 deletions
@@ -88,7 +88,7 @@ class Relay(
"NOTICE" -> listeners.forEach {
//Log.w("Relay", "Relay onNotice $url, $channel")
// "channel" being the second string in the string array ...
it.onError(this@Relay, channel, Error("Relay sent notice: $channel"))
it.onError(this@Relay, channel, Error("Relay sent notice: " + channel))
}
"OK" -> listeners.forEach {
//Log.w("Relay", "Relay onOK $url, $channel")
@@ -10,6 +10,7 @@ import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.core.net.toUri
import java.io.File
import com.vitorpamplona.amethyst.R
import okhttp3.*
import okio.BufferedSource
import okio.IOException
@@ -49,7 +50,7 @@ object ImageSaver {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val contentType = response.header("Content-Type")
checkNotNull(contentType) {
"Can't find out the content type"
context.getString(R.string.can_t_find_out_the_content_type)
}
saveContentQ(
@@ -57,6 +58,7 @@ object ImageSaver {
contentType = contentType,
contentSource = response.body.source(),
contentResolver = context.contentResolver,
context = context
)
} else {
saveContentDefault(
@@ -80,6 +82,7 @@ object ImageSaver {
contentType: String,
contentSource: BufferedSource,
contentResolver: ContentResolver,
context: Context
) {
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
@@ -93,13 +96,13 @@ object ImageSaver {
val uri =
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
checkNotNull(uri) {
"Can't insert the new content"
context.getString(R.string.can_t_insert_the_new_content)
}
try {
val outputStream = contentResolver.openOutputStream(uri)
checkNotNull(outputStream) {
"Can't open the content output stream"
context.getString(R.string.can_t_open_the_content_output_stream)
}
outputStream.use {
@@ -1,6 +1,7 @@
package com.vitorpamplona.amethyst.ui.actions
import android.content.ContentResolver
import android.content.Context
import android.net.Uri
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import java.io.IOException
@@ -8,6 +9,7 @@ import java.util.UUID
import okhttp3.Call
import okhttp3.Callback
import okhttp3.MediaType
import com.vitorpamplona.amethyst.R
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
@@ -23,6 +25,7 @@ object ImageUploader {
contentResolver: ContentResolver,
onSuccess: (String) -> Unit,
onError: (Throwable) -> Unit,
context : Context
) {
val contentType = contentResolver.getType(uri)
@@ -40,7 +43,7 @@ object ImageUploader {
override fun writeTo(sink: BufferedSink) {
val imageInputStream = contentResolver.openInputStream(uri)
checkNotNull(imageInputStream) {
"Can't open the image input stream"
context.getString(R.string.can_t_open_the_image_input_stream)
}
imageInputStream.source().use(sink::writeAll)
@@ -63,7 +66,7 @@ object ImageUploader {
val tree = jacksonObjectMapper().readTree(body.string())
val url = tree?.get("data")?.get("link")?.asText()
checkNotNull(url) {
"There must be an uploaded image URL in the response"
context.getString(R.string.there_must_be_an_uploaded_image_url_in_the_response)
}
onSuccess(url)
@@ -17,12 +17,15 @@ import androidx.compose.runtime.Composable
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.TextStyle
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Channel
@@ -67,13 +70,13 @@ fun NewChannelView(onClose: () -> Unit, account: Account, channel: Channel? = nu
Spacer(modifier = Modifier.height(15.dp))
OutlinedTextField(
label = { Text(text = "Channel Name") },
label = { Text(text = stringResource(R.string.channel_name)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.channelName.value,
onValueChange = { postViewModel.channelName.value = it },
placeholder = {
Text(
text = "My Awesome Group",
text = stringResource(R.string.my_awesome_group),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -86,7 +89,7 @@ fun NewChannelView(onClose: () -> Unit, account: Account, channel: Channel? = nu
Spacer(modifier = Modifier.height(15.dp))
OutlinedTextField(
label = { Text(text = "Picture Url") },
label = { Text(text = stringResource(R.string.picture_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.channelPicture.value,
onValueChange = { postViewModel.channelPicture.value = it },
@@ -101,13 +104,13 @@ fun NewChannelView(onClose: () -> Unit, account: Account, channel: Channel? = nu
Spacer(modifier = Modifier.height(15.dp))
OutlinedTextField(
label = { Text(text = "Description") },
label = { Text(text = stringResource(R.string.description)) },
modifier = Modifier.fillMaxWidth().height(100.dp),
value = postViewModel.channelDescription.value,
onValueChange = { postViewModel.channelDescription.value = it },
placeholder = {
Text(
text = "About us.. ",
text = stringResource(R.string.about_us),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -25,6 +25,7 @@ import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextDirection
import androidx.compose.ui.unit.dp
@@ -136,7 +137,7 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
},
placeholder = {
Text(
text = "What's on your mind?",
text = stringResource(R.string.what_s_on_your_mind),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -221,7 +222,7 @@ fun CloseButton(onCancel: () -> Unit) {
backgroundColor = Color.Gray
)
) {
Text(text = "Cancel", color = Color.White)
Text(text = stringResource(R.string.cancel), color = Color.White)
}
}
@@ -240,7 +241,7 @@ fun PostButton(onPost: () -> Unit = {}, isActive: Boolean, modifier: Modifier =
backgroundColor = if (isActive) MaterialTheme.colors.primary else Color.Gray
)
) {
Text(text = "Post", color = Color.White)
Text(text = stringResource(R.string.post), color = Color.White)
}
}
@@ -259,7 +260,7 @@ fun SaveButton(onPost: () -> Unit = {}, isActive: Boolean, modifier: Modifier =
backgroundColor = if (isActive) MaterialTheme.colors.primary else Color.Gray
)
) {
Text(text = "Save", color = Color.White)
Text(text = stringResource(R.string.save), color = Color.White)
}
}
@@ -278,7 +279,7 @@ fun CreateButton(onPost: () -> Unit = {}, isActive: Boolean, modifier: Modifier
backgroundColor = if (isActive) MaterialTheme.colors.primary else Color.Gray
)
) {
Text(text = "Create", color = Color.White)
Text(text = stringResource(R.string.create), color = Color.White)
}
}
@@ -14,6 +14,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.model.parseDirtyWordForKey
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.components.isValidURL
import com.vitorpamplona.amethyst.ui.components.noProtocolUrlValidator
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -133,9 +134,10 @@ class NewPostViewModel: ViewModel() {
onError = {
isUploadingImage = false
viewModelScope.launch {
imageUploadingError.emit("Failed to upload the image")
imageUploadingError.emit(context.getString(R.string.failed_to_upload_the_image))
}
}
},
context = context
)
}
@@ -41,6 +41,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -141,7 +142,7 @@ fun ServerConfigHeader() {
Column(Modifier.weight(1f)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "Relay Address",
text = stringResource(R.string.relay_address),
modifier = Modifier.weight(1f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
@@ -154,7 +155,7 @@ fun ServerConfigHeader() {
Spacer(modifier = Modifier.size(25.dp))
Text(
text = "Posts",
text = stringResource(R.string.posts),
maxLines = 1,
fontSize = 14.sp,
modifier = Modifier.weight(1f),
@@ -164,7 +165,7 @@ fun ServerConfigHeader() {
Spacer(modifier = Modifier.size(10.dp))
Text(
text = "Posts",
text = stringResource(id = R.string.posts),
maxLines = 1,
fontSize = 14.sp,
modifier = Modifier.weight(1f),
@@ -174,7 +175,7 @@ fun ServerConfigHeader() {
Spacer(modifier = Modifier.size(10.dp))
Text(
text = "Errors",
text = stringResource(R.string.errors),
maxLines = 1,
fontSize = 14.sp,
modifier = Modifier.weight(1f),
@@ -227,7 +228,9 @@ fun ServerConfig(
Icon(
imageVector = Icons.Default.Cancel,
null,
modifier = Modifier.padding(end = 5.dp).size(15.dp),
modifier = Modifier
.padding(end = 5.dp)
.size(15.dp),
tint = Color.Red
)
}
@@ -252,8 +255,10 @@ fun ServerConfig(
) {
Icon(
painterResource(R.drawable.ic_home),
"Home Feed",
modifier = Modifier.padding(end = 5.dp).size(15.dp),
stringResource(R.string.home_feed),
modifier = Modifier
.padding(end = 5.dp)
.size(15.dp),
tint = if (item.feedTypes.contains(FeedType.FOLLOWS)) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -265,8 +270,10 @@ fun ServerConfig(
) {
Icon(
painterResource(R.drawable.ic_dm),
"Private Message Feed",
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
stringResource(R.string.private_message_feed),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.feedTypes.contains(FeedType.PRIVATE_DMS)) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -278,8 +285,10 @@ fun ServerConfig(
) {
Icon(
imageVector = Icons.Default.Groups,
"Public Chat Feed",
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
stringResource(R.string.public_chat_feed),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.feedTypes.contains(FeedType.PUBLIC_CHATS)) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -291,8 +300,10 @@ fun ServerConfig(
) {
Icon(
imageVector = Icons.Default.Public,
"Global Feed",
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
stringResource(R.string.global_feed),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.feedTypes.contains(FeedType.GLOBAL)) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -310,7 +321,9 @@ fun ServerConfig(
Icon(
imageVector = Icons.Default.Download,
null,
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.read) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -332,7 +345,9 @@ fun ServerConfig(
Icon(
imageVector = Icons.Default.Upload,
null,
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.write) Color.Green else MaterialTheme.colors.onSurface.copy(
alpha = 0.32f
)
@@ -350,7 +365,9 @@ fun ServerConfig(
Icon(
imageVector = Icons.Default.SyncProblem,
null,
modifier = Modifier.padding(horizontal = 5.dp).size(15.dp),
modifier = Modifier
.padding(horizontal = 5.dp)
.size(15.dp),
tint = if (item.errorCount > 0) Color.Yellow else Color.Green
)
@@ -396,7 +413,7 @@ fun EditableServerConfig(relayToAdd: String, onNewRelay: (RelaySetupInfo) -> Uni
Row(verticalAlignment = Alignment.CenterVertically) {
OutlinedTextField(
label = { Text(text = "Add a Relay") },
label = { Text(text = stringResource(R.string.add_a_relay)) },
modifier = Modifier.weight(1f),
value = url,
onValueChange = { url = it },
@@ -449,7 +466,7 @@ fun EditableServerConfig(relayToAdd: String, onNewRelay: (RelaySetupInfo) -> Uni
backgroundColor = if (url.isNotBlank()) MaterialTheme.colors.primary else MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
) {
Text(text = "Add", color = Color.White)
Text(text = stringResource(id = R.string.add), color = Color.White)
}
}
@@ -17,11 +17,13 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account
@OptIn(ExperimentalComposeUiApi::class)
@@ -69,13 +71,13 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Row(modifier = Modifier.fillMaxWidth(1f), verticalAlignment = Alignment.CenterVertically) {
OutlinedTextField(
label = { Text(text = "Display Name") },
label = { Text(text = stringResource(R.string.display_name)) },
modifier = Modifier.weight(1f),
value = postViewModel.displayName.value,
onValueChange = { postViewModel.displayName.value = it },
placeholder = {
Text(
text = "My display name",
text = stringResource(R.string.my_display_name),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -88,13 +90,13 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Text("@", Modifier.padding(5.dp))
OutlinedTextField(
label = { Text(text = "Username") },
label = { Text(text = stringResource(R.string.username)) },
modifier = Modifier.weight(1f),
value = postViewModel.userName.value,
onValueChange = { postViewModel.userName.value = it },
placeholder = {
Text(
text = "My username",
text = stringResource(R.string.my_username),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -105,7 +107,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "About me") },
label = { Text(text = stringResource(R.string.about_me)) },
modifier = Modifier
.fillMaxWidth()
.height(100.dp),
@@ -113,7 +115,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
onValueChange = { postViewModel.about.value = it },
placeholder = {
Text(
text = "About me",
text = stringResource(id = R.string.about_me),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -126,7 +128,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "Avatar URL") },
label = { Text(text = stringResource(R.string.avatar_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.picture.value,
onValueChange = { postViewModel.picture.value = it },
@@ -142,7 +144,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "Banner URL") },
label = { Text(text = stringResource(R.string.banner_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.banner.value,
onValueChange = { postViewModel.banner.value = it },
@@ -158,7 +160,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "Website URL") },
label = { Text(text = stringResource(R.string.website_url)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.website.value,
onValueChange = { postViewModel.website.value = it },
@@ -174,7 +176,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "NIP-05") },
label = { Text(text = stringResource(R.string.nip_05)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.nip05.value,
onValueChange = { postViewModel.nip05.value = it },
@@ -189,7 +191,7 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "LN Address") },
label = { Text(text = stringResource(R.string.ln_address)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.lnAddress.value,
onValueChange = { postViewModel.lnAddress.value = it },
@@ -205,13 +207,13 @@ fun NewUserMetadataView(onClose: () -> Unit, account: Account) {
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = "LN URL (outdated)") },
label = { Text(text = stringResource(R.string.ln_url_outdated)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.lnURL.value,
onValueChange = { postViewModel.lnURL.value = it },
placeholder = {
Text(
text = "LNURL...",
text = stringResource(R.string.lnurl),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -11,10 +11,12 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.vitorpamplona.amethyst.R
import kotlinx.coroutines.launch
/**
@@ -29,6 +31,7 @@ fun SaveToGallery(url: String) {
val localContext = LocalContext.current
val scope = rememberCoroutineScope()
fun saveImage() {
ImageSaver.saveImage(
context = localContext,
@@ -37,7 +40,7 @@ fun SaveToGallery(url: String) {
scope.launch {
Toast.makeText(
localContext,
"Image saved to the gallery",
localContext.getString(R.string.image_saved_to_the_gallery),
Toast.LENGTH_SHORT
)
.show()
@@ -47,7 +50,7 @@ fun SaveToGallery(url: String) {
scope.launch {
Toast.makeText(
localContext,
"Failed to save the image",
localContext.getString(R.string.failed_to_save_the_image),
Toast.LENGTH_SHORT
)
.show()
@@ -78,6 +81,6 @@ fun SaveToGallery(url: String) {
backgroundColor = Color.Gray
)
) {
Text(text = "Save", color = Color.White)
Text(text = stringResource(id = R.string.save), color = Color.White)
}
}
@@ -12,10 +12,12 @@ import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState
import com.vitorpamplona.amethyst.R
@OptIn(ExperimentalPermissionsApi::class)
@Composable
@@ -54,9 +56,9 @@ fun UploadFromGallery(
}
) {
if (!isUploading) {
Text("Upload Image")
Text(stringResource(R.string.upload_image))
} else {
Text("Uploading…")
Text(stringResource(R.string.uploading))
}
}
}
@@ -68,9 +70,9 @@ fun UploadFromGallery(
enabled = !isUploading,
) {
if (!isUploading) {
Text("Upload Image")
Text(stringResource(R.string.upload_image))
} else {
Text("Uploading…")
Text(stringResource(R.string.uploading))
}
}
}
@@ -16,6 +16,8 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.ui.actions.NewChannelView
@@ -38,7 +40,7 @@ fun NewChannelButton(account: Account) {
) {
Icon(
imageVector = Icons.Outlined.Add,
contentDescription = "New Channel",
contentDescription = stringResource(R.string.new_channel),
modifier = Modifier.size(26.dp),
tint = Color.White
)
@@ -25,6 +25,8 @@ import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import com.vitorpamplona.amethyst.R
import androidx.compose.ui.res.stringResource
@Composable
fun ExpandableRichTextViewer(
@@ -67,7 +69,7 @@ fun ExpandableRichTextViewer(
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Show More", color = Color.White)
Text(text = stringResource(R.string.show_more), color = Color.White)
}
}
}
@@ -22,6 +22,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -68,7 +69,7 @@ fun InvoicePreview(lnInvoice: String) {
)
Text(
text = "Lightning Invoice",
text = stringResource(R.string.lightning_invoice),
fontSize = 20.sp,
fontWeight = FontWeight.W500,
modifier = Modifier.padding(start = 10.dp)
@@ -79,7 +80,9 @@ fun InvoicePreview(lnInvoice: String) {
amount?.let {
Text(
text = "${NumberFormat.getInstance().format(amount)} sats",
text = "${
NumberFormat.getInstance().format(amount)
} ${stringResource(id = R.string.sats)}",
fontSize = 25.sp,
fontWeight = FontWeight.W500,
modifier = Modifier
@@ -90,7 +93,9 @@ fun InvoicePreview(lnInvoice: String) {
Button(
modifier = Modifier.fillMaxWidth().padding(vertical = 10.dp),
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 10.dp),
onClick = {
runCatching {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("lightning:$lnInvoice"))
@@ -102,7 +107,7 @@ fun InvoicePreview(lnInvoice: String) {
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = "Pay", color = Color.White, fontSize = 20.sp)
Text(text = stringResource(R.string.pay), color = Color.White, fontSize = 20.sp)
}
}
}
@@ -30,6 +30,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
@@ -73,7 +74,7 @@ fun InvoiceRequest(lud16: String, toUserPubKeyHex: String, account: Account, onC
)
Text(
text = "Lightning Tips",
text = stringResource(R.string.lightning_tips),
fontSize = 20.sp,
fontWeight = FontWeight.W500,
modifier = Modifier.padding(start = 10.dp)
@@ -86,13 +87,13 @@ fun InvoiceRequest(lud16: String, toUserPubKeyHex: String, account: Account, onC
var amount by remember { mutableStateOf(1000L) }
OutlinedTextField(
label = { Text(text = "Note to Receiver") },
label = { Text(text = stringResource(R.string.note_to_receiver)) },
modifier = Modifier.fillMaxWidth(),
value = message,
onValueChange = { message = it },
placeholder = {
Text(
text = "Thank you so much!",
text = stringResource(R.string.thank_you_so_much),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -103,7 +104,7 @@ fun InvoiceRequest(lud16: String, toUserPubKeyHex: String, account: Account, onC
)
OutlinedTextField(
label = { Text(text = "Amount in Sats") },
label = { Text(text = stringResource(R.string.amount_in_sats)) },
modifier = Modifier.fillMaxWidth(),
value = amount.toString(),
onValueChange = {
@@ -152,7 +153,7 @@ fun InvoiceRequest(lud16: String, toUserPubKeyHex: String, account: Account, onC
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = "Send Sats", color = Color.White, fontSize = 20.sp)
Text(text = stringResource(R.string.send_sats), color = Color.White, fontSize = 20.sp)
}
}
}
@@ -27,6 +27,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
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.style.TextOverflow
@@ -34,6 +35,7 @@ import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.core.os.ConfigurationCompat
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.lang.LanguageTranslatorService
import com.vitorpamplona.amethyst.service.lang.ResultOrError
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -110,17 +112,17 @@ fun TranslateableRichTextViewer(
val annotatedTranslationString = buildAnnotatedString {
withStyle(clickableTextStyle) {
pushStringAnnotation("langSettings", true.toString())
append("Auto")
append(stringResource(R.string.auto))
}
append("-translated from ")
append("-${stringResource(R.string.translated_from)} ")
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", true.toString())
append(Locale(source).displayName)
}
append(" to ")
append(" ${stringResource(R.string.to)} ")
withStyle(clickableTextStyle) {
pushStringAnnotation("showOriginal", false.toString())
@@ -163,7 +165,7 @@ fun TranslateableRichTextViewer(
Spacer(modifier = Modifier.size(10.dp))
Text("Never translate from ${Locale(source).displayName}")
Text(stringResource(R.string.never_translate_from) + "${Locale(source).displayName}")
}
Divider()
DropdownMenuItem(onClick = {
@@ -181,7 +183,14 @@ fun TranslateableRichTextViewer(
Spacer(modifier = Modifier.size(10.dp))
Text("Show in ${Locale(source).displayName} first")
// TODO : Rashed translate this
Text(
"${stringResource(R.string.show_in)} ${Locale(source).displayName} ${
stringResource(
R.string.first
)
}"
)
}
DropdownMenuItem(onClick = {
accountViewModel.prefer(source, target, target)
@@ -198,7 +207,7 @@ fun TranslateableRichTextViewer(
Spacer(modifier = Modifier.size(10.dp))
Text("Show in ${Locale(target).displayName} first")
Text("${stringResource(id = R.string.show_in)} ${Locale(target).displayName} ${R.string.first}")
}
Divider()
@@ -221,7 +230,7 @@ fun TranslateableRichTextViewer(
Spacer(modifier = Modifier.size(10.dp))
Text("Always translate to ${lang.displayName}")
Text("${stringResource(R.string.always_translate_to)}${lang.displayName}")
}
}
}
@@ -8,8 +8,10 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import com.baha.url.preview.IUrlPreviewCallback
import com.baha.url.preview.UrlInfoItem
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.UrlCachedPreviewer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -18,7 +20,7 @@ import kotlinx.coroutines.withContext
@Composable
fun UrlPreview(url: String, urlText: String, showUrlIfError: Boolean = true) {
var urlPreviewState by remember { mutableStateOf<UrlPreviewState>(UrlPreviewState.Loading) }
var context = LocalContext.current
// Doesn't use a viewModel because of viewModel reusing issues (too many UrlPreview are created).
LaunchedEffect(url) {
withContext(Dispatchers.IO) {
@@ -31,7 +33,7 @@ fun UrlPreview(url: String, urlText: String, showUrlIfError: Boolean = true) {
}
override fun onFailed(throwable: Throwable) {
urlPreviewState = UrlPreviewState.Error("Error parsing preview for ${url}: ${throwable.message}")
urlPreviewState = UrlPreviewState.Error(context.getString(R.string.error_parsing_preview_for, url, throwable.message))
}
})
}
@@ -15,10 +15,12 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil.compose.AsyncImage
import com.baha.url.preview.UrlInfoItem
import com.vitorpamplona.amethyst.R
@Composable
fun UrlPreviewCard(
@@ -36,7 +38,7 @@ fun UrlPreviewCard(
Column {
AsyncImage(
model = previewInfo.image,
contentDescription = "Preview Card Image for ${url}",
contentDescription = stringResource(R.string.preview_card_image_for, url),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxWidth()
)
@@ -17,7 +17,9 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.stringResource
import coil.compose.AsyncImage
import com.vitorpamplona.amethyst.R
@Composable
fun ZoomableAsyncImage(imageUrl: String) {
@@ -46,14 +48,16 @@ fun ZoomableAsyncImage(imageUrl: String) {
) {
AsyncImage(
model = imageUrl,
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
contentScale = ContentScale.FillWidth,
modifier = Modifier.fillMaxSize().graphicsLayer(
scaleX = scale,
scaleY = scale,
translationX = offsetX,
translationY = offsetY
),
modifier = Modifier
.fillMaxSize()
.graphicsLayer(
scaleX = scale,
scaleY = scale,
translationX = offsetX,
translationY = offsetY
),
)
}
}
@@ -36,6 +36,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
@@ -201,7 +202,7 @@ fun MainTopBar(scaffoldState: ScaffoldState, accountViewModel: AccountViewModel)
placeholder = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
modifier = Modifier
.width(34.dp)
.height(34.dp)
@@ -51,6 +51,8 @@ import com.vitorpamplona.amethyst.ui.components.ResizeImage
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import kotlinx.coroutines.launch
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.platform.LocalContext
@Composable
fun DrawerContent(navController: NavHostController,
@@ -111,7 +113,7 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol
if (banner != null && banner.isNotBlank()) {
AsyncImageProxy(
model = ResizeImage(banner, 150.dp),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
@@ -120,7 +122,7 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol
} else {
Image(
painter = painterResource(R.drawable.profile_banner),
contentDescription = "Profile Banner",
contentDescription = stringResource(R.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
@@ -131,7 +133,7 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol
Column(modifier = modifier) {
AsyncImageProxy(
model = ResizeImage(accountUser.profilePicture(), 100.dp),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
placeholder = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(ctx, accountUser.pubkeyHex)),
@@ -187,11 +189,11 @@ fun ProfileContent(baseAccountUser: User, modifier: Modifier = Modifier, scaffol
})) {
Row() {
Text("${accountUserFollows.follows.size}", fontWeight = FontWeight.Bold)
Text(" Following")
Text(stringResource(R.string.following))
}
Row(modifier = Modifier.padding(start = 10.dp)) {
Text("${accountUserFollows.followers.size}", fontWeight = FontWeight.Bold)
Text(" Followers")
Text(stringResource(R.string.followers))
}
}
}
@@ -216,7 +218,7 @@ fun ListContent(
scaffoldState,
"User/${accountUser.pubkeyHex}",
Route.Profile.icon,
"Profile"
stringResource(R.string.profile)
)
Divider(
@@ -231,14 +233,14 @@ fun ListContent(
}
})) {
Text(
text = "Security Filters",
text = stringResource(R.string.security_filters),
fontSize = 18.sp,
fontWeight = W500
)
}
Row(modifier = Modifier.clickable(onClick = { accountViewModel.logOff() })) {
Text(
text = "Log out",
text = stringResource(R.string.log_out),
modifier = Modifier.padding(vertical = 15.dp),
fontSize = 18.sp,
fontWeight = W500
@@ -15,9 +15,11 @@ 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.unit.dp
import androidx.navigation.NavController
import com.google.accompanist.flowlayout.FlowRow
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
@@ -37,7 +39,7 @@ fun BlankNote(modifier: Modifier = Modifier, isQuote: Boolean = false) {
horizontalArrangement = Arrangement.Center
) {
Text(
text = "Post not found",
text = stringResource(R.string.referenced_post_not_found),
modifier = Modifier.padding(30.dp),
color = Color.Gray,
)
@@ -67,7 +69,7 @@ fun HiddenNote(reports: Set<Note>, loggedIn: User, modifier: Modifier = Modifier
) {
Column(horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(30.dp)) {
Text(
text = "Post was flagged as inappropriate by",
text = stringResource(R.string.post_was_flagged_as_inappropriate_by),
color = Color.Gray,
)
FlowRow(modifier = Modifier.padding(top = 10.dp)) {
@@ -91,7 +93,7 @@ fun HiddenNote(reports: Set<Note>, loggedIn: User, modifier: Modifier = Modifier
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Show Anyway", color = Color.White)
Text(text = stringResource(R.string.show_anyway), color = Color.White)
}
}
}
@@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.Color
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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDirection
@@ -38,6 +39,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.NotificationCache
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.RoboHashCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
@@ -71,9 +73,9 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
val noteEvent = note.event
val description = if (noteEvent is ChannelCreateEvent) {
"Channel created"
stringResource(R.string.channel_created)
} else if (noteEvent is ChannelMetadataEvent) {
"Channel Information changed to "
"${stringResource(R.string.channel_information_changed_to)} "
} else {
noteEvent?.content
}
@@ -97,7 +99,7 @@ fun ChatroomCompose(baseNote: Note, accountViewModel: AccountViewModel, navContr
style = LocalTextStyle.current.copy(textDirection = TextDirection.Content)
)
Text(
" Public Chat",
" ${stringResource(R.string.public_chat)}",
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -158,7 +160,7 @@ fun ChannelName(
placeholder = channelPicturePlaceholder,
fallback = channelPicturePlaceholder,
error = channelPicturePlaceholder,
contentDescription = "Channel Image",
contentDescription = stringResource(R.string.channel_image),
modifier = Modifier
.width(55.dp)
.height(55.dp)
@@ -182,6 +184,8 @@ fun ChannelName(
hasNewMessages: Boolean,
onClick: () -> Unit
) {
val context = LocalContext.current
Column(modifier = Modifier.clickable(onClick = onClick) ) {
Row(
modifier = Modifier.padding(start = 12.dp, end = 12.dp, top = 10.dp)
@@ -198,7 +202,7 @@ fun ChannelName(
channelLastTime?.let {
Text(
timeAgo(channelLastTime),
timeAgo(channelLastTime, context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.52f)
)
}
@@ -217,7 +221,7 @@ fun ChannelName(
)
else
Text(
"Referenced event not found",
stringResource(R.string.referenced_event_not_found),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.52f),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
@@ -45,6 +45,7 @@ import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
@@ -53,6 +54,7 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.google.accompanist.flowlayout.FlowRow
import com.vitorpamplona.amethyst.NotificationCache
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.RoboHashCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
@@ -193,7 +195,7 @@ fun ChatroomMessageCompose(
placeholder = BitmapPainter(RoboHashCache.get(context, author.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(context, author.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(context, author.pubkeyHex)),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
modifier = Modifier
.width(25.dp)
.height(25.dp)
@@ -238,15 +240,19 @@ fun ChatroomMessageCompose(
Row(verticalAlignment = Alignment.CenterVertically) {
val event = note.event
if (event is ChannelCreateEvent) {
Text(text = "${note.author?.toBestDisplayName()} created " +
"${event.channelInfo.name ?: ""} with " +
"description of '${event.channelInfo.about ?: ""}', " +
"and picture '${event.channelInfo.picture ?: ""}'")
Text(text = note.author?.toBestDisplayName()
.toString() + " ${stringResource(R.string.created)} " + (event.channelInfo.name
?: "") +" ${stringResource(R.string.with_description_of)} '" + (event.channelInfo.about
?: "") + "', ${stringResource(R.string.and_picture)} '" + (event.channelInfo.picture
?: "") + "'"
)
} else if (event is ChannelMetadataEvent) {
Text(text = "${note.author?.toBestDisplayName()} changed " +
"chat name to '${event.channelInfo.name ?: ""}', " +
"description to '${event.channelInfo.about ?: ""}', " +
"and picture to '${event.channelInfo.picture ?: ""}'")
Text(text = note.author?.toBestDisplayName()
.toString() + " ${stringResource(R.string.changed_chat_name_to)} '" + (event.channelInfo.name
?: "") + "$', {stringResource(R.string.description_to)} '" + (event.channelInfo.about
?: "") + "', ${stringResource(R.string.and_picture_to)} '" + (event.channelInfo.picture
?: "") + "'"
)
} else {
val eventContent = accountViewModel.decrypt(note)
@@ -266,7 +272,7 @@ fun ChatroomMessageCompose(
)
} else {
TranslateableRichTextViewer(
"Could Not decrypt the message",
stringResource(R.string.could_not_decrypt_the_message),
true,
Modifier,
note.event?.tags,
@@ -289,7 +295,7 @@ fun ChatroomMessageCompose(
) {
Row() {
Text(
timeAgoShort(note.event?.createdAt),
timeAgoShort(note.event?.createdAt, context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
fontSize = 12.sp
)
@@ -343,7 +349,7 @@ private fun RelayBadges(baseNote: Note) {
placeholder = BitmapPainter(RoboHashCache.get(ctx, url)),
fallback = BitmapPainter(RoboHashCache.get(ctx, url)),
error = BitmapPainter(RoboHashCache.get(ctx, url)),
contentDescription = "Relay Icon",
contentDescription = stringResource(id = R.string.relay_icon),
colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }),
modifier = Modifier
.fillMaxSize(1f)
@@ -22,6 +22,7 @@ import androidx.compose.ui.platform.LocalClipboardManager
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.font.FontWeight
import androidx.compose.ui.unit.Dp
@@ -185,7 +186,7 @@ fun NoteCompose(
placeholder = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
fallback = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
error = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
contentDescription = "Group Picture",
contentDescription = stringResource(R.string.group_picture),
modifier = Modifier
.width(30.dp)
.height(30.dp)
@@ -234,7 +235,7 @@ fun NoteCompose(
}
Text(
timeAgo(noteEvent.createdAt),
timeAgo(noteEvent.createdAt, context = context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1
)
@@ -257,7 +258,7 @@ fun NoteCompose(
if (note.author != null && !makeItShort) {
ObserveDisplayNip05Status(note.author!!)
}
Spacer(modifier = Modifier.height(3.dp))
if (noteEvent is TextNoteEvent && (note.replyTo != null || note.mentions != null)) {
@@ -317,11 +318,11 @@ fun NoteCompose(
} else if (noteEvent is ReportEvent) {
val reportType = noteEvent.reportType.map {
when (it) {
ReportEvent.ReportType.EXPLICIT -> "Explicit Content"
ReportEvent.ReportType.SPAM -> "Spam"
ReportEvent.ReportType.IMPERSONATION -> "Impersonation"
ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior"
else -> "Unknown"
ReportEvent.ReportType.EXPLICIT -> stringResource(R.string.explicit_content)
ReportEvent.ReportType.SPAM -> stringResource(R.string.spam)
ReportEvent.ReportType.IMPERSONATION -> stringResource(R.string.impersonation)
ReportEvent.ReportType.ILLEGAL -> stringResource(R.string.illegal_behavior)
else -> stringResource(R.string.unknown)
}
}.joinToString(", ")
@@ -391,7 +392,7 @@ private fun RelayBadges(baseNote: Note) {
placeholder = BitmapPainter(RoboHashCache.get(ctx, url)),
fallback = BitmapPainter(RoboHashCache.get(ctx, url)),
error = BitmapPainter(RoboHashCache.get(ctx, url)),
contentDescription = "Relay Icon",
contentDescription = stringResource(R.string.relay_icon),
colorFilter = ColorFilter.colorMatrix(ColorMatrix().apply { setToSaturation(0f) }),
modifier = Modifier
.fillMaxSize(1f)
@@ -460,7 +461,7 @@ fun NoteAuthorPicture(
if (author == null) {
Image(
painter = BitmapPainter(RoboHashCache.get(ctx, "ohnothisauthorisnotfound")),
contentDescription = "Unknown Author",
contentDescription = stringResource(R.string.unknown_author),
modifier = pictureModifier
.fillMaxSize(1f)
.clip(shape = CircleShape)
@@ -505,7 +506,7 @@ fun UserPicture(
AsyncImageProxy(
model = ResizeImage(user.profilePicture(), size),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
placeholder = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
@@ -544,7 +545,7 @@ fun UserPicture(
Icon(
painter = painterResource(R.drawable.ic_verified),
"Following",
stringResource(id = R.string.following),
modifier = Modifier.fillMaxSize(),
tint = Following
)
@@ -564,17 +565,17 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
onDismissRequest = onDismiss
) {
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(accountViewModel.decrypt(note) ?: "")); onDismiss() }) {
Text("Copy Text")
Text(stringResource(R.string.copy_text))
}
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(note.author?.pubkeyNpub() ?: "")); onDismiss() }) {
Text("Copy User PubKey")
Text(stringResource(R.string.copy_user_pubkey))
}
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(note.idNote())); onDismiss() }) {
Text("Copy Note ID")
Text(stringResource(R.string.copy_note_id))
}
Divider()
DropdownMenuItem(onClick = { accountViewModel.broadcast(note); onDismiss() }) {
Text("Broadcast")
Text(stringResource(R.string.broadcast))
}
if (note.author == accountViewModel.accountLiveData.value?.account?.userProfile()) {
Divider()
@@ -592,7 +593,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
)
}; onDismiss()
}) {
Text("Block & Hide Author")
Text(stringResource(R.string.block_hide_user))
}
Divider()
DropdownMenuItem(onClick = {
@@ -600,28 +601,28 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
note.author?.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Spam / Scam")
Text(stringResource(R.string.report_spam_scam))
}
DropdownMenuItem(onClick = {
accountViewModel.report(note, ReportEvent.ReportType.IMPERSONATION);
note.author?.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Impersonation")
Text(stringResource(R.string.report_impersonation))
}
DropdownMenuItem(onClick = {
accountViewModel.report(note, ReportEvent.ReportType.EXPLICIT);
note.author?.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Explicit Content")
Text(stringResource(R.string.report_explicit_content))
}
DropdownMenuItem(onClick = {
accountViewModel.report(note, ReportEvent.ReportType.ILLEGAL);
note.author?.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Illegal Behaviour")
Text(stringResource(R.string.report_illegal_behaviour))
}
}
}
@@ -47,6 +47,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
@@ -141,7 +142,7 @@ fun ReplyReaction(
scope.launch {
Toast.makeText(
context,
"Login with a Private key to be able to reply",
context.getString(R.string.login_with_a_private_key_to_be_able_to_reply),
Toast.LENGTH_SHORT
).show()
}
@@ -193,7 +194,7 @@ private fun BoostReaction(
scope.launch {
Toast.makeText(
context,
"Login with a Private key to be able to boost posts",
context.getString(R.string.login_with_a_private_key_to_be_able_to_boost_posts),
Toast.LENGTH_SHORT
).show()
}
@@ -264,7 +265,7 @@ fun LikeReaction(
scope.launch {
Toast.makeText(
context,
"Login with a Private key to like Posts",
context.getString(R.string.login_with_a_private_key_to_like_posts),
Toast.LENGTH_SHORT
).show()
}
@@ -329,7 +330,7 @@ fun ZapReaction(
Toast
.makeText(
context,
"No Zap Amount Setup. Long Press to change",
context.getString(R.string.no_zap_amount_setup_long_press_to_change),
Toast.LENGTH_SHORT
)
.show()
@@ -339,7 +340,7 @@ fun ZapReaction(
Toast
.makeText(
context,
"Login with a Private key to be able to send Zaps",
context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps),
Toast.LENGTH_SHORT
)
.show()
@@ -386,14 +387,14 @@ fun ZapReaction(
if (zappedNote?.isZappedBy(account.userProfile()) == true) {
Icon(
imageVector = Icons.Default.Bolt,
contentDescription = "Zaps",
contentDescription = stringResource(R.string.zaps),
modifier = Modifier.size(20.dp),
tint = BitcoinOrange
)
} else {
Icon(
imageVector = Icons.Outlined.Bolt,
contentDescription = "Zaps",
contentDescription = stringResource(id = R.string.zaps),
modifier = Modifier.size(20.dp),
tint = grayTint
)
@@ -433,7 +434,7 @@ private fun ViewCountReaction(baseNote: Note, textModifier: Modifier = Modifier)
.diskCachePolicy(CachePolicy.DISABLED)
.memoryCachePolicy(CachePolicy.ENABLED)
.build(),
contentDescription = "View count",
contentDescription = stringResource(R.string.view_count),
modifier = Modifier.height(24.dp),
colorFilter = ColorFilter.tint(grayTint)
)
@@ -461,7 +462,7 @@ private fun BoostTypeChoicePopup(baseNote: Note, accountViewModel: AccountViewMo
backgroundColor = MaterialTheme.colors.primary
)
) {
Text("Boost", color = Color.White, textAlign = TextAlign.Center)
Text(stringResource(R.string.boost), color = Color.White, textAlign = TextAlign.Center)
}
Button(
@@ -473,7 +474,7 @@ private fun BoostTypeChoicePopup(baseNote: Note, accountViewModel: AccountViewMo
backgroundColor = MaterialTheme.colors.primary
)
) {
Text("Quote", color = Color.White, textAlign = TextAlign.Center)
Text(stringResource(R.string.quote), color = Color.White, textAlign = TextAlign.Center)
}
}
}
@@ -640,7 +641,7 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) {
OutlinedTextField(
label = { Text(text = "New Amount in Sats") },
label = { Text(text = stringResource(R.string.new_amount_in_sats)) },
value = postViewModel.nextAmount,
onValueChange = {
postViewModel.nextAmount = it
@@ -656,7 +657,9 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
)
},
singleLine = true,
modifier = Modifier.padding(end = 10.dp).weight(1f)
modifier = Modifier
.padding(end = 10.dp)
.weight(1f)
)
Button(
@@ -667,7 +670,7 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account) {
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = "Add", color = Color.White)
Text(text = stringResource(R.string.add), color = Color.White)
}
}
}
@@ -17,10 +17,13 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.RelayInfo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import java.time.Instant
@@ -38,6 +41,8 @@ fun RelayCompose(
val accountState by accountViewModel.accountLiveData.observeAsState()
val account = accountState?.account ?: return
val context = LocalContext.current
Column() {
Row(
modifier = Modifier
@@ -58,13 +63,13 @@ fun RelayCompose(
)
Text(
timeAgo(relay.lastEvent),
timeAgo(relay.lastEvent, context = context),
maxLines = 1
)
}
Text(
"${relay.counter} posts received",
"${relay.counter} ${stringResource(R.string.posts_received)}",
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1,
overflow = TextOverflow.Ellipsis
@@ -99,7 +104,7 @@ fun AddRelayButton(onClick: () -> Unit) {
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Add", color = Color.White)
Text(text = stringResource(id = R.string.add), color = Color.White)
}
}
@@ -115,7 +120,7 @@ fun RemoveRelayButton(onClick: () -> Unit) {
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Remove", color = Color.White)
Text(text = stringResource(R.string.remove), color = Color.White)
}
}
@@ -7,6 +7,9 @@ import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -15,6 +18,7 @@ import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.google.accompanist.flowlayout.FlowRow
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Channel
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
@@ -37,7 +41,7 @@ fun ReplyInformation(replyTo: List<Note>?, dupMentions: List<User>?, account: Ac
val repliesToDisplay = if (expanded) mentions else mentions.take(2)
Text(
"replying to ",
stringResource(R.string.replying_to),
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -62,7 +66,7 @@ fun ReplyInformation(replyTo: List<Note>?, dupMentions: List<User>?, account: Ac
)
} else if (idx < repliesToDisplay.size - 1) {
Text(
" and ",
" ${stringResource(R.string.and)} ",
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -76,7 +80,7 @@ fun ReplyInformation(replyTo: List<Note>?, dupMentions: List<User>?, account: Ac
)
} else if (idx < repliesToDisplay.size) {
Text(
" and ",
" ${stringResource(R.string.and)} ",
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -128,7 +132,7 @@ fun ReplyInformationChannel(replyTo: List<Note>?,
FlowRow() {
Text(
"in channel ",
stringResource(R.string.in_channel),
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -142,7 +146,7 @@ fun ReplyInformationChannel(replyTo: List<Note>?,
if (mentions != null && mentions.isNotEmpty()) {
if (replyTo != null && replyTo.isNotEmpty()) {
Text(
"replying to ",
stringResource(id = R.string.replying_to),
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -168,7 +172,7 @@ fun ReplyInformationChannel(replyTo: List<Note>?,
)
} else if (idx < mentionSet.size - 1) {
Text(
" and ",
" ${stringResource(id = R.string.add)} ",
fontSize = 13.sp,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
@@ -1,10 +1,12 @@
package com.vitorpamplona.amethyst.ui.note
import android.content.Context
import android.text.format.DateUtils
import com.vitorpamplona.amethyst.R
fun timeAgo(mills: Long?): String {
fun timeAgo(mills: Long?, context : Context): String {
if (mills == null) return " "
if (mills == 0L) return " • never"
if (mills == 0L) return "${context.getString(R.string.never)}"
var humanReadable = DateUtils.getRelativeTimeSpanString(
mills * 1000,
@@ -13,13 +15,13 @@ fun timeAgo(mills: Long?): String {
DateUtils.FORMAT_ABBREV_ALL
).toString()
if (humanReadable.startsWith("In") || humanReadable.startsWith("0")) {
humanReadable = "now";
humanReadable = context.getString(R.string.now);
}
return "" + humanReadable
.replace(" hr. ago", "h")
.replace(" min. ago", "m")
.replace(" days ago", "d")
.replace(" hr. ago", context.getString(R.string.h))
.replace(" min. ago", context.getString(R.string.m))
.replace(" days ago", context.getString(R.string.d))
}
fun timeAgoShort(mills: Long?): String {
@@ -38,7 +40,7 @@ fun timeAgoShort(mills: Long?): String {
return humanReadable
}
fun timeAgoLong(mills: Long?): String {
fun timeAgoLong(mills: Long?, context: Context): String {
if (mills == null) return " "
var humanReadable = DateUtils.getRelativeTimeSpanString(
@@ -48,7 +50,7 @@ fun timeAgoLong(mills: Long?): String {
DateUtils.FORMAT_SHOW_TIME
).toString()
if (humanReadable.startsWith("In") || humanReadable.startsWith("0")) {
humanReadable = "now";
humanReadable = context.getString(R.string.now);
}
return humanReadable
@@ -15,11 +15,14 @@ import androidx.compose.runtime.rememberCoroutineScope
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.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.LocalPreferences
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.service.model.LnZapEvent
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -94,7 +97,7 @@ fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewMode
verticalArrangement = Arrangement.Center
) {
Text(
showAmount(amount) + " sats",
"${showAmount(amount)} ${stringResource(R.string.sats)}",
color = BitcoinOrange,
fontSize = 20.sp,
fontWeight = FontWeight.W500,
@@ -24,10 +24,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.accompanist.flowlayout.FlowRow
import com.vitorpamplona.amethyst.NotificationCache
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.model.ChannelMessageEvent
import com.vitorpamplona.amethyst.ui.screen.ZapSetCard
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -94,9 +96,11 @@ fun ZapSetCompose(zapSetCard: ZapSetCard, modifier: Modifier = Modifier, isInner
.padding(0.dp)) {
Icon(
imageVector = Icons.Default.Bolt,
contentDescription = "Zaps",
contentDescription = stringResource(id = R.string.zaps),
tint = BitcoinOrange,
modifier = Modifier.size(25.dp).align(Alignment.TopEnd)
modifier = Modifier
.size(25.dp)
.align(Alignment.TopEnd)
)
}
}
@@ -28,11 +28,15 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import coil.compose.AsyncImage
import coil.compose.rememberAsyncImagePainter
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.RoboHashCache
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.actions.CloseButton
@@ -83,7 +87,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
placeholder = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(ctx, user.pubkeyHex)),
contentDescription = "Profile Image",
contentDescription = stringResource(R.string.profile_image),
modifier = Modifier
.width(100.dp)
.height(100.dp)
@@ -129,7 +133,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = "Scan QR")
Text(text = stringResource(R.string.scan_qr))
}
}
@@ -137,7 +141,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) {
Text(
"Point to the QR Code",
stringResource(R.string.point_to_the_qr_code),
modifier = Modifier.padding(top = 7.dp),
fontWeight = FontWeight.Bold,
fontSize = 25.sp
@@ -167,7 +171,7 @@ fun ShowQRDialog(user: User, onScan: (String) -> Unit, onClose: () -> Unit) {
backgroundColor = MaterialTheme.colors.primary
)
) {
Text(text = "Show QR")
Text(text = stringResource(R.string.show_qr))
}
}
@@ -22,10 +22,12 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import com.google.accompanist.swiperefresh.SwipeRefresh
import com.google.accompanist.swiperefresh.rememberSwipeRefreshState
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.note.NoteCompose
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -122,7 +124,7 @@ fun LoadingFeed() {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Loading feed")
Text(stringResource(R.string.loading_feed))
}
}
@@ -135,12 +137,12 @@ fun FeedError(errorMessage: String, onRefresh: () -> Unit) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Error loading replies: $errorMessage")
Text("${stringResource(R.string.error_loading_replies)} $errorMessage")
Button(
modifier = Modifier.align(Alignment.CenterHorizontally),
onClick = onRefresh
) {
Text(text = "Try again")
Text(text = stringResource(R.string.try_again))
}
}
}
@@ -154,9 +156,9 @@ fun FeedEmpty(onRefresh: () -> Unit) {
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text("Feed is empty.")
Text(stringResource(R.string.feed_is_empty))
OutlinedButton(onClick = onRefresh) {
Text(text = "Refresh")
Text(text = stringResource(R.string.refresh))
}
}
}
@@ -50,6 +50,7 @@ import com.vitorpamplona.amethyst.ui.note.ReactionsRow
import com.vitorpamplona.amethyst.ui.note.timeAgo
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
import kotlinx.coroutines.delay
import androidx.compose.ui.platform.LocalContext
@Composable
fun ThreadFeedView(noteId: String, viewModel: FeedViewModel, accountViewModel: AccountViewModel, navController: NavController) {
@@ -192,6 +193,8 @@ fun NoteMaster(baseNote: Note,
var showHiddenNote by remember { mutableStateOf(false) }
val context = LocalContext.current
var moreActionsExpanded by remember { mutableStateOf(false) }
val noteEvent = note?.event
@@ -232,7 +235,7 @@ fun NoteMaster(baseNote: Note,
NoteUsernameDisplay(baseNote, Modifier.weight(1f))
Text(
timeAgo(noteEvent.createdAt),
timeAgo(noteEvent.createdAt, context = context),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
maxLines = 1
)
@@ -8,6 +8,7 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.map
import com.vitorpamplona.amethyst.service.lnurl.LightningAddressResolver
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.AccountState
import com.vitorpamplona.amethyst.model.Note
@@ -51,7 +52,7 @@ class AccountViewModel(private val account: Account): ViewModel() {
val lud16 = note.author?.info?.lud16?.trim() ?: note.author?.info?.lud06?.trim()
if (lud16.isNullOrBlank()) {
onError("User does not have a lightning address setup to receive sats")
onError(context.getString(R.string.user_does_not_have_a_lightning_address_setup_to_receive_sats))
return
}
@@ -47,6 +47,7 @@ import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
@@ -59,6 +60,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.RoboHashCache
import com.vitorpamplona.amethyst.model.Account
import com.vitorpamplona.amethyst.model.Channel
@@ -183,7 +185,7 @@ fun ChannelScreen(channelId: String?, accountViewModel: AccountViewModel, accoun
modifier = Modifier.weight(1f, true),
placeholder = {
Text(
text = "reply here.. ",
text = stringResource(R.string.reply_here),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -226,7 +228,7 @@ fun ChannelHeader(baseChannel: Channel, account: Account, accountStateViewModel:
placeholder = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
fallback = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
error = BitmapPainter(RoboHashCache.get(context, channel.idHex)),
contentDescription = "Profile Image",
contentDescription = context.getString(R.string.profile_image),
modifier = Modifier
.width(35.dp)
.height(35.dp)
@@ -302,7 +304,7 @@ private fun NoteCopyButton(
Icon(
tint = Color.White,
imageVector = Icons.Default.Share,
contentDescription = "Copies the Note ID to the clipboard for sharing"
contentDescription = stringResource(R.string.copies_the_note_id_to_the_clipboard_for_sharing)
)
DropdownMenu(
@@ -310,7 +312,7 @@ private fun NoteCopyButton(
onDismissRequest = { popupExpanded = false }
) {
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(note.idNote())); popupExpanded = false }) {
Text("Copy Channel ID (Note) to the Clipboard")
Text(stringResource(R.string.copy_channel_id_note_to_the_clipboard))
}
}
}
@@ -339,7 +341,7 @@ private fun EditButton(account: Account, channel: Channel) {
Icon(
tint = Color.White,
imageVector = Icons.Default.EditNote,
contentDescription = "Edits the Channel Metadata"
contentDescription = stringResource(R.string.edits_the_channel_metadata)
)
}
}
@@ -359,7 +361,7 @@ private fun JoinButton(account: Account, channel: Channel, navController: NavCon
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Join", color = Color.White)
Text(text = stringResource(R.string.join), color = Color.White)
}
}
@@ -378,6 +380,6 @@ private fun LeaveButton(account: Account, channel: Channel, navController: NavCo
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Leave", color = Color.White)
Text(text = stringResource(R.string.leave), color = Color.White)
}
}
@@ -16,6 +16,7 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
@@ -32,6 +33,7 @@ import com.vitorpamplona.amethyst.ui.screen.ChatroomListFeedView
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListKnownFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.NostrChatroomListNewFeedViewModel
import kotlinx.coroutines.launch
import com.vitorpamplona.amethyst.R
@OptIn(ExperimentalPagerApi::class)
@Composable
@@ -57,7 +59,7 @@ fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavCon
selected = pagerState.currentPage == 0,
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
text = {
Text(text = "Known")
Text(text = stringResource(R.string.known))
}
)
@@ -65,7 +67,7 @@ fun ChatroomListScreen(accountViewModel: AccountViewModel, navController: NavCon
selected = pagerState.currentPage == 1,
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } },
text = {
Text(text = "New Requests")
Text(text = stringResource(R.string.new_requests))
}
)
}
@@ -39,6 +39,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.style.TextDirection
@@ -47,6 +48,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.RoboHashCache
import com.vitorpamplona.amethyst.model.Note
import com.vitorpamplona.amethyst.model.User
@@ -169,7 +171,7 @@ fun ChatroomScreen(userId: String?, accountViewModel: AccountViewModel, navContr
shape = RoundedCornerShape(25.dp),
placeholder = {
Text(
text = "reply here.. ",
text = stringResource(id = R.string.reply_here),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -216,7 +218,7 @@ fun ChatroomHeader(baseUser: User, accountViewModel: AccountViewModel, navContro
placeholder = BitmapPainter(RoboHashCache.get(ctx, author.pubkeyHex)),
fallback = BitmapPainter(RoboHashCache.get(ctx, author.pubkeyHex)),
error = BitmapPainter(RoboHashCache.get(ctx, author.pubkeyHex)),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
modifier = Modifier
.width(35.dp)
.height(35.dp)
@@ -13,6 +13,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
@@ -20,6 +21,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.pagerTabIndicatorOffset
import com.google.accompanist.pager.rememberPagerState
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.dal.HiddenAccountsFeedFilter
import com.vitorpamplona.amethyst.ui.screen.NostrHiddenAccountsFeedViewModel
import com.vitorpamplona.amethyst.ui.screen.UserFeedView
@@ -55,7 +57,7 @@ fun FiltersScreen(accountViewModel: AccountViewModel, navController: NavControll
selected = pagerState.currentPage == 0,
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
text = {
Text(text = "Blocked Users")
Text(text = stringResource(R.string.blocked_users))
}
)
}
@@ -16,6 +16,7 @@ import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
@@ -25,6 +26,7 @@ import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.pagerTabIndicatorOffset
import com.google.accompanist.pager.rememberPagerState
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
import com.vitorpamplona.amethyst.ui.dal.HomeConversationsFeedFilter
import com.vitorpamplona.amethyst.ui.dal.HomeNewThreadFeedFilter
@@ -95,7 +97,7 @@ fun HomeScreen(accountViewModel: AccountViewModel, navController: NavController)
selected = pagerState.currentPage == 0,
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(0) } },
text = {
Text(text = "New Threads")
Text(text = stringResource(R.string.new_threads))
}
)
@@ -103,7 +105,7 @@ fun HomeScreen(accountViewModel: AccountViewModel, navController: NavController)
selected = pagerState.currentPage == 1,
onClick = { coroutineScope.launch { pagerState.animateScrollToPage(1) } },
text = {
Text(text = "Conversations")
Text(text = stringResource(R.string.conversations))
}
)
}
@@ -31,6 +31,7 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@@ -179,34 +180,34 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
) {
val tabs = listOf<@Composable() (() -> Unit)?>(
{
Text(text = "Notes")
Text(text = stringResource(R.string.notes))
},
{
Text(text = "Replies")
Text(text = stringResource(R.string.replies))
},
{
val userState by baseUser.live().follows.observeAsState()
val userFollows = userState?.user?.follows?.size ?: "--"
Text(text = "$userFollows Follows")
Text(text = "$userFollows ${stringResource(R.string.follows)}")
},
{
val userState by baseUser.live().follows.observeAsState()
val userFollows = userState?.user?.followers?.size ?: "--"
val userFollowers = userState?.user?.followers?.size ?: "--"
Text(text = "$userFollows Followers")
Text(text = "$userFollowers ${stringResource(id = R.string.followers)}")
},
{
val userState by baseUser.live().zaps.observeAsState()
val userZaps = userState?.user?.zappedAmount()
Text(text = "${showAmount(userZaps)} Zaps")
Text(text = "${showAmount(userZaps)} ${stringResource(id = R.string.zaps)}")
},
{
val userState by baseUser.live().reports.observeAsState()
val userReports = userState?.user?.reports?.values?.flatten()?.count()
Text(text = "${userReports} Reports")
Text(text = "${userReports.toString()} ${stringResource(R.string.reports)}")
},
{
val userState by baseUser.live().relays.observeAsState()
@@ -215,7 +216,7 @@ fun ProfileScreen(userId: String?, accountViewModel: AccountViewModel, navContro
val userStateRelayInfo by baseUser.live().relayInfo.observeAsState()
val userRelays = userStateRelayInfo?.user?.relays?.size ?: "--"
Text(text = "$userRelaysBeingUsed / $userRelays Relays")
Text(text = "$userRelaysBeingUsed / $userRelays ${stringResource(R.string.relays)}")
}
)
@@ -288,7 +289,7 @@ private fun ProfileHeader(
Icon(
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
imageVector = Icons.Default.MoreVert,
contentDescription = "More Options",
contentDescription = stringResource(R.string.more_options),
)
UserProfileDropDownMenu(baseUser, popupExpanded, { popupExpanded = false }, accountViewModel)
@@ -386,7 +387,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account) {
Icon(
tint = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
imageVector = Icons.Default.Link,
contentDescription = "Website",
contentDescription = stringResource(R.string.website),
modifier = Modifier.size(16.dp)
)
@@ -408,7 +409,7 @@ private fun DrawAdditionalInfo(baseUser: User, account: Account) {
Icon(
tint = BitcoinOrange,
imageVector = Icons.Default.Bolt,
contentDescription = "Lightning Address",
contentDescription = stringResource(R.string.lightning_address),
modifier = Modifier.size(16.dp)
)
@@ -450,7 +451,7 @@ private fun DrawBanner(baseUser: User) {
if (banner != null && banner.isNotBlank()) {
AsyncImageProxy(
model = ResizeImage(banner, 125.dp),
contentDescription = "Profile Image",
contentDescription = stringResource(id = R.string.profile_image),
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
@@ -459,7 +460,7 @@ private fun DrawBanner(baseUser: User) {
} else {
Image(
painter = painterResource(R.drawable.profile_banner),
contentDescription = "Profile Banner",
contentDescription = stringResource(id = R.string.profile_banner),
contentScale = ContentScale.FillWidth,
modifier = Modifier
.fillMaxWidth()
@@ -638,7 +639,7 @@ private fun NSecCopyButton(
Icon(
tint = Color.White,
imageVector = Icons.Default.Key,
contentDescription = "Copies the Nsec ID (your password) to the clipboard for backup"
contentDescription = stringResource(R.string.copies_the_nsec_id_your_password_to_the_clipboard_for_backup)
)
DropdownMenu(
@@ -646,7 +647,7 @@ private fun NSecCopyButton(
onDismissRequest = { popupExpanded = false }
) {
DropdownMenuItem(onClick = { account.loggedIn.privKey?.let { clipboardManager.setText(AnnotatedString(it.toNsec())) }; popupExpanded = false }) {
Text("Copy Private Key to the Clipboard")
Text(stringResource(R.string.copy_private_key_to_the_clipboard))
}
}
}
@@ -673,7 +674,7 @@ private fun NPubCopyButton(
Icon(
tint = Color.White,
imageVector = Icons.Default.Share,
contentDescription = "Copies the public key to the clipboard for sharing"
contentDescription = stringResource(R.string.copies_the_public_key_to_the_clipboard_for_sharing)
)
DropdownMenu(
@@ -681,7 +682,7 @@ private fun NPubCopyButton(
onDismissRequest = { popupExpanded = false }
) {
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(user.pubkeyNpub())); popupExpanded = false }) {
Text("Copy Public Key (NPub) to the Clipboard")
Text(stringResource(R.string.copy_public_key_npub_to_the_clipboard))
}
}
}
@@ -702,7 +703,7 @@ private fun MessageButton(user: User, navController: NavController) {
) {
Icon(
painter = painterResource(R.drawable.ic_dm),
"Send a Direct Message",
stringResource(R.string.send_a_direct_message),
modifier = Modifier.size(20.dp),
tint = Color.White
)
@@ -732,7 +733,7 @@ private fun EditButton(account: Account) {
Icon(
tint = Color.White,
imageVector = Icons.Default.EditNote,
contentDescription = "Edits the User's Metadata"
contentDescription = stringResource(R.string.edits_the_user_s_metadata)
)
}
}
@@ -749,7 +750,7 @@ fun UnfollowButton(onClick: () -> Unit) {
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Unfollow", color = Color.White)
Text(text = stringResource(R.string.unfollow), color = Color.White)
}
}
@@ -765,7 +766,7 @@ fun FollowButton(onClick: () -> Unit) {
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Follow", color = Color.White, textAlign = TextAlign.Center)
Text(text = stringResource(R.string.follow), color = Color.White, textAlign = TextAlign.Center)
}
}
@@ -781,7 +782,7 @@ fun ShowUserButton(onClick: () -> Unit) {
),
contentPadding = PaddingValues(vertical = 6.dp, horizontal = 16.dp)
) {
Text(text = "Unblock", color = Color.White)
Text(text = stringResource(R.string.unblock), color = Color.White)
}
}
@@ -799,7 +800,7 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
onDismissRequest = onDismiss
) {
DropdownMenuItem(onClick = { clipboardManager.setText(AnnotatedString(user.pubkeyNpub())); onDismiss() }) {
Text("Copy User ID")
Text(stringResource(R.string.copy_user_id))
}
if ( account.userProfile() != user) {
@@ -813,11 +814,11 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
)
}; onDismiss()
}) {
Text("Unblock User")
Text(stringResource(R.string.unblock_user))
}
} else {
DropdownMenuItem(onClick = { user.let { accountViewModel.hide(it, context) }; onDismiss() }) {
Text("Block & Hide User")
Text(stringResource(id = R.string.block_hide_user))
}
}
Divider()
@@ -826,28 +827,28 @@ fun UserProfileDropDownMenu(user: User, popupExpanded: Boolean, onDismiss: () ->
user.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Spam / Scam")
Text(stringResource(id = R.string.report_spam_scam))
}
DropdownMenuItem(onClick = {
accountViewModel.report(user, ReportEvent.ReportType.IMPERSONATION);
user.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Impersonation")
Text(stringResource(id = R.string.report_impersonation))
}
DropdownMenuItem(onClick = {
accountViewModel.report(user, ReportEvent.ReportType.EXPLICIT);
user.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Explicit Content")
Text(stringResource(id = R.string.report_explicit_content))
}
DropdownMenuItem(onClick = {
accountViewModel.report(user, ReportEvent.ReportType.ILLEGAL);
user.let { accountViewModel.hide(it, context) }
onDismiss()
}) {
Text("Report Illegal Behaviour")
Text(stringResource(id = R.string.report_illegal_behaviour))
}
}
}
@@ -40,6 +40,7 @@ import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.style.TextOverflow
@@ -203,7 +204,7 @@ private fun SearchBar(accountViewModel: AccountViewModel, navController: NavCont
.defaultMinSize(minHeight = 20.dp),
placeholder = {
Text(
text = "npub, hex, username ",
text = stringResource(R.string.npub_hex_username),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -221,7 +222,7 @@ private fun SearchBar(accountViewModel: AccountViewModel, navController: NavCont
) {
Icon(
imageVector = Icons.Default.Clear,
contentDescription = "Clear"
contentDescription = stringResource(R.string.clear)
)
}
}
@@ -38,8 +38,10 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
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
@@ -60,6 +62,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
val acceptedTerms = remember { mutableStateOf(false) }
var termsAcceptanceIsRequired by remember { mutableStateOf("") }
val uri = LocalUriHandler.current
val context = LocalContext.current
Column(
modifier = Modifier
@@ -81,7 +84,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
Image(
painterResource(id = R.drawable.amethyst),
contentDescription = "App Logo",
contentDescription = stringResource(R.string.app_logo),
modifier = Modifier.size(200.dp),
contentScale = ContentScale.Inside
)
@@ -102,7 +105,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
),
placeholder = {
Text(
text = "nsec / npub / hex private key",
text = stringResource(R.string.nsec_npub_hex_private_key),
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f)
)
},
@@ -110,7 +113,8 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
IconButton(onClick = { showPassword = !showPassword }) {
Icon(
imageVector = if (showPassword) Icons.Outlined.VisibilityOff else Icons.Outlined.Visibility,
contentDescription = if (showPassword) "Show Password" else "Hide Password"
contentDescription = if (showPassword) stringResource(R.string.show_password) else stringResource(
R.string.hide_password)
)
}
},
@@ -120,7 +124,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
try {
accountViewModel.login(key.value.text)
} catch (e: Exception) {
errorMessage = "Invalid key"
errorMessage = context.getString(R.string.invalid_key)
}
}
)
@@ -141,10 +145,10 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
onCheckedChange = { acceptedTerms.value = it }
)
Text(text = "I accept the ")
Text(text = stringResource(R.string.i_accept_the))
ClickableText(
text = AnnotatedString("terms of use"),
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),
)
@@ -164,18 +168,18 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
Button(
onClick = {
if (!acceptedTerms.value) {
termsAcceptanceIsRequired = "Acceptance of terms is required"
termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required)
}
if (key.value.text.isBlank()) {
errorMessage = "Key is required"
errorMessage = context.getString(R.string.key_is_required)
}
if (acceptedTerms.value && key.value.text.isNotBlank()) {
try {
accountViewModel.login(key.value.text)
} catch (e: Exception) {
errorMessage = "Invalid key"
errorMessage = context.getString(R.string.invalid_key)
}
}
},
@@ -188,14 +192,14 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
backgroundColor = if (acceptedTerms.value) MaterialTheme.colors.primary else Color.Gray
)
) {
Text(text = "Login")
Text(text = stringResource(R.string.login))
}
}
}
// The last child is glued to the bottom.
ClickableText(
text = AnnotatedString("Generate a new key"),
text = AnnotatedString(stringResource(R.string.generate_a_new_key)),
modifier = Modifier
.padding(20.dp)
.fillMaxWidth(),
@@ -203,7 +207,7 @@ fun LoginPage(accountViewModel: AccountStateViewModel) {
if (acceptedTerms.value) {
accountViewModel.newKey()
} else {
termsAcceptanceIsRequired = "Acceptance of terms is required"
termsAcceptanceIsRequired = context.getString(R.string.acceptance_of_terms_is_required)
}
},
style = TextStyle(