Reducing recompositions on images.
This commit is contained in:
@@ -145,7 +145,7 @@ private fun RenderSeach(
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
LocalCache.live.newEventBundles.collect {
|
||||
if (searchBarViewModel.isSearching()) {
|
||||
searchBarViewModel.invalidateData()
|
||||
|
||||
@@ -117,8 +117,6 @@ fun isNIP94Server(selectedServer: ServersAvailable?): Boolean {
|
||||
|
||||
@Composable
|
||||
fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val fileServers = listOf(
|
||||
// Triple(ServersAvailable.IMGUR_NIP_94, stringResource(id = R.string.upload_server_imgur_nip94), stringResource(id = R.string.upload_server_imgur_nip94_explainer)),
|
||||
Triple(ServersAvailable.NOSTRIMG_NIP_94, stringResource(id = R.string.upload_server_nostrimg_nip94), stringResource(id = R.string.upload_server_nostrimg_nip94_explainer)),
|
||||
@@ -152,7 +150,7 @@ fun ImageVideoPost(postViewModel: NewMediaModel, acc: Account) {
|
||||
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = postViewModel.galleryUri) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
postViewModel.galleryUri?.let {
|
||||
try {
|
||||
bitmap = resolver.loadThumbnail(it, Size(1200, 1000), null)
|
||||
|
||||
@@ -727,7 +727,6 @@ fun ImageVideoDescription(
|
||||
) {
|
||||
val resolver = LocalContext.current.contentResolver
|
||||
val mediaType = resolver.getType(uri) ?: ""
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val isImage = mediaType.startsWith("image")
|
||||
val isVideo = mediaType.startsWith("video")
|
||||
@@ -830,7 +829,7 @@ fun ImageVideoDescription(
|
||||
var bitmap by remember { mutableStateOf<Bitmap?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = uri) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
try {
|
||||
bitmap = resolver.loadThumbnail(uri, Size(1200, 1000), null)
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent
|
||||
import com.vitorpamplona.amethyst.service.model.PrivateDmEvent
|
||||
import com.vitorpamplona.amethyst.service.nip19.Nip19
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@Composable
|
||||
@@ -132,7 +133,7 @@ private fun DisplayNote(
|
||||
var noteBase by remember(nip19) { mutableStateOf<Note?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = nip19.hex) {
|
||||
withContext(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
noteBase = LocalCache.checkGetOrCreateNote(nip19.hex)
|
||||
}
|
||||
}
|
||||
@@ -188,7 +189,7 @@ private fun DisplayAddress(
|
||||
var noteBase by remember(nip19) { mutableStateOf<Note?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = nip19.hex) {
|
||||
withContext(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
noteBase = LocalCache.checkGetOrCreateAddressableNote(nip19.hex)
|
||||
}
|
||||
}
|
||||
@@ -220,7 +221,7 @@ private fun DisplayUser(
|
||||
var userBase by remember(nip19) { mutableStateOf<User?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = nip19.hex) {
|
||||
withContext(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
userBase = LocalCache.checkGetOrCreateUser(nip19.hex)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,10 +88,9 @@ fun LoadThumbAndThenVideoView(videoUri: String, description: String? = null, thu
|
||||
var loadingFinished by remember { mutableStateOf<Pair<Boolean, Drawable?>>(Pair(false, null)) }
|
||||
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
try {
|
||||
val request = ImageRequest.Builder(context).data(thumbUri).build()
|
||||
val myCover = context.imageLoader.execute(request).drawable
|
||||
|
||||
@@ -214,12 +214,12 @@ private fun LocalImageView(
|
||||
content: ZoomableLocalImage,
|
||||
mainImageModifier: Modifier
|
||||
) {
|
||||
// store the dialog open or close state
|
||||
var imageState by remember {
|
||||
mutableStateOf<AsyncImagePainter.State?>(null)
|
||||
}
|
||||
|
||||
BoxWithConstraints(contentAlignment = Alignment.Center) {
|
||||
// store the dialog open or close state
|
||||
var imageLoadingState by remember {
|
||||
mutableStateOf<Boolean?>(null)
|
||||
}
|
||||
|
||||
val myModifier = remember {
|
||||
mainImageModifier
|
||||
.widthIn(max = maxWidth)
|
||||
@@ -241,17 +241,22 @@ private fun LocalImageView(
|
||||
contentDescription = content.description,
|
||||
contentScale = contentScale,
|
||||
modifier = myModifier,
|
||||
onLoading = {
|
||||
imageState = it
|
||||
onError = {
|
||||
if (imageLoadingState != false)
|
||||
imageLoadingState = false
|
||||
},
|
||||
onSuccess = {
|
||||
imageState = it
|
||||
if (imageLoadingState != true)
|
||||
imageLoadingState = true
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (imageState is AsyncImagePainter.State.Success) {
|
||||
HashVerificationSymbol(content.isVerified, Modifier.align(Alignment.TopEnd))
|
||||
if (imageLoadingState == true) {
|
||||
if (content.isVerified != null)
|
||||
HashVerificationSymbol(content.isVerified, Modifier.align(Alignment.TopEnd))
|
||||
} else if (imageLoadingState == false || content.localFile == null || !content.localFile.exists()) {
|
||||
BlankNote()
|
||||
} else {
|
||||
if (content.blurhash != null) {
|
||||
DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier)
|
||||
@@ -261,10 +266,6 @@ private fun LocalImageView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (imageState is AsyncImagePainter.State.Error || content.localFile == null || !content.localFile.exists()) {
|
||||
BlankNote()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,27 +274,20 @@ private fun UrlImageView(
|
||||
content: ZoomableUrlImage,
|
||||
mainImageModifier: Modifier
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
BoxWithConstraints(contentAlignment = Alignment.Center) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val context = LocalContext.current
|
||||
|
||||
// store the dialog open or close state
|
||||
var imageState by remember {
|
||||
mutableStateOf<AsyncImagePainter.State?>(null)
|
||||
var imageLoadingStatus by remember {
|
||||
mutableStateOf<Boolean?>(null)
|
||||
}
|
||||
|
||||
var verifiedHash by remember {
|
||||
mutableStateOf<Boolean?>(null)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = content.url, key2 = imageState) {
|
||||
if (imageState is AsyncImagePainter.State.Success) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
verifiedHash = verifyHash(content, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val myModifier = remember {
|
||||
mainImageModifier
|
||||
.widthIn(max = maxWidth)
|
||||
@@ -314,16 +308,28 @@ private fun UrlImageView(
|
||||
contentDescription = content.description,
|
||||
contentScale = contentScale,
|
||||
modifier = myModifier,
|
||||
onLoading = {
|
||||
imageState = it
|
||||
onError = {
|
||||
if (imageLoadingStatus != false)
|
||||
imageLoadingStatus = false
|
||||
},
|
||||
onSuccess = {
|
||||
imageState = it
|
||||
if (verifiedHash == null) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
verifiedHash = verifyHash(content, context)
|
||||
}
|
||||
}
|
||||
if (imageLoadingStatus != true) {
|
||||
imageLoadingStatus = true
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
if (imageState is AsyncImagePainter.State.Success) {
|
||||
HashVerificationSymbol(verifiedHash, Modifier.align(Alignment.TopEnd))
|
||||
if (imageLoadingStatus == true) {
|
||||
verifiedHash?.let {
|
||||
HashVerificationSymbol(it, Modifier.align(Alignment.TopEnd))
|
||||
}
|
||||
} else if (imageLoadingStatus == false) {
|
||||
ClickableUrl(urlText = "${content.url} ", url = content.url)
|
||||
} else {
|
||||
if (content.blurhash != null) {
|
||||
DisplayBlurHash(content.blurhash, content.description, contentScale, myModifier)
|
||||
@@ -333,10 +339,6 @@ private fun UrlImageView(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (imageState is AsyncImagePainter.State.Error) {
|
||||
ClickableUrl(urlText = "${content.url} ", url = content.url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,10 +422,12 @@ private fun DisplayBlurHash(
|
||||
|
||||
val context = LocalContext.current
|
||||
AsyncImage(
|
||||
model = BlurHashRequester.imageRequest(
|
||||
context,
|
||||
blurhash
|
||||
),
|
||||
model = remember {
|
||||
BlurHashRequester.imageRequest(
|
||||
context,
|
||||
blurhash
|
||||
)
|
||||
},
|
||||
contentDescription = description,
|
||||
contentScale = contentScale,
|
||||
modifier = modifier
|
||||
@@ -522,9 +526,7 @@ private fun verifyHash(content: ZoomableUrlContent, context: Context): Boolean?
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HashVerificationSymbol(verifiedHash: Boolean?, modifier: Modifier) {
|
||||
if (verifiedHash == null) return
|
||||
|
||||
private fun HashVerificationSymbol(verifiedHash: Boolean, modifier: Modifier) {
|
||||
val localContext = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
|
||||
@@ -110,8 +110,6 @@ private fun RowScope.HasNewItemsIcon(
|
||||
accountViewModel: AccountViewModel,
|
||||
navController: NavHostController
|
||||
) {
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = remember(accountState) { accountState?.account } ?: return
|
||||
|
||||
@@ -121,7 +119,7 @@ private fun RowScope.HasNewItemsIcon(
|
||||
var hasNewItems by remember { mutableStateOf<Boolean>(false) }
|
||||
|
||||
LaunchedEffect(key1 = notifState, key2 = accountState) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
val newHasNewItems = route.hasNewItems(account, notif, emptySet())
|
||||
if (newHasNewItems != hasNewItems) {
|
||||
hasNewItems = newHasNewItems
|
||||
@@ -129,8 +127,8 @@ private fun RowScope.HasNewItemsIcon(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(accountState) {
|
||||
scope.launch(Dispatchers.IO) {
|
||||
LaunchedEffect(Unit) {
|
||||
launch(Dispatchers.IO) {
|
||||
LocalCache.live.newEventBundles.collect {
|
||||
val newHasNewItems = route.hasNewItems(account, notif, it)
|
||||
if (newHasNewItems != hasNewItems) {
|
||||
@@ -140,6 +138,8 @@ private fun RowScope.HasNewItemsIcon(
|
||||
}
|
||||
}
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
BottomIcon(
|
||||
icon = route.icon,
|
||||
size = if ("Home" == route.base) 25.dp else 23.dp,
|
||||
|
||||
@@ -51,7 +51,6 @@ fun AppNavigation(
|
||||
nextPage: String? = null
|
||||
) {
|
||||
var actionableNextPage by remember { mutableStateOf<String?>(nextPage) }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val nav = remember {
|
||||
{ route: String ->
|
||||
@@ -68,7 +67,7 @@ fun AppNavigation(
|
||||
|
||||
LaunchedEffect(key1 = it) {
|
||||
if (scrollToTop) {
|
||||
scope.launch {
|
||||
launch {
|
||||
videoFeedViewModel.sendToTop()
|
||||
it.arguments?.remove("scrollToTop")
|
||||
}
|
||||
@@ -89,7 +88,7 @@ fun AppNavigation(
|
||||
|
||||
LaunchedEffect(key1 = it) {
|
||||
if (scrollToTop) {
|
||||
scope.launch {
|
||||
launch {
|
||||
searchFeedViewModel.sendToTop()
|
||||
it.arguments?.remove("scrollToTop")
|
||||
}
|
||||
@@ -111,7 +110,7 @@ fun AppNavigation(
|
||||
|
||||
LaunchedEffect(key1 = it) {
|
||||
if (scrollToTop) {
|
||||
scope.launch {
|
||||
launch {
|
||||
homeFeedViewModel.sendToTop()
|
||||
repliesFeedViewModel.sendToTop()
|
||||
it.arguments?.remove("scrollToTop")
|
||||
@@ -129,7 +128,7 @@ fun AppNavigation(
|
||||
|
||||
if (nip47 != null) {
|
||||
LaunchedEffect(key1 = Unit) {
|
||||
scope.launch {
|
||||
launch {
|
||||
delay(1000)
|
||||
it.arguments?.remove("nip47")
|
||||
}
|
||||
@@ -144,7 +143,7 @@ fun AppNavigation(
|
||||
|
||||
LaunchedEffect(key1 = it) {
|
||||
if (scrollToTop) {
|
||||
scope.launch {
|
||||
launch {
|
||||
notifFeedViewModel.clear()
|
||||
notifFeedViewModel.sendToTop()
|
||||
it.arguments?.remove("scrollToTop")
|
||||
|
||||
@@ -44,7 +44,6 @@ fun BoostSetCompose(boostSetCard: BoostSetCard, isInnerNote: Boolean = false, ro
|
||||
val accountState by accountViewModel.accountLiveData.observeAsState()
|
||||
val account = accountState?.account ?: return
|
||||
|
||||
val noteEvent = note?.event
|
||||
var popupExpanded by remember { mutableStateOf(false) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
@@ -1785,18 +1785,20 @@ fun FileHeaderDisplay(note: Note) {
|
||||
var content by remember { mutableStateOf<ZoomableContent?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = event.id) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val blurHash = event.blurhash()
|
||||
val hash = event.hash()
|
||||
val dimensions = event.dimensions()
|
||||
val description = event.content
|
||||
val removedParamsFromUrl = fullUrl.split("?")[0].lowercase()
|
||||
val isImage = imageExtensions.any { removedParamsFromUrl.endsWith(it) }
|
||||
val uri = "nostr:" + note.toNEvent()
|
||||
content = if (isImage) {
|
||||
ZoomableUrlImage(fullUrl, description, hash, blurHash, dimensions, uri)
|
||||
} else {
|
||||
ZoomableUrlVideo(fullUrl, description, hash, uri)
|
||||
if (content == null) {
|
||||
launch(Dispatchers.IO) {
|
||||
val blurHash = event.blurhash()
|
||||
val hash = event.hash()
|
||||
val dimensions = event.dimensions()
|
||||
val description = event.content
|
||||
val removedParamsFromUrl = fullUrl.split("?")[0].lowercase()
|
||||
val isImage = imageExtensions.any { removedParamsFromUrl.endsWith(it) }
|
||||
val uri = "nostr:" + note.toNEvent()
|
||||
content = if (isImage) {
|
||||
ZoomableUrlImage(fullUrl, description, hash, blurHash, dimensions, uri)
|
||||
} else {
|
||||
ZoomableUrlVideo(fullUrl, description, hash, uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1814,7 +1816,7 @@ fun FileStorageHeaderDisplay(baseNote: Note) {
|
||||
var fileNote by remember { mutableStateOf<Note?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = eventHeader.id) {
|
||||
withContext(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
fileNote = eventHeader.dataEventId()?.let { LocalCache.checkGetOrCreateNote(it) }
|
||||
}
|
||||
}
|
||||
@@ -1826,33 +1828,35 @@ fun FileStorageHeaderDisplay(baseNote: Note) {
|
||||
var content by remember { mutableStateOf<ZoomableContent?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = eventHeader.id, key2 = noteState, key3 = note?.event) {
|
||||
withContext(Dispatchers.IO) {
|
||||
val uri = "nostr:" + baseNote.toNEvent()
|
||||
val localDir = note?.idHex?.let { File(File(appContext.externalCacheDir, "NIP95"), it) }
|
||||
val blurHash = eventHeader.blurhash()
|
||||
val dimensions = eventHeader.dimensions()
|
||||
val description = eventHeader.content
|
||||
val mimeType = eventHeader.mimeType()
|
||||
if (content == null) {
|
||||
launch(Dispatchers.IO) {
|
||||
val uri = "nostr:" + baseNote.toNEvent()
|
||||
val localDir = note?.idHex?.let { File(File(appContext.externalCacheDir, "NIP95"), it) }
|
||||
val blurHash = eventHeader.blurhash()
|
||||
val dimensions = eventHeader.dimensions()
|
||||
val description = eventHeader.content
|
||||
val mimeType = eventHeader.mimeType()
|
||||
|
||||
content = if (mimeType?.startsWith("image") == true) {
|
||||
ZoomableLocalImage(
|
||||
localFile = localDir,
|
||||
mimeType = mimeType,
|
||||
description = description,
|
||||
blurhash = blurHash,
|
||||
dim = dimensions,
|
||||
isVerified = true,
|
||||
uri = uri
|
||||
)
|
||||
} else {
|
||||
ZoomableLocalVideo(
|
||||
localFile = localDir,
|
||||
mimeType = mimeType,
|
||||
description = description,
|
||||
dim = dimensions,
|
||||
isVerified = true,
|
||||
uri = uri
|
||||
)
|
||||
content = if (mimeType?.startsWith("image") == true) {
|
||||
ZoomableLocalImage(
|
||||
localFile = localDir,
|
||||
mimeType = mimeType,
|
||||
description = description,
|
||||
blurhash = blurHash,
|
||||
dim = dimensions,
|
||||
isVerified = true,
|
||||
uri = uri
|
||||
)
|
||||
} else {
|
||||
ZoomableLocalVideo(
|
||||
localFile = localDir,
|
||||
mimeType = mimeType,
|
||||
description = description,
|
||||
dim = dimensions,
|
||||
isVerified = true,
|
||||
uri = uri
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ fun ZapNoteCompose(baseNote: Pair<Note, Note>, accountViewModel: AccountViewMode
|
||||
var zapAmount by remember { mutableStateOf<BigDecimal?>(null) }
|
||||
|
||||
LaunchedEffect(key1 = noteZap) {
|
||||
coroutineScope.launch(Dispatchers.IO) {
|
||||
launch(Dispatchers.IO) {
|
||||
zapAmount = (noteZap.event as? LnZapEvent)?.amount
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user