...
This commit is contained in:
parent
be016409d7
commit
a72b1778a9
@ -96,6 +96,16 @@ port.onMessage.addListener(response => {
|
|||||||
// try {contents = toonContents(document.querySelector("#novel_content"))}catch (e) {}
|
// try {contents = toonContents(document.querySelector("#novel_content"))}catch (e) {}
|
||||||
// console.log("listBody", listBody);
|
// console.log("listBody", listBody);
|
||||||
// console.log("title", title);
|
// console.log("title", title);
|
||||||
|
|
||||||
|
const keyword = "보안";
|
||||||
|
const elements = document.querySelectorAll(".main-content"); // 또는 getElementsByClassName("item")
|
||||||
|
|
||||||
|
const matched = Array.from(elements).filter(el =>
|
||||||
|
el.textContent.includes(keyword) // 대소문자 구분
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(listBody) {
|
if(listBody) {
|
||||||
// getList(listBody.children)
|
// getList(listBody.children)
|
||||||
} else if(title && contents) {
|
} else if(title && contents) {
|
||||||
@ -110,6 +120,8 @@ port.onMessage.addListener(response => {
|
|||||||
// }
|
// }
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
} else if(matched.length > 0){
|
||||||
|
hideBook()
|
||||||
} else {
|
} else {
|
||||||
loadComplete()
|
loadComplete()
|
||||||
}
|
}
|
||||||
@ -129,7 +141,8 @@ port.onMessage.addListener(response => {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "ViewerTouch": {
|
case "ViewerTouch": {
|
||||||
if (document.querySelector(".show_viewer")) {
|
if (document.querySelector(".show_viewer") && document.querySelector(".mcv-visible")) {
|
||||||
|
|
||||||
var area = response["area"]
|
var area = response["area"]
|
||||||
var current = Number(document.querySelector("#mcv_currentPageNum").innerHTML)
|
var current = Number(document.querySelector("#mcv_currentPageNum").innerHTML)
|
||||||
var total = Number(document.querySelector("#mcv_totalPagesNum").innerHTML)
|
var total = Number(document.querySelector("#mcv_totalPagesNum").innerHTML)
|
||||||
@ -146,8 +159,10 @@ port.onMessage.addListener(response => {
|
|||||||
}else {
|
}else {
|
||||||
document.querySelector("#goNextBtn").click()
|
document.querySelector("#goNextBtn").click()
|
||||||
}
|
}
|
||||||
document.querySelector(".link_ad")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if(document.querySelector(".show_viewer")){
|
||||||
|
document.querySelector(".show_viewer").click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -350,8 +365,13 @@ function scrollByPercentUpDown(isToDown , max) {
|
|||||||
window.scrollTo({ top: currentScroll + (moveAmount * isToDown) , behavior: "smooth" });
|
window.scrollTo({ top: currentScroll + (moveAmount * isToDown) , behavior: "smooth" });
|
||||||
}
|
}
|
||||||
function loadComplete() {
|
function loadComplete() {
|
||||||
// try {port.postMessage(JSON.stringify({type: "NotRegistered"}));}catch (e) {}
|
try {port.postMessage(JSON.stringify({type: "NotRegistered"}));}catch (e) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hideBook() {
|
||||||
|
try {port.postMessage(JSON.stringify({type: "NotRegistered"}));}catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
function sendMessage(msg) {
|
function sendMessage(msg) {
|
||||||
port.postMessage(JSON.stringify(msg));
|
port.postMessage(JSON.stringify(msg));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,17 @@
|
|||||||
|
package bums.lunatic.launcher.common
|
||||||
|
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
|
||||||
|
abstract class RemoteGestureFragment : Fragment() {
|
||||||
|
|
||||||
|
// 자식에서 필요한 동작만 구현 (기본적으로는 소비하지 않음)
|
||||||
|
open fun onRemoteUp(isDouble : Boolean) {}
|
||||||
|
open fun onRemoteDown(isDouble : Boolean) {}
|
||||||
|
open fun onRemoteLeft(isDouble : Boolean) {}
|
||||||
|
open fun onRemoteRight(isDouble : Boolean) {}
|
||||||
|
open fun onRemoteCenterClick() {}
|
||||||
|
open fun onRemoteCenterDoubleClick() {}
|
||||||
|
|
||||||
|
// 이벤트를 가로챌지 여부를 결정하는 플래그
|
||||||
|
open val isRemoteEnabled: Boolean = true
|
||||||
|
}
|
||||||
@ -348,6 +348,11 @@ open class GeckoWeb @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun goBack() {
|
||||||
|
if (true == canGoBack)
|
||||||
|
session?.goBack()
|
||||||
|
}
|
||||||
|
|
||||||
// [Progress Delegate]
|
// [Progress Delegate]
|
||||||
private val progressDelegate = object : GeckoSession.ProgressDelegate {
|
private val progressDelegate = object : GeckoSession.ProgressDelegate {
|
||||||
override fun onProgressChange(session: GeckoSession, progress: Int) {
|
override fun onProgressChange(session: GeckoSession, progress: Int) {
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import android.os.Build
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.view.GestureDetector
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.KeyEvent.ACTION_UP
|
import android.view.KeyEvent.ACTION_UP
|
||||||
import android.view.KeyEvent.KEYCODE_BUTTON_A
|
import android.view.KeyEvent.KEYCODE_BUTTON_A
|
||||||
@ -19,6 +20,11 @@ import android.view.KeyEvent.KEYCODE_BUTTON_X
|
|||||||
import android.view.KeyEvent.KEYCODE_BUTTON_Y
|
import android.view.KeyEvent.KEYCODE_BUTTON_Y
|
||||||
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
|
import android.view.KeyEvent.KEYCODE_DPAD_DOWN
|
||||||
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
import android.view.KeyEvent.KEYCODE_DPAD_UP
|
||||||
|
import android.view.KeyEvent.KEYCODE_MEDIA_PAUSE
|
||||||
|
import android.view.KeyEvent.KEYCODE_MEDIA_PLAY
|
||||||
|
import android.view.KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
|
||||||
|
import android.view.KeyEvent.KEYCODE_VOLUME_DOWN
|
||||||
|
import android.view.KeyEvent.KEYCODE_VOLUME_UP
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.PointerIcon
|
import android.view.PointerIcon
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -35,6 +41,7 @@ import androidx.fragment.app.Fragment
|
|||||||
import bums.lunatic.launcher.LunaticLauncher
|
import bums.lunatic.launcher.LunaticLauncher
|
||||||
import bums.lunatic.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
import bums.lunatic.launcher.common.CommonActivity
|
import bums.lunatic.launcher.common.CommonActivity
|
||||||
|
import bums.lunatic.launcher.common.RemoteGestureFragment
|
||||||
import bums.lunatic.launcher.databinding.RssActivityBinding
|
import bums.lunatic.launcher.databinding.RssActivityBinding
|
||||||
import bums.lunatic.launcher.helpers.ForeGroundService
|
import bums.lunatic.launcher.helpers.ForeGroundService
|
||||||
import bums.lunatic.launcher.helpers.HeadsetActionButtonReceiver
|
import bums.lunatic.launcher.helpers.HeadsetActionButtonReceiver
|
||||||
@ -61,6 +68,7 @@ import org.mozilla.geckoview.GeckoRuntime
|
|||||||
import org.mozilla.geckoview.GeckoRuntimeSettings
|
import org.mozilla.geckoview.GeckoRuntimeSettings
|
||||||
import org.mozilla.geckoview.GeckoRuntimeSettings.ALLOW_ALL
|
import org.mozilla.geckoview.GeckoRuntimeSettings.ALLOW_ALL
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
interface KeyEventHandler {
|
interface KeyEventHandler {
|
||||||
// 이벤트를 소비(consume)했으면 true, 아니면 false 반환
|
// 이벤트를 소비(consume)했으면 true, 아니면 false 반환
|
||||||
@ -117,9 +125,35 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
var actionButtonPressY = 0f
|
var actionButtonPressY = 0f
|
||||||
var onExit = false
|
var onExit = false
|
||||||
var lastAction = MotionEvent.ACTION_HOVER_EXIT
|
var lastAction = MotionEvent.ACTION_HOVER_EXIT
|
||||||
|
|
||||||
|
|
||||||
|
override fun onKeyLongPress(keyCode: Int, ev: KeyEvent?): Boolean {
|
||||||
|
Blog.LOGE("keyEvent >>>>> ${ev?.device?.name}:${keyCode}: onKeyLongPress >>> ${ev} ")
|
||||||
|
return super.onKeyLongPress(keyCode, ev)
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
|
override fun dispatchKeyEvent(ev: KeyEvent): Boolean {
|
||||||
Blog.LOGE("dispatchKeyEvent >>> ${ev}")
|
Blog.LOGE("keyEvent >>>>> ${ev?.device?.name}:dispatchKeyEvent >>> ${ev} ")
|
||||||
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
|
if (ev?.device?.name?.contains("JX-05") == true) {
|
||||||
|
// (ev.action?.equals(KeyEvent.ACTION_DOWN) == true || ev.action?.equals(KeyEvent.ACTION_UP) == true)
|
||||||
|
if (ev.action?.equals(KeyEvent.ACTION_UP) == true) {
|
||||||
|
when(ev.keyCode) {
|
||||||
|
KEYCODE_MEDIA_PLAY_PAUSE->{
|
||||||
|
onRemoteKeyDetected("RIGHT_ARROW", true)
|
||||||
|
}
|
||||||
|
KEYCODE_MEDIA_PAUSE->{
|
||||||
|
// onRemoteKeyDetected("LEFT_ARROW", true)
|
||||||
|
}
|
||||||
|
KEYCODE_VOLUME_UP->{
|
||||||
|
onRemoteKeyDetected("UP_ARROW", true)
|
||||||
|
}
|
||||||
|
KEYCODE_VOLUME_DOWN->{
|
||||||
|
onRemoteKeyDetected("DOWN_ARROW", true)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
return true
|
||||||
|
}else
|
||||||
|
if (ev?.device?.name?.contains("SM-031N Mouse") == true) {
|
||||||
when(ev.action) {
|
when(ev.action) {
|
||||||
ACTION_UP -> {
|
ACTION_UP -> {
|
||||||
Blog.LOGE("dispatch dispatchKeyEvent>>> ${ev}")
|
Blog.LOGE("dispatch dispatchKeyEvent>>> ${ev}")
|
||||||
@ -175,39 +209,116 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
return super.dispatchKeyEvent(ev)
|
return super.dispatchKeyEvent(ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val flingHandler = Handler(Looper.getMainLooper())
|
||||||
|
private var pendingFlingRunnable: Runnable? = null
|
||||||
|
private var lastFlingTime = 0L
|
||||||
|
private var lastFlingDirection = ""
|
||||||
|
private val DOUBLE_TAP_TIMEOUT = 300L
|
||||||
|
|
||||||
|
private val remoteGestureDetector by lazy {
|
||||||
|
GestureDetector(this, object : GestureDetector.SimpleOnGestureListener() {
|
||||||
|
|
||||||
|
private fun processFling(direction: String) {
|
||||||
|
// 이전에 예약된 싱글 실행이 있다면 일단 제거 (더블 체크를 위해)
|
||||||
|
pendingFlingRunnable?.let { flingHandler.removeCallbacks(it) }
|
||||||
|
|
||||||
|
val currentTime = System.currentTimeMillis()
|
||||||
|
|
||||||
|
// 1. 방향이 같고 시간 내에 들어왔는가?
|
||||||
|
if (direction == lastFlingDirection && (currentTime - lastFlingTime) < DOUBLE_TAP_TIMEOUT) {
|
||||||
|
Blog.LOGE("Detected DOUBLE FLING: $direction")
|
||||||
|
onRemoteKeyDetected(direction, true) // isDouble = true 전달
|
||||||
|
lastFlingTime = 0L // 더블 처리 후 시간 초기화
|
||||||
|
lastFlingDirection = ""
|
||||||
|
} else {
|
||||||
|
// 2. 일단 싱글 후보로 등록
|
||||||
|
lastFlingTime = currentTime
|
||||||
|
lastFlingDirection = direction
|
||||||
|
|
||||||
|
pendingFlingRunnable = Runnable {
|
||||||
|
Blog.LOGE("Detected SINGLE FLING: $direction")
|
||||||
|
onRemoteKeyDetected(direction, false) // isDouble = false 전달
|
||||||
|
// 실행 후 상태 초기화는 하지 않음 (다음 클릭이 더블이 될 수 있으므로)
|
||||||
|
}.also {
|
||||||
|
flingHandler.postDelayed(it, DOUBLE_TAP_TIMEOUT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFling(e1: MotionEvent?, e2: MotionEvent, vx: Float, vy: Float): Boolean {
|
||||||
|
if (abs(vy) > abs(vx)) {
|
||||||
|
if (vy > 0) processFling("UP_ARROW")
|
||||||
|
else processFling("DOWN_ARROW")
|
||||||
|
} else {
|
||||||
|
if (vx > 0) processFling("LEFT_ARROW")
|
||||||
|
else processFling("RIGHT_ARROW")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 중앙 버튼은 기존대로 유지 (탭 기반이므로 잘 동작함)
|
||||||
|
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
|
||||||
|
onRemoteKeyDetected("CENTER_SINGLE_TAP")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDoubleTap(e: MotionEvent): Boolean {
|
||||||
|
onRemoteKeyDetected("CENTER_DOUBLE_TAP")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onRemoteKeyDetected(keyType: String, isDouble : Boolean = false) {
|
||||||
|
Blog.LOGE("Remote Mapping Success: $keyType")
|
||||||
|
val currentFragment = supportFragmentManager.fragments.find { it.isVisible }
|
||||||
|
if (currentFragment is RemoteGestureFragment && currentFragment.isRemoteEnabled) {
|
||||||
|
when(keyType) {
|
||||||
|
"UP_ARROW"->{currentFragment.onRemoteUp(isDouble)}
|
||||||
|
"DOWN_ARROW"->{currentFragment.onRemoteDown(isDouble)}
|
||||||
|
"RIGHT_ARROW"->{currentFragment.onRemoteRight(isDouble)}
|
||||||
|
"LEFT_ARROW"->{currentFragment.onRemoteLeft(isDouble)}
|
||||||
|
"CENTER_SINGLE_TAP" -> { currentFragment.onRemoteCenterClick() }
|
||||||
|
"CENTER_DOUBLE_TAP" -> { currentFragment.onRemoteCenterDoubleClick() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when(keyType) {
|
||||||
|
"UP_ARROW"->{showContents(R.id.feeds)}
|
||||||
|
"DOWN_ARROW"->{showContents(R.id.close)}
|
||||||
|
"RIGHT_ARROW"->{showContents(R.id.books)}
|
||||||
|
"LEFT_ARROW"->{ }
|
||||||
|
"CENTER_SINGLE_TAP" -> { }
|
||||||
|
"CENTER_DOUBLE_TAP" -> { showContents(R.id.btn_torrent) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
|
||||||
|
Blog.LOGE("keyEvent >>>>> dispatchTouchEvent ${ev}")
|
||||||
|
if (ev?.device?.name?.contains("JX-05") == true) {
|
||||||
|
// 리모컨 이벤트인 경우 제스처 디텍터에 위임
|
||||||
|
if (remoteGestureDetector.onTouchEvent(ev)) {
|
||||||
|
return true // 앱의 다른 터치 로직(GeckoView 등)으로 전파되지 않도록 차단
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return super.dispatchTouchEvent(ev)
|
||||||
|
}
|
||||||
|
|
||||||
override fun dispatchTrackballEvent(event: MotionEvent?): Boolean {
|
override fun dispatchTrackballEvent(event: MotionEvent?): Boolean {
|
||||||
|
Blog.LOGE("keyEvent >>>>> dispatchTrackballEvent ${event}")
|
||||||
return super.dispatchTrackballEvent(event)
|
return super.dispatchTrackballEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean {
|
override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean {
|
||||||
|
Blog.LOGE("keyEvent >>>>> dispatchKeyShortcutEvent ${event}")
|
||||||
return super.dispatchKeyShortcutEvent(event)
|
return super.dispatchKeyShortcutEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onClickCenterButton() {
|
|
||||||
WorkersDb.getRealm().apply {
|
|
||||||
writeBlocking {
|
|
||||||
delete(
|
|
||||||
query<RssData>()
|
|
||||||
.query("pubDate < $0",
|
|
||||||
beforeDay(28)
|
|
||||||
)
|
|
||||||
.query("vote != $0", true).apply {
|
|
||||||
Blog.LOGE("onClickCenterButton DELETE >> ${this.description()}")
|
|
||||||
}.find()
|
|
||||||
)
|
|
||||||
var ddd = copyFromRealm(WorkersDb.getRssQuery("", RssDataType.getExcAdt(),false).limit(100).query("read == $0", 0).query("vote != $0", true).apply {
|
|
||||||
Blog.LOGE("onClickCenterButton SELECT >> ${this.description()}")
|
|
||||||
}.find()).map { it.originPage() }
|
|
||||||
var origin = ddd.first()
|
|
||||||
var jjjj = hashSetOf<String>()
|
|
||||||
jjjj.addAll(ddd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
|
override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
|
||||||
|
Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}")
|
||||||
if (ev?.device?.name?.contains("BLE-M3") == true) {
|
if (ev?.device?.name?.contains("BLE-M3") == true) {
|
||||||
Blog.LOGE("keyEvent >>>>> dispatchGenericMotionEvent ${ev}")
|
|
||||||
ev?.action?.let { action ->
|
ev?.action?.let { action ->
|
||||||
when(action) {
|
when(action) {
|
||||||
MotionEvent.ACTION_HOVER_ENTER -> {
|
MotionEvent.ACTION_HOVER_ENTER -> {
|
||||||
@ -267,6 +378,27 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
}
|
}
|
||||||
return super.dispatchGenericMotionEvent(ev)
|
return super.dispatchGenericMotionEvent(ev)
|
||||||
}
|
}
|
||||||
|
fun onClickCenterButton() {
|
||||||
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
delete(
|
||||||
|
query<RssData>()
|
||||||
|
.query("pubDate < $0",
|
||||||
|
beforeDay(28)
|
||||||
|
)
|
||||||
|
.query("vote != $0", true).apply {
|
||||||
|
Blog.LOGE("onClickCenterButton DELETE >> ${this.description()}")
|
||||||
|
}.find()
|
||||||
|
)
|
||||||
|
var ddd = copyFromRealm(WorkersDb.getRssQuery("", RssDataType.getExcAdt(),false).limit(100).query("read == $0", 0).query("vote != $0", true).apply {
|
||||||
|
Blog.LOGE("onClickCenterButton SELECT >> ${this.description()}")
|
||||||
|
}.find()).map { it.originPage() }
|
||||||
|
var origin = ddd.first()
|
||||||
|
var jjjj = hashSetOf<String>()
|
||||||
|
jjjj.addAll(ddd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun floatClick(v : View) {
|
fun floatClick(v : View) {
|
||||||
showContents(v.id)
|
showContents(v.id)
|
||||||
@ -475,6 +607,7 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
private fun handleBackPress() {
|
private fun handleBackPress() {
|
||||||
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
|
||||||
override fun handleOnBackPressed() {
|
override fun handleOnBackPressed() {
|
||||||
|
Blog.LOGE("handleBackPress")
|
||||||
val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
|
val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
|
||||||
if (currentFragment == null) showContents(R.id.close)
|
if (currentFragment == null) showContents(R.id.close)
|
||||||
when(currentFragment) {
|
when(currentFragment) {
|
||||||
@ -499,7 +632,7 @@ open class NeoRssActivity : CommonActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// val experimentDelegate = object : ExperimentDelegate {
|
// val experimentDelegate = object : ExperimentDelegate {
|
||||||
// override fun onGetExperimentFeature(feature: String): GeckoResult<JSONObject?> {
|
// override fun onGetExperimentFeature(feature: String): GeckoResult<JSONObject?> {
|
||||||
// Blog.LOGE("onGetExperimentFeature $feature")
|
// Blog.LOGE("onGetExperimentFeature $feature")
|
||||||
// return super.onGetExperimentFeature(feature)
|
// return super.onGetExperimentFeature(feature)
|
||||||
|
|||||||
@ -45,6 +45,7 @@ import androidx.recyclerview.widget.DividerItemDecoration
|
|||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import bums.lunatic.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.common.RemoteGestureFragment
|
||||||
import bums.lunatic.launcher.common.letTrue
|
import bums.lunatic.launcher.common.letTrue
|
||||||
import bums.lunatic.launcher.databinding.LauncherHomeBinding
|
import bums.lunatic.launcher.databinding.LauncherHomeBinding
|
||||||
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
import bums.lunatic.launcher.helpers.Constants.Companion.PREFS_SETTINGS
|
||||||
@ -83,7 +84,7 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
|
||||||
internal class RssHome : Fragment() , KeyEventHandler {
|
internal class RssHome : RemoteGestureFragment() , KeyEventHandler {
|
||||||
|
|
||||||
lateinit var binding: LauncherHomeBinding
|
lateinit var binding: LauncherHomeBinding
|
||||||
private lateinit var fragManager: FragmentManager
|
private lateinit var fragManager: FragmentManager
|
||||||
@ -95,6 +96,75 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
var lastedFinishedPageUrl: String = ""
|
var lastedFinishedPageUrl: String = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun doubleCount(isDouble : Boolean) = if(isDouble) {8}else{1}
|
||||||
|
|
||||||
|
override fun onRemoteUp(isDouble : Boolean) {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.pageUp()
|
||||||
|
} else {
|
||||||
|
moveSelection(doubleCount(isDouble) * -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteDown(isDouble : Boolean) {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.pageDown()
|
||||||
|
} else {
|
||||||
|
moveSelection(doubleCount(isDouble) * +1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteLeft(isDouble : Boolean) {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
doNextPage()
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteRight(isDouble : Boolean) {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
binding.lunaticBrowser.geckoWeb.goBack()
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteCenterClick() {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
vote()
|
||||||
|
} else {
|
||||||
|
if (selectedIndex > -1) {
|
||||||
|
openGecko(lasted.get(selectedIndex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteCenterDoubleClick() {
|
||||||
|
if (binding.lunaticBrowser.isVisible) {
|
||||||
|
binding.lunaticBrowser.visibility = View.GONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var selectedIndex = -1
|
||||||
|
private fun moveSelection(delta: Int) {
|
||||||
|
if (lasted.isEmpty()) return
|
||||||
|
|
||||||
|
// 인덱스 갱신
|
||||||
|
val nextIndex = selectedIndex + delta
|
||||||
|
if (nextIndex in 0 until lasted.size) {
|
||||||
|
val oldIndex = selectedIndex
|
||||||
|
selectedIndex = nextIndex
|
||||||
|
|
||||||
|
// 1. 이전 선택된 아이템 UI 초기화, 2. 새 아이템 UI 강조
|
||||||
|
mRssAdapter.notifyItemChanged(oldIndex)
|
||||||
|
mRssAdapter.selectedIndex = selectedIndex
|
||||||
|
mRssAdapter.notifyItemChanged(selectedIndex)
|
||||||
|
|
||||||
|
// 3. 해당 위치로 부드럽게 스크롤
|
||||||
|
binding.infoList.smoothScrollToPosition(selectedIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val commandHandler = Handler(Looper.getMainLooper())
|
val commandHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
val infoUpdate = Runnable { chooseAdpater() }
|
val infoUpdate = Runnable { chooseAdpater() }
|
||||||
@ -227,7 +297,7 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
binding.lunaticBrowser.geckoWeb.pageDown()
|
binding.lunaticBrowser.geckoWeb.pageDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
|
||||||
}
|
}
|
||||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||||
@ -436,6 +506,7 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
var currentRss : RssData? = null
|
var currentRss : RssData? = null
|
||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
fun openGecko(rssData: RssData? = null) {
|
fun openGecko(rssData: RssData? = null) {
|
||||||
|
lasted.removeIf { it.originPage.equals(currentRss?.originPage) }
|
||||||
binding.layoutRssSummary.root.visibility = View.GONE
|
binding.layoutRssSummary.root.visibility = View.GONE
|
||||||
binding.lunaticBrowser.visibility = View.GONE
|
binding.lunaticBrowser.visibility = View.GONE
|
||||||
binding.lunaticBrowser.setupForRssHome()
|
binding.lunaticBrowser.setupForRssHome()
|
||||||
@ -544,10 +615,10 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
// 1. 상단 바 RssHome 전용 기능 연결
|
// 1. 상단 바 RssHome 전용 기능 연결
|
||||||
browser.binding.btnHome.setOnClickListener {
|
browser.binding.btnHome.setOnClickListener {
|
||||||
// if (binding.lunaticBrowser.isVisible || binding.layoutRssSummary.root.isVisible) {
|
// if (binding.lunaticBrowser.isVisible || binding.layoutRssSummary.root.isVisible) {
|
||||||
binding.lunaticBrowser.visibility = View.GONE
|
binding.lunaticBrowser.visibility = View.GONE
|
||||||
binding.layoutRssSummary.root.visibility = View.GONE
|
binding.layoutRssSummary.root.visibility = View.GONE
|
||||||
// } else {
|
// } else {
|
||||||
queryInfos()
|
queryInfos()
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,7 +714,20 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun vote() {
|
fun vote() {
|
||||||
binding.lunaticBrowser.geckoWeb?.saveMd(true)
|
WorkersDb.getRealm().apply {
|
||||||
|
writeBlocking {
|
||||||
|
currentRss?.originPage?.let {
|
||||||
|
val result = query<RssData>().query("originPage == $0", it).find()
|
||||||
|
if (result.size > 0) {
|
||||||
|
result.forEach {
|
||||||
|
it.vote = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doNextPage()
|
||||||
|
// binding.lunaticBrowser.geckoWeb?.saveMd(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokiFragment 또는 GeckoView를 사용하는 프래그먼트 내부
|
// TokiFragment 또는 GeckoView를 사용하는 프래그먼트 내부
|
||||||
@ -663,19 +747,20 @@ internal class RssHome : Fragment() , KeyEventHandler {
|
|||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
fun doNextPage() {
|
fun doNextPage() {
|
||||||
currentRss?.originPage.let {
|
// currentRss?.originPage.let {
|
||||||
WorkersDb.getRealm().apply {
|
// WorkersDb.getRealm().apply {
|
||||||
writeBlocking {
|
// writeBlocking {
|
||||||
val result = query<RssData>().query(
|
// val result = query<RssData>().query(
|
||||||
if (imageView) "thumbnail == $0" else "originPage == $0",
|
// if (imageView) "thumbnail == $0" else "originPage == $0",
|
||||||
it
|
// it
|
||||||
).find()
|
// ).find()
|
||||||
if (result.size > 0) {
|
// if (result.size > 0) {
|
||||||
result.forEach { it.read = it.read + nomoreShowCount }
|
// result.forEach { it.read = it.read + nomoreShowCount }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
openGecko(randomOrNull())
|
openGecko(randomOrNull())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ package bums.lunatic.launcher.home.adapters
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.Color
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -81,7 +82,7 @@ internal class RssItemAdapter (
|
|||||||
return rssDataItemLis.size
|
return rssDataItemLis.size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var selectedIndex = -1
|
||||||
val mSimpleFingerGestures = SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{
|
val mSimpleFingerGestures = SimpleFingerGestures(omfgl = object : SimpleFingerGestures.OnFingerGestureListener{
|
||||||
|
|
||||||
override fun onSwipeUp(
|
override fun onSwipeUp(
|
||||||
@ -171,7 +172,7 @@ internal class RssItemAdapter (
|
|||||||
})
|
})
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
@SuppressLint("SetTextI18n", "ClickableViewAccessibility")
|
||||||
override fun onBindViewHolder(holder: RssHolder, position: Int) {
|
override fun onBindViewHolder(holder: RssHolder, @SuppressLint("RecyclerView") position: Int) {
|
||||||
synchronized(rssDataItemLis) {
|
synchronized(rssDataItemLis) {
|
||||||
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
|
if (rssDataItemLis.isNotEmpty() && rssDataItemLis.size > position) {
|
||||||
try {
|
try {
|
||||||
@ -238,6 +239,11 @@ internal class RssItemAdapter (
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
holder.itemView.setOnLongClickListener(mLongClickListener)
|
holder.itemView.setOnLongClickListener(mLongClickListener)
|
||||||
|
if (position == selectedIndex) {
|
||||||
|
holder.view.root.setBackgroundColor(Color.parseColor("#33FFFFFF")) // 강조색
|
||||||
|
} else {
|
||||||
|
holder.view.root.setBackgroundColor(Color.TRANSPARENT)
|
||||||
|
}
|
||||||
} catch (e: Exception){}
|
} catch (e: Exception){}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import androidx.core.net.toUri
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import bums.lunatic.launcher.R
|
import bums.lunatic.launcher.R
|
||||||
|
import bums.lunatic.launcher.common.RemoteGestureFragment
|
||||||
import bums.lunatic.launcher.databinding.BooktokiBinding
|
import bums.lunatic.launcher.databinding.BooktokiBinding
|
||||||
import bums.lunatic.launcher.home.GeckoWeb
|
import bums.lunatic.launcher.home.GeckoWeb
|
||||||
import bums.lunatic.launcher.home.GeckoWeb.JxEvent
|
import bums.lunatic.launcher.home.GeckoWeb.JxEvent
|
||||||
@ -66,7 +67,7 @@ import java.util.Date
|
|||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
// 기존 BaseToki 및 하위 클래스들을 통합한 단일 클래스
|
// 기존 BaseToki 및 하위 클래스들을 통합한 단일 클래스
|
||||||
class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
class TokiFragment : RemoteGestureFragment(), PagedTextViewInterface,KeyEventHandler {
|
||||||
|
|
||||||
// --- Configuration Properties (Arguments에서 로드) ---
|
// --- Configuration Properties (Arguments에서 로드) ---
|
||||||
private lateinit var contentsType: String
|
private lateinit var contentsType: String
|
||||||
@ -101,7 +102,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
var canGoBack: Boolean? = null
|
var canGoBack: Boolean? = null
|
||||||
protected lateinit var binding: BooktokiBinding
|
protected lateinit var binding: BooktokiBinding
|
||||||
|
|
||||||
var mPort: WebExtension.Port? = null
|
// var mPort: WebExtension.Port? = null
|
||||||
val mPortNam = "browser"
|
val mPortNam = "browser"
|
||||||
val extPath = "resource://android/assets/extensions/my_extension/"
|
val extPath = "resource://android/assets/extensions/my_extension/"
|
||||||
val extId = "messaging@booktoki468.com"
|
val extId = "messaging@booktoki468.com"
|
||||||
@ -230,7 +231,56 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Unified Gesture Implementation ---
|
override fun onRemoteCenterClick() {
|
||||||
|
super.onRemoteCenterClick()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteCenterDoubleClick() {
|
||||||
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
onSwipeDown(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteRight(isDouble : Boolean) {
|
||||||
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
actionNextEvent(isDouble)
|
||||||
|
} else if (contentsType.contains("comics")) {
|
||||||
|
if (contentsType == "comics") sendViewerTouch("right") else actionNextEvent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteLeft(isDouble : Boolean) {
|
||||||
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
actionPrevEvent(isDouble)
|
||||||
|
} else if (contentsType.contains("comics")) {
|
||||||
|
if (contentsType == "comics") sendViewerTouch("left") else actionNextEvent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteDown(isDouble : Boolean) {
|
||||||
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (binding.lunaticBrowser.geckoWeb.scrollState > 0) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
binding.lunaticBrowser.geckoWeb.pageDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoteUp(isDouble : Boolean) {
|
||||||
|
if (binding.pagedLayer.isVisible) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (binding.lunaticBrowser.geckoWeb.scrollState < 0) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
binding.lunaticBrowser.geckoWeb.pageUp()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onTouch(touchArea: TouchArea) {
|
override fun onTouch(touchArea: TouchArea) {
|
||||||
if (!enableGestures) return
|
if (!enableGestures) return
|
||||||
@ -435,7 +485,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
// 일반 WebView라면: webView.onPause() 및 webView.pauseTimers()
|
// 일반 WebView라면: webView.onPause() 및 webView.pauseTimers()
|
||||||
} else {
|
} else {
|
||||||
// 💡 다시 나타날 때: 다시 시작
|
// 💡 다시 나타날 때: 다시 시작
|
||||||
// binding.menuWeb?.onResume()
|
binding.lunaticBrowser.geckoWeb?.onResume()
|
||||||
// 일반 WebView라면: webView.onResume() 및 webView.resumeTimers()
|
// 일반 WebView라면: webView.onResume() 및 webView.resumeTimers()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -506,15 +556,15 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
}
|
}
|
||||||
it.setOnGenericMotionListener(mOnGenericMotionListener)
|
it.setOnGenericMotionListener(mOnGenericMotionListener)
|
||||||
it.onPageStopCallback = { success->
|
it.onPageStopCallback = { success->
|
||||||
if (success && mPort != null) {
|
// if (success && mPort != null) {
|
||||||
if (mPort != null) {
|
//// if (mPort != null) {
|
||||||
if (lastedUrl?.contains("youtube.com") == true) {
|
//// if (lastedUrl?.contains("youtube.com") == true) {
|
||||||
|
////
|
||||||
} else {
|
//// } else {
|
||||||
|
////
|
||||||
}
|
//// }
|
||||||
}
|
//// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
it.onPageStartCallback = { url ->
|
it.onPageStartCallback = { url ->
|
||||||
// binding.lunaticBrowser.binding.progress.visibility = VISIBLE
|
// binding.lunaticBrowser.binding.progress.visibility = VISIBLE
|
||||||
@ -564,6 +614,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
it.onPortMessageCallback
|
||||||
it.onLocationChangeCallback = { url ->
|
it.onLocationChangeCallback = { url ->
|
||||||
if (url?.startsWith("about") ?: true) {
|
if (url?.startsWith("about") ?: true) {
|
||||||
|
|
||||||
@ -1282,7 +1333,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
} catch (ex: JSONException) {
|
} catch (ex: JSONException) {
|
||||||
throw RuntimeException(ex)
|
throw RuntimeException(ex)
|
||||||
}
|
}
|
||||||
mPort?.postMessage(message)
|
binding.lunaticBrowser.geckoWeb.mPort?.postMessage(message)
|
||||||
// Blog.LOGD(log = "Successfully opened realm: ${realm.configuration.name}")
|
// Blog.LOGD(log = "Successfully opened realm: ${realm.configuration.name}")
|
||||||
}
|
}
|
||||||
private fun sendViewerTouch(string: String) {
|
private fun sendViewerTouch(string: String) {
|
||||||
@ -1293,8 +1344,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
} catch (ex: JSONException) {
|
} catch (ex: JSONException) {
|
||||||
throw RuntimeException(ex)
|
throw RuntimeException(ex)
|
||||||
}
|
}
|
||||||
Blog.LOGE(Gson().toJson(message))
|
binding.lunaticBrowser.geckoWeb.mPort?.postMessage(message)
|
||||||
mPort?.postMessage(message)
|
|
||||||
}
|
}
|
||||||
fun sendScrollDown(isUp: Boolean) {
|
fun sendScrollDown(isUp: Boolean) {
|
||||||
val message: JSONObject = JSONObject()
|
val message: JSONObject = JSONObject()
|
||||||
@ -1305,7 +1355,7 @@ class TokiFragment : Fragment(), PagedTextViewInterface,KeyEventHandler {
|
|||||||
throw RuntimeException(ex)
|
throw RuntimeException(ex)
|
||||||
}
|
}
|
||||||
Blog.LOGE(Gson().toJson(message))
|
Blog.LOGE(Gson().toJson(message))
|
||||||
mPort?.postMessage(message)
|
binding.lunaticBrowser.geckoWeb.mPort?.postMessage(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun goToHome() {
|
private fun goToHome() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user