...
This commit is contained in:
@@ -130,7 +130,7 @@
|
|||||||
android:name=".player.DocumentViewerActivity"
|
android:name=".player.DocumentViewerActivity"
|
||||||
android:theme="@style/Theme.Player"
|
android:theme="@style/Theme.Player"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
|
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density|fontScale"
|
||||||
android:screenOrientation="portrait"
|
android:screenOrientation="portrait"
|
||||||
android:excludeFromRecents="false"
|
android:excludeFromRecents="false"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
|
|||||||
@@ -499,6 +499,7 @@ class CompletedFilesFragment : Fragment() {
|
|||||||
FileViewMode.GRID_SMALL -> "apps"
|
FileViewMode.GRID_SMALL -> "apps"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val MAX_COUNT = 9
|
||||||
private fun setupControls(view: View) {
|
private fun setupControls(view: View) {
|
||||||
val layoutTitleDefault = view.findViewById<View>(R.id.layoutTitleDefault)
|
val layoutTitleDefault = view.findViewById<View>(R.id.layoutTitleDefault)
|
||||||
val layoutTitleSearch = view.findViewById<View>(R.id.layoutTitleSearch)
|
val layoutTitleSearch = view.findViewById<View>(R.id.layoutTitleSearch)
|
||||||
@@ -577,8 +578,8 @@ class CompletedFilesFragment : Fragment() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val message = if (protectedCount > 5) {
|
val message = if (protectedCount > MAX_COUNT) {
|
||||||
Toast.makeText(context, "보호된 폴더 내부는 5개 이하만 동시 삭제 가능함.", Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, "보호된 폴더 내부는 ${MAX_COUNT}개 이하만 동시 삭제 가능함.", Toast.LENGTH_SHORT).show()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
} else {
|
} else {
|
||||||
"선택한 ${selectedFiles.size}개 항목을 삭제하시겠습니까?"
|
"선택한 ${selectedFiles.size}개 항목을 삭제하시겠습니까?"
|
||||||
|
|||||||
@@ -160,11 +160,13 @@ class PagedTextLayout : ConstraintLayout , PagedTextGenerateInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentPageTextView : TextView? = null
|
var currentPageTextView : TextView? = null
|
||||||
|
var currentChapter : TextView? = null
|
||||||
fun initView(context: Context) {
|
fun initView(context: Context) {
|
||||||
inflate(context, R.layout.layout_textviewer, this)
|
inflate(context, R.layout.layout_textviewer, this)
|
||||||
mainTextView = findViewById(R.id.first_view)
|
mainTextView = findViewById(R.id.first_view)
|
||||||
sencondTextView = findViewById(R.id.sencond_view)
|
sencondTextView = findViewById(R.id.sencond_view)
|
||||||
currentPageTextView = findViewById(R.id.current_page)
|
currentPageTextView = findViewById(R.id.current_page)
|
||||||
|
currentChapter = findViewById(R.id.current_chapter)
|
||||||
if (mPagedTextViewInterface?.usePageInfo() ?: false) {
|
if (mPagedTextViewInterface?.usePageInfo() ?: false) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -29,6 +29,88 @@ class DocumentViewerActivity : AppCompatActivity(), PagedTextViewInterface {
|
|||||||
private var encoding: String = "utf-8"
|
private var encoding: String = "utf-8"
|
||||||
private lateinit var pageIndexer: PageIndexer
|
private lateinit var pageIndexer: PageIndexer
|
||||||
private var currentPageIndex = 0
|
private var currentPageIndex = 0
|
||||||
|
private var indexingJob: kotlinx.coroutines.Job? = null
|
||||||
|
|
||||||
|
// 2. 기존 initializeReader() 함수를 크기 변경 시에도 재사용 가능하도록 리팩토링
|
||||||
|
private fun initializeReader(targetOffset: Long = -1L) {
|
||||||
|
// 기존 작동 중인 인덱싱이 있다면 취소
|
||||||
|
indexingJob?.cancel()
|
||||||
|
|
||||||
|
indexingJob = lifecycleScope.launch {
|
||||||
|
currentFile?.let { file ->
|
||||||
|
// 인코딩은 최초 1회만 구해도 무방하므로 검증 로직 제외 가능
|
||||||
|
if (encoding.isEmpty()) encoding = detectFileEncoding(file)
|
||||||
|
|
||||||
|
val paint = pagedLayout.mainTextView?.paint ?: return@launch
|
||||||
|
val targetWidth = (pagedLayout.mainTextView!!.width * 0.8).toInt()
|
||||||
|
val targetHeight = (pagedLayout.mainTextView!!.height * 0.8).toInt()
|
||||||
|
|
||||||
|
// 0 이하의 크기 방어 (뷰가 아직 가로세로 측정이 안 되었을 때)
|
||||||
|
if (targetWidth <= 0 || targetHeight <= 0) return@launch
|
||||||
|
|
||||||
|
pageIndexer = PageIndexer(
|
||||||
|
file, encoding, paint, targetWidth, targetHeight
|
||||||
|
)
|
||||||
|
|
||||||
|
var hasRestoredPage = false
|
||||||
|
|
||||||
|
pageIndexer.buildIndex { progress ->
|
||||||
|
runOnUiThread {
|
||||||
|
val currentOffsetsSize = pageIndexer.pageOffsets.size
|
||||||
|
|
||||||
|
if (!hasRestoredPage) {
|
||||||
|
if (targetOffset >= 0L) {
|
||||||
|
// [크기 재조정 케이스] 기억해둔 오프셋 위치가 확보되었는지 확인
|
||||||
|
val foundIndex = pageIndexer.pageOffsets.indexOfLast { it <= targetOffset }
|
||||||
|
// 마지막 오프셋이거나, 다음 페이지 오프셋까지 리스트에 확보되었을 때 전환
|
||||||
|
if (foundIndex >= 0 && (foundIndex < currentOffsetsSize - 1 || progress >= 100)) {
|
||||||
|
showPage(foundIndex)
|
||||||
|
hasRestoredPage = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// [최초 진입 케이스] SharedPreferences 복구
|
||||||
|
val savedPageIndex = sharedPreferences.getInt(file.absolutePath, 0)
|
||||||
|
if (currentOffsetsSize > savedPageIndex) {
|
||||||
|
showPage(savedPageIndex)
|
||||||
|
hasRestoredPage = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pagedLayout.currentPageTextView?.text = "${currentPageIndex + 1} / $currentOffsetsSize"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 팝업 크기 변경 감지 콜백 구현
|
||||||
|
override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
|
||||||
|
super.onConfigurationChanged(newConfig)
|
||||||
|
|
||||||
|
// 현재 읽고 있던 페이지의 실제 파일 시작 offset을 백업합니다.
|
||||||
|
val currentOffsetBackup = if (::pageIndexer.isInitialized && currentPageIndex in pageIndexer.pageOffsets.indices) {
|
||||||
|
pageIndexer.pageOffsets[currentPageIndex]
|
||||||
|
} else {
|
||||||
|
-1L
|
||||||
|
}
|
||||||
|
|
||||||
|
// 뷰가 새로운 크기로 완전히 배치(Layout)된 후 재인덱싱을 돌려야 정확한 가로/세로가 나옵니다.
|
||||||
|
pagedLayout.post {
|
||||||
|
initializeReader(targetOffset = currentOffsetBackup)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. onDestroy 스케줄러 취소 안전장치 추가
|
||||||
|
override fun onDestroy() {
|
||||||
|
indexingJob?.cancel()
|
||||||
|
super.onDestroy()
|
||||||
|
try {
|
||||||
|
raf.close()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SharedPreferences 정의 (마지막 페이지 저장용)
|
// SharedPreferences 정의 (마지막 페이지 저장용)
|
||||||
private val sharedPreferences by lazy {
|
private val sharedPreferences by lazy {
|
||||||
@@ -151,14 +233,19 @@ class DocumentViewerActivity : AppCompatActivity(), PagedTextViewInterface {
|
|||||||
val pageText = String(buffer, Charset.forName(encoding))
|
val pageText = String(buffer, Charset.forName(encoding))
|
||||||
pagedLayout.text = pageText
|
pagedLayout.text = pageText
|
||||||
pagedLayout.currentPageTextView?.text = "${currentPageIndex + 1} / ${pageIndexer.pageOffsets.size}"
|
pagedLayout.currentPageTextView?.text = "${currentPageIndex + 1} / ${pageIndexer.pageOffsets.size}"
|
||||||
|
pagedLayout.currentChapter?.text = pageIndexer.getChapterForPage(currentPageIndex)?.title
|
||||||
|
pagedLayout.currentChapter?.setOnClickListener {
|
||||||
|
if (!::pageIndexer.isInitialized || pageIndexer.pageOffsets.isEmpty()) return@setOnClickListener
|
||||||
|
showChapterListDialog()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouch(touchArea: TouchArea) {
|
override fun onTouch(touchArea: TouchArea) {
|
||||||
if (!::pageIndexer.isInitialized || pageIndexer.pageOffsets.isEmpty()) return
|
// if (!::pageIndexer.isInitialized || pageIndexer.pageOffsets.isEmpty()) return
|
||||||
if (touchArea == TouchArea.Center) {
|
// if (touchArea == TouchArea.Center) {
|
||||||
// showPageSeekDialog()
|
//// showPageSeekDialog()
|
||||||
showChapterListDialog()
|
// showChapterListDialog()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun moveToNextChapter() {
|
private fun moveToNextChapter() {
|
||||||
@@ -302,18 +389,14 @@ class DocumentViewerActivity : AppCompatActivity(), PagedTextViewInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLongClick() {}
|
override fun onLongClick() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
override fun usePageInfo(): Boolean = true
|
override fun usePageInfo(): Boolean = true
|
||||||
override fun onTimeoverTouch() {}
|
override fun onTimeoverTouch() {}
|
||||||
override fun onSwipeDown(count: Int) {}
|
override fun onSwipeDown(count: Int) {}
|
||||||
override fun onSwipeUp(count: Int) {}
|
override fun onSwipeUp(count: Int) {}
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
super.onDestroy()
|
|
||||||
try {
|
|
||||||
raf.close()
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,10 @@ class PageIndexer(
|
|||||||
val pageOffsets = ArrayList<Long>()
|
val pageOffsets = ArrayList<Long>()
|
||||||
val chapters = ArrayList<Chapter>()
|
val chapters = ArrayList<Chapter>()
|
||||||
private val charset = Charset.forName(encoding)
|
private val charset = Charset.forName(encoding)
|
||||||
|
fun getChapterForPage(currentPageIndex: Int): Chapter? {
|
||||||
|
// 현재 페이지보다 작거나 같은 시작 페이지를 가진 챕터 중, 가장 마지막 챕터를 찾습니다.
|
||||||
|
return chapters.lastOrNull { it.pageIndex <= currentPageIndex }
|
||||||
|
}
|
||||||
private val chapterPattern = Pattern.compile(
|
private val chapterPattern = Pattern.compile(
|
||||||
"(?:제\\s*)?\\d+\\s*[화|장|막|절|편]"
|
"(?:제\\s*)?\\d+\\s*[화|장|막|절|편]"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user