Merge branch 'vitorpamplona:main' into profiles-list-management
This commit is contained in:
@@ -44,8 +44,8 @@ android {
|
|||||||
applicationId = "com.vitorpamplona.amethyst"
|
applicationId = "com.vitorpamplona.amethyst"
|
||||||
minSdk = libs.versions.android.minSdk.get().toInteger()
|
minSdk = libs.versions.android.minSdk.get().toInteger()
|
||||||
targetSdk = libs.versions.android.targetSdk.get().toInteger()
|
targetSdk = libs.versions.android.targetSdk.get().toInteger()
|
||||||
versionCode = 427
|
versionCode = 428
|
||||||
versionName = generateVersionName("1.02.1")
|
versionName = generateVersionName("1.03.0")
|
||||||
buildConfigField "String", "RELEASE_NOTES_ID", "\"08abe267baf5d7ce14db7975866f929e2794cc23484171aef0816c60a2416597\""
|
buildConfigField "String", "RELEASE_NOTES_ID", "\"08abe267baf5d7ce14db7975866f929e2794cc23484171aef0816c60a2416597\""
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ abstract class Channel : NotesGatherer {
|
|||||||
return new
|
return new
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun participatingAuthors() = notes.mapNotNull { key, value -> value.author }
|
||||||
|
|
||||||
abstract fun toBestDisplayName(): String
|
abstract fun toBestDisplayName(): String
|
||||||
|
|
||||||
open fun relays(): Set<NormalizedRelayUrl> =
|
open fun relays(): Set<NormalizedRelayUrl> =
|
||||||
|
|||||||
+38
-8
@@ -26,6 +26,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.vitorpamplona.amethyst.model.Channel
|
import com.vitorpamplona.amethyst.model.Channel
|
||||||
import com.vitorpamplona.amethyst.model.ChannelState
|
import com.vitorpamplona.amethyst.model.ChannelState
|
||||||
|
import com.vitorpamplona.amethyst.model.LocalCache.notes
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
import com.vitorpamplona.amethyst.model.nip28PublicChats.PublicChatChannel
|
import com.vitorpamplona.amethyst.model.nip28PublicChats.PublicChatChannel
|
||||||
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
import com.vitorpamplona.amethyst.model.nip53LiveActivities.LiveActivitiesChannel
|
||||||
@@ -69,16 +70,10 @@ fun observeChannelNoteAuthors(
|
|||||||
.flow()
|
.flow()
|
||||||
.notes.stateFlow
|
.notes.stateFlow
|
||||||
.mapLatest {
|
.mapLatest {
|
||||||
it.channel.notes
|
channelToParticipatingUsers(it.channel, accountViewModel)
|
||||||
.mapNotNull { key, value -> value.author }
|
|
||||||
.toSet()
|
|
||||||
.toImmutableList()
|
|
||||||
}.onStart {
|
}.onStart {
|
||||||
emit(
|
emit(
|
||||||
baseChannel.notes
|
channelToParticipatingUsers(baseChannel, accountViewModel),
|
||||||
.mapNotNull { key, value -> value.author }
|
|
||||||
.toSet()
|
|
||||||
.toImmutableList(),
|
|
||||||
)
|
)
|
||||||
}.distinctUntilChanged()
|
}.distinctUntilChanged()
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
@@ -87,6 +82,41 @@ fun observeChannelNoteAuthors(
|
|||||||
return flow.collectAsStateWithLifecycle(persistentListOf())
|
return flow.collectAsStateWithLifecycle(persistentListOf())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun channelToParticipatingUsers(
|
||||||
|
channel: Channel,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
): ImmutableList<User> {
|
||||||
|
val users = mutableSetOf<User>()
|
||||||
|
|
||||||
|
channel.participatingAuthors().forEach {
|
||||||
|
users.add(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel is LiveActivitiesChannel) {
|
||||||
|
val noteAuthor = channel.infoNote?.author
|
||||||
|
if (noteAuthor != null) {
|
||||||
|
users.add(noteAuthor)
|
||||||
|
}
|
||||||
|
|
||||||
|
val pKeys = channel.info?.participantKeys() ?: emptyList()
|
||||||
|
|
||||||
|
pKeys.forEach {
|
||||||
|
val u = accountViewModel.checkGetOrCreateUser(it)
|
||||||
|
if (u != null) {
|
||||||
|
users.add(u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return users
|
||||||
|
.sortedWith(
|
||||||
|
compareBy(
|
||||||
|
{ !accountViewModel.isFollowing(it) },
|
||||||
|
{ it.pubkeyHex },
|
||||||
|
),
|
||||||
|
).toImmutableList()
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun observeChannelPicture(
|
fun observeChannelPicture(
|
||||||
|
|||||||
+164
-151
@@ -34,7 +34,6 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AlternateEmail
|
import androidx.compose.material.icons.filled.AlternateEmail
|
||||||
import androidx.compose.material.icons.filled.Block
|
import androidx.compose.material.icons.filled.Block
|
||||||
@@ -65,7 +64,6 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.shadow
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
@@ -82,6 +80,7 @@ import com.vitorpamplona.amethyst.R
|
|||||||
import com.vitorpamplona.amethyst.model.AddressableNote
|
import com.vitorpamplona.amethyst.model.AddressableNote
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.model.User
|
import com.vitorpamplona.amethyst.model.User
|
||||||
|
import com.vitorpamplona.amethyst.ui.navigation.navs.EmptyNav.scope
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo
|
import com.vitorpamplona.amethyst.ui.navigation.routes.routeEditDraftTo
|
||||||
import com.vitorpamplona.amethyst.ui.painterRes
|
import com.vitorpamplona.amethyst.ui.painterRes
|
||||||
@@ -89,6 +88,8 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.report.ReportNoteDialog
|
||||||
import com.vitorpamplona.amethyst.ui.stringRes
|
import com.vitorpamplona.amethyst.ui.stringRes
|
||||||
import com.vitorpamplona.amethyst.ui.theme.LightRedColor
|
import com.vitorpamplona.amethyst.ui.theme.LightRedColor
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.QuickActionPopupShadow
|
||||||
|
import com.vitorpamplona.amethyst.ui.theme.SmallestBorder
|
||||||
import com.vitorpamplona.amethyst.ui.theme.isLight
|
import com.vitorpamplona.amethyst.ui.theme.isLight
|
||||||
import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground
|
import com.vitorpamplona.amethyst.ui.theme.secondaryButtonBackground
|
||||||
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
|
import com.vitorpamplona.quartz.experimental.audio.track.AudioTrackEvent
|
||||||
@@ -231,20 +232,40 @@ private fun RenderMainPopup(
|
|||||||
showDeleteAlertDialog: MutableState<Boolean>,
|
showDeleteAlertDialog: MutableState<Boolean>,
|
||||||
showReportDialog: MutableState<Boolean>,
|
showReportDialog: MutableState<Boolean>,
|
||||||
onWantsToEditDraft: () -> Unit,
|
onWantsToEditDraft: () -> Unit,
|
||||||
|
) {
|
||||||
|
Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) {
|
||||||
|
val backgroundColor =
|
||||||
|
if (MaterialTheme.colorScheme.isLight) {
|
||||||
|
MaterialTheme.colorScheme.primary
|
||||||
|
} else {
|
||||||
|
MaterialTheme.colorScheme.secondaryButtonBackground
|
||||||
|
}
|
||||||
|
|
||||||
|
Card(
|
||||||
|
modifier = QuickActionPopupShadow,
|
||||||
|
shape = SmallestBorder,
|
||||||
|
colors = CardDefaults.cardColors(containerColor = backgroundColor),
|
||||||
|
) {
|
||||||
|
CardBody(accountViewModel, note, onDismiss, showBlockAlertDialog, showDeleteAlertDialog, showReportDialog, onWantsToEditDraft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardBody(
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
note: Note,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
showBlockAlertDialog: MutableState<Boolean>,
|
||||||
|
showDeleteAlertDialog: MutableState<Boolean>,
|
||||||
|
showReportDialog: MutableState<Boolean>,
|
||||||
|
onWantsToEditDraft: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val primaryLight = lightenColor(MaterialTheme.colorScheme.primary, 0.1f)
|
val primaryLight = lightenColor(MaterialTheme.colorScheme.primary, 0.1f)
|
||||||
val cardShape = RoundedCornerShape(5.dp)
|
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val backgroundColor =
|
|
||||||
if (MaterialTheme.colorScheme.isLight) {
|
|
||||||
MaterialTheme.colorScheme.primary
|
|
||||||
} else {
|
|
||||||
MaterialTheme.colorScheme.secondaryButtonBackground
|
|
||||||
}
|
|
||||||
|
|
||||||
val showToast = { stringRes: Int ->
|
val showToast = { stringRes: Int ->
|
||||||
scope.launch {
|
scope.launch {
|
||||||
Toast
|
Toast
|
||||||
@@ -259,157 +280,149 @@ private fun RenderMainPopup(
|
|||||||
val isOwnNote = accountViewModel.isLoggedUser(note.author)
|
val isOwnNote = accountViewModel.isLoggedUser(note.author)
|
||||||
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author)
|
val isFollowingUser = !isOwnNote && accountViewModel.isFollowing(note.author)
|
||||||
|
|
||||||
Popup(onDismissRequest = onDismiss, alignment = Alignment.Center) {
|
Column(modifier = Modifier.width(IntrinsicSize.Min)) {
|
||||||
Card(
|
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||||
modifier = Modifier.shadow(elevation = 6.dp, shape = cardShape),
|
NoteQuickActionItem(
|
||||||
shape = cardShape,
|
icon = Icons.Default.ContentCopy,
|
||||||
colors = CardDefaults.cardColors(containerColor = backgroundColor),
|
label = stringRes(R.string.quick_action_copy_text),
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.width(IntrinsicSize.Min)) {
|
accountViewModel.decrypt(note) {
|
||||||
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
clipboardManager.setText(AnnotatedString(it))
|
||||||
NoteQuickActionItem(
|
showToast(R.string.copied_note_text_to_clipboard)
|
||||||
icon = Icons.Default.ContentCopy,
|
}
|
||||||
label = stringRes(R.string.quick_action_copy_text),
|
|
||||||
) {
|
|
||||||
accountViewModel.decrypt(note) {
|
|
||||||
clipboardManager.setText(AnnotatedString(it))
|
|
||||||
showToast(R.string.copied_note_text_to_clipboard)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
VerticalDivider(color = primaryLight)
|
||||||
|
NoteQuickActionItem(
|
||||||
|
Icons.Default.AlternateEmail,
|
||||||
|
stringRes(R.string.quick_action_copy_user_id),
|
||||||
|
) {
|
||||||
|
note.author?.let {
|
||||||
|
scope.launch {
|
||||||
|
clipboardManager.setText(AnnotatedString(it.toNostrUri()))
|
||||||
|
showToast(R.string.copied_user_id_to_clipboard)
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
VerticalDivider(color = primaryLight)
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.AlternateEmail,
|
|
||||||
stringRes(R.string.quick_action_copy_user_id),
|
|
||||||
) {
|
|
||||||
note.author?.let {
|
|
||||||
scope.launch {
|
|
||||||
clipboardManager.setText(AnnotatedString(it.toNostrUri()))
|
|
||||||
showToast(R.string.copied_user_id_to_clipboard)
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
VerticalDivider(color = primaryLight)
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.FormatQuote,
|
|
||||||
stringRes(R.string.quick_action_copy_note_id),
|
|
||||||
) {
|
|
||||||
scope.launch {
|
|
||||||
clipboardManager.setText(AnnotatedString(note.toNostrUri()))
|
|
||||||
showToast(R.string.copied_note_id_to_clipboard)
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isOwnNote) {
|
|
||||||
VerticalDivider(color = primaryLight)
|
|
||||||
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.Block,
|
|
||||||
stringRes(R.string.quick_action_block),
|
|
||||||
) {
|
|
||||||
if (accountViewModel.account.settings.hideBlockAlertDialog) {
|
|
||||||
note.author?.let { accountViewModel.hide(it) }
|
|
||||||
onDismiss()
|
|
||||||
} else {
|
|
||||||
showBlockAlertDialog.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
HorizontalDivider(
|
}
|
||||||
color = primaryLight,
|
VerticalDivider(color = primaryLight)
|
||||||
)
|
NoteQuickActionItem(
|
||||||
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
Icons.Default.FormatQuote,
|
||||||
if (isOwnNote) {
|
stringRes(R.string.quick_action_copy_note_id),
|
||||||
NoteQuickActionItem(
|
) {
|
||||||
Icons.Default.Delete,
|
scope.launch {
|
||||||
stringRes(R.string.quick_action_delete),
|
clipboardManager.setText(AnnotatedString(note.toNostrUri()))
|
||||||
) {
|
showToast(R.string.copied_note_id_to_clipboard)
|
||||||
if (accountViewModel.account.settings.hideDeleteRequestDialog) {
|
onDismiss()
|
||||||
accountViewModel.delete(note)
|
}
|
||||||
onDismiss()
|
}
|
||||||
} else {
|
|
||||||
showDeleteAlertDialog.value = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isFollowingUser) {
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.PersonRemove,
|
|
||||||
stringRes(R.string.quick_action_unfollow),
|
|
||||||
) {
|
|
||||||
accountViewModel.unfollow(note.author!!)
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.PersonAdd,
|
|
||||||
stringRes(R.string.quick_action_follow),
|
|
||||||
) {
|
|
||||||
accountViewModel.follow(note.author!!)
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VerticalDivider(color = primaryLight)
|
if (!isOwnNote) {
|
||||||
NoteQuickActionItem(
|
VerticalDivider(color = primaryLight)
|
||||||
icon = ImageVector.vectorResource(id = R.drawable.relays),
|
|
||||||
label = stringRes(R.string.broadcast),
|
NoteQuickActionItem(
|
||||||
) {
|
Icons.Default.Block,
|
||||||
accountViewModel.broadcast(note)
|
stringRes(R.string.quick_action_block),
|
||||||
// showSelectTextDialog = true
|
) {
|
||||||
|
if (accountViewModel.account.settings.hideBlockAlertDialog) {
|
||||||
|
note.author?.let { accountViewModel.hide(it) }
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
|
||||||
VerticalDivider(color = primaryLight)
|
|
||||||
if (isOwnNote && note.isDraft()) {
|
|
||||||
NoteQuickActionItem(
|
|
||||||
Icons.Default.Edit,
|
|
||||||
stringRes(R.string.edit_draft),
|
|
||||||
) {
|
|
||||||
onWantsToEditDraft()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
NoteQuickActionItem(
|
showBlockAlertDialog.value = true
|
||||||
icon = Icons.Default.Share,
|
|
||||||
label = stringRes(R.string.quick_action_share),
|
|
||||||
) {
|
|
||||||
val sendIntent =
|
|
||||||
Intent().apply {
|
|
||||||
action = Intent.ACTION_SEND
|
|
||||||
type = "text/plain"
|
|
||||||
putExtra(
|
|
||||||
Intent.EXTRA_TEXT,
|
|
||||||
externalLinkForNote(note),
|
|
||||||
)
|
|
||||||
putExtra(
|
|
||||||
Intent.EXTRA_TITLE,
|
|
||||||
stringRes(context, R.string.quick_action_share_browser_link),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val shareIntent =
|
|
||||||
Intent.createChooser(
|
|
||||||
sendIntent,
|
|
||||||
stringRes(context, R.string.quick_action_share),
|
|
||||||
)
|
|
||||||
context.startActivity(shareIntent)
|
|
||||||
onDismiss()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!isOwnNote) {
|
}
|
||||||
VerticalDivider(color = primaryLight)
|
}
|
||||||
|
HorizontalDivider(
|
||||||
NoteQuickActionItem(
|
color = primaryLight,
|
||||||
Icons.Default.Report,
|
)
|
||||||
stringRes(R.string.quick_action_report),
|
Row(modifier = Modifier.height(IntrinsicSize.Min)) {
|
||||||
) {
|
if (isOwnNote) {
|
||||||
showReportDialog.value = true
|
NoteQuickActionItem(
|
||||||
}
|
Icons.Default.Delete,
|
||||||
|
stringRes(R.string.quick_action_delete),
|
||||||
|
) {
|
||||||
|
if (accountViewModel.account.settings.hideDeleteRequestDialog) {
|
||||||
|
accountViewModel.delete(note)
|
||||||
|
onDismiss()
|
||||||
|
} else {
|
||||||
|
showDeleteAlertDialog.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (isFollowingUser) {
|
||||||
|
NoteQuickActionItem(
|
||||||
|
Icons.Default.PersonRemove,
|
||||||
|
stringRes(R.string.quick_action_unfollow),
|
||||||
|
) {
|
||||||
|
accountViewModel.unfollow(note.author!!)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NoteQuickActionItem(
|
||||||
|
Icons.Default.PersonAdd,
|
||||||
|
stringRes(R.string.quick_action_follow),
|
||||||
|
) {
|
||||||
|
accountViewModel.follow(note.author!!)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerticalDivider(color = primaryLight)
|
||||||
|
NoteQuickActionItem(
|
||||||
|
icon = ImageVector.vectorResource(id = R.drawable.relays),
|
||||||
|
label = stringRes(R.string.broadcast),
|
||||||
|
) {
|
||||||
|
accountViewModel.broadcast(note)
|
||||||
|
// showSelectTextDialog = true
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
VerticalDivider(color = primaryLight)
|
||||||
|
if (isOwnNote && note.isDraft()) {
|
||||||
|
NoteQuickActionItem(
|
||||||
|
Icons.Default.Edit,
|
||||||
|
stringRes(R.string.edit_draft),
|
||||||
|
) {
|
||||||
|
onWantsToEditDraft()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NoteQuickActionItem(
|
||||||
|
icon = Icons.Default.Share,
|
||||||
|
label = stringRes(R.string.quick_action_share),
|
||||||
|
) {
|
||||||
|
val sendIntent =
|
||||||
|
Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
type = "text/plain"
|
||||||
|
putExtra(
|
||||||
|
Intent.EXTRA_TEXT,
|
||||||
|
externalLinkForNote(note),
|
||||||
|
)
|
||||||
|
putExtra(
|
||||||
|
Intent.EXTRA_TITLE,
|
||||||
|
stringRes(context, R.string.quick_action_share_browser_link),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val shareIntent =
|
||||||
|
Intent.createChooser(
|
||||||
|
sendIntent,
|
||||||
|
stringRes(context, R.string.quick_action_share),
|
||||||
|
)
|
||||||
|
context.startActivity(shareIntent)
|
||||||
|
onDismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isOwnNote) {
|
||||||
|
VerticalDivider(color = primaryLight)
|
||||||
|
|
||||||
|
NoteQuickActionItem(
|
||||||
|
Icons.Default.Report,
|
||||||
|
stringRes(R.string.quick_action_report),
|
||||||
|
) {
|
||||||
|
showReportDialog.value = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import androidx.compose.material3.Shapes
|
|||||||
import androidx.compose.material3.ripple
|
import androidx.compose.material3.ripple
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.Placeholder
|
import androidx.compose.ui.text.Placeholder
|
||||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||||
@@ -62,6 +63,7 @@ val RippleRadius45dp = 45.dp // Ripple should be +10.dp over the component size
|
|||||||
val BottomTopHeight = Modifier.height(50.dp)
|
val BottomTopHeight = Modifier.height(50.dp)
|
||||||
val TabRowHeight = Modifier
|
val TabRowHeight = Modifier
|
||||||
|
|
||||||
|
val SmallestBorder = RoundedCornerShape(5.dp)
|
||||||
val SmallBorder = RoundedCornerShape(7.dp)
|
val SmallBorder = RoundedCornerShape(7.dp)
|
||||||
val SmallishBorder = RoundedCornerShape(9.dp)
|
val SmallishBorder = RoundedCornerShape(9.dp)
|
||||||
val QuoteBorder = RoundedCornerShape(15.dp)
|
val QuoteBorder = RoundedCornerShape(15.dp)
|
||||||
@@ -360,3 +362,5 @@ val MaxWidthPaddingTop5dp = Modifier.fillMaxWidth().padding(top = 5.dp)
|
|||||||
val VoiceHeightModifier = Modifier.fillMaxWidth().height(100.dp)
|
val VoiceHeightModifier = Modifier.fillMaxWidth().height(100.dp)
|
||||||
|
|
||||||
val PaddingHorizontal12Modifier = Modifier.padding(horizontal = 12.dp)
|
val PaddingHorizontal12Modifier = Modifier.padding(horizontal = 12.dp)
|
||||||
|
|
||||||
|
val QuickActionPopupShadow = Modifier.shadow(elevation = Size6dp, shape = SmallestBorder)
|
||||||
|
|||||||
@@ -163,7 +163,12 @@ kotlin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
androidUnitTest.configure { dependsOn(jvmTest.get()) }
|
androidUnitTest.configure {
|
||||||
|
dependencies {
|
||||||
|
// Bitcoin secp256k1 bindings
|
||||||
|
implementation(libs.secp256k1.kmp.jni.jvm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
androidInstrumentedTest {
|
androidInstrumentedTest {
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|||||||
+1
-1
@@ -176,7 +176,7 @@ class MetadataEvent(
|
|||||||
|
|
||||||
val tags =
|
val tags =
|
||||||
latest.tags.builder {
|
latest.tags.builder {
|
||||||
alt("User profile for ${currentMetadata.get("name").asText() ?: "Anonymous"}")
|
alt("User profile for ${currentMetadata.get("name")?.asText() ?: "Anonymous"}")
|
||||||
|
|
||||||
// For https://github.com/nostr-protocol/nips/pull/1770
|
// For https://github.com/nostr-protocol/nips/pull/1770
|
||||||
currentMetadata.get(NameTag.TAG_NAME)?.asText()?.let { name(it) } ?: run { remove(NameTag.TAG_NAME) }
|
currentMetadata.get(NameTag.TAG_NAME)?.asText()?.let { name(it) } ?: run { remove(NameTag.TAG_NAME) }
|
||||||
|
|||||||
+5
-2
@@ -93,8 +93,10 @@ class RelayUrlNormalizer {
|
|||||||
|
|
||||||
@OptIn(ExperimentalContracts::class)
|
@OptIn(ExperimentalContracts::class)
|
||||||
fun fix(url: String): String? {
|
fun fix(url: String): String? {
|
||||||
if (url.length < 3) return null
|
if (url.length < 4) return null
|
||||||
if (url.length > 100) {
|
if (url.length > 50) {
|
||||||
|
if (url.indexOf("%00") > -1) return null
|
||||||
|
|
||||||
// removes multiple urls in the same line
|
// removes multiple urls in the same line
|
||||||
val schemeIdx = url.indexOf("://")
|
val schemeIdx = url.indexOf("://")
|
||||||
val nextScheme = url.indexOf("://", schemeIdx + 3)
|
val nextScheme = url.indexOf("://", schemeIdx + 3)
|
||||||
@@ -184,6 +186,7 @@ class RelayUrlNormalizer {
|
|||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
if (e is CancellationException) throw e
|
if (e is CancellationException) throw e
|
||||||
|
normalizedUrls.put(url, NormalizationResult.Error)
|
||||||
Log.w("NormalizedRelayUrl", "Rejected Error $url")
|
Log.w("NormalizedRelayUrl", "Rejected Error $url")
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -89,6 +89,8 @@ class LiveActivitiesEvent(
|
|||||||
|
|
||||||
fun totalParticipants() = tags.firstNotNullOfOrNull(TotalParticipantsTag::parse)
|
fun totalParticipants() = tags.firstNotNullOfOrNull(TotalParticipantsTag::parse)
|
||||||
|
|
||||||
|
fun participantKeys(): List<HexKey> = tags.mapNotNull(ParticipantTag::parseKey)
|
||||||
|
|
||||||
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
fun participants() = tags.mapNotNull(ParticipantTag::parse)
|
||||||
|
|
||||||
fun relays() = tags.mapNotNull(RelayListTag::parse)
|
fun relays() = tags.mapNotNull(RelayListTag::parse)
|
||||||
|
|||||||
Reference in New Issue
Block a user