mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-23 23:10:58 +02:00
Merge remote-tracking branch 'origin/HEAD'
# Conflicts: # app/src/main/java/com/vitorpamplona/amethyst/ui/components/UrlPreview.kt
This commit is contained in:
commit
01b8b2a5fa
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
Amethyst
|
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="11" />
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
3
.idea/inspectionProfiles/Project_Default.xml
generated
3
.idea/inspectionProfiles/Project_Default.xml
generated
@ -5,6 +5,9 @@
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
</inspection_tool>
|
||||
<inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
|
||||
<option name="composableFile" value="true" />
|
||||
<option name="previewFile" value="true" />
|
||||
|
6
.idea/kotlinc.xml
generated
Normal file
6
.idea/kotlinc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.10" />
|
||||
</component>
|
||||
</project>
|
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="Android Studio default JDK" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -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")
|
||||
|
@ -21,6 +21,7 @@ import com.vitorpamplona.amethyst.service.relays.Client
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountScreen
|
||||
import com.vitorpamplona.amethyst.ui.screen.AccountStateViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.AmethystTheme
|
||||
import java.util.Locale
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -61,6 +62,8 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
Client.lenient = true
|
||||
|
||||
Locale.setDefault(Locale.ENGLISH)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -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,7 +16,9 @@ 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.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.vitorpamplona.amethyst.R
|
||||
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,6 +20,7 @@ import kotlinx.coroutines.withContext
|
||||
@Composable
|
||||
fun UrlPreview(url: String, urlText: String) {
|
||||
val default = UrlCachedPreviewer.cache[url]?.let { UrlPreviewState.Loaded(it) } ?: UrlPreviewState.Loading
|
||||
var context = LocalContext.current
|
||||
|
||||
var urlPreviewState by remember { mutableStateOf(default) }
|
||||
|
||||
@ -34,8 +37,13 @@ fun UrlPreview(url: String, urlText: String) {
|
||||
}
|
||||
|
||||
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.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
|
||||
@ -186,7 +187,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)
|
||||
@ -235,7 +236,7 @@ fun NoteCompose(
|
||||
}
|
||||
|
||||
Text(
|
||||
timeAgo(noteEvent.createdAt),
|
||||
timeAgo(noteEvent.createdAt, context = context),
|
||||
color = MaterialTheme.colors.onSurface.copy(alpha = 0.32f),
|
||||
maxLines = 1
|
||||
)
|
||||
@ -258,7 +259,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)) {
|
||||
@ -316,15 +317,15 @@ fun NoteCompose(
|
||||
)
|
||||
}
|
||||
} else if (noteEvent is ReportEvent) {
|
||||
val reportType = (noteEvent.reportedPost + noteEvent.reportedAuthor).map {
|
||||
when (it.reportType) {
|
||||
ReportEvent.ReportType.EXPLICIT -> "Explicit Content"
|
||||
ReportEvent.ReportType.NUDITY -> "Nudity"
|
||||
ReportEvent.ReportType.PROFANITY -> "Profanity / Hateful speech"
|
||||
ReportEvent.ReportType.SPAM -> "Spam"
|
||||
ReportEvent.ReportType.IMPERSONATION -> "Impersonation"
|
||||
ReportEvent.ReportType.ILLEGAL -> "Illegal Behavior"
|
||||
else -> "Unknown"
|
||||
val reportType = noteEvent.reportType.map {
|
||||
when (it) {
|
||||
ReportEvent.ReportType.EXPLICIT -> stringResource(R.string.explicit_content)
|
||||
ReportEvent.ReportType.NUDITY -> stringResource(R.string.nudity)
|
||||
ReportEvent.ReportType.PROFANITY -> stringResource(R.string.profanity_hateful_speech)
|
||||
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)
|
||||
}
|
||||
}.toSet().joinToString(", ")
|
||||
|
||||
@ -395,7 +396,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)
|
||||
@ -464,7 +465,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)
|
||||
@ -509,7 +510,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)),
|
||||
@ -548,7 +549,7 @@ fun UserPicture(
|
||||
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_verified),
|
||||
"Following",
|
||||
stringResource(id = R.string.following),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
tint = Following
|
||||
)
|
||||
@ -568,17 +569,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()
|
||||
@ -596,7 +597,7 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
||||
)
|
||||
}; onDismiss()
|
||||
}) {
|
||||
Text("Block & Hide Author")
|
||||
Text(stringResource(R.string.block_hide_user))
|
||||
}
|
||||
Divider()
|
||||
DropdownMenuItem(onClick = {
|
||||
@ -604,7 +605,7 @@ 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.PROFANITY);
|
||||
@ -618,21 +619,21 @@ fun NoteDropDownMenu(note: Note, popupExpanded: Boolean, onDismiss: () -> Unit,
|
||||
note.author?.let { accountViewModel.hide(it, context) }
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Report Impersonation")
|
||||
Text(stringResource(R.string.report_impersonation))
|
||||
}
|
||||
DropdownMenuItem(onClick = {
|
||||
accountViewModel.report(note, ReportEvent.ReportType.NUDITY);
|
||||
note.author?.let { accountViewModel.hide(it, context) }
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Report Nudity")
|
||||
Text(stringResource(R.string.report_nudity_porn))
|
||||
}
|
||||
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)
|
||||
)
|
||||
@ -88,7 +92,7 @@ fun ReplyInformation(replyTo: List<Note>?, dupMentions: List<User>?, account: Ac
|
||||
)
|
||||
|
||||
Text(
|
||||
" others",
|
||||
" ${stringResource(R.string.others)}",
|
||||
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,16 +15,16 @@ 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 {
|
||||
fun timeAgoShort(mills: Long?, context: Context): String {
|
||||
if (mills == null) return " "
|
||||
|
||||
var humanReadable = DateUtils.getRelativeTimeSpanString(
|
||||
@ -32,13 +34,13 @@ fun timeAgoShort(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
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
@ -286,4 +289,4 @@ fun NoteMaster(baseNote: Note,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
@ -74,7 +76,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))
|
||||
}
|
||||
)
|
||||
|
||||
@ -82,7 +84,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,35 +827,35 @@ 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.PROFANITY);
|
||||
user.let { accountViewModel.hide(it, context) }
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Report Hateful speech")
|
||||
Text(stringResource(R.string.report_hateful_speech))
|
||||
}
|
||||
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.NUDITY);
|
||||
user.let { accountViewModel.hide(it, context) }
|
||||
onDismiss()
|
||||
}) {
|
||||
Text("Report Nudity / Porn")
|
||||
Text(stringResource(R.string.report_nudity_porn))
|
||||
}
|
||||
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
|
||||
@ -202,7 +203,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)
|
||||
)
|
||||
},
|
||||
@ -220,7 +221,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(
|
||||
|
178
app/src/main/res/values-ar/strings.xml
Normal file
178
app/src/main/res/values-ar/strings.xml
Normal file
@ -0,0 +1,178 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name_release">Amethyst</string>
|
||||
<string name="app_name_debug">Amethyst Debug</string>
|
||||
<string name="point_to_the_qr_code">أشر إلى رمز QR</string>
|
||||
<string name="show_qr">أظهر QR</string>
|
||||
<string name="profile_image">صورة الملف الشخصي</string>
|
||||
<string name="scan_qr">مسح QR</string>
|
||||
<string name="show_anyway">عرض على أي حال</string>
|
||||
<string name="post_was_flagged_as_inappropriate_by">تم وضع علامة على المنشور على أنه غير لائق بواسطة</string>
|
||||
<string name="post_not_found">المنشور غير موجود</string>
|
||||
<string name="channel_image">صورة القناة</string>
|
||||
<string name="referenced_event_not_found">لم يتم العثور على الحدث المشار إليه</string>
|
||||
<string name="could_not_decrypt_the_message">لا يمكن فك تشفير الرسالة</string>
|
||||
<string name="group_picture">صورة المجموعة</string>
|
||||
<string name="explicit_content">محتوى فاضح</string>
|
||||
<string name="spam">رسائل عشوائية</string>
|
||||
<string name="impersonation">التمثيل</string>
|
||||
<string name="illegal_behavior">تصرف غير قانوني</string>
|
||||
<string name="unknown">غير معروف</string>
|
||||
<string name="relay_icon">Relay Icon</string>
|
||||
<string name="unknown_author">كاتب غير معروف</string>
|
||||
<string name="copy_text">نسخ النص</string>
|
||||
<string name="copy_user_pubkey">نسخ المفتاح العام</string>
|
||||
<string name="copy_note_id">نسخ معرف </string>
|
||||
<string name="broadcast">بث</string>
|
||||
<string name="block_hide_user">حظر و إخفاء المستخدم</string>
|
||||
<string name="report_spam_scam">الابلاغ عن البريد العشوائي / الاحتيال</string>
|
||||
<string name="report_impersonation">الإبلاغ عن التمثيل</string>
|
||||
<string name="report_explicit_content">الإبلاغ عن المحتوى الصريح / الفاضح</string>
|
||||
<string name="report_illegal_behaviour">الإبلاغ عن سلوك غير قانوني</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_reply">قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من الرد</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_boost_posts">قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من تعزيز المشاركات</string>
|
||||
<string name="login_with_a_private_key_to_like_posts">تسجيل الدخول باستخدام مفتاح خاص لإبداء الإعجاب بالمنشورات</string>
|
||||
<string name="no_zap_amount_setup_long_press_to_change">لا يوجد إعداد لمبلغ Zap. اضغط لفترة طويلة للتغيير</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_send_zaps">قم بتسجيل الدخول باستخدام مفتاح خاص لتتمكن من إرسال Zaps</string>
|
||||
<string name="zaps">Zaps</string>
|
||||
<string name="view_count">مشاهدة العد</string>
|
||||
<string name="boost">تعزيز</string>
|
||||
<string name="quote">إقتباس</string>
|
||||
<string name="new_amount_in_sats">مبلغ جديد في Sats</string>
|
||||
<string name="add">إضافة</string>
|
||||
<string name="replying_to">الرد على</string>
|
||||
<string name="and">" و "</string>
|
||||
<string name="in_channel">"في القناة "</string>
|
||||
<string name="profile_banner">لافتة الملف الشخصي</string>
|
||||
<string name="following">المتابعون</string>
|
||||
<string name="followers">متابِعاً</string>
|
||||
<string name="profile">الملف الشخصي</string>
|
||||
<string name="security_filters">مرشحات الأمان</string>
|
||||
<string name="log_out">تسجيل الخروج</string>
|
||||
<string name="show_more">إظهار المزيد</string>
|
||||
<string name="lightning_invoice">Lightning فاتورة</string>
|
||||
<string name="pay">اإدفع</string>
|
||||
<string name="lightning_tips">Lightning تبرع</string>
|
||||
<string name="note_to_receiver">ملاحظة للمستقبل</string>
|
||||
<string name="thank_you_so_much">شكرا جزيلا!</string>
|
||||
<string name="amount_in_sats">المبلغ في Sats</string>
|
||||
<string name="send_sats">إرسال Sats</string>
|
||||
<string name="never_translate_from">"لا تترجم ابداً من "</string>
|
||||
<string name="error_parsing_preview_for">خطأ في تحليل المعاينة لـ %1$s : %2$s</string>
|
||||
<string name="preview_card_image_for">معاينة صورة البطاقة لـ %1$s</string>
|
||||
<string name="new_channel">قناة جديدة</string>
|
||||
<string name="can_t_find_out_the_content_type">لا يمكن معرفة نوع المحتوى</string>
|
||||
<string name="can_t_insert_the_new_content">لا يمكن إدراج المحتوى الجديد</string>
|
||||
<string name="can_t_open_the_content_output_stream">لا يمكن فتح دفق إخراج المحتوى</string>
|
||||
<string name="can_t_open_the_image_input_stream">لا يمكن فتح دفق إدخال الصورة</string>
|
||||
<string name="there_must_be_an_uploaded_image_url_in_the_response">يجب أن يكون هناك عنوان URL للصورة التي تم تحميلها في الاستجابة</string>
|
||||
<string name="channel_name">اسم القناة</string>
|
||||
<string name="my_awesome_group">مجموعتي الرائعة</string>
|
||||
<string name="picture_url">رابط الصورة</string>
|
||||
<string name="description">الوصف</string>
|
||||
<string name="about_us">معلومات عن القناة..</string>
|
||||
<string name="what_s_on_your_mind">ما الذي يدور في ذهنك؟</string>
|
||||
<string name="post">نشر</string>
|
||||
<string name="save">حفظ</string>
|
||||
<string name="create">إنشاء</string>
|
||||
<string name="cancel">إلغاء</string>
|
||||
<string name="failed_to_upload_the_image">فشل تحميل الصورة</string>
|
||||
<string name="relay_address">Relay عنوان</string>
|
||||
<string name="posts">المنشورات</string>
|
||||
<string name="errors">الأخطاء</string>
|
||||
<string name="home_feed">المنشورات الرئيسية</string>
|
||||
<string name="private_message_feed"> الرسائل الخاصة</string>
|
||||
<string name="public_chat_feed">الرسائل العامة</string>
|
||||
<string name="global_feed">الموجز العام</string>
|
||||
<string name="add_a_relay">أضف Relay</string>
|
||||
<string name="display_name">إسم العرض</string>
|
||||
<string name="my_display_name">إسم العرض الخاص بي</string>
|
||||
<string name="username">اسم المستخدم</string>
|
||||
<string name="my_username">اسم المستخدم الخاص بي</string>
|
||||
<string name="about_me">ْعَنِّي</string>
|
||||
<string name="avatar_url">رابط الصورة الزمزية</string>
|
||||
<string name="banner_url">رابط الشعار</string>
|
||||
<string name="website_url">رابط الموقع</string>
|
||||
<string name="ln_address">LN عنوان</string>
|
||||
<string name="ln_url_outdated">LN رابط (قديم)</string>
|
||||
<string name="image_saved_to_the_gallery">تم حفظ الصورة في المعرض</string>
|
||||
<string name="failed_to_save_the_image">فشل حفظ الصورة</string>
|
||||
<string name="upload_image">تحميل الصورة</string>
|
||||
<string name="uploading">جاري التحميل…</string>
|
||||
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">لا يمتلك المستخدم إعداد عنوان lighting لاستقبال sats</string>
|
||||
<string name="reply_here">"الرد هنا.. "</string>
|
||||
<string name="copies_the_note_id_to_the_clipboard_for_sharing">نسخ معرف الملاحظة إلى الحافظة للمشاركة</string>
|
||||
<string name="copy_channel_id_note_to_the_clipboard">انسخ معرف القناة (ملاحظة) إلى الحافظة</string>
|
||||
<string name="edits_the_channel_metadata">تعديل البيانات الوصفية للقناة</string>
|
||||
<string name="join">إنضمام</string>
|
||||
<string name="known">معروف</string>
|
||||
<string name="new_requests">طلبات جديدة</string>
|
||||
<string name="blocked_users">المستخدمين المحظورين</string>
|
||||
<string name="new_threads">المنشورات</string>
|
||||
<string name="conversations">المحادثات</string>
|
||||
<string name="notes">الملاحظات</string>
|
||||
<string name="replies">الردود</string>
|
||||
<string name="follows">المتابَعون</string>
|
||||
<string name="reports">التقارير</string>
|
||||
<string name="more_options">المزيد من الخيارات</string>
|
||||
<string name="relays">Relays</string>
|
||||
<string name="website">الموقع</string>
|
||||
<string name="lightning_address">Lightning عنوان</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">نسخ معرف Nsec (كلمة المرور الخاصة بك) إلى الحافظة للنسخ الاحتياطي</string>
|
||||
<string name="copy_private_key_to_the_clipboard">نسخ المفتاح الخاص إلى الحافظة</string>
|
||||
<string name="copies_the_public_key_to_the_clipboard_for_sharing">نسخ المفتاح العام إلى الحافظة للمشاركة</string>
|
||||
<string name="copy_public_key_npub_to_the_clipboard">انسخ المفتاح العام (NPub) إلى الحافظة</string>
|
||||
<string name="send_a_direct_message">إرسال رسالة مباشرة</string>
|
||||
<string name="edits_the_user_s_metadata">القيام بتحرير metadata للمستخدم</string>
|
||||
<string name="follow">متابعة</string>
|
||||
<string name="unblock">رفع الحظر</string>
|
||||
<string name="copy_user_id">نسخ معرف المستخدم</string>
|
||||
<string name="unblock_user">إلغاء حظر عن مستخدم</string>
|
||||
<string name="npub_hex_username">npub, hex, username </string>
|
||||
<string name="clear">نظف</string>
|
||||
<string name="app_logo">شعار التطبيق</string>
|
||||
<string name="nsec_npub_hex_private_key">nsec / npub / hex private key</string>
|
||||
<string name="show_password">إظهار كلمة السر</string>
|
||||
<string name="hide_password">اخفاء كلمة السر</string>
|
||||
<string name="invalid_key">مفتاح غير صحيح</string>
|
||||
<string name="i_accept_the">"اقبل شروط الاستخدام "</string>
|
||||
<string name="terms_of_use">شروط الاستخدام</string>
|
||||
<string name="acceptance_of_terms_is_required">يجب قبول شروط الإستخدام</string>
|
||||
<string name="key_is_required">المفتاح مطلوب</string>
|
||||
<string name="login">تسجيل دخول</string>
|
||||
<string name="generate_a_new_key">إنشاء مفتاح جديد</string>
|
||||
<string name="loading_feed">بإنتظار التحديثات</string>
|
||||
<string name="error_loading_replies">خطأ في تحميل الردود:</string>
|
||||
<string name="try_again">المحاولة مرة اخرى</string>
|
||||
<string name="feed_is_empty">لا توجد ملاحظات.</string>
|
||||
<string name="refresh">تحديث</string>
|
||||
<string name="created">انشئ</string>
|
||||
<string name="with_description_of">مع وصف</string>
|
||||
<string name="and_picture">و صورة</string>
|
||||
<string name="changed_chat_name_to">تم تغيير اسم الدردشة إلى</string>
|
||||
<string name="description_to">الوصف الى</string>
|
||||
<string name="and_picture_to">و الصورة الى</string>
|
||||
<string name="leave">مغادرة</string>
|
||||
<string name="unfollow">الغاء المتابعة</string>
|
||||
<string name="channel_created">تم انشاء القناة</string>
|
||||
<string name="channel_information_changed_to">تم تغيير معلومات القناة إلى</string>
|
||||
<string name="public_chat">الدردشة العامة</string>
|
||||
<string name="posts_received">تم استلام المشاركات</string>
|
||||
<string name="remove">ازالة</string>
|
||||
<string name="auto">تلقائي</string>
|
||||
<string name="translated_from">مترجم من</string>
|
||||
<string name="to">الى</string>
|
||||
<string name="show_in">تظهر في</string>
|
||||
<string name="first">اولا</string>
|
||||
<string name="always_translate_to">ترجمة إلى</string>
|
||||
<string name="never">ابداً</string>
|
||||
<string name="now">الان</string>
|
||||
<string name="h">س</string>
|
||||
<string name="m">د</string>
|
||||
<string name="d">يوم</string>
|
||||
<string name="nudity">عُري</string>
|
||||
<string name="profanity_hateful_speech">الألفاظ النابية / خطاب كراهية</string>
|
||||
<string name="report_hateful_speech">أبلغ عن كلام يحض على الكراهية</string>
|
||||
<string name="report_nudity_porn">الإبلاغ عن عُري / إباحي</string>
|
||||
<string name="others">others</string>
|
||||
</resources>
|
@ -1,4 +1,180 @@
|
||||
<resources>
|
||||
<string name="app_name_release">Amethyst</string>
|
||||
<string name="app_name_debug">Amethyst Debug</string>
|
||||
<string name="app_name_release" translatable="false">Amethyst</string>
|
||||
<string name="app_name_debug" translatable="false">Amethyst Debug</string>
|
||||
<string name="point_to_the_qr_code">Point to the QR Code</string>
|
||||
<string name="show_qr">Show QR</string>
|
||||
<string name="profile_image">Profile Image</string>
|
||||
<string name="scan_qr">Scan QR</string>
|
||||
<string name="show_anyway">Show Anyway</string>
|
||||
<string name="post_was_flagged_as_inappropriate_by">Post was flagged as inappropriate by</string>
|
||||
<string name="post_not_found">post not found</string>
|
||||
<string name="channel_image">Channel Image</string>
|
||||
<string name="referenced_event_not_found">Referenced event not found</string>
|
||||
<string name="could_not_decrypt_the_message">Could Not decrypt the message</string>
|
||||
<string name="group_picture">Group Picture</string>
|
||||
<string name="explicit_content">Explicit Content</string>
|
||||
<string name="spam">Spam</string>
|
||||
<string name="impersonation">Impersonation</string>
|
||||
<string name="illegal_behavior">Illegal Behavior</string>
|
||||
<string name="unknown">Unknown</string>
|
||||
<string name="relay_icon">Relay Icon</string>
|
||||
<string name="unknown_author">Unknown Author</string>
|
||||
<string name="copy_text">Copy Text</string>
|
||||
<string name="copy_user_pubkey">Copy User PubKey</string>
|
||||
<string name="copy_note_id">Copy Note ID</string>
|
||||
<string name="broadcast">Broadcast</string>
|
||||
<string name="block_hide_user"><![CDATA[Block & Hide User]]></string>
|
||||
<string name="report_spam_scam">Report Spam / Scam</string>
|
||||
<string name="report_impersonation">Report Impersonation</string>
|
||||
<string name="report_explicit_content">Report Explicit Content</string>
|
||||
<string name="report_illegal_behaviour">Report Illegal Behaviour</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_reply">Login with a Private key to be able to reply</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_boost_posts">Login with a Private key to be able to boost posts</string>
|
||||
<string name="login_with_a_private_key_to_like_posts">Login with a Private key to like Posts</string>
|
||||
<string name="no_zap_amount_setup_long_press_to_change">No Zap Amount Setup. Long Press to change</string>
|
||||
<string name="login_with_a_private_key_to_be_able_to_send_zaps">Login with a Private key to be able to send Zaps</string>
|
||||
<string name="zaps">Zaps</string>
|
||||
<string name="view_count">View count</string>
|
||||
<string name="boost">Boost</string>
|
||||
<string name="quote">Quote</string>
|
||||
<string name="new_amount_in_sats">New Amount in Sats</string>
|
||||
<string name="add">Add</string>
|
||||
<string name="replying_to">"replying to "</string>
|
||||
<string name="and">" and "</string>
|
||||
<string name="in_channel">"in channel "</string>
|
||||
<string name="profile_banner">Profile Banner</string>
|
||||
<string name="following">"Following"</string>
|
||||
<string name="followers">"Followers"</string>
|
||||
<string name="profile">Profile</string>
|
||||
<string name="security_filters">Security Filters</string>
|
||||
<string name="log_out">Log out</string>
|
||||
<string name="show_more">Show More</string>
|
||||
<string name="lightning_invoice">Lightning Invoice</string>
|
||||
<string name="pay">Pay</string>
|
||||
<string name="lightning_tips">Lightning Tips</string>
|
||||
<string name="note_to_receiver">Note to Receiver</string>
|
||||
<string name="thank_you_so_much">Thank you so much!</string>
|
||||
<string name="amount_in_sats">Amount in Sats</string>
|
||||
<string name="send_sats">Send Sats</string>
|
||||
<string name="never_translate_from">"Never translate from "</string>
|
||||
<string name="error_parsing_preview_for">"Error parsing preview for %1$s : %2$s"</string>
|
||||
<string name="preview_card_image_for">"Preview Card Image for %1$s"</string>
|
||||
<string name="new_channel">New Channel</string>
|
||||
<string name="can_t_find_out_the_content_type">Can\'t find out the content type</string>
|
||||
<string name="can_t_insert_the_new_content">Can\'t insert the new content</string>
|
||||
<string name="can_t_open_the_content_output_stream">Can\'t open the content output stream</string>
|
||||
<string name="can_t_open_the_image_input_stream">Can\'t open the image input stream</string>
|
||||
<string name="there_must_be_an_uploaded_image_url_in_the_response">There must be an uploaded image URL in the response</string>
|
||||
<string name="channel_name">Channel Name</string>
|
||||
<string name="my_awesome_group">My Awesome Group</string>
|
||||
<string name="picture_url">Picture Url</string>
|
||||
<string name="description">Description</string>
|
||||
<string name="about_us">"About us.. "</string>
|
||||
<string name="what_s_on_your_mind">What\'s on your mind?</string>
|
||||
<string name="post">Post</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="create">Create</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="failed_to_upload_the_image">Failed to upload the image</string>
|
||||
<string name="relay_address">Relay Address</string>
|
||||
<string name="posts">Posts</string>
|
||||
<string name="errors">Errors</string>
|
||||
<string name="home_feed">Home Feed</string>
|
||||
<string name="private_message_feed">Private Message Feed</string>
|
||||
<string name="public_chat_feed">Public Chat Feed</string>
|
||||
<string name="global_feed">Global Feed</string>
|
||||
<string name="add_a_relay">Add a Relay</string>
|
||||
<string name="display_name">Display Name</string>
|
||||
<string name="my_display_name">My display name</string>
|
||||
<string name="username">Username</string>
|
||||
<string name="my_username">My username</string>
|
||||
<string name="about_me">About me</string>
|
||||
<string name="avatar_url">Avatar URL</string>
|
||||
<string name="banner_url">Banner URL</string>
|
||||
<string name="website_url">Website URL</string>
|
||||
<string name="ln_address">LN Address</string>
|
||||
<string name="ln_url_outdated">LN URL (outdated)</string>
|
||||
<string name="image_saved_to_the_gallery">Image saved to the gallery</string>
|
||||
<string name="failed_to_save_the_image">Failed to save the image</string>
|
||||
<string name="upload_image">Upload Image</string>
|
||||
<string name="uploading">Uploading…</string>
|
||||
<string name="user_does_not_have_a_lightning_address_setup_to_receive_sats">User does not have a lightning address setup to receive sats</string>
|
||||
<string name="reply_here">"reply here.. "</string>
|
||||
<string name="copies_the_note_id_to_the_clipboard_for_sharing">Copies the Note ID to the clipboard for sharing</string>
|
||||
<string name="copy_channel_id_note_to_the_clipboard">Copy Channel ID (Note) to the Clipboard</string>
|
||||
<string name="edits_the_channel_metadata">Edits the Channel Metadata</string>
|
||||
<string name="join">Join</string>
|
||||
<string name="known">Known</string>
|
||||
<string name="new_requests">New Requests</string>
|
||||
<string name="blocked_users">Blocked Users</string>
|
||||
<string name="new_threads">New Threads</string>
|
||||
<string name="conversations">Conversations</string>
|
||||
<string name="notes">Notes</string>
|
||||
<string name="replies">Replies</string>
|
||||
<string name="follows">"Follows"</string>
|
||||
<string name="reports">"Reports"</string>
|
||||
<string name="more_options">More Options</string>
|
||||
<string name="relays">" Relays"</string>
|
||||
<string name="website">Website</string>
|
||||
<string name="lightning_address">Lightning Address</string>
|
||||
<string name="copies_the_nsec_id_your_password_to_the_clipboard_for_backup">Copies the Nsec ID (your password) to the clipboard for backup</string>
|
||||
<string name="copy_private_key_to_the_clipboard">Copy Private Key to the Clipboard</string>
|
||||
<string name="copies_the_public_key_to_the_clipboard_for_sharing">Copies the public key to the clipboard for sharing</string>
|
||||
<string name="copy_public_key_npub_to_the_clipboard">Copy Public Key (NPub) to the Clipboard</string>
|
||||
<string name="send_a_direct_message">Send a Direct Message</string>
|
||||
<string name="edits_the_user_s_metadata">Edits the User\'s Metadata</string>
|
||||
<string name="follow">Follow</string>
|
||||
<string name="unblock">Unblock</string>
|
||||
<string name="copy_user_id">Copy User ID</string>
|
||||
<string name="unblock_user">Unblock User</string>
|
||||
<string name="npub_hex_username">"npub, hex, username "</string>
|
||||
<string name="clear">Clear</string>
|
||||
<string name="app_logo">App Logo</string>
|
||||
<string name="nsec_npub_hex_private_key">nsec / npub / hex private key</string>
|
||||
<string name="show_password">Show Password</string>
|
||||
<string name="hide_password">Hide Password</string>
|
||||
<string name="invalid_key">Invalid key</string>
|
||||
<string name="i_accept_the">"I accept the "</string>
|
||||
<string name="terms_of_use">terms of use</string>
|
||||
<string name="acceptance_of_terms_is_required">Acceptance of terms is required</string>
|
||||
<string name="key_is_required">Key is required</string>
|
||||
<string name="login">Login</string>
|
||||
<string name="generate_a_new_key">Generate a new key</string>
|
||||
<string name="loading_feed">Loading feed</string>
|
||||
<string name="error_loading_replies">"Error loading replies: "</string>
|
||||
<string name="try_again">Try again</string>
|
||||
<string name="feed_is_empty">Feed is empty.</string>
|
||||
<string name="refresh">Refresh</string>
|
||||
<string name="created">created</string>
|
||||
<string name="with_description_of">with description of</string>
|
||||
<string name="and_picture">and picture</string>
|
||||
<string name="changed_chat_name_to">changed chat name to</string>
|
||||
<string name="description_to">description to</string>
|
||||
<string name="and_picture_to">and picture to</string>
|
||||
<string name="leave">Leave</string>
|
||||
<string name="unfollow">Unfollow</string>
|
||||
<string name="channel_created">Channel created</string>
|
||||
<string name="channel_information_changed_to">"Channel Information changed to"</string>
|
||||
<string name="public_chat">Public Chat</string>
|
||||
<string name="posts_received">posts received</string>
|
||||
<string name="remove">Remove</string>
|
||||
<string name="sats" translatable="false">sats</string>
|
||||
<string name="auto">Auto</string>
|
||||
<string name="translated_from">translated from</string>
|
||||
<string name="to">to</string>
|
||||
<string name="show_in">Show in</string>
|
||||
<string name="first">first</string>
|
||||
<string name="always_translate_to">Always translate to</string>
|
||||
<string name="nip_05" translatable="false">NIP-05</string>
|
||||
<string name="lnurl" translatable="false">LNURL...</string>
|
||||
<string name="never">never</string>
|
||||
<string name="now">now</string>
|
||||
<string name="h">h</string>
|
||||
<string name="m">m</string>
|
||||
<string name="d">d</string>
|
||||
<string name="nudity">Nudity</string>
|
||||
<string name="profanity_hateful_speech">Profanity / Hateful speech</string>
|
||||
<string name="report_hateful_speech">Report Hateful speech</string>
|
||||
<string name="report_nudity_porn">Report Nudity / Porn</string>
|
||||
<string name="others">others</string>
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user