This commit is contained in:
lunaticbum 2026-03-12 17:09:35 +09:00
parent be016409d7
commit a72b1778a9
7 changed files with 383 additions and 67 deletions

View File

@ -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));
} }

View File

@ -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
}

View File

@ -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) {

View File

@ -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)

View File

@ -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())
} }

View File

@ -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){}
} }

View File

@ -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() {