mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-22 07:48:27 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
29b8f6916b | ||
|
|
a6519d57c6 | ||
|
|
2b2ee5bbfc | ||
|
|
62a6b7b7e0 | ||
|
|
5e0a1f9de1 | ||
|
|
571b1bc9cf | ||
|
|
a3e76225e6 |
@@ -12,8 +12,8 @@ android {
|
||||
applicationId "com.vitorpamplona.amethyst"
|
||||
minSdk 26
|
||||
targetSdk 34
|
||||
versionCode 372
|
||||
versionName "0.87.3"
|
||||
versionCode 373
|
||||
versionName "0.87.4"
|
||||
buildConfigField "String", "RELEASE_NOTES_ID", "\"863124b6592359494396c22b917f9d251ad12ac31b09ea29e0265e3c088ce9f8\""
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -36,6 +36,7 @@ fun TranslatableRichTextViewer(
|
||||
tags: ImmutableListOfLists<String>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
id: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) = ExpandableRichTextViewer(
|
||||
@@ -46,6 +47,7 @@ fun TranslatableRichTextViewer(
|
||||
tags,
|
||||
backgroundColor,
|
||||
id,
|
||||
callbackUri,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
@@ -40,6 +40,7 @@ import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import kotlin.time.measureTimedValue
|
||||
|
||||
@@ -53,7 +54,9 @@ class Amethyst : Application() {
|
||||
|
||||
val videoCache: VideoCache by lazy {
|
||||
val newCache = VideoCache()
|
||||
newCache.initFileCache(this)
|
||||
runBlocking {
|
||||
newCache.initFileCache(this@Amethyst)
|
||||
}
|
||||
newCache
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,12 @@ object CachedRichTextParser {
|
||||
fun parseText(
|
||||
content: String,
|
||||
tags: ImmutableListOfLists<String>,
|
||||
callbackUri: String? = null,
|
||||
): RichTextViewerState {
|
||||
return if (richTextCache[content] != null) {
|
||||
richTextCache[content]
|
||||
} else {
|
||||
val newUrls = RichTextParser().parseText(content, tags)
|
||||
val newUrls = RichTextParser().parseText(content, tags, callbackUri)
|
||||
richTextCache.put(content, newUrls)
|
||||
newUrls
|
||||
}
|
||||
|
||||
@@ -86,6 +86,8 @@ class MultiPlayerPlaybackManager(
|
||||
applicationContext: Context,
|
||||
): MediaSession {
|
||||
val existingSession = playingMap.get(id) ?: cache.get(id)
|
||||
// avoids saving positions for live streams otherwise caching goes crazy
|
||||
val mustCachePositions = !uri.contains(".m3u8", true)
|
||||
if (existingSession != null) return existingSession
|
||||
|
||||
val player =
|
||||
@@ -115,7 +117,9 @@ class MultiPlayerPlaybackManager(
|
||||
playingMap.put(id, mediaSession)
|
||||
} else {
|
||||
player.setWakeMode(C.WAKE_MODE_NONE)
|
||||
cachedPositions.add(uri, player.currentPosition)
|
||||
if (mustCachePositions) {
|
||||
cachedPositions.add(uri, player.currentPosition)
|
||||
}
|
||||
cache.put(id, mediaSession)
|
||||
playingMap.remove(id, mediaSession)
|
||||
}
|
||||
@@ -125,20 +129,22 @@ class MultiPlayerPlaybackManager(
|
||||
when (playbackState) {
|
||||
STATE_IDLE -> {
|
||||
// only saves if it wqs playing
|
||||
if (abs(player.currentPosition) > 1) {
|
||||
if (mustCachePositions && abs(player.currentPosition) > 1) {
|
||||
cachedPositions.add(uri, player.currentPosition)
|
||||
}
|
||||
}
|
||||
STATE_READY -> {
|
||||
cachedPositions.get(uri)?.let { lastPosition ->
|
||||
if (abs(player.currentPosition - lastPosition) > 5 * 60) {
|
||||
player.seekTo(lastPosition)
|
||||
if (mustCachePositions) {
|
||||
cachedPositions.get(uri)?.let { lastPosition ->
|
||||
if (abs(player.currentPosition - lastPosition) > 5 * 60) {
|
||||
player.seekTo(lastPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
// only saves if it wqs playing
|
||||
if (abs(player.currentPosition) > 1) {
|
||||
if (mustCachePositions && abs(player.currentPosition) > 1) {
|
||||
cachedPositions.add(uri, player.currentPosition)
|
||||
}
|
||||
}
|
||||
@@ -150,7 +156,9 @@ class MultiPlayerPlaybackManager(
|
||||
newPosition: PositionInfo,
|
||||
reason: Int,
|
||||
) {
|
||||
cachedPositions.add(uri, newPosition.positionMs)
|
||||
if (mustCachePositions) {
|
||||
cachedPositions.add(uri, newPosition.positionMs)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -34,41 +34,38 @@ import androidx.media3.session.MediaSession
|
||||
import androidx.media3.session.MediaSessionService
|
||||
import com.vitorpamplona.amethyst.Amethyst
|
||||
import com.vitorpamplona.amethyst.service.HttpClientManager
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class WssOrHttpFactory(httpClient: OkHttpClient) : MediaSource.Factory {
|
||||
@UnstableApi
|
||||
val http = DefaultMediaSourceFactory(OkHttpDataSource.Factory(httpClient))
|
||||
/**
|
||||
* HLS LiveStreams cannot use cache.
|
||||
*/
|
||||
@UnstableApi
|
||||
class CustomMediaSourceFactory() : MediaSource.Factory {
|
||||
private var cachingFactory: MediaSource.Factory =
|
||||
DefaultMediaSourceFactory(Amethyst.instance.videoCache.get(HttpClientManager.getHttpClient()))
|
||||
private var nonCachingFactory: MediaSource.Factory =
|
||||
DefaultMediaSourceFactory(OkHttpDataSource.Factory(HttpClientManager.getHttpClient()))
|
||||
|
||||
@UnstableApi
|
||||
val wss = DefaultMediaSourceFactory(WssStreamDataSource.Factory(httpClient))
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun setDrmSessionManagerProvider(drmSessionManagerProvider: DrmSessionManagerProvider): MediaSource.Factory {
|
||||
http.setDrmSessionManagerProvider(drmSessionManagerProvider)
|
||||
wss.setDrmSessionManagerProvider(drmSessionManagerProvider)
|
||||
cachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider)
|
||||
nonCachingFactory.setDrmSessionManagerProvider(drmSessionManagerProvider)
|
||||
return this
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy): MediaSource.Factory {
|
||||
http.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
|
||||
wss.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
|
||||
cachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
|
||||
nonCachingFactory.setLoadErrorHandlingPolicy(loadErrorHandlingPolicy)
|
||||
return this
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun getSupportedTypes(): IntArray {
|
||||
return http.supportedTypes
|
||||
return nonCachingFactory.supportedTypes
|
||||
}
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun createMediaSource(mediaItem: MediaItem): MediaSource {
|
||||
return if (mediaItem.mediaId.startsWith("wss")) {
|
||||
wss.createMediaSource(mediaItem)
|
||||
} else {
|
||||
http.createMediaSource(mediaItem)
|
||||
if (mediaItem.mediaId.contains(".m3u8", true)) {
|
||||
return nonCachingFactory.createMediaSource(mediaItem)
|
||||
}
|
||||
return cachingFactory.createMediaSource(mediaItem)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +78,7 @@ class PlaybackService : MediaSessionService() {
|
||||
fun newAllInOneDataSource(): MediaSource.Factory {
|
||||
// This might be needed for live kit.
|
||||
// return WssOrHttpFactory(HttpClientManager.getHttpClient())
|
||||
return DefaultMediaSourceFactory(Amethyst.instance.videoCache.get(HttpClientManager.getHttpClient()))
|
||||
return CustomMediaSourceFactory()
|
||||
}
|
||||
|
||||
fun lazyDS(): MultiPlayerPlaybackManager {
|
||||
|
||||
@@ -27,6 +27,8 @@ import androidx.media3.datasource.cache.CacheDataSource
|
||||
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
|
||||
import androidx.media3.datasource.cache.SimpleCache
|
||||
import androidx.media3.datasource.okhttp.OkHttpDataSource
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.File
|
||||
|
||||
@@ -41,16 +43,17 @@ class VideoCache {
|
||||
|
||||
lateinit var cacheDataSourceFactory: CacheDataSource.Factory
|
||||
|
||||
@Synchronized
|
||||
fun initFileCache(context: Context) {
|
||||
suspend fun initFileCache(context: Context) {
|
||||
exoDatabaseProvider = StandaloneDatabaseProvider(context)
|
||||
|
||||
simpleCache =
|
||||
SimpleCache(
|
||||
File(context.cacheDir, "exoplayer"),
|
||||
leastRecentlyUsedCacheEvictor,
|
||||
exoDatabaseProvider,
|
||||
)
|
||||
withContext(Dispatchers.IO) {
|
||||
simpleCache =
|
||||
SimpleCache(
|
||||
File(context.cacheDir, "exoplayer"),
|
||||
leastRecentlyUsedCacheEvictor,
|
||||
exoDatabaseProvider,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// This method should be called when proxy setting changes.
|
||||
|
||||
@@ -308,7 +308,7 @@ fun EditPostView(
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
} else {
|
||||
LoadUrlPreview(myUrlPreview, myUrlPreview, accountViewModel)
|
||||
LoadUrlPreview(myUrlPreview, myUrlPreview, null, accountViewModel)
|
||||
}
|
||||
} else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) {
|
||||
val bgColor = MaterialTheme.colorScheme.background
|
||||
@@ -323,7 +323,7 @@ fun EditPostView(
|
||||
nav = nav,
|
||||
)
|
||||
} else if (RichTextParser.isUrlWithoutScheme(myUrlPreview)) {
|
||||
LoadUrlPreview("https://$myUrlPreview", myUrlPreview, accountViewModel)
|
||||
LoadUrlPreview("https://$myUrlPreview", myUrlPreview, null, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -429,7 +429,7 @@ fun NewPostView(
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
} else {
|
||||
LoadUrlPreview(myUrlPreview, myUrlPreview, accountViewModel)
|
||||
LoadUrlPreview(myUrlPreview, myUrlPreview, null, accountViewModel)
|
||||
}
|
||||
} else if (RichTextParser.startsWithNIP19Scheme(myUrlPreview)) {
|
||||
val bgColor = MaterialTheme.colorScheme.background
|
||||
@@ -444,7 +444,7 @@ fun NewPostView(
|
||||
nav = nav,
|
||||
)
|
||||
} else if (RichTextParser.isUrlWithoutScheme(myUrlPreview)) {
|
||||
LoadUrlPreview("https://$myUrlPreview", myUrlPreview, accountViewModel)
|
||||
LoadUrlPreview("https://$myUrlPreview", myUrlPreview, null, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,15 +63,16 @@ fun NotifyRequestDialog(
|
||||
val background = remember { mutableStateOf(defaultBackground) }
|
||||
|
||||
TranslatableRichTextViewer(
|
||||
textContent,
|
||||
content = textContent,
|
||||
canPreview = true,
|
||||
quotesLeft = 1,
|
||||
Modifier.fillMaxWidth(),
|
||||
EmptyTagList,
|
||||
background,
|
||||
textContent,
|
||||
accountViewModel,
|
||||
nav,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = background,
|
||||
id = textContent,
|
||||
callbackUri = null,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
|
||||
@@ -64,6 +64,7 @@ fun ExpandableRichTextViewer(
|
||||
tags: ImmutableListOfLists<String>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
id: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@@ -99,6 +100,7 @@ fun ExpandableRichTextViewer(
|
||||
modifier.align(Alignment.TopStart),
|
||||
tags,
|
||||
backgroundColor,
|
||||
callbackUri,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
@@ -37,6 +37,7 @@ import com.vitorpamplona.amethyst.ui.theme.HalfVertPadding
|
||||
fun LoadUrlPreview(
|
||||
url: String,
|
||||
urlText: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
val automaticallyShowUrlPreview = remember { accountViewModel.settings.showUrlPreview.value }
|
||||
@@ -61,7 +62,7 @@ fun LoadUrlPreview(
|
||||
) { state ->
|
||||
when (state) {
|
||||
is UrlPreviewState.Loaded -> {
|
||||
RenderLoaded(state, url, accountViewModel)
|
||||
RenderLoaded(state, url, callbackUri, accountViewModel)
|
||||
}
|
||||
else -> {
|
||||
ClickableUrl(urlText, url)
|
||||
@@ -75,12 +76,13 @@ fun LoadUrlPreview(
|
||||
fun RenderLoaded(
|
||||
state: UrlPreviewState.Loaded,
|
||||
url: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
) {
|
||||
if (state.previewInfo.mimeType.type == "image") {
|
||||
Box(modifier = HalfVertPadding) {
|
||||
ZoomableContentView(
|
||||
content = MediaUrlImage(url),
|
||||
content = MediaUrlImage(url, uri = callbackUri),
|
||||
roundedCorner = true,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
@@ -88,7 +90,7 @@ fun RenderLoaded(
|
||||
} else if (state.previewInfo.mimeType.type == "video") {
|
||||
Box(modifier = HalfVertPadding) {
|
||||
ZoomableContentView(
|
||||
content = MediaUrlVideo(url),
|
||||
content = MediaUrlVideo(url, uri = callbackUri),
|
||||
roundedCorner = true,
|
||||
accountViewModel = accountViewModel,
|
||||
)
|
||||
|
||||
@@ -121,14 +121,15 @@ fun RichTextViewer(
|
||||
modifier: Modifier,
|
||||
tags: ImmutableListOfLists<String>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
if (remember(content) { isMarkdown(content) }) {
|
||||
RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
RenderContentAsMarkdown(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav)
|
||||
} else {
|
||||
RenderRegular(content, tags, canPreview, quotesLeft, backgroundColor, accountViewModel, nav)
|
||||
RenderRegular(content, tags, canPreview, quotesLeft, backgroundColor, callbackUri, accountViewModel, nav)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -267,7 +268,7 @@ fun RenderRegularPreview3() {
|
||||
) { word, state ->
|
||||
when (word) {
|
||||
// is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel)
|
||||
is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel)
|
||||
is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, null, accountViewModel)
|
||||
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
||||
is InvoiceSegment -> MayBeInvoicePreview(word.segmentText)
|
||||
is WithdrawSegment -> MayBeWithdrawal(word.segmentText)
|
||||
@@ -291,16 +292,18 @@ private fun RenderRegular(
|
||||
canPreview: Boolean,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
RenderRegular(content, tags) { word, state ->
|
||||
RenderRegular(content, tags, callbackUri) { word, state ->
|
||||
if (canPreview) {
|
||||
RenderWordWithPreview(
|
||||
word,
|
||||
state,
|
||||
backgroundColor,
|
||||
quotesLeft,
|
||||
callbackUri,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
@@ -321,9 +324,10 @@ private fun RenderRegular(
|
||||
fun RenderRegular(
|
||||
content: String,
|
||||
tags: ImmutableListOfLists<String>,
|
||||
callbackUri: String? = null,
|
||||
wordRenderer: @Composable (Segment, RichTextViewerState) -> Unit,
|
||||
) {
|
||||
val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags)) }
|
||||
val state by remember(content, tags) { mutableStateOf(CachedRichTextParser.parseText(content, tags, callbackUri)) }
|
||||
|
||||
val spaceWidth = measureSpaceWidth(LocalTextStyle.current)
|
||||
|
||||
@@ -412,12 +416,13 @@ private fun RenderWordWithPreview(
|
||||
state: RichTextViewerState,
|
||||
backgroundColor: MutableState<Color>,
|
||||
quotesLeft: Int,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
when (word) {
|
||||
is ImageSegment -> ZoomableContentView(word.segmentText, state, accountViewModel)
|
||||
is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, accountViewModel)
|
||||
is LinkSegment -> LoadUrlPreview(word.segmentText, word.segmentText, callbackUri, accountViewModel)
|
||||
is EmojiSegment -> RenderCustomEmoji(word.segmentText, state)
|
||||
is InvoiceSegment -> MayBeInvoicePreview(word.segmentText)
|
||||
is WithdrawSegment -> MayBeWithdrawal(word.segmentText)
|
||||
|
||||
@@ -542,15 +542,13 @@ fun GetVideoController(
|
||||
}
|
||||
}
|
||||
if (event == Lifecycle.Event.ON_PAUSE) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
if (!keepPlaying.value) {
|
||||
// Stops and releases the media.
|
||||
controller.value?.let {
|
||||
Log.d("PlaybackService", "Releasing Video from Pause $videoUri ")
|
||||
it.stop()
|
||||
it.release()
|
||||
controller.value = null
|
||||
}
|
||||
if (!keepPlaying.value) {
|
||||
// Stops and releases the media.
|
||||
controller.value?.let {
|
||||
Log.d("PlaybackService", "Releasing Video from Pause $videoUri ")
|
||||
it.stop()
|
||||
it.release()
|
||||
controller.value = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,7 @@ class MarkdownMediaRenderer(
|
||||
val canPreview: Boolean,
|
||||
val quotesLeft: Int,
|
||||
val backgroundColor: MutableState<Color>,
|
||||
val callbackUri: String? = null,
|
||||
val accountViewModel: AccountViewModel,
|
||||
val nav: (String) -> Unit,
|
||||
) : MediaRenderer {
|
||||
@@ -107,7 +108,7 @@ class MarkdownMediaRenderer(
|
||||
uri: String,
|
||||
richTextStringBuilder: RichTextString.Builder,
|
||||
) {
|
||||
val content = parser.parseMediaUrl(uri, eventTags = tags ?: EmptyTagList, startOfText)
|
||||
val content = parser.parseMediaUrl(uri, eventTags = tags ?: EmptyTagList, startOfText, callbackUri)
|
||||
|
||||
if (canPreview) {
|
||||
if (content != null) {
|
||||
@@ -123,7 +124,7 @@ class MarkdownMediaRenderer(
|
||||
renderAsCompleteLink(title ?: uri, uri, richTextStringBuilder)
|
||||
} else {
|
||||
renderInlineFullWidth(richTextStringBuilder) {
|
||||
LoadUrlPreview(uri, title ?: uri, accountViewModel)
|
||||
LoadUrlPreview(uri, title ?: uri, callbackUri, accountViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ fun RenderContentAsMarkdown(
|
||||
canPreview: Boolean,
|
||||
quotesLeft: Int,
|
||||
backgroundColor: MutableState<Color>,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@@ -70,13 +71,14 @@ fun RenderContentAsMarkdown(
|
||||
val renderer =
|
||||
remember(content) {
|
||||
MarkdownMediaRenderer(
|
||||
content.take(100),
|
||||
tags,
|
||||
canPreview,
|
||||
quotesLeft,
|
||||
backgroundColor,
|
||||
accountViewModel,
|
||||
nav,
|
||||
startOfText = content.take(100),
|
||||
tags = tags,
|
||||
canPreview = canPreview,
|
||||
quotesLeft = quotesLeft,
|
||||
backgroundColor = backgroundColor,
|
||||
callbackUri = callbackUri,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -396,9 +396,12 @@ fun AppNavigation(
|
||||
LaunchedEffect(intentNextPage) {
|
||||
if (actionableNextPage != null) {
|
||||
actionableNextPage?.let {
|
||||
navController.navigate(it) {
|
||||
popUpTo(Route.Home.route)
|
||||
launchSingleTop = true
|
||||
val currentRoute = getRouteWithArguments(navController)
|
||||
if (!isSameRoute(currentRoute, it)) {
|
||||
navController.navigate(it) {
|
||||
popUpTo(Route.Home.route)
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
actionableNextPage = null
|
||||
}
|
||||
|
||||
@@ -642,6 +642,7 @@ private fun RenderRegularTextNote(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundBubbleColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -655,6 +656,7 @@ private fun RenderRegularTextNote(
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = backgroundBubbleColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -179,6 +179,7 @@ private fun OptionNote(
|
||||
pollViewModel = pollViewModel,
|
||||
nonClickablePrepend = {
|
||||
RenderOptionAfterVote(
|
||||
baseNote,
|
||||
poolOption,
|
||||
color,
|
||||
canPreview,
|
||||
@@ -217,6 +218,7 @@ private fun OptionNote(
|
||||
|
||||
@Composable
|
||||
private fun RenderOptionAfterVote(
|
||||
baseNote: Note,
|
||||
poolOption: PollOption,
|
||||
color: Color,
|
||||
canPreview: Boolean,
|
||||
@@ -276,7 +278,8 @@ private fun RenderOptionAfterVote(
|
||||
Modifier,
|
||||
tags,
|
||||
backgroundColor,
|
||||
poolOption.descriptor,
|
||||
baseNote.idHex + poolOption.descriptor,
|
||||
baseNote.toNostrUri(),
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
@@ -236,6 +236,7 @@ fun RenderAppDefinition(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -220,6 +220,7 @@ fun AudioHeader(
|
||||
tags = tags,
|
||||
backgroundColor = background,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -188,6 +188,7 @@ private fun RenderGitPatchEvent(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -291,6 +292,7 @@ private fun RenderGitIssueEvent(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -100,15 +100,16 @@ fun DisplayHighlight(
|
||||
}
|
||||
|
||||
TranslatableRichTextViewer(
|
||||
quote,
|
||||
content = quote,
|
||||
canPreview = canPreview && !makeItShort,
|
||||
quotesLeft,
|
||||
Modifier.fillMaxWidth(),
|
||||
EmptyTagList,
|
||||
backgroundColor,
|
||||
quotesLeft = quotesLeft,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = backgroundColor,
|
||||
id = quote,
|
||||
accountViewModel,
|
||||
nav,
|
||||
callbackUri = null,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
DisplayQuoteAuthor(authorHex ?: "", url, postAddress, accountViewModel, nav)
|
||||
|
||||
@@ -138,6 +138,7 @@ fun RenderNIP90ContentDiscoveryResponse(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -41,7 +41,6 @@ import com.vitorpamplona.amethyst.ui.note.elements.DisplayUncitedHashtags
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||
import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer
|
||||
import com.vitorpamplona.amethyst.ui.theme.placeholderText
|
||||
import com.vitorpamplona.quartz.events.BaseTextNoteEvent
|
||||
import com.vitorpamplona.quartz.events.CommunityDefinitionEvent
|
||||
import com.vitorpamplona.quartz.events.EmptyTagList
|
||||
import com.vitorpamplona.quartz.events.PollNoteEvent
|
||||
@@ -65,22 +64,18 @@ fun RenderPoll(
|
||||
val showReply by
|
||||
remember(note) {
|
||||
derivedStateOf {
|
||||
noteEvent is BaseTextNoteEvent && !makeItShort && unPackReply && (note.replyTo != null || noteEvent.hasAnyTaggedUser())
|
||||
!makeItShort && unPackReply && (note.replyTo != null || noteEvent.hasAnyTaggedUser())
|
||||
}
|
||||
}
|
||||
|
||||
if (showReply) {
|
||||
val replyingDirectlyTo =
|
||||
remember(note) {
|
||||
if (noteEvent is BaseTextNoteEvent) {
|
||||
val replyingTo = noteEvent.replyingToAddressOrEvent()
|
||||
if (replyingTo != null) {
|
||||
val newNote = accountViewModel.getNoteIfExists(replyingTo)
|
||||
if (newNote != null && newNote.channelHex() == null && newNote.event?.kind() != CommunityDefinitionEvent.KIND) {
|
||||
newNote
|
||||
} else {
|
||||
note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND }
|
||||
}
|
||||
val replyingTo = noteEvent.replyingToAddressOrEvent()
|
||||
if (replyingTo != null) {
|
||||
val newNote = accountViewModel.getNoteIfExists(replyingTo)
|
||||
if (newNote != null && newNote.channelHex() == null && newNote.event?.kind() != CommunityDefinitionEvent.KIND) {
|
||||
newNote
|
||||
} else {
|
||||
note.replyTo?.lastOrNull { it.event?.kind() != CommunityDefinitionEvent.KIND }
|
||||
}
|
||||
@@ -116,6 +111,7 @@ fun RenderPoll(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -115,6 +115,7 @@ fun RenderPrivateMessage(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -144,6 +145,7 @@ fun RenderPrivateMessage(
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -76,6 +76,7 @@ fun RenderReport(
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
quotesLeft = 1,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
|
||||
@@ -149,6 +149,7 @@ fun RenderTextEvent(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -119,6 +119,7 @@ fun RenderTextModificationEvent(
|
||||
tags = EmptyTagList,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -169,6 +169,7 @@ fun VideoDisplay(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = note.idHex,
|
||||
callbackUri = note.toNostrUri(),
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
|
||||
@@ -338,8 +338,8 @@
|
||||
<string name="zap_type_nonzap_explainer">नोस्ट्र में कोई पदचिह्न नहीं, केवल लैटनिंग पर</string>
|
||||
<string name="file_server">अभिलेख सेवासंगणक</string>
|
||||
<string name="zap_forward_lnAddress">लै॰जाल पता अथवा @उपयोगकर्ता</string>
|
||||
<string name="upload_server_relays_nip95">आपके पुनःप्रसारक (NIP-95)</string>
|
||||
<string name="upload_server_relays_nip95_explainer">अभिलेख आपके पुनःप्रसारक द्वारा रखे जाते हैं। नया NIP: जाँच करें यदि वे सक्षम हैं</string>
|
||||
<string name="upload_server_relays_nip95">आपके पुनःप्रसारक (निप॰-९५)</string>
|
||||
<string name="upload_server_relays_nip95_explainer">अभिलेख आपके पुनःप्रसारक द्वारा रखे जाते हैं। नया निप॰: जाँच करें यदि वे अवलम्बन करते हैं</string>
|
||||
<string name="connect_via_tor_short">टोर / ओर्बोट स्थापन</string>
|
||||
<string name="connect_via_tor">आपकी ओर्बोट स्थापना द्वारा संयोजन करें</string>
|
||||
<string name="do_you_really_want_to_disable_tor_title">क्या आपके ओर्बोट / टोर से संयोजन काट दें</string>
|
||||
@@ -352,11 +352,11 @@
|
||||
<string name="follow_list_mute_list">मौन सूची</string>
|
||||
<string name="connect_through_your_orbot_setup_markdown">## टोर द्वारा संयोजन करें ओर्बोट के साथ
|
||||
\n\n१. स्थापित करें [ओर्बोट](https://play.google.com/store/apps/details?id=org.torproject.android)
|
||||
\n२. ओर्बोट आरम्भ करें
|
||||
\n२. ओर्बोट चलाएँ
|
||||
\n३. ओर्बोट में, सोक्स॰ द्वार का जाँच करें। मूलविकल्पतः ९०५० का प्रयोग करता है।
|
||||
\n४. यदि आवश्यक हो तो ओर्बोट में द्वार परिवर्तित करें
|
||||
\n५. सोक्स॰ द्वार की समाकृति करें इस पटल पर
|
||||
\n६. सक्रिय करें घुण्डी दबाएँ ओर्बोट को मध्यस्थ के रूप में प्रयोग करने के लिए
|
||||
\n६. सक्रिय करें सूचकयुक्त घुण्डी दबाएँ ओर्बोट को प्रतिनिधि के रूप में प्रयोग करने के लिए
|
||||
</string>
|
||||
<string name="orbot_socks_port">ओर्बोट सोक्स॰ द्वार</string>
|
||||
<string name="invalid_port_number">द्वार अंक अमान्य</string>
|
||||
@@ -372,7 +372,7 @@
|
||||
<string name="reply_notify">सूचित करें : </string>
|
||||
<string name="channel_list_join_conversation">संवाद में जुड जाएँ</string>
|
||||
<string name="channel_list_user_or_group_id">उपयोगकर्ता अथवा झुण्ड विभेदक</string>
|
||||
<string name="channel_list_user_or_group_id_demo">npub, nevent अथवा षोडशांकरूप</string>
|
||||
<string name="channel_list_user_or_group_id_demo">एनपुब॰, एनइवेण्ट॰ अथवा षोडशांकरूप</string>
|
||||
<string name="channel_list_create_channel">बनाएँ</string>
|
||||
<string name="channel_list_join_channel">जुडें</string>
|
||||
<string name="today">आज</string>
|
||||
@@ -383,7 +383,7 @@
|
||||
<string name="content_warning_see_warnings">विषयवस्तु चेतावनियाँ सर्वदा दिखाएँ</string>
|
||||
<string name="recommended_apps">पुनःप्रशंसित : </string>
|
||||
<string name="filter_spam_from_strangers">अपरिचित जन के भेजे गये कचरालेखों को छलनी द्वारा हटाएँ</string>
|
||||
<string name="warn_when_posts_have_reports_from_your_follows">चेतावनी दें जब पत्र सूचित किये गये हों आपके द्वारा अनुचरणित व्यक्तियों से</string>
|
||||
<string name="warn_when_posts_have_reports_from_your_follows">चेतावनी दें जब पत्र सूचित किये गये हों आपके द्वारा अनुचरित व्यक्तियों से</string>
|
||||
<string name="new_reaction_symbol">नया प्रतिक्रिया चिह्न</string>
|
||||
<string name="no_reaction_type_setup_long_press_to_change">इस उपयोगकर्ता के लिए कोई प्रतिक्रिया प्रकार पूर्व चयनित नहीं। हृदयचिह्न घुण्डी पर दीर्घतः दबाएँ परिवर्तन करने के लिए</string>
|
||||
<string name="zapraiser">ज्सापोपार्जन योजना</string>
|
||||
@@ -399,7 +399,7 @@
|
||||
<string name="version">संस्करण</string>
|
||||
<string name="software">क्रमक</string>
|
||||
<string name="contact">सम्पर्क</string>
|
||||
<string name="supports">सक्षम NIPs</string>
|
||||
<string name="supports">अवलम्बन किए हुए निप॰ सूची</string>
|
||||
<string name="admission_fees">प्रवेश शुल्क</string>
|
||||
<string name="payments_url">भुगतान जालपता</string>
|
||||
<string name="limitations">परिसीमाएँ</string>
|
||||
@@ -414,13 +414,13 @@
|
||||
<string name="minimum_prefix">न्यूनतम उपसर्ग</string>
|
||||
<string name="maximum_event_tags">अधिकतम घटना विषयसूचक</string>
|
||||
<string name="content_length">विषयवस्तु लम्बाई</string>
|
||||
<string name="minimum_pow">न्यूनतम PoW</string>
|
||||
<string name="minimum_pow">न्यूनतम श्रमप्रमाण</string>
|
||||
<string name="auth">प्रमाणीकरण</string>
|
||||
<string name="payment">भुगतान</string>
|
||||
<string name="cashu">काश्यु लिपिखण्ड</string>
|
||||
<string name="cashu">काशयु लिपिखण्ड</string>
|
||||
<string name="cashu_redeem">चुकाएँ</string>
|
||||
<string name="cashu_redeem_to_zap">ज्साप धनकोष को भेजें</string>
|
||||
<string name="cashu_redeem_to_cashu">काश्यु धनकोष में खोलें</string>
|
||||
<string name="cashu_redeem_to_cashu">काशयु धनकोष में खोलें</string>
|
||||
<string name="cashu_copy_token">लिपिखण्ड की अनुकृति करें</string>
|
||||
<string name="no_lightning_address_set">कोई लैटनिंग पता स्थापित नहीं</string>
|
||||
<string name="copied_token_to_clipboard">लिपिखण्ड की अनुकृति की गयी टाँकाफलक में</string>
|
||||
@@ -445,9 +445,9 @@
|
||||
<string name="add_sensitive_content_description">इसे दिखाने से पूर्व संवेदनशील विषयवस्तु चेतावनी जोडता है</string>
|
||||
<string name="settings">स्थापना विकल्प</string>
|
||||
<string name="connectivity_type_always">सर्वदा</string>
|
||||
<string name="connectivity_type_wifi_only">केवल वैफै</string>
|
||||
<string name="connectivity_type_wifi_only">केवल वै॰फै॰</string>
|
||||
<string name="connectivity_type_never">कभी नहीं</string>
|
||||
<string name="ui_feature_set_type_complete">सम्पन्न</string>
|
||||
<string name="ui_feature_set_type_complete">सम्पूर्ण</string>
|
||||
<string name="ui_feature_set_type_simplified">सरलीकृत</string>
|
||||
<string name="system">यन्त्रव्यवस्था</string>
|
||||
<string name="light">प्रकाशवान</string>
|
||||
@@ -458,17 +458,17 @@
|
||||
<string name="automatically_load_images_gifs">चित्र पूर्वीक्षण</string>
|
||||
<string name="automatically_play_videos">चलचित्र का चालन</string>
|
||||
<string name="automatically_show_url_preview">जालपता पूर्वीक्षण</string>
|
||||
<string name="automatically_hide_nav_bars">निमग्न पृष्ठघुमाव</string>
|
||||
<string name="automatically_hide_nav_bars">निमग्नकारी पृष्ठघुमाव</string>
|
||||
<string name="automatically_hide_nav_bars_description">मार्गदर्शनपट्टियों को छिपाएँ पृष्ठघुमाव करने पर</string>
|
||||
<string name="ui_style">प्रयोगमाध्यम शैली</string>
|
||||
<string name="ui_style_description">पत्र प्रकाशन शैली का चयन करें</string>
|
||||
<string name="load_image">चित्र प्राप्त करें</string>
|
||||
<string name="spamming_users">कचरालेख प्रेषक</string>
|
||||
<string name="muted_button">मौन किया गया। सुनने के लिए टाँकें</string>
|
||||
<string name="muted_button">मौन किया गया। अमौन करने के लिए टाँकें</string>
|
||||
<string name="mute_button">ध्वनि सक्रिय। मौन करने के लिए टाँकें</string>
|
||||
<string name="search_button">स्थानीय तथा दूरस्थ अभिलेखों को खोजें</string>
|
||||
<string name="nip05_verified">नोस्ट्र पता का सत्यापन सफल</string>
|
||||
<string name="nip05_failed">नोस्ट्र पता का सत्यातन असफल</string>
|
||||
<string name="nip05_failed">नोस्ट्र पता का सत्यापन असफल</string>
|
||||
<string name="nip05_checking">नोस्ट्र पता का जाँच चल रहा है</string>
|
||||
<string name="select_deselect_all">सब का चयन / अचयन करें</string>
|
||||
<string name="default_relays">मूलविकल्प</string>
|
||||
@@ -479,7 +479,7 @@
|
||||
<string name="geohash_explainer">आपका भूगोलिक स्थान विभेदक जोडता है पत्र में। जनता जान जाएगी कि आप वर्तमान स्थान से ५ कि॰मे॰ (३ मी॰) की दूरी के अन्दर हैं</string>
|
||||
<string name="add_sensitive_content_explainer">आपके विषयवस्तु दिखाने से पूर्व संवेदनशील विषयवस्तु चेतावनी जोडता है। यह आदर्श है किसी कार्यालय अनुचित विषयवस्तु के लिए अथवा जो कुछ लोगों के लिए आपत्तिजनक अथवा व्याकुल करनेवाला लग सकता है</string>
|
||||
<string name="new_feature_nip17_might_not_be_available_title">नयी सुविधा</string>
|
||||
<string name="new_feature_nip17_might_not_be_available_description">इस कार्यशैली सक्षम करने के लिए अमेथिस्ट के द्वारा NIP-17 संदेश (उपहारकोषयुक्त, आच्छादित सीधा तथा झुण्ड संदेश) भेजना पडेगा। यह NIP-17 नया है तथा अनेक ग्राहक इसे कार्यान्वित किया नहीं अब तक। सुनिश्चित करें कि प्राप्तकर्ता एक अनुकूल ग्राहक का प्रयोग कर रहे हैं।</string>
|
||||
<string name="new_feature_nip17_might_not_be_available_description">इस कार्यशैली सक्षम करने के लिए अमेथिस्ट के द्वारा निप॰-१७ संदेश (उपहारकोषयुक्त, आच्छादित सीधा तथा झुण्ड संदेश) भेजना पडेगा। यह निप॰-१७ नया है तथा अनेक ग्राहक इसे कार्यान्वित किया नहीं अब तक। सुनिश्चित करें कि प्राप्तकर्ता एक अनुकूल ग्राहक का प्रयोग कर रहे हैं।</string>
|
||||
<string name="new_feature_nip17_activate">सक्रिय करें</string>
|
||||
<string name="messages_create_public_chat">सार्वजनिक</string>
|
||||
<string name="messages_create_public_private_chat_desription">नया निजी अथवा सार्वजनिक झुण्ड</string>
|
||||
@@ -494,12 +494,12 @@
|
||||
<string name="paste_from_clipboard">टाँकाफलक से चिपकाएँ</string>
|
||||
<string name="language_description">क्रमक के प्रयोगमाध्यम के लिए</string>
|
||||
<string name="theme_description">अन्धकारमय, प्रकाशवान अथवा यन्त्रव्यवस्थित प्रदर्शनशैली</string>
|
||||
<string name="automatically_load_images_gifs_description">स्वचालित रूप से चित्र तथा GIFs का अवरोहण करें</string>
|
||||
<string name="automatically_play_videos_description">स्वचालित रूप से चलचित्र तथा GIFs चलाता है</string>
|
||||
<string name="automatically_load_images_gifs_description">स्वचालित रूप से चित्र तथा जिफ॰ का अवरोहण करें</string>
|
||||
<string name="automatically_play_videos_description">स्वचालित रूप से चलचित्र तथा जिफ॰ चलाता है</string>
|
||||
<string name="automatically_show_url_preview_description">जालपता के पूर्वीक्षण दिखाएँ</string>
|
||||
<string name="load_image_description">चित्रों का अवरोहण कब करें</string>
|
||||
<string name="copy_to_clipboard">टाँकाफलक में अनुकृति करें</string>
|
||||
<string name="copy_npub_to_clipboard">टाँकाफलक में npub का अनुकरण करें</string>
|
||||
<string name="copy_npub_to_clipboard">टाँकाफलक में एनपुब॰ की अनुकृति करें</string>
|
||||
<string name="copy_url_to_clipboard">टाँकाफलक में जालपता की अनुकृति करें</string>
|
||||
<string name="copy_the_note_id_to_the_clipboard">टाँकाफलक में टीका विभेदक की अनुकृति करें</string>
|
||||
<string name="created_at">तब बनाया गया</string>
|
||||
@@ -548,14 +548,14 @@
|
||||
<string name="error_dialog_pay_invoice_error">चालान का भुगतान नहीं कर पाए</string>
|
||||
<string name="error_dialog_pay_withdraw_error">निकाल नहीं पाए</string>
|
||||
<string name="error_parsing_nip47_title">धनकोष संयोजन स्थापित नहीं कर पाए</string>
|
||||
<string name="error_parsing_nip47">NIP-47 संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s। अपक्रम : %2$s</string>
|
||||
<string name="error_parsing_nip47_no_error">NIP-47 संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s।</string>
|
||||
<string name="cashu_failed_redemption">काश्यु नहीं चुका पाए</string>
|
||||
<string name="error_parsing_nip47">निप॰-४७ संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s। अपक्रम : %2$s</string>
|
||||
<string name="error_parsing_nip47_no_error">निप॰-४७ संयोजन सूत्र परखने में अपक्रम। जाँच करें यदि यह सम्यक है अपने धनकोष सेवा प्रदाता के साथ : %1$s।</string>
|
||||
<string name="cashu_failed_redemption">काशयु नहीं चुका पाए</string>
|
||||
<string name="cashu_failed_redemption_explainer_error_msg">टकसाल ने यह अपक्रम संदेश उपलब्ध किया : %1$s</string>
|
||||
<string name="cashu_failed_redemption_explainer_already_spent">काश्यु लिपिखण्ड का व्यय हो चुका।</string>
|
||||
<string name="cashu_successful_redemption">काश्यु प्राप्त</string>
|
||||
<string name="cashu_failed_redemption_explainer_already_spent">काशयु लिपिखण्ड का व्यय हो चुका।</string>
|
||||
<string name="cashu_successful_redemption">काशयु प्राप्त</string>
|
||||
<string name="cashu_successful_redemption_explainer">%1$s साट्स भेजे गये आपके धनकोष में। (शुल्क : %2$s साट्स)</string>
|
||||
<string name="cashu_no_wallet_found">कोई अनुकूल काश्यु धनकोष उपलब्ध नहीं यन्त्र में</string>
|
||||
<string name="cashu_no_wallet_found">कोई अनुकूल काशयु धनकोष उपलब्ध नहीं यन्त्र में</string>
|
||||
<string name="error_unable_to_fetch_invoice">ग्राहक के सेवा संगणक से चालान नहीं लाया जा सका</string>
|
||||
<string name="wallet_connect_pay_invoice_error_error">आपका धनकोष संयोजन प्रदाता ने यह अपक्रम लौटाया : %1$s</string>
|
||||
<string name="could_not_connect_to_tor">टोर से जुड नहीं पाए</string>
|
||||
@@ -565,17 +565,17 @@
|
||||
<string name="could_not_resolve_check_if_you_are_connected_if_the_server_is_up_and_if_the_lightning_address_is_correct">%1$s का सुलझाव नहीं कर पाए। जाँच करें यदि आप संयोजित हैं, यदि सेवा संगणक चल रहा है तथा यदि लैटनिंग पता %2$s सम्यक है</string>
|
||||
<string name="could_not_resolve_check_if_you_are_connected_if_the_server_is_up_and_if_the_lightning_address_is_correct_exception">%1$s का सुलझाव नहीं कर पाए। जाँच करें यदि आप संयोजित हैं, यदि सेवा संगणक चल रहा है तथा यदि लैटनिंग पता %2$s सम्यक है।\n\nअपवर्ग था : %3$s</string>
|
||||
<string name="could_not_fetch_invoice_from">%1$s से चालान नहीं लाया जा सका</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup">लैटनिंग पता से JSON परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup_with_user">%1$s से JSON परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup">लैटनिंग पता से जेसोन॰ परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_check_the_user_s_lightning_setup_with_user">%1$s से जेसोन॰ परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="callback_url_not_found_in_the_user_s_lightning_address_server_configuration">प्रत्याह्वान जालपता उपलब्ध नहीं उपयोगकर्ता के लैटनिंग पता सेवासंगणक की समाकृति में</string>
|
||||
<string name="callback_url_not_found_in_the_user_s_lightning_address_server_configuration_with_user">प्रत्याह्वान जालपता उपलब्ध नहीं %1$s के उत्तर से</string>
|
||||
<string name="error_parsing_json_from_lightning_address_s_invoice_fetch_check_the_user_s_lightning_setup">लैटनिंग पता के चालान लाने के JSON परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_s_invoice_fetch_check_the_user_s_lightning_setup_with_user">%1$s के चालान लाने के JSON परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_s_invoice_fetch_check_the_user_s_lightning_setup">लैटनिंग पता से लाये गये चालान के जेसोन॰ परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="error_parsing_json_from_lightning_address_s_invoice_fetch_check_the_user_s_lightning_setup_with_user">%1$s से लाए गए चालान के जेसोन॰ परखनें में अपक्रम। उपयोगकर्ता की लैटनिंग स्थापना की जाँच करें</string>
|
||||
<string name="incorrect_invoice_amount_sats_from_it_should_have_been">%2$s से चालान की मात्रा (%1$s साट्स) में दोष है। %3$s होना चाहिए था।</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_the_receiver_s_lightning_wallet_sent_the_following_error">ज्साप भेजने से पहले लैटनिंग चालान नहीं बना पाए। ग्राहक के लैटनिंग धनकोष ने यह अपक्रम की सूचना दी : %1$s</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_the_receiver_s_lightning_wallet_sent_the_following_error_with_user">लैटनिंग चालान नहीं बना पाए। %1$s से संदेश : %2$s</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json">ज्साप भेजने से पहले लैटनिंग चालान नहीं बना पाए। परिणाम JSON में pr अम्श उपलब्ध नहीं।</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json_with_user">%1$s से लैटनिंग चालान नहीं बना पाए। परिणाम JSON में pr अम्श उपलब्ध नहीं।</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json">ज्साप भेजने से पहले लैटनिंग चालान नहीं बना पाए। परिणाम जेसोन॰ में pr अम्श उपलब्ध नहीं।</string>
|
||||
<string name="unable_to_create_a_lightning_invoice_before_sending_the_zap_element_pr_not_found_in_the_resulting_json_with_user">%1$s से लैटनिंग चालान नहीं बना पाए। परिणाम जेसोन॰ में pr अम्श उपलब्ध नहीं।</string>
|
||||
<string name="read_only_user">केवल पढनेवाला उपयोगकर्ता</string>
|
||||
<string name="no_reactions_setup">कोई प्रतिक्रियाएँ स्थापित नहीं</string>
|
||||
<string name="select_push_server">संयुक्तप्रेषण क्रमक का चयन करें</string>
|
||||
@@ -585,7 +585,7 @@
|
||||
<string name="push_server_none_explainer">प्रेषित सूचनाएँ अक्षम करता है</string>
|
||||
<string name="push_server_uses_app_explainer">%1$s क्रमक का प्रयोग करता है</string>
|
||||
<string name="push_server_install_app">प्रेषित सूचना स्थापन</string>
|
||||
<string name="push_server_install_app_description"> प्रेषित सूचनाएँ प्राप्त करने के लिए, किसी भी क्रमक की स्थापना करें जो [संयुक्त प्रेषण](https://unifiedpush.org/) का अवलम्बन करता है, जैसे [Nfty](https://ntfy.sh/)।
|
||||
<string name="push_server_install_app_description"> प्रेषित सूचनाएँ प्राप्त करने के लिए, किसी भी क्रमक की स्थापना करें जो [संयुक्त प्रेषण](https://unifiedpush.org/) का अवलम्बन करता है, जैसे [एनटीफै](https://ntfy.sh/)।
|
||||
स्थापना पश्चात, जिस क्रमक का उपयोग करना चाहते हैं उसका चयन करें स्थापना विकल्पों में।
|
||||
</string>
|
||||
<string name="payment_required_title">%1$s से संदेश</string>
|
||||
@@ -634,7 +634,7 @@
|
||||
<string name="could_not_download_from_the_server">सेवासंगणक से आरोहणकृत चित्र चलचित्र का अवरोहण नहीं कर पाए</string>
|
||||
<string name="could_not_prepare_local_file_to_upload">स्थानीय अभिलेख अनुकूल नहीं बना सके आरोहण के लिए : %1$s</string>
|
||||
<string name="edit_draft">पाण्डुलिपि का सम्पादन करें</string>
|
||||
<string name="login_with_qr_code">क्यूआर क्रमचित्र के साथ प्रवेशांकन करें</string>
|
||||
<string name="login_with_qr_code">क्यूआर॰ क्रमचित्र के साथ प्रवेशांकन करें</string>
|
||||
<string name="route">मार्ग</string>
|
||||
<string name="route_home">घर</string>
|
||||
<string name="route_search">खोज</string>
|
||||
@@ -671,7 +671,7 @@
|
||||
<string name="cancel_zap_split">ज्साप विभाजन निरस्त करें</string>
|
||||
<string name="add_content_warning">विषयवस्तु चेतावनी जोडें</string>
|
||||
<string name="remove_content_warning">विषयवस्तु चेतावनी हटाएँ</string>
|
||||
<string name="show_npub_as_a_qr_code">क्यूआर क्रमचित्र के रूप में npub को दिखाएँ</string>
|
||||
<string name="show_npub_as_a_qr_code">क्यूआर॰ क्रमचित्र के रूप में एनपुब॰ को दिखाएँ</string>
|
||||
<string name="invalid_nip19_uri">अमान्य पता</string>
|
||||
<string name="invalid_nip19_uri_description">अमेथिस्ट को एक वैश्विक वस्तु विभेदक प्राप्त हुआ खोलने के लिए परन्तु वह विभेदक अमान्य था : %1$s</string>
|
||||
<string name="dm_relays_title">सी॰सं॰ आगतपेटिका पुनःप्रसारक</string>
|
||||
@@ -684,8 +684,8 @@
|
||||
<string name="dm_relays_not_found_create_now">अभी स्थापना करें</string>
|
||||
<string name="search_relays_title">खोज पुनःप्रसारक</string>
|
||||
<string name="search_relays_not_found">आपके खोज पुनःप्रसारकों की स्थापना करें</string>
|
||||
<string name="search_relays_not_found_description">खोज तथा उपयोगकर्ता अंकन के लिए स्पष्टतः रूपांकित पुनःप्रसारक सूची बनाने से इन परिणामों में शोधन होगा।</string>
|
||||
<string name="search_relays_not_found_editing">विषयवस्तु खोजने के लिए अथवा उपयोगकर्ता अंकित करने में उपयोग करनें के लिए १ - ३ पुनःप्रसारकों को जोडें। सुनिश्चित करें कि आपके चयनित पुनःप्रसारक निप॰-५० को कार्यान्वित किये हैं।</string>
|
||||
<string name="search_relays_not_found_description">खोज तथा उपयोगकर्ता सूचक जोडने के लिए स्पष्टतः रूपांकित पुनःप्रसारक सूची बनाने से इन परिणामों में शोधन होगा।</string>
|
||||
<string name="search_relays_not_found_editing">विषयवस्तु खोजने के लिए अथवा उपयोगकर्ता सूचक जोडने में उपयोग करनें के लिए १ - ३ पुनःप्रसारकों को जोडें। सुनिश्चित करें कि आपके चयनित पुनःप्रसारक निप॰-५० को कार्यान्वित किये हैं।</string>
|
||||
<string name="search_relays_not_found_examples">ये अच्छे विकल्प हैं :\n - nostr.wine\n - relay.nostr.band\n - relay.noswhere.com</string>
|
||||
<string name="relay_settings">पुनःप्रसारक स्थापना विकल्प</string>
|
||||
<string name="public_home_section">सार्वजनिक मुख्य पुनःप्रसारक</string>
|
||||
@@ -699,10 +699,10 @@
|
||||
<string name="kind_3_section">सामान्य पुनःप्रसारक</string>
|
||||
<string name="kind_3_section_description">अमेथिस्ट इन पुनःप्रसारकों का प्रयोग करता है आपके पत्रों का अवरोहण करने के लिए।</string>
|
||||
<string name="search_section">खोज पुनःप्रसारक</string>
|
||||
<string name="search_section_explainer">पुनःप्रसारकों की सूची जिनको किसी विषयवस्तु अथवा उपयोगकर्ताओं को खोजने में प्रयोग करना चाहिए। कोई विकल्प नहीं तो अंकन तथा खोज निष्क्रिय होंगे। सुनिश्चित करें कि वे निप॰-५० को कार्यान्वित किये हैं।</string>
|
||||
<string name="search_section_explainer">पुनःप्रसारकों की सूची जिनको किसी विषयवस्तु अथवा उपयोगकर्ताओं को खोजने में प्रयोग करना चाहिए। कोई विकल्प नहीं तो उपयोगकर्ता सूचक जोडना तथा खोज निष्क्रिय होंगे। सुनिश्चित करें कि वे निप॰-५० को कार्यान्वित किये हैं।</string>
|
||||
<string name="local_section">स्थानीय पुनःप्रसारक</string>
|
||||
<string name="local_section_explainer">पुनःप्रसारकों की सूची जो इस यन्त्र पर चल रहे हैं।</string>
|
||||
<string name="zap_the_devs_title">क्रमलखकों को ज्साप करें!</string>
|
||||
<string name="zap_the_devs_title">क्रमलेखकों को ज्साप करें!</string>
|
||||
<string name="zap_the_devs_description">आपका दान हमारा सहायक है परिवर्तन लाने में। प्रत्येक साट गणनीय है!</string>
|
||||
<string name="donate_now">दान करें अभी</string>
|
||||
<string name="brought_to_you_by">आप तक लाया गया इनके द्वारा :</string>
|
||||
@@ -727,11 +727,11 @@
|
||||
<string name="accessibility_download_for_offline">अवरोहण</string>
|
||||
<string name="accessibility_lyrics_on">संगीत पद्य दिखाएँ</string>
|
||||
<string name="accessibility_lyrics_off">संगीत पद्य ना दिखाएँ</string>
|
||||
<string name="accessibility_turn_on_sealed_message">आवृत संदेश निष्क्रिय। आवृत संदेश सक्रिय करने के लिए टाँकें</string>
|
||||
<string name="accessibility_turn_off_sealed_message">आवृत संदेश सक्रिय। आवृत संदेश निष्क्रिय करने के लिए टाँकें</string>
|
||||
<string name="accessibility_turn_on_sealed_message">समावृत संदेश निष्क्रिय। समावृत संदेश सक्रिय करने के लिए टाँकें</string>
|
||||
<string name="accessibility_turn_off_sealed_message">समावृत संदेश सक्रिय। समावृत संदेश निष्क्रिय करने के लिए टाँकें</string>
|
||||
<string name="accessibility_send">भेजें</string>
|
||||
<string name="accessibility_play_username">उपयोगकर्ता नाम को ध्वनि के रूप में चलाएँ</string>
|
||||
<string name="accessibility_scan_qr_code">क्यूआर क्रमचित्र परखें</string>
|
||||
<string name="accessibility_scan_qr_code">क्यूआर॰ क्रमचित्र परखें</string>
|
||||
<string name="accessibility_navigate_to_alby">तृतीय पक्ष धनकोष प्रदाता आल्बी तक जाएँ</string>
|
||||
<string name="it_s_not_possible_to_reply_to_a_draft_note">एक टीका पाण्डुलिपि को उत्तर नहीं दे सकते</string>
|
||||
<string name="it_s_not_possible_to_quote_to_a_draft_note">एक टीका पाण्डुलिपि पर टीका नहीं लिख सकते</string>
|
||||
|
||||
@@ -407,6 +407,7 @@
|
||||
<string name="languages">语言</string>
|
||||
<string name="tags">标签</string>
|
||||
<string name="posting_policy">发布政策</string>
|
||||
<string name="relay_error_messages">该中继的错误和通知</string>
|
||||
<string name="message_length">消息长度</string>
|
||||
<string name="subscriptions">订阅</string>
|
||||
<string name="filters">筛选器</string>
|
||||
|
||||
@@ -77,6 +77,7 @@ fun TranslatableRichTextViewer(
|
||||
tags: ImmutableListOfLists<String>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
id: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@@ -103,6 +104,7 @@ fun TranslatableRichTextViewer(
|
||||
tags = tags,
|
||||
backgroundColor = backgroundColor,
|
||||
id = id,
|
||||
callbackUri = callbackUri,
|
||||
accountViewModel = accountViewModel,
|
||||
nav = nav,
|
||||
)
|
||||
@@ -119,6 +121,7 @@ private fun RenderText(
|
||||
tags: ImmutableListOfLists<String>,
|
||||
backgroundColor: MutableState<Color>,
|
||||
id: String,
|
||||
callbackUri: String? = null,
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
@@ -139,6 +142,7 @@ private fun RenderText(
|
||||
tags,
|
||||
backgroundColor,
|
||||
id,
|
||||
callbackUri,
|
||||
accountViewModel,
|
||||
nav,
|
||||
)
|
||||
|
||||
@@ -46,6 +46,7 @@ class RichTextParser() {
|
||||
fullUrl: String,
|
||||
eventTags: ImmutableListOfLists<String>,
|
||||
description: String?,
|
||||
callbackUri: String? = null,
|
||||
): MediaUrlContent? {
|
||||
val removedParamsFromUrl = removeQueryParamsForExtensionComparison(fullUrl)
|
||||
return if (imageExtensions.any { removedParamsFromUrl.endsWith(it) }) {
|
||||
@@ -59,6 +60,7 @@ class RichTextParser() {
|
||||
blurhash = frags[FileHeaderEvent.BLUR_HASH] ?: tags[FileHeaderEvent.BLUR_HASH],
|
||||
dim = frags[FileHeaderEvent.DIMENSION] ?: tags[FileHeaderEvent.DIMENSION],
|
||||
contentWarning = frags["content-warning"] ?: tags["content-warning"],
|
||||
uri = callbackUri,
|
||||
)
|
||||
} else if (videoExtensions.any { removedParamsFromUrl.endsWith(it) }) {
|
||||
val frags = Nip54InlineMetadata().parse(fullUrl)
|
||||
@@ -70,6 +72,7 @@ class RichTextParser() {
|
||||
blurhash = frags[FileHeaderEvent.BLUR_HASH] ?: tags[FileHeaderEvent.BLUR_HASH],
|
||||
dim = frags[FileHeaderEvent.DIMENSION] ?: tags[FileHeaderEvent.DIMENSION],
|
||||
contentWarning = frags["content-warning"] ?: tags["content-warning"],
|
||||
uri = callbackUri,
|
||||
)
|
||||
} else {
|
||||
null
|
||||
@@ -103,11 +106,12 @@ class RichTextParser() {
|
||||
fun parseText(
|
||||
content: String,
|
||||
tags: ImmutableListOfLists<String>,
|
||||
callbackUri: String?,
|
||||
): RichTextViewerState {
|
||||
val urlSet = parseValidUrls(content)
|
||||
|
||||
val imagesForPager =
|
||||
urlSet.mapNotNull { fullUrl -> parseMediaUrl(fullUrl, tags, content) }.associateBy { it.url }
|
||||
urlSet.mapNotNull { fullUrl -> parseMediaUrl(fullUrl, tags, content, callbackUri) }.associateBy { it.url }
|
||||
val imageList = imagesForPager.values.toList()
|
||||
|
||||
val emojiMap = Nip30CustomEmoji.createEmojiMap(tags)
|
||||
|
||||
Reference in New Issue
Block a user