mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2024-09-29 08:20:51 +00:00
Adds sensitive-content tags to NIP94 and NIP95 media
This commit is contained in:
parent
5c78135f1a
commit
b520a0faed
@ -474,6 +474,7 @@ class Account(
|
||||
dimensions = headerInfo.dim,
|
||||
blurhash = headerInfo.blurHash,
|
||||
description = headerInfo.description,
|
||||
sensitiveContent = headerInfo.sensitiveContent,
|
||||
privateKey = loggedIn.privKey!!
|
||||
)
|
||||
|
||||
@ -503,6 +504,7 @@ class Account(
|
||||
dimensions = headerInfo.dim,
|
||||
blurhash = headerInfo.blurHash,
|
||||
description = headerInfo.description,
|
||||
sensitiveContent = headerInfo.sensitiveContent,
|
||||
privateKey = loggedIn.privKey!!
|
||||
)
|
||||
|
||||
|
@ -16,15 +16,16 @@ class FileHeader(
|
||||
val size: Int,
|
||||
val dim: String?,
|
||||
val blurHash: String?,
|
||||
val description: String? = null
|
||||
val description: String? = null,
|
||||
val sensitiveContent: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
suspend fun prepare(fileUrl: String, mimeType: String?, description: String?, onReady: (FileHeader) -> Unit, onError: () -> Unit) {
|
||||
suspend fun prepare(fileUrl: String, mimeType: String?, description: String?, sensitiveContent: Boolean, onReady: (FileHeader) -> Unit, onError: () -> Unit) {
|
||||
try {
|
||||
val imageData: ByteArray? = ImageDownloader().waitAndGetImage(fileUrl)
|
||||
|
||||
if (imageData != null) {
|
||||
prepare(imageData, fileUrl, mimeType, description, onReady, onError)
|
||||
prepare(imageData, fileUrl, mimeType, description, sensitiveContent, onReady, onError)
|
||||
} else {
|
||||
onError()
|
||||
}
|
||||
@ -39,6 +40,7 @@ class FileHeader(
|
||||
fileUrl: String,
|
||||
mimeType: String?,
|
||||
description: String?,
|
||||
sensitiveContent: Boolean,
|
||||
onReady: (FileHeader) -> Unit,
|
||||
onError: () -> Unit
|
||||
) {
|
||||
@ -79,7 +81,7 @@ class FileHeader(
|
||||
Pair(null, null)
|
||||
}
|
||||
|
||||
onReady(FileHeader(fileUrl, mimeType, hash, size, dim, blurHash, description))
|
||||
onReady(FileHeader(fileUrl, mimeType, hash, size, dim, blurHash, description, sensitiveContent))
|
||||
} catch (e: Exception) {
|
||||
Log.e("ImageDownload", "Couldn't convert image in to File Header: ${e.message}")
|
||||
onError()
|
||||
|
@ -50,6 +50,7 @@ class FileHeaderEvent(
|
||||
magnetURI: String? = null,
|
||||
torrentInfoHash: String? = null,
|
||||
encryptionKey: AESGCM? = null,
|
||||
sensitiveContent: Boolean? = null,
|
||||
privateKey: ByteArray,
|
||||
createdAt: Long = Date().time / 1000
|
||||
): FileHeaderEvent {
|
||||
@ -62,7 +63,14 @@ class FileHeaderEvent(
|
||||
blurhash?.let { listOf(BLUR_HASH, it) },
|
||||
magnetURI?.let { listOf(MAGNET_URI, it) },
|
||||
torrentInfoHash?.let { listOf(TORRENT_INFOHASH, it) },
|
||||
encryptionKey?.let { listOf(ENCRYPTION_KEY, it.key, it.nonce) }
|
||||
encryptionKey?.let { listOf(ENCRYPTION_KEY, it.key, it.nonce) },
|
||||
sensitiveContent?.let {
|
||||
if (it) {
|
||||
listOf("content-warning", "")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val content = description ?: ""
|
||||
|
@ -50,6 +50,7 @@ class FileStorageHeaderEvent(
|
||||
magnetURI: String? = null,
|
||||
torrentInfoHash: String? = null,
|
||||
encryptionKey: AESGCM? = null,
|
||||
sensitiveContent: Boolean? = null,
|
||||
privateKey: ByteArray,
|
||||
createdAt: Long = Date().time / 1000
|
||||
): FileStorageHeaderEvent {
|
||||
@ -62,7 +63,14 @@ class FileStorageHeaderEvent(
|
||||
blurhash?.let { listOf(BLUR_HASH, it) },
|
||||
magnetURI?.let { listOf(MAGNET_URI, it) },
|
||||
torrentInfoHash?.let { listOf(TORRENT_INFOHASH, it) },
|
||||
encryptionKey?.let { listOf(ENCRYPTION_KEY, it.key, it.nonce) }
|
||||
encryptionKey?.let { listOf(ENCRYPTION_KEY, it.key, it.nonce) },
|
||||
sensitiveContent?.let {
|
||||
if (it) {
|
||||
listOf("content-warning", "")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
val content = description ?: ""
|
||||
|
@ -26,6 +26,7 @@ open class NewMediaModel : ViewModel() {
|
||||
|
||||
var selectedServer by mutableStateOf<ServersAvailable?>(null)
|
||||
var description by mutableStateOf("")
|
||||
var sensitiveContent by mutableStateOf(false)
|
||||
|
||||
// Images and Videos
|
||||
var galleryUri by mutableStateOf<Uri?>(null)
|
||||
@ -77,7 +78,7 @@ open class NewMediaModel : ViewModel() {
|
||||
uploadingPercentage.value = 0.2f
|
||||
uploadingDescription.value = "Loading"
|
||||
contentResolver.openInputStream(fileUri)?.use {
|
||||
createNIP95Record(it.readBytes(), contentType, description)
|
||||
createNIP95Record(it.readBytes(), contentType, description, sensitiveContent)
|
||||
}
|
||||
?: run {
|
||||
viewModelScope.launch {
|
||||
@ -97,7 +98,7 @@ open class NewMediaModel : ViewModel() {
|
||||
server = serverToUse,
|
||||
contentResolver = contentResolver,
|
||||
onSuccess = { imageUrl, mimeType ->
|
||||
createNIP94Record(imageUrl, mimeType, description)
|
||||
createNIP94Record(imageUrl, mimeType, description, sensitiveContent)
|
||||
},
|
||||
onError = {
|
||||
isUploadingImage = false
|
||||
@ -137,7 +138,7 @@ open class NewMediaModel : ViewModel() {
|
||||
return !isUploadingImage && galleryUri != null && selectedServer != null
|
||||
}
|
||||
|
||||
fun createNIP94Record(imageUrl: String, mimeType: String?, description: String) {
|
||||
fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean) {
|
||||
uploadingPercentage.value = 0.40f
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
uploadingDescription.value = "Server Processing"
|
||||
@ -157,6 +158,7 @@ open class NewMediaModel : ViewModel() {
|
||||
imageUrl,
|
||||
mimeType,
|
||||
description,
|
||||
sensitiveContent,
|
||||
onReady = {
|
||||
uploadingPercentage.value = 0.90f
|
||||
uploadingDescription.value = "Sending"
|
||||
@ -189,7 +191,7 @@ open class NewMediaModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String) {
|
||||
fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean) {
|
||||
uploadingPercentage.value = 0.30f
|
||||
uploadingDescription.value = "Hashing"
|
||||
|
||||
@ -199,6 +201,7 @@ open class NewMediaModel : ViewModel() {
|
||||
"",
|
||||
mimeType,
|
||||
description,
|
||||
sensitiveContent,
|
||||
onReady = {
|
||||
uploadingDescription.value = "Signing"
|
||||
uploadingPercentage.value = 0.40f
|
||||
|
@ -203,6 +203,18 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) {
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
SettingSwitchItem(
|
||||
checked = postViewModel.sensitiveContent,
|
||||
onCheckedChange = { postViewModel.sensitiveContent = it },
|
||||
title = R.string.add_sensitive_content_label,
|
||||
description = R.string.add_sensitive_content_description
|
||||
)
|
||||
}
|
||||
|
||||
if (isNIP94Server(postViewModel.selectedServer) ||
|
||||
postViewModel.selectedServer == ServersAvailable.NIP95
|
||||
) {
|
||||
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.selection.toggleable
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
@ -41,6 +42,7 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
@ -52,11 +54,13 @@ 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.semantics.Role
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDirection
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
@ -257,8 +261,8 @@ fun NewPostView(onClose: () -> Unit, baseReplyTo: Note? = null, quote: Note? = n
|
||||
ImageVideoDescription(
|
||||
url,
|
||||
account.defaultFileServer,
|
||||
onAdd = { description, server ->
|
||||
postViewModel.upload(url, description, server, context)
|
||||
onAdd = { description, server, sensitiveContent ->
|
||||
postViewModel.upload(url, description, sensitiveContent, server, context)
|
||||
account.changeDefaultFileServer(server)
|
||||
},
|
||||
onCancel = {
|
||||
@ -830,7 +834,7 @@ enum class ServersAvailable {
|
||||
fun ImageVideoDescription(
|
||||
uri: Uri,
|
||||
defaultServer: ServersAvailable,
|
||||
onAdd: (String, ServersAvailable) -> Unit,
|
||||
onAdd: (String, ServersAvailable, Boolean) -> Unit,
|
||||
onCancel: () -> Unit,
|
||||
onError: (String) -> Unit
|
||||
) {
|
||||
@ -859,6 +863,7 @@ fun ImageVideoDescription(
|
||||
|
||||
var selectedServer by remember { mutableStateOf(defaultServer) }
|
||||
var message by remember { mutableStateOf("") }
|
||||
var sensitiveContent by remember { mutableStateOf(false) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@ -983,6 +988,18 @@ fun ImageVideoDescription(
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
SettingSwitchItem(
|
||||
checked = sensitiveContent,
|
||||
onCheckedChange = { sensitiveContent = it },
|
||||
title = R.string.add_sensitive_content_label,
|
||||
description = R.string.add_sensitive_content_description
|
||||
)
|
||||
}
|
||||
|
||||
if (isNIP94Server(selectedServer) ||
|
||||
selectedServer == ServersAvailable.NIP95
|
||||
) {
|
||||
@ -1017,7 +1034,7 @@ fun ImageVideoDescription(
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 10.dp),
|
||||
onClick = {
|
||||
onAdd(message, selectedServer)
|
||||
onAdd(message, selectedServer, sensitiveContent)
|
||||
},
|
||||
shape = QuoteBorder,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
@ -1036,3 +1053,54 @@ data class ImmutableListOfLists<T>(val lists: List<List<T>> = emptyList())
|
||||
fun List<List<String>>.toImmutableListOfLists(): ImmutableListOfLists<String> {
|
||||
return ImmutableListOfLists(this)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingSwitchItem(
|
||||
modifier: Modifier = Modifier,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
title: Int,
|
||||
description: Int,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp)
|
||||
.toggleable(
|
||||
value = checked,
|
||||
enabled = enabled,
|
||||
role = Role.Switch,
|
||||
onValueChange = onCheckedChange
|
||||
),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1.0f),
|
||||
verticalArrangement = Arrangement.spacedBy(3.dp)
|
||||
) {
|
||||
val contentAlpha = if (enabled) ContentAlpha.high else ContentAlpha.disabled
|
||||
|
||||
Text(
|
||||
text = stringResource(id = title),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.alpha(contentAlpha)
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = description),
|
||||
style = MaterialTheme.typography.caption,
|
||||
color = Color.Gray,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier.alpha(contentAlpha)
|
||||
)
|
||||
}
|
||||
|
||||
Switch(
|
||||
checked = checked,
|
||||
onCheckedChange = null,
|
||||
enabled = enabled
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -179,7 +179,7 @@ open class NewPostViewModel() : ViewModel() {
|
||||
cancel()
|
||||
}
|
||||
|
||||
fun upload(galleryUri: Uri, description: String, server: ServersAvailable, context: Context) {
|
||||
fun upload(galleryUri: Uri, description: String, sensitiveContent: Boolean, server: ServersAvailable, context: Context) {
|
||||
isUploadingImage = true
|
||||
contentToAddUrl = null
|
||||
|
||||
@ -194,7 +194,7 @@ open class NewPostViewModel() : ViewModel() {
|
||||
onReady = { fileUri, contentType, size ->
|
||||
if (server == ServersAvailable.NIP95) {
|
||||
contentResolver.openInputStream(fileUri)?.use {
|
||||
createNIP95Record(it.readBytes(), contentType, description)
|
||||
createNIP95Record(it.readBytes(), contentType, description, sensitiveContent)
|
||||
}
|
||||
} else {
|
||||
ImageUploader.uploadImage(
|
||||
@ -205,7 +205,7 @@ open class NewPostViewModel() : ViewModel() {
|
||||
contentResolver = contentResolver,
|
||||
onSuccess = { imageUrl, mimeType ->
|
||||
if (isNIP94Server(server)) {
|
||||
createNIP94Record(imageUrl, mimeType, description)
|
||||
createNIP94Record(imageUrl, mimeType, description, sensitiveContent)
|
||||
} else {
|
||||
isUploadingImage = false
|
||||
message = TextFieldValue(message.text + "\n\n" + imageUrl)
|
||||
@ -370,13 +370,14 @@ open class NewPostViewModel() : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun createNIP94Record(imageUrl: String, mimeType: String?, description: String) {
|
||||
fun createNIP94Record(imageUrl: String, mimeType: String?, description: String, sensitiveContent: Boolean) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
// Images don't seem to be ready immediately after upload
|
||||
FileHeader.prepare(
|
||||
imageUrl,
|
||||
mimeType,
|
||||
description,
|
||||
sensitiveContent,
|
||||
onReady = {
|
||||
val note = account?.sendHeader(it)
|
||||
|
||||
@ -400,13 +401,14 @@ open class NewPostViewModel() : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String) {
|
||||
fun createNIP95Record(bytes: ByteArray, mimeType: String?, description: String, sensitiveContent: Boolean) {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
FileHeader.prepare(
|
||||
bytes,
|
||||
"",
|
||||
mimeType,
|
||||
description,
|
||||
sensitiveContent,
|
||||
onReady = {
|
||||
val nip95 = account?.createNip95(bytes, headerInfo = it)
|
||||
val note = nip95?.let { it1 -> account?.sendNip95(it1.first, it1.second) }
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.vitorpamplona.amethyst.ui.components
|
||||
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@ -75,7 +76,8 @@ fun SensitivityWarning(
|
||||
mutableStateOf(accountState?.account?.showSensitiveContent != true)
|
||||
}
|
||||
|
||||
if (showContentWarningNote) {
|
||||
Crossfade(targetState = showContentWarningNote) {
|
||||
if (it) {
|
||||
ContentWarningNote() {
|
||||
showContentWarningNote = false
|
||||
}
|
||||
@ -83,6 +85,7 @@ fun SensitivityWarning(
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ContentWarningNote(onDismiss: () -> Unit) {
|
||||
|
@ -71,6 +71,7 @@ import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdStartPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifier
|
||||
import com.vitorpamplona.amethyst.ui.theme.WidthAuthorPictureModifierWithPadding
|
||||
import com.vitorpamplona.amethyst.ui.theme.bitcoinColor
|
||||
import com.vitorpamplona.amethyst.ui.theme.newItemBackgroundColor
|
||||
import com.vitorpamplona.amethyst.ui.theme.overPictureBackground
|
||||
import com.vitorpamplona.amethyst.ui.theme.profile35dpModifier
|
||||
@ -445,7 +446,7 @@ fun CrossfadeToDisplayAmount(authorComment: MutableState<ZapAmountCommentNotific
|
||||
Text(
|
||||
text = it,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = MaterialTheme.colors.secondaryVariant,
|
||||
color = MaterialTheme.colors.bitcoinColor,
|
||||
fontSize = commentTextSize,
|
||||
modifier = bottomPadding1dp
|
||||
)
|
||||
|
@ -447,8 +447,8 @@ fun NormalNote(
|
||||
nav = nav
|
||||
)
|
||||
is BadgeDefinitionEvent -> BadgeDisplay(baseNote = baseNote)
|
||||
is FileHeaderEvent -> FileHeaderDisplay(baseNote)
|
||||
is FileStorageHeaderEvent -> FileStorageHeaderDisplay(baseNote)
|
||||
is FileHeaderEvent -> FileHeaderDisplay(baseNote, accountViewModel)
|
||||
is FileStorageHeaderEvent -> FileStorageHeaderDisplay(baseNote, accountViewModel)
|
||||
else ->
|
||||
LongPressToQuickAction(baseNote = baseNote, accountViewModel = accountViewModel) { showPopup ->
|
||||
CheckNewAndRenderNote(
|
||||
@ -2870,7 +2870,7 @@ private fun RenderBadge(
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FileHeaderDisplay(note: Note) {
|
||||
fun FileHeaderDisplay(note: Note, accountViewModel: AccountViewModel) {
|
||||
val event = (note.event as? FileHeaderEvent) ?: return
|
||||
val fullUrl = event.url() ?: return
|
||||
|
||||
@ -2901,13 +2901,15 @@ fun FileHeaderDisplay(note: Note) {
|
||||
|
||||
Crossfade(targetState = content) {
|
||||
if (it != null) {
|
||||
SensitivityWarning(note = note, accountViewModel = accountViewModel) {
|
||||
ZoomableContentView(content = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FileStorageHeaderDisplay(baseNote: Note) {
|
||||
fun FileStorageHeaderDisplay(baseNote: Note, accountViewModel: AccountViewModel) {
|
||||
val eventHeader = (baseNote.event as? FileStorageHeaderEvent) ?: return
|
||||
|
||||
var fileNote by remember { mutableStateOf<Note?>(null) }
|
||||
@ -2925,20 +2927,21 @@ fun FileStorageHeaderDisplay(baseNote: Note) {
|
||||
|
||||
Crossfade(targetState = fileNote) {
|
||||
if (it != null) {
|
||||
RenderNIP95(it, eventHeader, baseNote)
|
||||
RenderNIP95(it, eventHeader, baseNote, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderNIP95(
|
||||
it: Note,
|
||||
content: Note,
|
||||
eventHeader: FileStorageHeaderEvent,
|
||||
baseNote: Note
|
||||
header: Note,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
val appContext = LocalContext.current.applicationContext
|
||||
|
||||
val noteState by it.live().metadata.observeAsState()
|
||||
val noteState by content.live().metadata.observeAsState()
|
||||
val note = remember(noteState) { noteState?.note }
|
||||
|
||||
var content by remember { mutableStateOf<ZoomableContent?>(null) }
|
||||
@ -2946,7 +2949,7 @@ private fun RenderNIP95(
|
||||
if (content == null) {
|
||||
LaunchedEffect(key1 = eventHeader.id, key2 = noteState, key3 = note?.event) {
|
||||
launch(Dispatchers.IO) {
|
||||
val uri = "nostr:" + baseNote.toNEvent()
|
||||
val uri = "nostr:" + header.toNEvent()
|
||||
val localDir =
|
||||
note?.idHex?.let { File(File(appContext.externalCacheDir, "NIP95"), it) }
|
||||
val blurHash = eventHeader.blurhash()
|
||||
@ -2984,10 +2987,12 @@ private fun RenderNIP95(
|
||||
|
||||
Crossfade(targetState = content) {
|
||||
if (it != null) {
|
||||
SensitivityWarning(note = header, accountViewModel = accountViewModel) {
|
||||
ZoomableContentView(content = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||
|
@ -399,9 +399,9 @@ fun NoteMaster(
|
||||
if ((noteEvent is ChannelCreateEvent || noteEvent is ChannelMetadataEvent) && note.channelHex() != null) {
|
||||
ChannelHeader(channelHex = note.channelHex()!!, showVideo = true, showBottomDiviser = false, accountViewModel = accountViewModel, nav = nav)
|
||||
} else if (noteEvent is FileHeaderEvent) {
|
||||
FileHeaderDisplay(baseNote)
|
||||
FileHeaderDisplay(baseNote, accountViewModel)
|
||||
} else if (noteEvent is FileStorageHeaderEvent) {
|
||||
FileStorageHeaderDisplay(baseNote)
|
||||
FileStorageHeaderDisplay(baseNote, accountViewModel)
|
||||
} else if (noteEvent is PeopleListEvent) {
|
||||
DisplayPeopleList(baseNote, backgroundColor, accountViewModel, nav)
|
||||
} else if (noteEvent is AudioTrackEvent) {
|
||||
|
@ -421,7 +421,7 @@ fun EditFieldRow(
|
||||
accountViewModel.account.defaultFileServer
|
||||
}
|
||||
|
||||
channelScreenModel.upload(it, "", fileServer, context)
|
||||
channelScreenModel.upload(it, "", false, fileServer, context)
|
||||
}
|
||||
},
|
||||
colors = TextFieldDefaults.textFieldColors(
|
||||
|
@ -259,16 +259,16 @@ private fun RenderVideoOrPictureNote(
|
||||
Row(remember { Modifier.weight(1f) }, verticalAlignment = Alignment.CenterVertically) {
|
||||
val noteEvent = remember { note.event }
|
||||
if (noteEvent is FileHeaderEvent) {
|
||||
FileHeaderDisplay(note)
|
||||
FileHeaderDisplay(note, accountViewModel)
|
||||
} else if (noteEvent is FileStorageHeaderEvent) {
|
||||
FileStorageHeaderDisplay(note)
|
||||
FileStorageHeaderDisplay(note, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row(verticalAlignment = Alignment.Bottom, modifier = remember { Modifier.fillMaxSize(1f) }) {
|
||||
Column(remember { Modifier.weight(1f) }) {
|
||||
RenderVideoOrPicture(note, nav, accountViewModel)
|
||||
RenderAuthorInformation(note, nav, accountViewModel)
|
||||
}
|
||||
|
||||
Column(
|
||||
@ -287,7 +287,7 @@ private fun RenderVideoOrPictureNote(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RenderVideoOrPicture(
|
||||
private fun RenderAuthorInformation(
|
||||
note: Note,
|
||||
nav: (String) -> Unit,
|
||||
accountViewModel: AccountViewModel
|
||||
|
@ -32,16 +32,19 @@ private val DarkColorPalette = darkColors(
|
||||
primary = Purple200,
|
||||
primaryVariant = Purple700,
|
||||
secondary = Teal200,
|
||||
secondaryVariant = Color(0xFFF7931A)
|
||||
secondaryVariant = Purple200
|
||||
)
|
||||
|
||||
private val LightColorPalette = lightColors(
|
||||
primary = Purple500,
|
||||
primaryVariant = Purple700,
|
||||
secondary = Teal200,
|
||||
secondaryVariant = Color(0xFFB66605)
|
||||
secondaryVariant = Purple500
|
||||
)
|
||||
|
||||
private val BitcoinDark = Color(0xFFF7931A)
|
||||
private val BitcoinLight = Color(0xFFB66605)
|
||||
|
||||
private val DarkNewItemBackground = DarkColorPalette.primary.copy(0.12f)
|
||||
private val LightNewItemBackground = LightColorPalette.primary.copy(0.12f)
|
||||
|
||||
@ -279,6 +282,9 @@ val Colors.hashVerified: Color
|
||||
val Colors.overPictureBackground: Color
|
||||
get() = if (isLight) LightOverPictureBackground else DarkOverPictureBackground
|
||||
|
||||
val Colors.bitcoinColor: Color
|
||||
get() = if (isLight) BitcoinLight else BitcoinDark
|
||||
|
||||
val Colors.markdownStyle: RichTextStyle
|
||||
get() = if (isLight) MarkDownStyleOnLight else MarkDownStyleOnDark
|
||||
|
||||
|
@ -480,4 +480,7 @@
|
||||
|
||||
<string name="groups_no_descriptor">This group does not have a description or rules. Talk to the owner to add one</string>
|
||||
<string name="community_no_descriptor">This community does not have a description. Talk to the owner to add one</string>
|
||||
|
||||
<string name="add_sensitive_content_label">Sensitive Content</string>
|
||||
<string name="add_sensitive_content_description">Adds sensitive content warning before showing this content</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user