...
This commit is contained in:
@@ -125,7 +125,16 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false">
|
||||
</activity>
|
||||
<activity android:name=".home.WebReaderActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
android:launchMode="singleInstance"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|density|fontScale|keyboardHidden|keyboard|layoutDirection|navigation"
|
||||
android:screenOrientation="portrait"
|
||||
android:excludeFromRecents="false"
|
||||
android:hardwareAccelerated="true"
|
||||
android:exported="false">
|
||||
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".player.DocumentViewerActivity"
|
||||
android:theme="@style/Theme.Player"
|
||||
@@ -240,10 +249,10 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- <service-->
|
||||
<!-- android:name=".feeds.rss.RssService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE"-->
|
||||
<!-- android:exported="false"/>-->
|
||||
<!-- <service-->
|
||||
<!-- android:name=".feeds.rss.RssService"-->
|
||||
<!-- android:permission="android.permission.BIND_JOB_SERVICE"-->
|
||||
<!-- android:exported="false"/>-->
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
@@ -629,7 +629,7 @@ open class NeoRssActivity : CommonActivity() {
|
||||
// 처음 호출되는 메뉴라면 인스턴스 생성 및 추가
|
||||
targetFragment = when(id) {
|
||||
R.id.feeds -> RssHome()
|
||||
R.id.books -> TokiFragment.newInstanceNovels()
|
||||
|
||||
// R.id.webtoons -> TokiFragment.newInstanceWebtoons()
|
||||
// R.id.comics -> TokiFragment.newInstanceComics()
|
||||
R.id.youtube -> TokiFragment.newInstanceYouTube()
|
||||
@@ -649,6 +649,11 @@ open class NeoRssActivity : CommonActivity() {
|
||||
R.id.btn_info -> SystemStatusFragment()
|
||||
R.id.btn_completed_files -> CompletedFilesFragment()
|
||||
R.id.btn_learn -> LearningFragment()
|
||||
R.id.books -> {
|
||||
startActivity(Intent(this@NeoRssActivity, WebReaderActivity::class.java))
|
||||
finish()
|
||||
return
|
||||
}
|
||||
R.id.close -> {
|
||||
finish()
|
||||
return
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package bums.lunatic.launcher.home
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.KeyEvent
|
||||
import android.webkit.ValueCallback
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebSettings
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import bums.lunatic.launcher.R
|
||||
|
||||
class WebReaderActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var webView: WebView
|
||||
|
||||
// 웹뷰에서 파일을 선택할 때 결과를 받을 콜백 변수
|
||||
private var filePathCallback: ValueCallback<Array<Uri>>? = null
|
||||
|
||||
// 파일 탐색기 결과를 처리하는 런처 (최신 Activity Result API 사용)
|
||||
private val fileChooserLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
) { result ->
|
||||
if (result.resultCode == Activity.RESULT_OK) {
|
||||
val data = result.data
|
||||
val uriList = if (data?.data != null) {
|
||||
arrayOf(data.data!!)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
// 웹뷰로 선택한 파일 URI 전달
|
||||
filePathCallback?.onReceiveValue(uriList)
|
||||
} else {
|
||||
// 취소했을 경우 반드시 null을 전달해야 웹뷰가 멈추지 않음
|
||||
filePathCallback?.onReceiveValue(null)
|
||||
}
|
||||
filePathCallback = null
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_wr)
|
||||
|
||||
webView = findViewById(R.id.webView)
|
||||
|
||||
setupWebView()
|
||||
|
||||
// assets 폴더에 넣은 HTML 파일 로드
|
||||
webView.loadUrl("https://git.lunaticbum.kr/reader.html")
|
||||
}
|
||||
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
// 볼륨 다운 버튼 -> 다음 페이지 (오른쪽 화살표)
|
||||
// 웹뷰에 JavaScript 키보드 이벤트를 강제로 발생시킴
|
||||
webView.evaluateJavascript(
|
||||
"window.dispatchEvent(new KeyboardEvent('keydown', {'key': 'ArrowRight'}));",
|
||||
null
|
||||
)
|
||||
return true // true를 반환하면 시스템 볼륨이 변경되지 않고 이벤트가 소비됨
|
||||
}
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
// 볼륨 업 버튼 -> 이전 페이지 (왼쪽 화살표)
|
||||
webView.evaluateJavascript(
|
||||
"window.dispatchEvent(new KeyboardEvent('keydown', {'key': 'ArrowLeft'}));",
|
||||
null
|
||||
)
|
||||
return true // true를 반환하면 시스템 볼륨이 변경되지 않음
|
||||
}
|
||||
}
|
||||
|
||||
// 볼륨 키가 아닌 다른 키(뒤로가기 등)는 기본 안드로이드 동작을 수행하도록 넘김
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
|
||||
private fun setupWebView() {
|
||||
// 1. 웹뷰 기본 설정
|
||||
webView.settings.apply {
|
||||
javaScriptEnabled = true // 자바스크립트 필수
|
||||
domStorageEnabled = true // localStorage, IndexedDB 사용을 위해 필수
|
||||
allowFileAccess = true // 로컬 파일 접근 허용
|
||||
allowContentAccess = true // Content URI 접근 허용
|
||||
mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW // 보안 정책 우회 (필요시)
|
||||
|
||||
// 모바일 화면에 맞게 뷰포트 설정
|
||||
useWideViewPort = true
|
||||
loadWithOverviewMode = true
|
||||
}
|
||||
|
||||
// 2. 새 창 열림 방지 (앱 내부에서만 렌더링)
|
||||
webView.webViewClient = WebViewClient()
|
||||
|
||||
// 3. 파일 업로드(<input type="file">) 처리를 위한 WebChromeClient 설정
|
||||
webView.webChromeClient = object : WebChromeClient() {
|
||||
override fun onShowFileChooser(
|
||||
webView: WebView?,
|
||||
filePathCallback: ValueCallback<Array<Uri>>?,
|
||||
fileChooserParams: FileChooserParams?
|
||||
): Boolean {
|
||||
// 이전 콜백이 남아있다면 취소 처리
|
||||
this@WebReaderActivity.filePathCallback?.onReceiveValue(null)
|
||||
this@WebReaderActivity.filePathCallback = filePathCallback
|
||||
|
||||
// 안드로이드 파일 탐색기 호출 Intent
|
||||
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
type = "*/*"
|
||||
// txt, epub만 선택하게 하려면 아래처럼 mimeTypes 지정 가능
|
||||
putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/plain", "application/epub+zip"))
|
||||
}
|
||||
|
||||
fileChooserLauncher.launch(intent)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 뒤로가기 버튼 처리 (웹뷰 내에서 뒤로 갈 수 있으면 웹뷰 뒤로가기 실행)
|
||||
override fun onBackPressed() {
|
||||
if (webView.canGoBack()) {
|
||||
webView.goBack()
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,13 +185,13 @@ class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHan
|
||||
putBoolean(ARG_ENABLE_GESTURE, false)
|
||||
}
|
||||
}
|
||||
|
||||
// https://git.lunaticbum.kr/reader.html
|
||||
fun newInstanceNovels(): TokiFragment = TokiFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putString(ARG_TYPE, "web")
|
||||
putInt(ARG_LAST_NUM, 468)
|
||||
putString(ARG_NAME, "sbxh2")
|
||||
putString(ARG_DOT, "com/novel")
|
||||
putString(ARG_NAME, "git.lunaticbum")
|
||||
putString(ARG_DOT, ".kr/reader.html")
|
||||
putBoolean(ARG_USE_NUM_URL, false)
|
||||
putBoolean(ARG_ENABLE_GESTURE, true)
|
||||
}
|
||||
|
||||
@@ -60,10 +60,12 @@ class DocumentViewerActivity : AppCompatActivity(), PagedTextViewInterface {
|
||||
|
||||
pageIndexer.buildIndex { progress ->
|
||||
runOnUiThread {
|
||||
try {
|
||||
val currentOffsetsSize = pageIndexer.pageOffsets.size
|
||||
|
||||
if (!hasRestoredPage) {
|
||||
if (targetOffset >= 0L) {
|
||||
|
||||
// [크기 재조정 케이스] 기억해둔 오프셋 위치가 확보되었는지 확인
|
||||
val foundIndex = pageIndexer.pageOffsets.indexOfLast { it <= targetOffset }
|
||||
// 마지막 오프셋이거나, 다음 페이지 오프셋까지 리스트에 확보되었을 때 전환
|
||||
@@ -83,6 +85,10 @@ class DocumentViewerActivity : AppCompatActivity(), PagedTextViewInterface {
|
||||
|
||||
pagedLayout.currentPageTextView?.text = "${currentPageIndex + 1} / $currentOffsetsSize"
|
||||
}
|
||||
catch (e : Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<WebView
|
||||
android:id="@+id/webView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
Reference in New Issue
Block a user