Moves OnlineChecker to a singleton class with cache.
This commit is contained in:
@@ -0,0 +1,40 @@
|
|||||||
|
package com.vitorpamplona.amethyst.service
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import android.util.LruCache
|
||||||
|
import com.google.errorprone.annotations.Immutable
|
||||||
|
import com.vitorpamplona.amethyst.BuildConfig
|
||||||
|
import okhttp3.Request
|
||||||
|
|
||||||
|
@Immutable
|
||||||
|
data class OnlineCheckResult(val timeInMs: Long, val online: Boolean)
|
||||||
|
|
||||||
|
object OnlineChecker {
|
||||||
|
val checkOnlineCache = LruCache<String, OnlineCheckResult>(10)
|
||||||
|
val fiveMinutes = 1000 * 60 * 5
|
||||||
|
|
||||||
|
fun isOnline(url: String?): Boolean {
|
||||||
|
checkNotInMainThread()
|
||||||
|
|
||||||
|
if (url.isNullOrBlank()) return false
|
||||||
|
if ((checkOnlineCache.get(url)?.timeInMs ?: 0) > System.currentTimeMillis() - fiveMinutes) {
|
||||||
|
return checkOnlineCache.get(url).online
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = Request.Builder()
|
||||||
|
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
||||||
|
.url(url)
|
||||||
|
.get()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val result = HttpClient.getHttpClient().newCall(request).execute().code == 200
|
||||||
|
checkOnlineCache.put(url, OnlineCheckResult(System.currentTimeMillis(), result))
|
||||||
|
result
|
||||||
|
} catch (e: Exception) {
|
||||||
|
checkOnlineCache.put(url, OnlineCheckResult(System.currentTimeMillis(), false))
|
||||||
|
Log.e("LiveActivities", "Failed to check streaming url $url", e)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-22
@@ -1,14 +1,11 @@
|
|||||||
package com.vitorpamplona.amethyst.ui.dal
|
package com.vitorpamplona.amethyst.ui.dal
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import com.vitorpamplona.amethyst.BuildConfig
|
|
||||||
import com.vitorpamplona.amethyst.model.Account
|
import com.vitorpamplona.amethyst.model.Account
|
||||||
import com.vitorpamplona.amethyst.model.LocalCache
|
import com.vitorpamplona.amethyst.model.LocalCache
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.HttpClient
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
import com.vitorpamplona.amethyst.service.checkNotInMainThread
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
||||||
import okhttp3.Request
|
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class HomeLiveActivitiesFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
class HomeLiveActivitiesFeedFilter(val account: Account) : AdditiveFeedFilter<Note>() {
|
||||||
@@ -41,7 +38,7 @@ class HomeLiveActivitiesFeedFilter(val account: Account) : AdditiveFeedFilter<No
|
|||||||
.asSequence()
|
.asSequence()
|
||||||
.filter { it ->
|
.filter { it ->
|
||||||
val noteEvent = it.event
|
val noteEvent = it.event
|
||||||
(noteEvent is LiveActivitiesEvent && noteEvent.createdAt > twoHrs && noteEvent.status() == "live" && checkIfOnline(noteEvent.streaming())) &&
|
(noteEvent is LiveActivitiesEvent && noteEvent.createdAt > twoHrs && noteEvent.status() == "live" && OnlineChecker.isOnline(noteEvent.streaming())) &&
|
||||||
(it.author?.pubkeyHex in followingKeySet || (noteEvent.isTaggedHashes(followingTagSet))) &&
|
(it.author?.pubkeyHex in followingKeySet || (noteEvent.isTaggedHashes(followingTagSet))) &&
|
||||||
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
// && account.isAcceptable(it) // This filter follows only. No need to check if acceptable
|
||||||
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true
|
it.author?.let { !account.isHidden(it.pubkeyHex) } ?: true
|
||||||
@@ -55,20 +52,3 @@ class HomeLiveActivitiesFeedFilter(val account: Account) : AdditiveFeedFilter<No
|
|||||||
return collection.sortedWith(compareBy({ it.createdAt() }, { it.idHex })).reversed()
|
return collection.sortedWith(compareBy({ it.createdAt() }, { it.idHex })).reversed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkIfOnline(url: String?): Boolean {
|
|
||||||
if (url.isNullOrBlank()) return false
|
|
||||||
|
|
||||||
val request = Request.Builder()
|
|
||||||
.header("User-Agent", "Amethyst/${BuildConfig.VERSION_NAME}")
|
|
||||||
.url(url)
|
|
||||||
.get()
|
|
||||||
.build()
|
|
||||||
|
|
||||||
return try {
|
|
||||||
HttpClient.getHttpClient().newCall(request).execute().code == 200
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("LiveActivities", "Failed to check streaming url $url", e)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.vitorpamplona.amethyst.ui.note
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
@@ -92,6 +93,7 @@ import com.vitorpamplona.amethyst.model.LocalCache
|
|||||||
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.model.UserMetadata
|
import com.vitorpamplona.amethyst.model.UserMetadata
|
||||||
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent
|
import com.vitorpamplona.amethyst.service.model.AppDefinitionEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.AudioTrackEvent
|
import com.vitorpamplona.amethyst.service.model.AudioTrackEvent
|
||||||
import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent
|
import com.vitorpamplona.amethyst.service.model.BadgeAwardEvent
|
||||||
@@ -143,7 +145,9 @@ import com.vitorpamplona.amethyst.ui.components.imageExtensions
|
|||||||
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
|
import com.vitorpamplona.amethyst.ui.screen.equalImmutableLists
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChannelHeader
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.LiveFlag
|
||||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ReportNoteDialog
|
||||||
|
import com.vitorpamplona.amethyst.ui.screen.loggedIn.ScheduledFlag
|
||||||
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DiviserThickness
|
import com.vitorpamplona.amethyst.ui.theme.DiviserThickness
|
||||||
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer
|
||||||
@@ -2611,64 +2615,110 @@ fun AudioTrackHeader(noteEvent: AudioTrackEvent, accountViewModel: AccountViewMo
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RenderLiveActivityEvent(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
fun RenderLiveActivityEvent(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
|
Row(modifier = Modifier.padding(top = 5.dp)) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
RenderLiveActivityEventInner(baseNote = baseNote, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RenderLiveActivityEventInner(baseNote: Note, accountViewModel: AccountViewModel, nav: (String) -> Unit) {
|
||||||
val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return
|
val noteEvent = baseNote.event as? LiveActivitiesEvent ?: return
|
||||||
|
|
||||||
val media = remember { noteEvent.streaming() }
|
val eventUpdates by baseNote.live().metadata.observeAsState()
|
||||||
val cover = remember { noteEvent.image() }
|
|
||||||
val subject = remember { noteEvent.title() }
|
|
||||||
val content = remember { noteEvent.summary() }
|
|
||||||
val participants = remember { noteEvent.participants() }
|
|
||||||
|
|
||||||
var participantUsers by remember { mutableStateOf<List<Pair<Participant, User>>>(emptyList()) }
|
val media = remember(eventUpdates) { noteEvent.streaming() }
|
||||||
|
val cover = remember(eventUpdates) { noteEvent.image() }
|
||||||
|
val subject = remember(eventUpdates) { noteEvent.title() }
|
||||||
|
val content = remember(eventUpdates) { noteEvent.summary() }
|
||||||
|
val participants = remember(eventUpdates) { noteEvent.participants() }
|
||||||
|
val status = remember(eventUpdates) { noteEvent.status() }
|
||||||
|
|
||||||
LaunchedEffect(key1 = participants) {
|
var isOnline by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
|
LaunchedEffect(key1 = media) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
participantUsers = participants.mapNotNull { part ->
|
isOnline = OnlineChecker.isOnline(media)
|
||||||
LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) }
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 5.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
subject?.let {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 3,
|
||||||
|
overflow = TextOverflow.Ellipsis
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Crossfade(targetState = status) {
|
||||||
|
when (it) {
|
||||||
|
"live" -> {
|
||||||
|
if (isOnline) {
|
||||||
|
LiveFlag()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"planned" -> {
|
||||||
|
ScheduledFlag()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row(modifier = Modifier.padding(top = 5.dp)) {
|
var participantUsers by remember {
|
||||||
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
|
mutableStateOf<ImmutableList<Pair<Participant, User>>>(
|
||||||
Row() {
|
persistentListOf()
|
||||||
subject?.let {
|
)
|
||||||
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 5.dp, bottom = 5.dp)) {
|
}
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
maxLines = 3,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
participantUsers.forEach {
|
LaunchedEffect(key1 = eventUpdates) {
|
||||||
Row(
|
launch(Dispatchers.IO) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
val newParticipantUsers = participants.mapNotNull { part ->
|
||||||
modifier = Modifier
|
LocalCache.checkGetOrCreateUser(part.key)?.let { Pair(part, it) }
|
||||||
.padding(top = 5.dp, start = 10.dp, end = 10.dp)
|
}.toImmutableList()
|
||||||
.clickable {
|
|
||||||
nav("User/${it.second.pubkeyHex}")
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
ClickableUserPicture(it.second, 25.dp, accountViewModel)
|
|
||||||
Spacer(Modifier.width(5.dp))
|
|
||||||
UsernameDisplay(it.second, Modifier.weight(1f))
|
|
||||||
Spacer(Modifier.width(5.dp))
|
|
||||||
it.first.role?.let {
|
|
||||||
Text(
|
|
||||||
text = it.capitalize(Locale.ROOT),
|
|
||||||
color = MaterialTheme.colors.placeholderText,
|
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
media?.let { media ->
|
if (!equalImmutableLists(newParticipantUsers, participantUsers)) {
|
||||||
|
participantUsers = newParticipantUsers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
participantUsers.forEach {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 5.dp, start = 10.dp, end = 10.dp)
|
||||||
|
.clickable {
|
||||||
|
nav("User/${it.second.pubkeyHex}")
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
ClickableUserPicture(it.second, 25.dp, accountViewModel)
|
||||||
|
Spacer(Modifier.width(5.dp))
|
||||||
|
UsernameDisplay(it.second, Modifier.weight(1f))
|
||||||
|
Spacer(Modifier.width(5.dp))
|
||||||
|
it.first.role?.let {
|
||||||
|
Text(
|
||||||
|
text = it.capitalize(Locale.ROOT),
|
||||||
|
color = MaterialTheme.colors.placeholderText,
|
||||||
|
maxLines = 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
media?.let { media ->
|
||||||
|
if (status == "live") {
|
||||||
|
if (isOnline) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
modifier = Modifier.padding(10.dp)
|
modifier = Modifier.padding(10.dp)
|
||||||
@@ -2678,6 +2728,32 @@ fun RenderLiveActivityEvent(baseNote: Note, accountViewModel: AccountViewModel,
|
|||||||
description = subject
|
description = subject
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.live_stream_is_offline),
|
||||||
|
color = MaterialTheme.colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (status == "ended") {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(10.dp)
|
||||||
|
.height(100.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.live_stream_has_ended),
|
||||||
|
color = MaterialTheme.colors.onBackground,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -714,9 +714,9 @@ private fun LiveChannelActionOptions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun LiveFlag() {
|
fun LiveFlag() {
|
||||||
Text(
|
Text(
|
||||||
text = "LIVE",
|
text = stringResource(id = R.string.live_stream_live_tag),
|
||||||
color = Color.White,
|
color = Color.White,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
modifier = remember {
|
modifier = remember {
|
||||||
@@ -728,6 +728,51 @@ private fun LiveFlag() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EndedFlag() {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.live_stream_ended_tag),
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = remember {
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.drawBehind { drawRect(Color.Black) }
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun OfflineFlag() {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.live_stream_offline_tag),
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = remember {
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.drawBehind { drawRect(Color.Black) }
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ScheduledFlag() {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.live_stream_planned_tag),
|
||||||
|
color = Color.White,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
modifier = remember {
|
||||||
|
Modifier
|
||||||
|
.clip(SmallBorder)
|
||||||
|
.drawBehind { drawRect(Color.Black) }
|
||||||
|
.padding(horizontal = 5.dp)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun NoteCopyButton(
|
private fun NoteCopyButton(
|
||||||
note: Channel
|
note: Channel
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ import androidx.lifecycle.LifecycleEventObserver
|
|||||||
import com.vitorpamplona.amethyst.R
|
import com.vitorpamplona.amethyst.R
|
||||||
import com.vitorpamplona.amethyst.model.Note
|
import com.vitorpamplona.amethyst.model.Note
|
||||||
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
import com.vitorpamplona.amethyst.service.NostrHomeDataSource
|
||||||
|
import com.vitorpamplona.amethyst.service.OnlineChecker
|
||||||
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
import com.vitorpamplona.amethyst.service.model.LiveActivitiesEvent
|
||||||
import com.vitorpamplona.amethyst.ui.dal.checkIfOnline
|
|
||||||
import com.vitorpamplona.amethyst.ui.navigation.Route
|
import com.vitorpamplona.amethyst.ui.navigation.Route
|
||||||
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
import com.vitorpamplona.amethyst.ui.note.UpdateZapAmountDialog
|
||||||
import com.vitorpamplona.amethyst.ui.screen.FeedState
|
import com.vitorpamplona.amethyst.ui.screen.FeedState
|
||||||
@@ -76,6 +76,8 @@ fun HomeScreen(
|
|||||||
|
|
||||||
val lifeCycleOwner = LocalLifecycleOwner.current
|
val lifeCycleOwner = LocalLifecycleOwner.current
|
||||||
DisposableEffect(accountViewModel) {
|
DisposableEffect(accountViewModel) {
|
||||||
|
liveActivitiesViewModel.invalidateData(true)
|
||||||
|
|
||||||
val observer = LifecycleEventObserver { _, event ->
|
val observer = LifecycleEventObserver { _, event ->
|
||||||
if (event == Lifecycle.Event.ON_RESUME) {
|
if (event == Lifecycle.Event.ON_RESUME) {
|
||||||
NostrHomeDataSource.invalidateFilters()
|
NostrHomeDataSource.invalidateFilters()
|
||||||
@@ -193,7 +195,7 @@ private fun FeedLoaded(
|
|||||||
state = listState
|
state = listState
|
||||||
) {
|
) {
|
||||||
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
itemsIndexed(state.feed.value, key = { _, item -> item.idHex }) { _, item ->
|
||||||
CheckIfOnline(item) {
|
CheckIfLiveActivityIsOnline(item) {
|
||||||
ChannelHeader(
|
ChannelHeader(
|
||||||
channelHex = remember { item.idHex },
|
channelHex = remember { item.idHex },
|
||||||
showVideo = false,
|
showVideo = false,
|
||||||
@@ -210,13 +212,13 @@ private fun FeedLoaded(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun CheckIfOnline(note: Note, whenOnline: @Composable () -> Unit) {
|
fun CheckIfLiveActivityIsOnline(note: Note, whenOnline: @Composable () -> Unit) {
|
||||||
val noteState by note.live().metadata.observeAsState()
|
val noteState by note.live().metadata.observeAsState()
|
||||||
var online by remember { mutableStateOf(false) }
|
var online by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
LaunchedEffect(key1 = noteState) {
|
LaunchedEffect(key1 = noteState) {
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
online = checkIfOnline((note.event as? LiveActivitiesEvent)?.streaming())
|
online = OnlineChecker.isOnline((note.event as? LiveActivitiesEvent)?.streaming())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -456,4 +456,12 @@
|
|||||||
<string name="minimum_pow">Minimum PoW</string>
|
<string name="minimum_pow">Minimum PoW</string>
|
||||||
<string name="auth">Auth</string>
|
<string name="auth">Auth</string>
|
||||||
<string name="payment">Payment</string>
|
<string name="payment">Payment</string>
|
||||||
|
|
||||||
|
<string name="live_stream_live_tag">LIVE</string>
|
||||||
|
<string name="live_stream_offline_tag">OFFLINE</string>
|
||||||
|
<string name="live_stream_ended_tag">ENDED</string>
|
||||||
|
<string name="live_stream_planned_tag">SCHEDULED</string>
|
||||||
|
|
||||||
|
<string name="live_stream_is_offline">Livestream is Offline</string>
|
||||||
|
<string name="live_stream_has_ended">Livestream Ended</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user