Merge pull request #3533 from element-hq/feature/bma/fixCrashes
Fix various crashes
This commit is contained in:
commit
b087874ad0
13 changed files with 146 additions and 51 deletions
|
|
@ -281,7 +281,11 @@ class ElementCallActivity :
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
override fun enterPipMode(): Boolean {
|
override fun enterPipMode(): Boolean {
|
||||||
return enterPictureInPictureMode(getPictureInPictureParams())
|
return if (lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
|
enterPictureInPictureMode(getPictureInPictureParams())
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import io.element.android.features.messages.impl.voicemessages.VoiceMessageExcep
|
||||||
import io.element.android.libraries.architecture.AsyncData
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runUpdatingState
|
import io.element.android.libraries.architecture.runUpdatingState
|
||||||
|
import io.element.android.libraries.core.extensions.flatMap
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.ui.utils.time.formatShort
|
import io.element.android.libraries.ui.utils.time.formatShort
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
|
|
@ -126,8 +127,8 @@ class VoiceMessagePresenter @AssistedInject constructor(
|
||||||
it
|
it
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
player.prepare().apply {
|
player.prepare().flatMap {
|
||||||
player.play()
|
runCatching { player.play() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,10 @@ fun Context.copyToClipboard(
|
||||||
* Shows notification settings for the current app.
|
* Shows notification settings for the current app.
|
||||||
* In android O will directly opens the notification settings, in lower version it will show the App settings
|
* In android O will directly opens the notification settings, in lower version it will show the App settings
|
||||||
*/
|
*/
|
||||||
fun Context.startNotificationSettingsIntent(activityResultLauncher: ActivityResultLauncher<Intent>? = null) {
|
fun Context.startNotificationSettingsIntent(
|
||||||
|
activityResultLauncher: ActivityResultLauncher<Intent>? = null,
|
||||||
|
noActivityFoundMessage: String = getString(R.string.error_no_compatible_app_found),
|
||||||
|
) {
|
||||||
val intent = Intent()
|
val intent = Intent()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
|
||||||
|
|
@ -85,10 +88,14 @@ fun Context.startNotificationSettingsIntent(activityResultLauncher: ActivityResu
|
||||||
intent.data = Uri.fromParts("package", packageName, null)
|
intent.data = Uri.fromParts("package", packageName, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activityResultLauncher != null) {
|
try {
|
||||||
activityResultLauncher.launch(intent)
|
if (activityResultLauncher != null) {
|
||||||
} else {
|
activityResultLauncher.launch(intent)
|
||||||
startActivity(intent)
|
} else {
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
toast(noActivityFoundMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.onStart
|
import kotlinx.coroutines.flow.onStart
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.matrix.rustcomponents.sdk.RoomInfo
|
import org.matrix.rustcomponents.sdk.RoomInfo
|
||||||
import org.matrix.rustcomponents.sdk.RoomInfoListener
|
import org.matrix.rustcomponents.sdk.RoomInfoListener
|
||||||
|
|
@ -104,10 +103,12 @@ class RustMatrixRoom(
|
||||||
override val roomId = RoomId(innerRoom.id())
|
override val roomId = RoomId(innerRoom.id())
|
||||||
|
|
||||||
override val roomInfoFlow: Flow<MatrixRoomInfo> = mxCallbackFlow {
|
override val roomInfoFlow: Flow<MatrixRoomInfo> = mxCallbackFlow {
|
||||||
launch {
|
runCatching { innerRoom.roomInfo() }
|
||||||
val initial = innerRoom.roomInfo().let(matrixRoomInfoMapper::map)
|
.getOrNull()
|
||||||
channel.trySend(initial)
|
?.let(matrixRoomInfoMapper::map)
|
||||||
}
|
?.let { initial ->
|
||||||
|
channel.trySend(initial)
|
||||||
|
}
|
||||||
innerRoom.subscribeToRoomInfoUpdates(object : RoomInfoListener {
|
innerRoom.subscribeToRoomInfoUpdates(object : RoomInfoListener {
|
||||||
override fun call(roomInfo: RoomInfo) {
|
override fun call(roomInfo: RoomInfo) {
|
||||||
channel.trySend(matrixRoomInfoMapper.map(roomInfo))
|
channel.trySend(matrixRoomInfoMapper.map(roomInfo))
|
||||||
|
|
@ -116,10 +117,8 @@ class RustMatrixRoom(
|
||||||
}
|
}
|
||||||
|
|
||||||
override val roomTypingMembersFlow: Flow<List<UserId>> = mxCallbackFlow {
|
override val roomTypingMembersFlow: Flow<List<UserId>> = mxCallbackFlow {
|
||||||
launch {
|
val initial = emptyList<UserId>()
|
||||||
val initial = emptyList<UserId>()
|
channel.trySend(initial)
|
||||||
channel.trySend(initial)
|
|
||||||
}
|
|
||||||
innerRoom.subscribeToTypingNotifications(object : TypingNotificationsListener {
|
innerRoom.subscribeToTypingNotifications(object : TypingNotificationsListener {
|
||||||
override fun call(typingUserIds: List<String>) {
|
override fun call(typingUserIds: List<String>) {
|
||||||
channel.trySend(
|
channel.trySend(
|
||||||
|
|
@ -625,9 +624,13 @@ class RustMatrixRoom(
|
||||||
innerRoom.sendCallNotificationIfNeeded()
|
innerRoom.sendCallNotificationIfNeeded()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setSendQueueEnabled(enabled: Boolean) = withContext(roomDispatcher) {
|
override suspend fun setSendQueueEnabled(enabled: Boolean) {
|
||||||
Timber.d("setSendQueuesEnabled: $enabled")
|
withContext(roomDispatcher) {
|
||||||
innerRoom.enableSendQueue(enabled)
|
Timber.d("setSendQueuesEnabled: $enabled")
|
||||||
|
runCatching {
|
||||||
|
innerRoom.enableSendQueue(enabled)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit> = runCatching {
|
override suspend fun saveComposerDraft(composerDraft: ComposerDraft): Result<Unit> = runCatching {
|
||||||
|
|
|
||||||
|
|
@ -97,9 +97,7 @@ internal fun RoomListServiceInterface.stateFlow(): Flow<RoomListServiceState> =
|
||||||
trySendBlocking(state)
|
trySendBlocking(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tryOrNull {
|
state(listener)
|
||||||
state(listener)
|
|
||||||
}
|
|
||||||
}.buffer(Channel.UNLIMITED)
|
}.buffer(Channel.UNLIMITED)
|
||||||
|
|
||||||
internal fun RoomListServiceInterface.syncIndicator(): Flow<RoomListServiceSyncIndicator> =
|
internal fun RoomListServiceInterface.syncIndicator(): Flow<RoomListServiceSyncIndicator> =
|
||||||
|
|
@ -109,13 +107,11 @@ internal fun RoomListServiceInterface.syncIndicator(): Flow<RoomListServiceSyncI
|
||||||
trySendBlocking(syncIndicator)
|
trySendBlocking(syncIndicator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tryOrNull {
|
syncIndicator(
|
||||||
syncIndicator(
|
SYNC_INDICATOR_DELAY_BEFORE_SHOWING,
|
||||||
SYNC_INDICATOR_DELAY_BEFORE_SHOWING,
|
SYNC_INDICATOR_DELAY_BEFORE_HIDING,
|
||||||
SYNC_INDICATOR_DELAY_BEFORE_HIDING,
|
listener,
|
||||||
listener,
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
}.buffer(Channel.UNLIMITED)
|
}.buffer(Channel.UNLIMITED)
|
||||||
|
|
||||||
internal fun RoomListServiceInterface.roomOrNull(roomId: String): RoomListItem? {
|
internal fun RoomListServiceInterface.roomOrNull(roomId: String): RoomListItem? {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
package io.element.android.libraries.matrix.impl.sync
|
package io.element.android.libraries.matrix.impl.sync
|
||||||
|
|
||||||
import io.element.android.libraries.core.data.tryOrNull
|
|
||||||
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
import io.element.android.libraries.matrix.impl.util.mxCallbackFlow
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.channels.trySendBlocking
|
import kotlinx.coroutines.channels.trySendBlocking
|
||||||
|
|
@ -24,7 +23,5 @@ fun SyncServiceInterface.stateFlow(): Flow<SyncServiceState> =
|
||||||
trySendBlocking(state)
|
trySendBlocking(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tryOrNull {
|
state(listener)
|
||||||
state(listener)
|
|
||||||
}
|
|
||||||
}.buffer(Channel.UNLIMITED)
|
}.buffer(Channel.UNLIMITED)
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import kotlinx.coroutines.channels.awaitClose
|
||||||
import kotlinx.coroutines.flow.callbackFlow
|
import kotlinx.coroutines.flow.callbackFlow
|
||||||
import org.matrix.rustcomponents.sdk.TaskHandle
|
import org.matrix.rustcomponents.sdk.TaskHandle
|
||||||
|
|
||||||
internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> TaskHandle?) =
|
internal fun <T> mxCallbackFlow(block: suspend ProducerScope<T>.() -> TaskHandle) =
|
||||||
callbackFlow {
|
callbackFlow {
|
||||||
val taskHandle: TaskHandle? = tryOrNull {
|
val taskHandle: TaskHandle? = tryOrNull {
|
||||||
block(this)
|
block(this)
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,9 @@
|
||||||
|
|
||||||
package io.element.android.libraries.mediapickers.api
|
package io.element.android.libraries.mediapickers.api
|
||||||
|
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
import androidx.activity.compose.ManagedActivityResultLauncher
|
import androidx.activity.compose.ManagedActivityResultLauncher
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper around [ManagedActivityResultLauncher] to be used with media/file pickers.
|
* Wrapper around [ManagedActivityResultLauncher] to be used with media/file pickers.
|
||||||
|
|
@ -25,11 +27,19 @@ class ComposePickerLauncher<Input, Output>(
|
||||||
private val defaultRequest: Input,
|
private val defaultRequest: Input,
|
||||||
) : PickerLauncher<Input, Output> {
|
) : PickerLauncher<Input, Output> {
|
||||||
override fun launch() {
|
override fun launch() {
|
||||||
managedLauncher.launch(defaultRequest)
|
try {
|
||||||
|
managedLauncher.launch(defaultRequest)
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
Timber.w(activityNotFoundException, "No activity found")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun launch(customInput: Input) {
|
override fun launch(customInput: Input) {
|
||||||
managedLauncher.launch(customInput)
|
try {
|
||||||
|
managedLauncher.launch(customInput)
|
||||||
|
} catch (activityNotFoundException: ActivityNotFoundException) {
|
||||||
|
Timber.w(activityNotFoundException, "No activity found")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ package io.element.android.libraries.mediaviewer.api.local.pdf
|
||||||
|
|
||||||
import android.graphics.pdf.PdfRenderer
|
import android.graphics.pdf.PdfRenderer
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
|
@ -25,20 +28,30 @@ class PdfRendererManager(
|
||||||
) {
|
) {
|
||||||
private val mutex = Mutex()
|
private val mutex = Mutex()
|
||||||
private var pdfRenderer: PdfRenderer? = null
|
private var pdfRenderer: PdfRenderer? = null
|
||||||
private val mutablePdfPages = MutableStateFlow<List<PdfPage>>(emptyList())
|
private val mutablePdfPages = MutableStateFlow<AsyncData<ImmutableList<PdfPage>>>(AsyncData.Uninitialized)
|
||||||
val pdfPages: StateFlow<List<PdfPage>> = mutablePdfPages
|
val pdfPages: StateFlow<AsyncData<ImmutableList<PdfPage>>> = mutablePdfPages
|
||||||
|
|
||||||
fun open() {
|
fun open() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
pdfRenderer = PdfRenderer(parcelFileDescriptor).apply {
|
pdfRenderer = runCatching {
|
||||||
// Preload just 3 pages so we can render faster
|
PdfRenderer(parcelFileDescriptor)
|
||||||
val firstPages = loadPages(from = 0, to = 3)
|
}.fold(
|
||||||
mutablePdfPages.value = firstPages
|
onSuccess = { pdfRenderer ->
|
||||||
val nextPages = loadPages(from = 3, to = pageCount)
|
pdfRenderer.apply {
|
||||||
mutablePdfPages.value = firstPages + nextPages
|
// Preload just 3 pages so we can render faster
|
||||||
}
|
val firstPages = loadPages(from = 0, to = 3)
|
||||||
|
mutablePdfPages.value = AsyncData.Success(firstPages.toImmutableList())
|
||||||
|
val nextPages = loadPages(from = 3, to = pageCount)
|
||||||
|
mutablePdfPages.value = AsyncData.Success((firstPages + nextPages).toImmutableList())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onFailure = {
|
||||||
|
mutablePdfPages.value = AsyncData.Failure(it)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +60,7 @@ class PdfRendererManager(
|
||||||
fun close() {
|
fun close() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
mutablePdfPages.value.forEach { pdfPage ->
|
mutablePdfPages.value.dataOrNull()?.forEach { pdfPage ->
|
||||||
pdfPage.close()
|
pdfPage.close()
|
||||||
}
|
}
|
||||||
pdfRenderer?.close()
|
pdfRenderer?.close()
|
||||||
|
|
|
||||||
|
|
@ -28,13 +28,19 @@ import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
import io.element.android.libraries.designsystem.text.roundToPx
|
import io.element.android.libraries.designsystem.text.roundToPx
|
||||||
import io.element.android.libraries.designsystem.text.toDp
|
import io.element.android.libraries.designsystem.text.toDp
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
|
||||||
import me.saket.telephoto.zoomable.zoomable
|
import me.saket.telephoto.zoomable.zoomable
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PdfViewer(
|
fun PdfViewer(
|
||||||
|
|
@ -59,7 +65,7 @@ fun PdfViewer(
|
||||||
}
|
}
|
||||||
val pdfPages = pdfViewerState.getPages()
|
val pdfPages = pdfViewerState.getPages()
|
||||||
PdfPagesView(
|
PdfPagesView(
|
||||||
pdfPages = pdfPages.toImmutableList(),
|
pdfPages = pdfPages,
|
||||||
lazyListState = pdfViewerState.lazyListState,
|
lazyListState = pdfViewerState.lazyListState,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -67,6 +73,48 @@ fun PdfViewer(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun PdfPagesView(
|
private fun PdfPagesView(
|
||||||
|
pdfPages: AsyncData<ImmutableList<PdfPage>>,
|
||||||
|
lazyListState: LazyListState,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
when (pdfPages) {
|
||||||
|
is AsyncData.Uninitialized,
|
||||||
|
is AsyncData.Loading -> Unit
|
||||||
|
is AsyncData.Failure -> PdfPagesErrorView(
|
||||||
|
pdfPages.error,
|
||||||
|
modifier,
|
||||||
|
)
|
||||||
|
is AsyncData.Success -> PdfPagesContentView(
|
||||||
|
pdfPages = pdfPages.data,
|
||||||
|
lazyListState = lazyListState,
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PdfPagesErrorView(
|
||||||
|
error: Throwable,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = modifier.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = buildString {
|
||||||
|
append(stringResource(id = CommonStrings.error_unknown))
|
||||||
|
append("\n\n")
|
||||||
|
append(error.localizedMessage)
|
||||||
|
},
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = ElementTheme.typography.fontBodyLgRegular,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun PdfPagesContentView(
|
||||||
pdfPages: ImmutableList<PdfPage>,
|
pdfPages: ImmutableList<PdfPage>,
|
||||||
lazyListState: LazyListState,
|
lazyListState: LazyListState,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|
@ -117,3 +165,11 @@ private fun PdfPageView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun PdfPagesErrorViewPreview() = ElementPreview {
|
||||||
|
PdfPagesErrorView(
|
||||||
|
error = IOException("file not in PDF format or corrupted"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import me.saket.telephoto.zoomable.ZoomableState
|
import me.saket.telephoto.zoomable.ZoomableState
|
||||||
import me.saket.telephoto.zoomable.rememberZoomableState
|
import me.saket.telephoto.zoomable.rememberZoomableState
|
||||||
|
|
@ -35,10 +37,10 @@ class PdfViewerState(
|
||||||
private var pdfRendererManager by mutableStateOf<PdfRendererManager?>(null)
|
private var pdfRendererManager by mutableStateOf<PdfRendererManager?>(null)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getPages(): List<PdfPage> {
|
fun getPages(): AsyncData<ImmutableList<PdfPage>> {
|
||||||
return pdfRendererManager?.run {
|
return pdfRendererManager?.run {
|
||||||
pdfPages.collectAsState().value
|
pdfPages.collectAsState().value
|
||||||
} ?: emptyList()
|
} ?: AsyncData.Uninitialized
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openForWidth(maxWidth: Int) {
|
fun openForWidth(maxWidth: Int) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cb0e18f25f8cd978830eb2a4db0cbef76376cdd34c025dc5e21dca39f0b8bd25
|
||||||
|
size 13315
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:336450bda0f5438f30b14fdb9d3a1d95ff9fe3a9ff325c4f860c50dbf6e7256b
|
||||||
|
size 13056
|
||||||
Loading…
Add table
Add a link
Reference in a new issue