Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PDF 화면 구성 및 PDF 렌더링 #27

Merged
merged 30 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bdff90f
Feat: PDF 렌더링
Guri999 Dec 5, 2024
e95c491
Feat: PDF Zoom & drag
Guri999 Dec 6, 2024
cf10836
Feat: PDF 해상도 증가
Guri999 Dec 6, 2024
0785726
Feat: PDF Topbar
Guri999 Dec 7, 2024
2d70b89
Feat: PDF TopBar Page calculation
Guri999 Dec 7, 2024
4b66946
Feat: Domain 모듈 제거
Guri999 Dec 7, 2024
58596a1
Feat: Domain 모듈 제거
Guri999 Dec 7, 2024
c4aa77c
Feat: File Model 생성, 파일 찾기 로직 분리
Guri999 Dec 7, 2024
e65341e
Feat: Room 생성
Guri999 Dec 8, 2024
809743a
Refactor: 파일 탐색 백그라운드 스레드로 변경
Guri999 Dec 31, 2024
0de159f
Refactor: Uri remember로 처리
Guri999 Jan 3, 2025
21a6a33
Refactor: 매직넘버 상수로 관리
Guri999 Jan 3, 2025
308e067
Refactor: page,onPageChange -> page, onPageChange
Guri999 Jan 3, 2025
830538f
Refactor: 빈 프리뷰 제거
Guri999 Jan 3, 2025
b7e491a
Refactor: TopBar 관리 캡슐화
Guri999 Jan 6, 2025
1a1ed20
Refactor: Permission 관리 변경
Guri999 Jan 6, 2025
641f6de
Chore: onTopBarVisibleChange -> onPdfBodyPressed 이름 변경
Guri999 Jan 6, 2025
6020dd8
Refactor: PdfToBitmap class 생성하여 pdf 렌더링 관리
Guri999 Jan 6, 2025
3bd4b0d
Chore: if문 괄호
Guri999 Jan 6, 2025
91e5fa5
Feat: Koin 설정
Guri999 Jan 7, 2025
003c38d
Refactor: PDF화면 MVI refactor
Guri999 Jan 7, 2025
a7f951d
Revert "Refactor: PDF화면 MVI refactor"
Guri999 Jan 7, 2025
39ab182
Revert "Feat: Koin 설정"
Guri999 Jan 7, 2025
ea25198
Refactor: TopBarState currentScope -> currentJob
Guri999 Jan 7, 2025
514b612
Refactor: TopBarState onBodyPress -> show
Guri999 Jan 7, 2025
1b8822a
Refactor: TopBarState 생성자 제한
Guri999 Jan 7, 2025
04c1ab7
Chore: bitmap 줄내림 수정
Guri999 Jan 7, 2025
6345800
Chore: if문 중괄호 표시
Guri999 Jan 7, 2025
9a39999
Chore: line 제거
Guri999 Jan 7, 2025
7afa071
Chore: ignore .idea 추가
Guri999 Jan 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 34 additions & 51 deletions feature/pdf/src/main/java/kr/co/pdf/PdfScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,10 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
Expand All @@ -43,12 +42,15 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.core.text.isDigitsOnly
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
import kr.co.ui.theme.SeeDocsTheme
import kr.co.ui.theme.Theme
import kr.co.ui.util.rememberTopBarState
import kr.co.ui.widget.SimpleTextField
import kr.co.ui.widget.TextFieldInputType
import kr.co.util.PdfToBitmap
import kr.co.util.rememberPdfState
import net.engawapg.lib.zoomable.rememberZoomState
import net.engawapg.lib.zoomable.zoomable
import java.io.File
Expand Down Expand Up @@ -86,7 +88,6 @@ internal fun PdfRoute(
listState.scrollToItem(page - 1)
}
},
popBackStack = popBackStack
)
}
}
Expand All @@ -95,11 +96,13 @@ internal fun PdfRoute(
private fun PdfScreen(
renderer: PdfRenderer,
listState: LazyListState = rememberLazyListState(),
pdfState: PdfToBitmap = rememberPdfState(renderer),
isTopBarVisible: Boolean = false,
onPdfBodyPressed: () -> Unit,
onPageIndexChange: (Int) -> Unit = {},
popBackStack: () -> Unit = {},
) {
val bitmaps = pdfState.bitmap.collectAsStateWithLifecycle()

Box(
modifier = Modifier
.fillMaxSize()
Expand All @@ -123,9 +126,12 @@ private fun PdfScreen(
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
items(renderer.pageCount) { page ->
LaunchedEffect(page) {
pdfState.renderPage(page)
}

PdfImage(
renderer = renderer,
pageIndex = page
bitmap = bitmaps.value[page],
)
}
}
Expand All @@ -150,52 +156,31 @@ private fun PdfScreen(

@Composable
private fun PdfImage(
renderer: PdfRenderer,
pageIndex: Int,
bitmap: Bitmap?,
) {
var bitmap by remember {
mutableStateOf<Bitmap?>(null)
}
var isLoading by remember { mutableStateOf(true) }

LaunchedEffect(Unit) {
isLoading = true
val page = renderer.openPage(pageIndex)
Bitmap.createBitmap(page.width * SCALE_UP, page.height * SCALE_UP, Bitmap.Config.ARGB_8888).also {
page.render(it, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
bitmap = it
page.close()
isLoading = false
}
}

if (isLoading) {
Box(
bitmap?.let {
Image(
bitmap = it.asImageBitmap(),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
contentAlignment = Alignment.Center
) {
Image(
painter = ColorPainter(Theme.colors.grayText),
contentDescription = null,
modifier = Modifier.fillMaxSize()
)
.aspectRatio(it.width.toFloat() / it.height.toFloat())
)
} ?: Box(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
contentAlignment = Alignment.Center
) {
Image(
painter = ColorPainter(Theme.colors.grayText),
contentDescription = null,
modifier = Modifier.fillMaxSize()
)

CircularProgressIndicator(
color = Theme.colors.highlight
)
}
} else {
bitmap?.let {
Image(
bitmap = it.asImageBitmap(),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.aspectRatio(it.width.toFloat() / it.height.toFloat())
)
}
CircularProgressIndicator(
color = Theme.colors.highlight
)
}
}

Expand Down Expand Up @@ -230,7 +215,7 @@ private fun PdfTopBar(
value = page,
onValueChange = {
onPageChange(it)
if(it.isNotEmpty() && it.isDigitsOnly()) onPageIndexChange(it.toInt())
if (it.isNotEmpty() && it.isDigitsOnly()) onPageIndexChange(it.toInt())
},
inputType = TextFieldInputType.NUMBER
)
Expand All @@ -247,8 +232,6 @@ private fun PdfTopBar(
)
}

private const val SCALE_UP = 3

@Preview
@Composable
private fun PreviewTopBar() {
Expand Down
67 changes: 67 additions & 0 deletions feature/pdf/src/main/java/kr/co/util/PdfToBitmap.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package kr.co.util

import android.graphics.Bitmap
import android.graphics.pdf.PdfRenderer
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

internal class PdfToBitmap(
private val renderer: PdfRenderer,
) {

private val _bitmap = MutableStateFlow<Map<Int, Bitmap>>(emptyMap())
val bitmap = _bitmap.asStateFlow()

private val renderingPages = mutableSetOf<Int>()

private val mutex = Mutex()

suspend fun renderPage(pageIndex: Int) {
mutex.withLock {
if (renderingPages.contains(pageIndex)) return

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if문 다음에 이어지는 줄이 있다면 {}를 생략하지 않는것이 가독성에 도움이 됩니다.
return문이 있기 때문에 이 상황에서는 좀 더 낫지만, 일관적인 컨벤션을 위해 괄호를 사용하는 것을 추천드립니다.

renderingPages.add(pageIndex)
}

val page = renderer.openPage(pageIndex)

val bitmap =
Bitmap.createBitmap(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의도된 줄내림 일까요?

page.width * SCALE_UP,
page.height * SCALE_UP,
Bitmap.Config.ARGB_8888
).also {
page.render(it, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY)
page.close()
}


Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new line이 두 개인데, 의도된 것일까요?

_bitmap.update { it + (pageIndex to bitmap) }
}

internal fun close() {
renderer.close()
}

private companion object {
private const val SCALE_UP = 3
}
}

@Composable
internal fun rememberPdfState(
renderer: PdfRenderer,
): PdfToBitmap {
val pdfState = remember { PdfToBitmap(renderer) }
DisposableEffect(Unit) {
onDispose {
pdfState.close()
}
}
return pdfState
}